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

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 (85) hide show
  1. package/dist/controllers/media.controller.js +0 -2
  2. package/dist/controllers/media.controller.js.map +1 -1
  3. package/dist/helpers/environment.helper.d.ts +0 -1
  4. package/dist/helpers/environment.helper.d.ts.map +1 -1
  5. package/dist/helpers/environment.helper.js +0 -4
  6. package/dist/helpers/environment.helper.js.map +1 -1
  7. package/dist/helpers/model-metadata-helper.service.d.ts +1 -2
  8. package/dist/helpers/model-metadata-helper.service.d.ts.map +1 -1
  9. package/dist/helpers/model-metadata-helper.service.js +2 -6
  10. package/dist/helpers/model-metadata-helper.service.js.map +1 -1
  11. package/dist/helpers/module-metadata-helper.service.js +1 -1
  12. package/dist/helpers/module-metadata-helper.service.js.map +1 -1
  13. package/dist/helpers/solid-registry.d.ts +1 -2
  14. package/dist/helpers/solid-registry.d.ts.map +1 -1
  15. package/dist/helpers/solid-registry.js.map +1 -1
  16. package/dist/index.d.ts +0 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +0 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/repository/scheduled-job.repository.d.ts +2 -2
  21. package/dist/repository/scheduled-job.repository.d.ts.map +1 -1
  22. package/dist/repository/scheduled-job.repository.js +3 -6
  23. package/dist/repository/scheduled-job.repository.js.map +1 -1
  24. package/dist/repository/security-rule.repository.d.ts +2 -2
  25. package/dist/repository/security-rule.repository.d.ts.map +1 -1
  26. package/dist/repository/security-rule.repository.js +3 -6
  27. package/dist/repository/security-rule.repository.js.map +1 -1
  28. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -1
  29. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +5 -7
  30. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -1
  31. package/dist/services/crud-helper.service.d.ts.map +1 -1
  32. package/dist/services/crud-helper.service.js +7 -0
  33. package/dist/services/crud-helper.service.js.map +1 -1
  34. package/dist/services/datasource-introspection.service.d.ts +1 -0
  35. package/dist/services/datasource-introspection.service.d.ts.map +1 -1
  36. package/dist/services/datasource-introspection.service.js +14 -5
  37. package/dist/services/datasource-introspection.service.js.map +1 -1
  38. package/dist/services/model-metadata.service.d.ts.map +1 -1
  39. package/dist/services/model-metadata.service.js +0 -16
  40. package/dist/services/model-metadata.service.js.map +1 -1
  41. package/dist/services/module-metadata.service.d.ts.map +1 -1
  42. package/dist/services/module-metadata.service.js +0 -28
  43. package/dist/services/module-metadata.service.js.map +1 -1
  44. package/dist/subscribers/audit.subscriber.d.ts.map +1 -1
  45. package/dist/subscribers/audit.subscriber.js +2 -8
  46. package/dist/subscribers/audit.subscriber.js.map +1 -1
  47. package/dist/subscribers/computed-entity-field.subscriber.d.ts +0 -8
  48. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  49. package/dist/subscribers/computed-entity-field.subscriber.js +3 -36
  50. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  51. package/dist/subscribers/created-by-updated-by.subscriber.d.ts.map +1 -1
  52. package/dist/subscribers/created-by-updated-by.subscriber.js.map +1 -1
  53. package/dist/subscribers/field-metadata.subscriber.d.ts.map +1 -1
  54. package/dist/subscribers/field-metadata.subscriber.js.map +1 -1
  55. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -1
  56. package/dist/subscribers/scheduled-job.subscriber.js +2 -3
  57. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -1
  58. package/dist/subscribers/security-rule.subscriber.d.ts.map +1 -1
  59. package/dist/subscribers/security-rule.subscriber.js +3 -5
  60. package/dist/subscribers/security-rule.subscriber.js.map +1 -1
  61. package/package.json +1 -1
  62. package/src/controllers/media.controller.ts +1 -1
  63. package/src/helpers/environment.helper.ts +0 -11
  64. package/src/helpers/model-metadata-helper.service.ts +2 -7
  65. package/src/helpers/module-metadata-helper.service.ts +1 -1
  66. package/src/helpers/solid-registry.ts +1 -7
  67. package/src/index.ts +0 -1
  68. package/src/repository/scheduled-job.repository.ts +4 -10
  69. package/src/repository/security-rule.repository.ts +4 -10
  70. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +5 -11
  71. package/src/services/crud-helper.service.ts +7 -0
  72. package/src/services/datasource-introspection.service.ts +18 -5
  73. package/src/services/model-metadata.service.ts +0 -22
  74. package/src/services/module-metadata.service.ts +0 -36
  75. package/src/subscribers/audit.subscriber.ts +2 -11
  76. package/src/subscribers/computed-entity-field.subscriber.ts +6 -63
  77. package/src/subscribers/created-by-updated-by.subscriber.ts +0 -3
  78. package/src/subscribers/field-metadata.subscriber.ts +0 -3
  79. package/src/subscribers/scheduled-job.subscriber.ts +2 -3
  80. package/src/subscribers/security-rule.subscriber.ts +3 -8
  81. package/dist/helpers/nodemon-heartbeat.d.ts +0 -5
  82. package/dist/helpers/nodemon-heartbeat.d.ts.map +0 -1
  83. package/dist/helpers/nodemon-heartbeat.js +0 -67
  84. package/dist/helpers/nodemon-heartbeat.js.map +0 -1
  85. package/src/helpers/nodemon-heartbeat.ts +0 -59
@@ -1 +1 @@
1
- {"version":3,"file":"created-by-updated-by.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/created-by-updated-by.subscriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmD;AACnD,6CAAmD;AACnD,iFAA6E;AAC7E,qCAA0F;AAInF,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAErC,YAEqB,iBAA6B,EAC7B,qBAA4C;QAD5C,sBAAiB,GAAjB,iBAAiB,CAAY;QAC7B,0BAAqB,GAArB,qBAAqB,CAAuB;IAGjE,CAAC;IAED,gBAAgB,CAAC,UAAsB;QACnC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAuB;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAuB;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,KAA0C,EAAE,QAAiB;QACtF,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,CAAC;QACzE,IAAI,CAAC,qBAAqB,EAAE,CAAC;YACzB,OAAO;QACX,CAAC;QAcD,IAAI,QAAQ,EAAE,CAAC;YACX,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;YACpD,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;QACxD,CAAC;aACI,CAAC;YACF,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;QACxD,CAAC;IACL,CAAC;CASJ,CAAA;AA7DY,oEAA4B;uCAA5B,4BAA4B;IAFxC,IAAA,mBAAU,EAAC,EAAE,KAAK,EAAE,cAAK,CAAC,SAAS,EAAE,CAAC;IAK9B,WAAA,IAAA,0BAAgB,GAAE,CAAA;qCACiB,oBAAU;QACN,+CAAqB;GALxD,4BAA4B,CA6DxC","sourcesContent":["import { Injectable, Scope } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport { RequestContextService } from \"src/services/request-context.service\";\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable({ scope: Scope.TRANSIENT })\n// @EventSubscriber()\nexport class CreatedByUpdatedBySubscriber implements EntitySubscriberInterface {\n private dataSource: DataSource;\n constructor(\n @InjectDataSource()\n private readonly defaultDataSource: DataSource,\n private readonly requestContextService: RequestContextService,\n ) {\n // this.dataSource.subscribers.push(this);\n }\n\n bindToDataSource(dataSource: DataSource) {\n this.dataSource = dataSource;\n this.dataSource.subscribers.push(this);\n }\n\n async beforeInsert(event: InsertEvent<any>) {\n await this.stampUserField(event, true);\n }\n\n async beforeUpdate(event: UpdateEvent<any>) {\n await this.stampUserField(event, false);\n }\n\n private async stampUserField(event: InsertEvent<any> | UpdateEvent<any>, isInsert: boolean) {\n if (!event.entity) {\n return;\n }\n // Get the current active user details from the request context\n const activeUserOrUndefined = this.requestContextService.getActiveUser();\n if (!activeUserOrUndefined) {\n return;\n }\n\n // NOTE: If re-enabling loadUser below, query via `event.queryRunner.manager`, NOT\n // `this.defaultDataSource.getRepository(...)`. A second connection opened mid-transaction\n // deadlocks single-threaded engines (PGlite).\n // const loadedUser = await this.loadUser(activeUserOrUndefined as unknown as ActiveUserData);\n // if (isInsert) {\n // event.entity.createdBy = loadedUser?.id;\n // event.entity.updatedBy = loadedUser?.id; // For insert, we set both createdBy and updatedBy to the same user\n // }\n // else {\n // event.entity.updatedBy = loadedUser?.id;\n // }\n\n if (isInsert) {\n event.entity.createdBy = activeUserOrUndefined?.sub;\n event.entity.updatedBy = activeUserOrUndefined?.sub; // For insert, we set both createdBy and updatedBy to the same user\n }\n else {\n event.entity.updatedBy = activeUserOrUndefined?.sub;\n }\n }\n\n // private async loadUser(activeUser: ActiveUserData): Promise<User> {\n // const userRepo = this.defaultDataSource.getRepository(User); // Assuming 'User' is the entity name for users in your application\n // const loadedUser = await userRepo.findOne({\n // where: { id: activeUser.sub }, // Assuming 'sub' is the user ID in the JWT token\n // });\n // return loadedUser;;\n // }\n}"]}
1
+ {"version":3,"file":"created-by-updated-by.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/created-by-updated-by.subscriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmD;AACnD,6CAAmD;AACnD,iFAA6E;AAC7E,qCAA0F;AAInF,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAErC,YAEqB,iBAA6B,EAC7B,qBAA4C;QAD5C,sBAAiB,GAAjB,iBAAiB,CAAY;QAC7B,0BAAqB,GAArB,qBAAqB,CAAuB;IAGjE,CAAC;IAED,gBAAgB,CAAC,UAAsB;QACnC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAuB;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAuB;QACtC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,KAA0C,EAAE,QAAiB;QACtF,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QAED,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC,aAAa,EAAE,CAAC;QACzE,IAAI,CAAC,qBAAqB,EAAE,CAAC;YACzB,OAAO;QACX,CAAC;QAWD,IAAI,QAAQ,EAAE,CAAC;YACX,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;YACpD,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;QACxD,CAAC;aACI,CAAC;YACF,KAAK,CAAC,MAAM,CAAC,SAAS,GAAG,qBAAqB,EAAE,GAAG,CAAC;QACxD,CAAC;IACL,CAAC;CASJ,CAAA;AA1DY,oEAA4B;uCAA5B,4BAA4B;IAFxC,IAAA,mBAAU,EAAC,EAAE,KAAK,EAAE,cAAK,CAAC,SAAS,EAAE,CAAC;IAK9B,WAAA,IAAA,0BAAgB,GAAE,CAAA;qCACiB,oBAAU;QACN,+CAAqB;GALxD,4BAA4B,CA0DxC","sourcesContent":["import { Injectable, Scope } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport { RequestContextService } from \"src/services/request-context.service\";\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable({ scope: Scope.TRANSIENT })\n// @EventSubscriber()\nexport class CreatedByUpdatedBySubscriber implements EntitySubscriberInterface {\n private dataSource: DataSource;\n constructor(\n @InjectDataSource()\n private readonly defaultDataSource: DataSource,\n private readonly requestContextService: RequestContextService,\n ) {\n // this.dataSource.subscribers.push(this);\n }\n\n bindToDataSource(dataSource: DataSource) {\n this.dataSource = dataSource;\n this.dataSource.subscribers.push(this);\n }\n\n async beforeInsert(event: InsertEvent<any>) {\n await this.stampUserField(event, true);\n }\n\n async beforeUpdate(event: UpdateEvent<any>) {\n await this.stampUserField(event, false);\n }\n\n private async stampUserField(event: InsertEvent<any> | UpdateEvent<any>, isInsert: boolean) {\n if (!event.entity) {\n return;\n }\n // Get the current active user details from the request context\n const activeUserOrUndefined = this.requestContextService.getActiveUser();\n if (!activeUserOrUndefined) {\n return;\n }\n\n // const loadedUser = await this.loadUser(activeUserOrUndefined as unknown as ActiveUserData);\n // if (isInsert) {\n // event.entity.createdBy = loadedUser?.id;\n // event.entity.updatedBy = loadedUser?.id; // For insert, we set both createdBy and updatedBy to the same user\n // }\n // else {\n // event.entity.updatedBy = loadedUser?.id;\n // }\n\n if (isInsert) {\n event.entity.createdBy = activeUserOrUndefined?.sub;\n event.entity.updatedBy = activeUserOrUndefined?.sub; // For insert, we set both createdBy and updatedBy to the same user\n }\n else {\n event.entity.updatedBy = activeUserOrUndefined?.sub;\n }\n }\n\n // private async loadUser(activeUser: ActiveUserData): Promise<User> {\n // const userRepo = this.defaultDataSource.getRepository(User); // Assuming 'User' is the entity name for users in your application\n // const loadedUser = await userRepo.findOne({\n // where: { id: activeUser.sub }, // Assuming 'sub' is the user ID in the JWT token\n // });\n // return loadedUser;;\n // }\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"field-metadata.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/field-metadata.subscriber.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAgC,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAGlE,qBACa,uBAAwB,YAAW,yBAAyB,CAAC,aAAa,CAAC;IAKpF,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAIhD,UAAU,EAAE,UAAU;IAKzC,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAgCpE"}
1
+ {"version":3,"file":"field-metadata.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/field-metadata.subscriber.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAgC,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAGlE,qBACa,uBAAwB,YAAW,yBAAyB,CAAC,aAAa,CAAC;IAKpF,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJ7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;gBAIhD,UAAU,EAAE,UAAU;IAKzC,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CA6BpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"field-metadata.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/field-metadata.subscriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAuE;AACvE,6CAAmD;AAEnD,qCAA2G;AAC3G,6EAAkE;AAI3D,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAGlC,YAEE,UAAuC;QAAtB,eAAU,GAAV,UAAU,CAAY;QAJxB,WAAM,GAAG,IAAI,eAAM,CAAC,yBAAuB,CAAC,IAAI,CAAC,CAAC;QAMjE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,QAAQ;QACN,OAAO,qCAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAiC;IA+BnD,CAAC;CACF,CAAA;AA9CY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,GAAE,CAAA;qCACU,oBAAU;GAL9B,uBAAuB,CA8CnC","sourcesContent":["import { Injectable, Logger, NotFoundException } from '@nestjs/common';\nimport { InjectDataSource } from '@nestjs/typeorm';\nimport { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';\nimport { DataSource, EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent } from 'typeorm';\nimport { FieldMetadata } from '../entities/field-metadata.entity';\n\n// @EventSubscriber()\n@Injectable()\nexport class FieldMetadataSubscriber implements EntitySubscriberInterface<FieldMetadata> {\n private readonly logger = new Logger(FieldMetadataSubscriber.name);\n\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return FieldMetadata;\n }\n\n async afterUpdate(event: UpdateEvent<FieldMetadata>): Promise<void> {\n // NOTE: If re-enabling the block below, use `event.queryRunner.manager` (the active\n // transaction's connection), NOT `this.dataSource.getRepository(...)`. A second\n // connection opened here mid-transaction deadlocks single-threaded engines (PGlite).\n // If a field of type relation.many-to-one is marked for removal, and this field had an inverse relation created \n // It means there is a field of type relation.one-to-many in the co-model, which needs to be removed\n // if (event.entity && event.entity.isMarkedForRemoval && event.entity.type === 'relation' && event.entity.relationType === 'many-to-one' && event.entity.relationCreateInverse === true) {\n // const relationCoModelSingularName = event.entity.relationCoModelSingularName;\n // const relationCoModelFieldName = event.entity.relationCoModelFieldName;\n\n // // Load the field metadata for the co-model.\n // const coModelFieldMetadata = await this.dataSource\n // .getRepository(FieldMetadata)\n // .findOne({\n // where: {\n // name: relationCoModelFieldName,\n // type: 'relation',\n // relationType: 'one-to-many',\n // model: {\n // singularName: relationCoModelSingularName\n // }\n // },\n // });\n\n // // Mark the co-model isMarkedForRemoval field for removal.\n // if (coModelFieldMetadata) {\n // coModelFieldMetadata.isMarkedForRemoval = true;\n // await this.dataSource.getRepository(FieldMetadata).save(coModelFieldMetadata);\n // this.logger.debug(`Marked field ${coModelFieldMetadata.name} in model ${relationCoModelSingularName} for removal.`);\n // }\n // }\n }\n}\n"]}
1
+ {"version":3,"file":"field-metadata.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/field-metadata.subscriber.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAuE;AACvE,6CAAmD;AAEnD,qCAA2G;AAC3G,6EAAkE;AAI3D,IAAM,uBAAuB,+BAA7B,MAAM,uBAAuB;IAGlC,YAEE,UAAuC;QAAtB,eAAU,GAAV,UAAU,CAAY;QAJxB,WAAM,GAAG,IAAI,eAAM,CAAC,yBAAuB,CAAC,IAAI,CAAC,CAAC;QAMjE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED,QAAQ;QACN,OAAO,qCAAa,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAiC;IA4BnD,CAAC;CACF,CAAA;AA3CY,0DAAuB;kCAAvB,uBAAuB;IADnC,IAAA,mBAAU,GAAE;IAKR,WAAA,IAAA,0BAAgB,GAAE,CAAA;qCACU,oBAAU;GAL9B,uBAAuB,CA2CnC","sourcesContent":["import { Injectable, Logger, NotFoundException } from '@nestjs/common';\nimport { InjectDataSource } from '@nestjs/typeorm';\nimport { ModelMetadataHelperService } from 'src/helpers/model-metadata-helper.service';\nimport { DataSource, EntitySubscriberInterface, EventSubscriber, InsertEvent, UpdateEvent } from 'typeorm';\nimport { FieldMetadata } from '../entities/field-metadata.entity';\n\n// @EventSubscriber()\n@Injectable()\nexport class FieldMetadataSubscriber implements EntitySubscriberInterface<FieldMetadata> {\n private readonly logger = new Logger(FieldMetadataSubscriber.name);\n\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return FieldMetadata;\n }\n\n async afterUpdate(event: UpdateEvent<FieldMetadata>): Promise<void> {\n // If a field of type relation.many-to-one is marked for removal, and this field had an inverse relation created \n // It means there is a field of type relation.one-to-many in the co-model, which needs to be removed\n // if (event.entity && event.entity.isMarkedForRemoval && event.entity.type === 'relation' && event.entity.relationType === 'many-to-one' && event.entity.relationCreateInverse === true) {\n // const relationCoModelSingularName = event.entity.relationCoModelSingularName;\n // const relationCoModelFieldName = event.entity.relationCoModelFieldName;\n\n // // Load the field metadata for the co-model.\n // const coModelFieldMetadata = await this.dataSource\n // .getRepository(FieldMetadata)\n // .findOne({\n // where: {\n // name: relationCoModelFieldName,\n // type: 'relation',\n // relationType: 'one-to-many',\n // model: {\n // singularName: relationCoModelSingularName\n // }\n // },\n // });\n\n // // Mark the co-model isMarkedForRemoval field for removal.\n // if (coModelFieldMetadata) {\n // coModelFieldMetadata.isMarkedForRemoval = true;\n // await this.dataSource.getRepository(FieldMetadata).save(coModelFieldMetadata);\n // this.logger.debug(`Marked field ${coModelFieldMetadata.name} in model ${relationCoModelSingularName} for removal.`);\n // }\n // }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-job.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EACL,UAAU,EAEV,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,qBACa,sBACX,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAW5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAZnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAGlE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAIlC;gBAGqC,UAAU,EAAE,UAAU,EAC1C,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAK3D,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAQ5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAqB5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;YAIpC,cAAc;YAkDd,cAAc;CA0D7B"}
1
+ {"version":3,"file":"scheduled-job.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EACL,UAAU,EAEV,yBAAyB,EACzB,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,SAAS,CAAC;AAEjB,qBACa,sBACX,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAW5B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAZnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;IAGlE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAIlC;gBAGqC,UAAU,EAAE,UAAU,EAC1C,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAK3D,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAQ5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAqB5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;YAIpC,cAAc;YAkDd,cAAc;CA0D7B"}
@@ -52,7 +52,6 @@ const typeorm_1 = require("@nestjs/typeorm");
52
52
  const fs = __importStar(require("fs/promises"));
53
53
  const module_metadata_entity_1 = require("../entities/module-metadata.entity");
54
54
  const scheduled_job_entity_1 = require("../entities/scheduled-job.entity");
55
- const environment_helper_1 = require("../helpers/environment.helper");
56
55
  const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
57
56
  const scheduled_job_repository_1 = require("../repository/scheduled-job.repository");
58
57
  const typeorm_2 = require("typeorm");
@@ -102,7 +101,7 @@ let ScheduledJobSubscriber = ScheduledJobSubscriber_1 = class ScheduledJobSubscr
102
101
  this.logger.error(`Module metadata not found for scheduled job with ID ${jobEntity?.id}`);
103
102
  return;
104
103
  }
105
- const moduleMetadataRepo = ((0, environment_helper_1.isEmbeddedDb)() ? event.queryRunner.manager : this.dataSource).getRepository(module_metadata_entity_1.ModuleMetadata);
104
+ const moduleMetadataRepo = this.dataSource.getRepository(module_metadata_entity_1.ModuleMetadata);
106
105
  const populatedModuleMetadata = await moduleMetadataRepo.findOne({
107
106
  where: { id: moduleMetadata.id },
108
107
  });
@@ -151,7 +150,7 @@ let ScheduledJobSubscriber = ScheduledJobSubscriber_1 = class ScheduledJobSubscr
151
150
  }
152
151
  const jobName = jobEntity.scheduleName;
153
152
  const existingIndex = metaData.scheduledJobs.findIndex((job) => job.scheduleName === jobName);
154
- const jobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob, (0, environment_helper_1.isEmbeddedDb)() ? entityManager : undefined);
153
+ const jobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob);
155
154
  const { moduleId, lastRunAt, nextRunAt, ...dtoToWrite } = jobDto;
156
155
  if (existingIndex !== -1) {
157
156
  metaData.scheduledJobs[existingIndex] = dtoToWrite;
@@ -1 +1 @@
1
- {"version":3,"file":"scheduled-job.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from \"fs/promises\";\nimport { CreateScheduledJobDto } from \"src/dtos/create-scheduled-job.dto\";\nimport { ModuleMetadata } from \"src/entities/module-metadata.entity\";\nimport { ScheduledJob } from \"src/entities/scheduled-job.entity\";\nimport { isEmbeddedDb } from \"src/helpers/environment.helper\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { ScheduledJobRepository } from \"src/repository/scheduled-job.repository\";\nimport {\n DataSource,\n EntityManager,\n EntitySubscriberInterface,\n InsertEvent,\n RemoveEvent,\n UpdateEvent,\n} from \"typeorm\";\n\n@Injectable()\nexport class ScheduledJobSubscriber\n implements EntitySubscriberInterface<ScheduledJob> {\n private readonly logger = new Logger(ScheduledJobSubscriber.name);\n\n /** Fields that, when changed (and only these changed), should NOT trigger metadata update. */\n private readonly ignoredUpdateFields: Array<keyof ScheduledJob | string> = [\n \"lastRunAt\",\n \"nextRunAt\",\n \"updatedAt\",\n ];\n\n constructor(\n @InjectDataSource() private readonly dataSource: DataSource,\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly scheduledJobRepo: ScheduledJobRepository\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return ScheduledJob;\n }\n\n async afterInsert(event: InsertEvent<ScheduledJob>) {\n if (!event.entity) {\n this.logger.debug('No schedule Job entity found in the afterInsert method');\n return;\n }\n await this.updateMetadata(event.entity, event.queryRunner.manager);\n }\n\n async afterUpdate(event: UpdateEvent<ScheduledJob>) {\n if (!event.databaseEntity) {\n this.logger.debug('No schedule Job entity found in the afterUpdate method');\n return;\n }\n\n // get hold of the changed field names \n const changedProps = (event.updatedColumns ?? []).map((c) => c.propertyName);\n\n // Decide whether to skip: only skip when *all* changed fields are in the ignore list\n const onlyIgnoredChanged = changedProps.every((p) => this.ignoredUpdateFields.includes(p));\n\n if (onlyIgnoredChanged) {\n this.logger.debug(`Skipping metadata update for ScheduledJob#${(event.databaseEntity as ScheduledJob).id}; only ignored fields changed: ${changedProps.join(\", \")}`\n );\n return;\n }\n\n await this.updateMetadata(event.databaseEntity, event.queryRunner.manager);\n }\n\n async afterRemove(event: RemoveEvent<ScheduledJob>) {\n await this.removeMetadata(event);\n }\n\n private async removeMetadata(event: RemoveEvent<ScheduledJob>) {\n const jobEntity = event.entity;\n const moduleMetadata = jobEntity?.module;\n\n if (!moduleMetadata) {\n this.logger.error(\n `Module metadata not found for scheduled job with ID ${jobEntity?.id}`\n );\n return;\n }\n\n const moduleMetadataRepo = (isEmbeddedDb() ? event.queryRunner.manager : this.dataSource).getRepository(ModuleMetadata);\n const populatedModuleMetadata = await moduleMetadataRepo.findOne({\n where: { id: moduleMetadata.id },\n });\n\n if (!populatedModuleMetadata) {\n this.logger.error(\n `Could not find ModuleMetadata with ID ${moduleMetadata.id}`\n );\n return;\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedModuleMetadata.name\n );\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n if (existingIndex !== -1) {\n metaData.scheduledJobs.splice(existingIndex, 1);\n this.logger.log(`Removed scheduled job ${jobName} from metadata`);\n }\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n\n private async updateMetadata(jobEntity: ScheduledJob, entityManager: EntityManager) {\n // populate the job with its relation\n const populatedScheduleJob = await entityManager.findOne(ScheduledJob, {\n where: { id: jobEntity.id },\n relations: ['module'],\n });\n\n if (!populatedScheduleJob) {\n throw new Error(`ScheduleJob not found for id ${jobEntity.id}`);\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedScheduleJob.module?.name\n );\n\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n\n // Ensure scheduledJobs exists\n if (!metaData.scheduledJobs) {\n metaData.scheduledJobs = [];\n }\n\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n // Insert or update job in metadata\n const jobDto: CreateScheduledJobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob as ScheduledJob, isEmbeddedDb() ? entityManager : undefined);\n // Strip out bookkeeping/runtime fields before persisting to metadata JSON.\n const {\n moduleId,\n lastRunAt,\n nextRunAt,\n ...dtoToWrite\n } = jobDto;\n if (existingIndex !== -1) {\n metaData.scheduledJobs[existingIndex] = dtoToWrite;\n this.logger.log(`Updated scheduled job ${jobName} in metadata`);\n } else {\n metaData.scheduledJobs.push(dtoToWrite);\n this.logger.log(`Added scheduled job ${jobName} to metadata`);\n }\n\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n}\n"]}
1
+ {"version":3,"file":"scheduled-job.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/scheduled-job.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from \"@nestjs/common\";\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from \"fs/promises\";\nimport { CreateScheduledJobDto } from \"src/dtos/create-scheduled-job.dto\";\nimport { ModuleMetadata } from \"src/entities/module-metadata.entity\";\nimport { ScheduledJob } from \"src/entities/scheduled-job.entity\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { ScheduledJobRepository } from \"src/repository/scheduled-job.repository\";\nimport {\n DataSource,\n EntityManager,\n EntitySubscriberInterface,\n InsertEvent,\n RemoveEvent,\n UpdateEvent,\n} from \"typeorm\";\n\n@Injectable()\nexport class ScheduledJobSubscriber\n implements EntitySubscriberInterface<ScheduledJob> {\n private readonly logger = new Logger(ScheduledJobSubscriber.name);\n\n /** Fields that, when changed (and only these changed), should NOT trigger metadata update. */\n private readonly ignoredUpdateFields: Array<keyof ScheduledJob | string> = [\n \"lastRunAt\",\n \"nextRunAt\",\n \"updatedAt\",\n ];\n\n constructor(\n @InjectDataSource() private readonly dataSource: DataSource,\n private readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n private readonly scheduledJobRepo: ScheduledJobRepository\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return ScheduledJob;\n }\n\n async afterInsert(event: InsertEvent<ScheduledJob>) {\n if (!event.entity) {\n this.logger.debug('No schedule Job entity found in the afterInsert method');\n return;\n }\n await this.updateMetadata(event.entity, event.queryRunner.manager);\n }\n\n async afterUpdate(event: UpdateEvent<ScheduledJob>) {\n if (!event.databaseEntity) {\n this.logger.debug('No schedule Job entity found in the afterUpdate method');\n return;\n }\n\n // get hold of the changed field names \n const changedProps = (event.updatedColumns ?? []).map((c) => c.propertyName);\n\n // Decide whether to skip: only skip when *all* changed fields are in the ignore list\n const onlyIgnoredChanged = changedProps.every((p) => this.ignoredUpdateFields.includes(p));\n\n if (onlyIgnoredChanged) {\n this.logger.debug(`Skipping metadata update for ScheduledJob#${(event.databaseEntity as ScheduledJob).id}; only ignored fields changed: ${changedProps.join(\", \")}`\n );\n return;\n }\n\n await this.updateMetadata(event.databaseEntity, event.queryRunner.manager);\n }\n\n async afterRemove(event: RemoveEvent<ScheduledJob>) {\n await this.removeMetadata(event);\n }\n\n private async removeMetadata(event: RemoveEvent<ScheduledJob>) {\n const jobEntity = event.entity;\n const moduleMetadata = jobEntity?.module;\n\n if (!moduleMetadata) {\n this.logger.error(\n `Module metadata not found for scheduled job with ID ${jobEntity?.id}`\n );\n return;\n }\n\n const moduleMetadataRepo = this.dataSource.getRepository(ModuleMetadata);\n const populatedModuleMetadata = await moduleMetadataRepo.findOne({\n where: { id: moduleMetadata.id },\n });\n\n if (!populatedModuleMetadata) {\n this.logger.error(\n `Could not find ModuleMetadata with ID ${moduleMetadata.id}`\n );\n return;\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedModuleMetadata.name\n );\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n if (existingIndex !== -1) {\n metaData.scheduledJobs.splice(existingIndex, 1);\n this.logger.log(`Removed scheduled job ${jobName} from metadata`);\n }\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n\n private async updateMetadata(jobEntity: ScheduledJob, entityManager: EntityManager) {\n // populate the job with its relation\n const populatedScheduleJob = await entityManager.findOne(ScheduledJob, {\n where: { id: jobEntity.id },\n relations: ['module'],\n });\n\n if (!populatedScheduleJob) {\n throw new Error(`ScheduleJob not found for id ${jobEntity.id}`);\n }\n const filePath =\n await this.moduleMetadataHelperService.getModuleMetadataFilePath(\n populatedScheduleJob.module?.name\n );\n\n try {\n await fs.access(filePath);\n } catch {\n this.logger.error(`Metadata file not found: ${filePath}`);\n return;\n }\n\n const metaData =\n await this.moduleMetadataHelperService.getModuleMetadataConfiguration(\n filePath\n );\n\n // Ensure scheduledJobs exists\n if (!metaData.scheduledJobs) {\n metaData.scheduledJobs = [];\n }\n\n // Remove, update or insert logic\n const jobName = jobEntity.scheduleName;\n const existingIndex = metaData.scheduledJobs.findIndex(\n (job) => job.scheduleName === jobName\n );\n // Insert or update job in metadata\n const jobDto: CreateScheduledJobDto = await this.scheduledJobRepo.toDto(populatedScheduleJob as ScheduledJob);\n // Strip out bookkeeping/runtime fields before persisting to metadata JSON.\n const {\n moduleId,\n lastRunAt,\n nextRunAt,\n ...dtoToWrite\n } = jobDto;\n if (existingIndex !== -1) {\n metaData.scheduledJobs[existingIndex] = dtoToWrite;\n this.logger.log(`Updated scheduled job ${jobName} in metadata`);\n } else {\n metaData.scheduledJobs.push(dtoToWrite);\n this.logger.log(`Added scheduled job ${jobName} to metadata`);\n }\n\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n this.logger.log(`Updated scheduledJobs in ${filePath}`);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"security-rule.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAEjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1F,qBACa,sBAAuB,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAI9E,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,QAAQ,CAAC,2BAA2B,EAAE,2BAA2B;IACjE,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB;IALrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG7C,UAAU,EAAE,UAAU,EAC9B,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAKrD,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC;CAqDvF"}
1
+ {"version":3,"file":"security-rule.subscriber.d.ts","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AACzF,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,yBAAyB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE1F,qBACa,sBAAuB,YAAW,yBAAyB,CAAC,YAAY,CAAC;IAI9E,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,QAAQ,CAAC,2BAA2B,EAAE,2BAA2B;IACjE,QAAQ,CAAC,gBAAgB,EAAE,sBAAsB;IALrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2C;gBAG7C,UAAU,EAAE,UAAU,EAC9B,2BAA2B,EAAE,2BAA2B,EACxD,gBAAgB,EAAE,sBAAsB;IAKrD,QAAQ;IAIF,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC;IAI5C,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,WAAW,CAAC,YAAY,CAAC;CAiDvF"}
@@ -53,7 +53,6 @@ const fs = __importStar(require("fs/promises"));
53
53
  const constants_1 = require("../constants");
54
54
  const model_metadata_entity_1 = require("../entities/model-metadata.entity");
55
55
  const security_rule_entity_1 = require("../entities/security-rule.entity");
56
- const environment_helper_1 = require("../helpers/environment.helper");
57
56
  const module_metadata_helper_service_1 = require("../helpers/module-metadata-helper.service");
58
57
  const security_rule_repository_1 = require("../repository/security-rule.repository");
59
58
  const typeorm_2 = require("typeorm");
@@ -81,8 +80,7 @@ let SecurityRuleSubscriber = SecurityRuleSubscriber_1 = class SecurityRuleSubscr
81
80
  this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);
82
81
  return;
83
82
  }
84
- const mgr = (0, environment_helper_1.isEmbeddedDb)() ? event.manager : this.dataSource;
85
- const modelMetadataRepo = mgr.getRepository(model_metadata_entity_1.ModelMetadata);
83
+ const modelMetadataRepo = this.dataSource.getRepository(model_metadata_entity_1.ModelMetadata);
86
84
  const populatedModelMetadata = await modelMetadataRepo.findOne({
87
85
  where: {
88
86
  id: modelMetadata.id
@@ -105,12 +103,12 @@ let SecurityRuleSubscriber = SecurityRuleSubscriber_1 = class SecurityRuleSubscr
105
103
  const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);
106
104
  if (metaData.securityRules) {
107
105
  const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile) => ruleFromFile.name === securityRule.name);
108
- const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, (0, environment_helper_1.isEmbeddedDb)() ? event.manager : undefined);
106
+ const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule);
109
107
  metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) };
110
108
  }
111
109
  else {
112
110
  const securityRules = [];
113
- const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, (0, environment_helper_1.isEmbeddedDb)() ? event.manager : undefined);
111
+ const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule);
114
112
  securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) });
115
113
  metaData.securityRules = securityRules;
116
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"security-rule.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from 'fs/promises'; // Use the Promise-based version of fs for async/await\nimport { SOLID_CORE_MODULE_NAME } from 'src/constants';\nimport { ModelMetadata } from 'src/entities/model-metadata.entity';\nimport { SecurityRule } from 'src/entities/security-rule.entity';\nimport { isEmbeddedDb } from \"src/helpers/environment.helper\";\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { SecurityRuleRepository } from 'src/repository/security-rule.repository';\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable()\nexport class SecurityRuleSubscriber implements EntitySubscriberInterface<SecurityRule> {\n private readonly logger = new Logger(SecurityRuleSubscriber.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n readonly securityRuleRepo: SecurityRuleRepository,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return SecurityRule;\n }\n\n async afterInsert(event: InsertEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async afterUpdate(event: UpdateEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async saveSecurityRules(event: UpdateEvent<SecurityRule> | InsertEvent<SecurityRule>) {\n const securityRule = event.entity as SecurityRule;\n const modelMetadata = event.entity.modelMetadata;\n if (!modelMetadata) {\n this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);\n return;\n }\n\n // On embedded PGlite, use the transaction's connection to avoid a\n // second pooled connection mid-transaction. On regular Postgres, use\n // the default DataSource (original behaviour).\n const mgr = isEmbeddedDb() ? event.manager : this.dataSource;\n const modelMetadataRepo = mgr.getRepository(ModelMetadata);\n const populatedModelMetadata = await modelMetadataRepo.findOne({\n where: {\n id: modelMetadata.id\n },\n relations: {\n module: true,\n }\n });\n\n // Ignore further processing if the module is solid core module, since solid core security rules cannot be seeded from the UI\n if (populatedModelMetadata.module.name === SOLID_CORE_MODULE_NAME) {\n return;\n }\n\n const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(populatedModelMetadata.module.name);\n try {\n await fs.access(filePath);\n } catch (error: any) {\n // FIXME - Should we actually delete the security rule here, if the file is not found?\n this.logger.error(`File not found at path: ${filePath}`);\n return;\n }\n const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);\n\n if (metaData.securityRules) {\n const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile: { name: string }) => ruleFromFile.name === securityRule.name);\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, isEmbeddedDb() ? event.manager : undefined)\n metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) }\n }\n else {\n const securityRules = []\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule, isEmbeddedDb() ? event.manager : undefined)\n securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) })\n metaData.securityRules = securityRules\n }\n // Write the updated object back to the file\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n }\n\n}"]}
1
+ {"version":3,"file":"security-rule.subscriber.js","sourceRoot":"","sources":["../../src/subscribers/security-rule.subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { InjectDataSource } from \"@nestjs/typeorm\";\nimport * as fs from 'fs/promises'; // Use the Promise-based version of fs for async/await\nimport { SOLID_CORE_MODULE_NAME } from 'src/constants';\nimport { ModelMetadata } from 'src/entities/model-metadata.entity';\nimport { SecurityRule } from 'src/entities/security-rule.entity';\nimport { ModuleMetadataHelperService } from \"src/helpers/module-metadata-helper.service\";\nimport { SecurityRuleRepository } from 'src/repository/security-rule.repository';\nimport { DataSource, EntitySubscriberInterface, InsertEvent, UpdateEvent } from \"typeorm\";\n\n@Injectable()\nexport class SecurityRuleSubscriber implements EntitySubscriberInterface<SecurityRule> {\n private readonly logger = new Logger(SecurityRuleSubscriber.name);\n constructor(\n @InjectDataSource()\n private readonly dataSource: DataSource,\n readonly moduleMetadataHelperService: ModuleMetadataHelperService,\n readonly securityRuleRepo: SecurityRuleRepository,\n ) {\n this.dataSource.subscribers.push(this);\n }\n\n listenTo() {\n return SecurityRule;\n }\n\n async afterInsert(event: InsertEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async afterUpdate(event: UpdateEvent<SecurityRule>) {\n await this.saveSecurityRules(event);\n }\n\n async saveSecurityRules(event: UpdateEvent<SecurityRule> | InsertEvent<SecurityRule>) {\n const securityRule = event.entity as SecurityRule;\n const modelMetadata = event.entity.modelMetadata;\n if (!modelMetadata) {\n this.logger.error(`Model metadata not found for security rule with id ${event.entity.id}`);\n return;\n }\n\n const modelMetadataRepo = this.dataSource.getRepository(ModelMetadata);\n const populatedModelMetadata = await modelMetadataRepo.findOne({\n where: {\n id: modelMetadata.id\n },\n relations: {\n module: true,\n }\n });\n\n // Ignore further processing if the module is solid core module, since solid core security rules cannot be seeded from the UI\n if (populatedModelMetadata.module.name === SOLID_CORE_MODULE_NAME) {\n return;\n }\n\n const filePath = await this.moduleMetadataHelperService.getModuleMetadataFilePath(populatedModelMetadata.module.name);\n try {\n await fs.access(filePath);\n } catch (error: any) {\n // FIXME - Should we actually delete the security rule here, if the file is not found?\n this.logger.error(`File not found at path: ${filePath}`);\n return;\n }\n const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);\n\n if (metaData.securityRules) {\n const securityRuleIndex = metaData.securityRules?.findIndex((ruleFromFile: { name: string }) => ruleFromFile.name === securityRule.name);\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule)\n metaData.securityRules[securityRuleIndex] = { ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) }\n }\n else {\n const securityRules = []\n const { id, roleId, modelMetadataId, ...requiredDto } = await this.securityRuleRepo.toDto(securityRule)\n securityRules.push({ ...requiredDto, securityRuleConfig: JSON.parse(securityRule.securityRuleConfig) })\n metaData.securityRules = securityRules\n }\n // Write the updated object back to the file\n const updatedContent = JSON.stringify(metaData, null, 2);\n await fs.writeFile(filePath, updatedContent);\n }\n\n}"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.11-beta.11",
3
+ "version": "0.1.11-beta.13",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -47,7 +47,7 @@ export class MediaController {
47
47
  return this.service.update(id, updateDto, files, true);
48
48
  }
49
49
 
50
- @Public()
50
+ // @Public()
51
51
  // @SkipThrottle({ short: false, login: true, burst: true, sustained: true }) //Enable the short throttle only
52
52
  @ApiBearerAuth("jwt")
53
53
  @Post('/upload')
@@ -13,15 +13,4 @@ export function isRedisConfigured(configService: ConfigService): boolean {
13
13
  const host = configService.get<string>('REDIS_HOST');
14
14
  const port = configService.get<string>('REDIS_PORT');
15
15
  return host && port && isNumber(parseInt(port));
16
- }
17
-
18
- /**
19
- * Returns true when the project is configured to use an embedded PGlite
20
- * database with a single-connection pool. Several TypeORM subscriber and
21
- * code-generation workarounds are only necessary (and only applied) under
22
- * this constraint; on a regular multi-connection Postgres pool the original
23
- * behaviour is preserved.
24
- */
25
- export function isEmbeddedDb(): boolean {
26
- return process.env.DEFAULT_DATABASE_DRIVER === 'pglite';
27
16
  }
@@ -4,10 +4,8 @@ import { forwardRef, Inject, Injectable, Logger } from "@nestjs/common";
4
4
  import { _ } from "lodash";
5
5
  import { LEGACY_TABLE_FIELDS_PREFIX } from "src/entities/legacy-common.entity-with-existing-id.entity";
6
6
  import { LegacyTableType } from "src/enums/legacy-table-type.enum";
7
- import { ModelMetadata } from "src/entities/model-metadata.entity";
8
7
  import { ModelMetadataRepository } from "src/repository/model-metadata.repository";
9
8
  import { SolidRegistry } from "./solid-registry";
10
- import { EntityManager } from "typeorm";
11
9
 
12
10
  @Injectable()
13
11
  export class ModelMetadataHelperService {
@@ -145,11 +143,8 @@ export class ModelMetadataHelperService {
145
143
  return systemFieldsMetadata;
146
144
  }
147
145
 
148
- async loadFieldHierarchy(modelName: any, manager?: EntityManager) {
149
- const repo = manager
150
- ? manager.getRepository(ModelMetadata)
151
- : this.modelMetadataRepo;
152
- const model = await repo.findOne({
146
+ async loadFieldHierarchy(modelName: any) {
147
+ const model = await this.modelMetadataRepo.findOne({
153
148
  where: {
154
149
  singularName: modelName,
155
150
  },
@@ -34,7 +34,7 @@ export class ModuleMetadataHelperService {
34
34
  if (!moduleName) {
35
35
  return '';
36
36
  }
37
- return path.resolve(process.cwd(), 'src', moduleName);
37
+ return path.resolve(process.cwd(), 'src', kebabCase(moduleName));
38
38
  }
39
39
 
40
40
  async getSolidUiModulePath(moduleName: string): Promise<string> {
@@ -8,7 +8,7 @@ import { Locale } from 'src/entities/locale.entity';
8
8
  import { SecurityRule } from 'src/entities/security-rule.entity';
9
9
  import { IScheduledJob } from 'src/services/scheduled-jobs/scheduled-job.interface';
10
10
  import { IDashboardWidgetDataProvider, IErrorCodeProvider, ISecurityRuleConfigProvider, ISelectionProvider, ISelectionProviderContext, ISolidDatabaseModule } from "../interfaces";
11
- import { EntityManager, ObjectLiteral } from 'typeorm';
11
+ import { ObjectLiteral } from 'typeorm';
12
12
 
13
13
  type ControllerMetadata = {
14
14
  name: string;
@@ -49,12 +49,6 @@ export interface TypeOrmEventContext {
49
49
  metadataName?: string;
50
50
  updatedColumns?: string[];
51
51
  updatedRelations?: string[];
52
- // Transaction-bound EntityManager from the originating TypeORM event. Providers that
53
- // need to query the DB during a pre-compute hook must use this (not an injected
54
- // DataSource/EntityManager) so the query runs on the active transaction's connection.
55
- // On single-threaded embedded engines (PGlite), a second connection mid-transaction
56
- // can deadlock.
57
- manager?: EntityManager;
58
52
  }
59
53
 
60
54
  export interface ComputedFieldMetadata<TContext = any> {
package/src/index.ts CHANGED
@@ -171,7 +171,6 @@ export * from './guards/permissions.guard'
171
171
  export * from './guards/roles.guard'
172
172
 
173
173
  export * from './helpers/command.service'
174
- export * from './helpers/nodemon-heartbeat'
175
174
  export * from './helpers/module.helper'
176
175
  export * from './helpers/schematic.service'
177
176
  export * from './helpers/solid-registry'
@@ -3,7 +3,7 @@ import { CreateScheduledJobDto } from "src/dtos/create-scheduled-job.dto";
3
3
  import { ModuleMetadata } from "src/entities/module-metadata.entity";
4
4
  import { ScheduledJob } from "src/entities/scheduled-job.entity";
5
5
  import { RequestContextService } from "src/services/request-context.service";
6
- import { DataSource, EntityManager } from "typeorm";
6
+ import { DataSource } from "typeorm";
7
7
  import { SecurityRuleRepository } from "./security-rule.repository";
8
8
  import { SolidBaseRepository } from "./solid-base.repository";
9
9
 
@@ -101,25 +101,19 @@ export class ScheduledJobRepository extends SolidBaseRepository<ScheduledJob> {
101
101
 
102
102
  /**
103
103
  * Converts an entity to a plain DTO object.
104
- * When manager is provided (e.g. from a TypeORM subscriber event), the
105
- * fallback relation load uses it so the query runs on the active
106
- * transaction's connection instead of the default DataSource pool.
107
104
  */
108
- async toDto(scheduledJob: ScheduledJob, manager?: EntityManager): Promise<CreateScheduledJobDto> {
105
+ async toDto(scheduledJob: ScheduledJob): Promise<CreateScheduledJobDto> {
109
106
  let populatedScheduledJob: ScheduledJob = scheduledJob;
110
107
  // If the scheduled job does not have the module relation loaded, load it
111
108
  if (!scheduledJob.module) {
112
- const repo = manager
113
- ? manager.getRepository(ScheduledJob)
114
- : this;
115
- populatedScheduledJob = await repo.findOne({
109
+ populatedScheduledJob = await this.findOne({
116
110
  where: {
117
111
  id: scheduledJob.id,
118
112
  },
119
113
  relations: {
120
114
  module: true,
121
115
  },
122
- }) ?? scheduledJob;
116
+ });
123
117
  }
124
118
 
125
119
  if (!populatedScheduledJob.module) {
@@ -9,7 +9,7 @@ import { SecurityRule } from 'src/entities/security-rule.entity';
9
9
  import { SolidRegistry } from 'src/helpers/solid-registry';
10
10
  import { ActiveUserData } from 'src/interfaces/active-user-data.interface';
11
11
  import { CrudHelperService } from 'src/services/crud-helper.service';
12
- import { Brackets, DataSource, EntityManager, SelectQueryBuilder } from 'typeorm';
12
+ import { Brackets, DataSource, SelectQueryBuilder } from 'typeorm';
13
13
  import { SolidBaseRepository } from './solid-base.repository';
14
14
 
15
15
  @Injectable()
@@ -84,18 +84,12 @@ export class SecurityRuleRepository extends SolidBaseRepository<SecurityRule> {
84
84
  return configString.replace('$activeUserId', activeUser.sub.toString());
85
85
  }
86
86
 
87
- async toDto(securityRule: SecurityRule, manager?: EntityManager): Promise<UpdateSecurityRuleDto> {
87
+ async toDto(securityRule: SecurityRule): Promise<UpdateSecurityRuleDto> {
88
88
  // load the role and model relations for the security rule
89
89
  let populatedSecurityRule: SecurityRule = securityRule;
90
90
  // If the security rule does not have the role and model relations loaded, load them
91
91
  if (!securityRule.role || !securityRule.modelMetadata) {
92
- // When a manager is provided (e.g. from a TypeORM subscriber event),
93
- // use it so the query runs on the active transaction's connection
94
- // instead of trying to acquire a second connection from the pool.
95
- const repo = manager
96
- ? manager.getRepository(SecurityRule)
97
- : this;
98
- populatedSecurityRule = await repo.findOne({
92
+ populatedSecurityRule = await this.findOne({
99
93
  where: {
100
94
  id: securityRule.id,
101
95
  },
@@ -103,7 +97,7 @@ export class SecurityRuleRepository extends SolidBaseRepository<SecurityRule> {
103
97
  role: true,
104
98
  modelMetadata: true,
105
99
  },
106
- }) ?? securityRule;
100
+ });
107
101
  }
108
102
 
109
103
  return {
@@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
2
2
  import { InjectEntityManager } from '@nestjs/typeorm';
3
3
  import { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';
4
4
  import { CommonEntity } from 'src/entities/common.entity';
5
- import { isEmbeddedDb } from 'src/helpers/environment.helper';
6
5
  import { ComputedFieldMetadata } from 'src/helpers/solid-registry';
7
6
  import { IEntityPreComputeFieldProvider } from 'src/interfaces';
8
7
  import { EntityManager } from 'typeorm';
@@ -46,12 +45,7 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
46
45
  }
47
46
  }
48
47
 
49
- // On embedded PGlite (pool size 1), use the originating transaction's EntityManager
50
- // so the uniqueness check runs on the active connection. On regular Postgres, use the
51
- // injected EntityManager (original behaviour).
52
- const manager = isEmbeddedDb() ? (eventContext?.manager ?? this.entityManager) : this.entityManager;
53
-
54
- const uniqueCode = await this.generateUniqueExternalId(manager, resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);
48
+ const uniqueCode = await this.generateUniqueExternalId(resolvedPrefix, codeLength, computedFieldMetadata.fieldName, entityName);
55
49
  const finalExternalId = resolvedPrefix ? `${resolvedPrefix}-${uniqueCode}` : uniqueCode;
56
50
 
57
51
  triggerEntity[computedFieldMetadata.fieldName] = finalExternalId;
@@ -66,8 +60,8 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
66
60
  return result;
67
61
  }
68
62
 
69
- private async isExternalIdUnique(manager: EntityManager, externalId: string, fieldName: string, entityName: string): Promise<boolean> {
70
- const count = await manager.count(entityName as any,
63
+ private async isExternalIdUnique(externalId: string, fieldName: string, entityName: string): Promise<boolean> {
64
+ const count = await this.entityManager.count(entityName as any,
71
65
  {
72
66
  where: { [fieldName]: externalId },
73
67
  }
@@ -75,7 +69,7 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
75
69
  return count === 0;
76
70
  }
77
71
 
78
- private async generateUniqueExternalId(manager: EntityManager, resolvedPrefix: string, codeLength: number, fieldName: string, entityName: string): Promise<string> {
72
+ private async generateUniqueExternalId(resolvedPrefix: string, codeLength: number, fieldName: string, entityName: string): Promise<string> {
79
73
  const maxAttempts = 10;
80
74
 
81
75
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
@@ -84,7 +78,7 @@ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> imple
84
78
 
85
79
  const fullId = resolvedPrefix ? `${resolvedPrefix}-${newId}` : newId;
86
80
 
87
- const isUnique = await this.isExternalIdUnique(manager, fullId, fieldName, entityName);
81
+ const isUnique = await this.isExternalIdUnique(fullId, fieldName, entityName);
88
82
 
89
83
  if (isUnique) {
90
84
  return newId;
@@ -293,9 +293,13 @@ export class CrudHelperService {
293
293
  const orderOptions = this.orderOptions(normalizedSort);
294
294
  if (orderOptions) {
295
295
  const orderOptionKeys = Object.keys(orderOptions) as Array<keyof typeof orderOptions>;
296
+ let hasExplicitIdSort = false;
296
297
  orderOptionKeys.forEach((key) => {
297
298
  const value = orderOptions[key] as 'ASC' | 'DESC';
298
299
  const field = String(key);
300
+ if (field === 'id') {
301
+ hasExplicitIdSort = true;
302
+ }
299
303
  if (field.includes('.')) {
300
304
  const { alias, property, created } = this.ensureRelationPathJoined(qb, entityAlias, field.split('.'));
301
305
  const orderColumn = `${alias}.${property}`;
@@ -305,6 +309,9 @@ export class CrudHelperService {
305
309
  qb.addOrderBy(`${entityAlias}.${field}`, value);
306
310
  }
307
311
  });
312
+ if (!hasExplicitIdSort) {
313
+ qb.addOrderBy(`${entityAlias}.id`, 'DESC');
314
+ }
308
315
  }
309
316
  }
310
317
 
@@ -405,10 +405,7 @@ export class DatasourceIntrospectionService {
405
405
  throw new BadRequestException("Persist the model mapping first so the generated entity can be registered before creating migration artifacts.");
406
406
  }
407
407
 
408
- if (plan.migration.willGenerate && plan.migration.content && plan.migration.filePath) {
409
- await fs.mkdir(path.dirname(plan.migration.filePath), { recursive: true });
410
- await fs.writeFile(plan.migration.filePath, plan.migration.content, "utf8");
411
- }
408
+ const migrationWritten = await this.writeMigrationFile(plan.migration);
412
409
 
413
410
  const datasourceFile = await this.syncTypeormDatasourceFile(
414
411
  module.name,
@@ -422,7 +419,7 @@ export class DatasourceIntrospectionService {
422
419
  operation: plan.operation,
423
420
  migration: {
424
421
  ...plan.migration,
425
- written: Boolean(plan.migration.willGenerate && plan.migration.filePath),
422
+ written: migrationWritten,
426
423
  },
427
424
  datasourceFile,
428
425
  summary: plan.summary,
@@ -1918,6 +1915,22 @@ export class DatasourceIntrospectionService {
1918
1915
  };
1919
1916
  }
1920
1917
 
1918
+ private async writeMigrationFile(migration: MappingPreviewRecord["migration"]) {
1919
+ if (!migration.willGenerate || !migration.content || !migration.filePath) {
1920
+ return false;
1921
+ }
1922
+
1923
+ await fs.mkdir(path.dirname(migration.filePath), { recursive: true });
1924
+ await fs.writeFile(migration.filePath, migration.content, "utf8");
1925
+
1926
+ const writtenContent = await fs.readFile(migration.filePath, "utf8").catch(() => null);
1927
+ if (writtenContent !== migration.content) {
1928
+ throw new BadRequestException(`Migration file could not be verified after writing: ${migration.filePath}`);
1929
+ }
1930
+
1931
+ return true;
1932
+ }
1933
+
1921
1934
  private renderTypeormDatasourceTemplate(input: {
1922
1935
  datasource: DatasourceRecord;
1923
1936
  entityClassName: string;
@@ -28,8 +28,6 @@ import { PermissionMetadata } from '../entities/permission-metadata.entity';
28
28
  import { RoleMetadata } from '../entities/role-metadata.entity';
29
29
  import { ViewMetadata } from '../entities/view-metadata.entity';
30
30
  import { CommandService } from '../helpers/command.service';
31
- import { isEmbeddedDb } from '../helpers/environment.helper';
32
- import { startNodemonHeartbeat } from '../helpers/nodemon-heartbeat';
33
31
  import {
34
32
  REFRESH_MODEL_COMMAND,
35
33
  REMOVE_FIELDS_COMMAND,
@@ -1032,26 +1030,6 @@ export class ModelMetadataService {
1032
1030
  @DisallowInProduction()
1033
1031
  async generateCodeViaCtl(modelId: number): Promise<string> {
1034
1032
  const model = await this.findOne(modelId);
1035
- const isEmbedded = isEmbeddedDb();
1036
-
1037
- // When using an embedded PGlite database, the single-connection limit means
1038
- // a spawned `solid refresh-model` subprocess cannot get its own DB connection
1039
- // while the API server is already holding it. Fall back to in-process code
1040
- // generation (which reuses the existing connection).
1041
- if (isEmbedded) {
1042
- this.logger.log('Embedded database detected — generating API code in-process');
1043
- // Prevent nodemon from restarting the server while schematics write files.
1044
- const heartbeat = startNodemonHeartbeat(path.join(process.cwd(), 'src'));
1045
- try {
1046
- return await this.handleGenerateCode({
1047
- modelUserKey: model.singularName,
1048
- dryRun: false,
1049
- });
1050
- } finally {
1051
- heartbeat.stop();
1052
- }
1053
- }
1054
-
1055
1033
  return this.commandService.executeCommandWithArgs({
1056
1034
  command: 'npx',
1057
1035
  args: ['@solidxai/solidctl@latest', 'generate', 'model', `--name=${model.singularName}`],
@@ -26,8 +26,6 @@ import {
26
26
  } from '../helpers/schematic.service';
27
27
  import { CommandService } from '../helpers/command.service';
28
28
  import { SolidRegistry } from '../helpers/solid-registry';
29
- import { isEmbeddedDb } from '../helpers/environment.helper';
30
- import { startNodemonHeartbeat } from '../helpers/nodemon-heartbeat';
31
29
  import { CodeGenerationOptions, ModuleMetadataConfiguration } from '../interfaces';
32
30
  import { CrudHelperService } from './crud-helper.service';
33
31
  import { ModelMetadataService } from './model-metadata.service';
@@ -536,40 +534,6 @@ export class ModuleMetadataService {
536
534
  @DisallowInProduction()
537
535
  async generateCodeViaCtl(moduleId: number): Promise<string> {
538
536
  const module = await this.findOne(moduleId);
539
- const isEmbedded = isEmbeddedDb();
540
-
541
- // When using an embedded PGlite database, the single-connection limit means
542
- // a spawned `solid refresh-module` subprocess cannot get its own DB connection
543
- // while the API server is already holding it. Fall back to in-process code
544
- // generation (which reuses the existing connection) and only spawn solidctl
545
- // for the UI module scaffold (which does not need a database connection).
546
- if (isEmbedded) {
547
- this.logger.log('Embedded database detected — generating API code in-process');
548
- // Prevent nodemon from restarting the server while schematics write files.
549
- // The heartbeat touches a watched file every 1.5 s (nodemon delay is 2 s),
550
- // keeping the delay from expiring during DB queries between schematic runs.
551
- const heartbeat = startNodemonHeartbeat(path.join(process.cwd(), 'src'));
552
- try {
553
- const apiOutput = await this.generateCode({
554
- moduleUserKey: module.name,
555
- dryRun: false,
556
- });
557
- let uiOutput = '';
558
- try {
559
- uiOutput = await this.commandService.executeCommandWithArgs({
560
- command: 'npx',
561
- args: ['@solidxai/solidctl@latest', 'generate', 'ui-module', `--name=${module.name}`],
562
- cwd: path.join(process.cwd(), '..'),
563
- });
564
- } catch (error) {
565
- this.logger.warn('UI module scaffold failed (solidctl may be outdated); API code was generated successfully.');
566
- }
567
- return `${apiOutput}\n${uiOutput}`;
568
- } finally {
569
- heartbeat.stop();
570
- }
571
- }
572
-
573
537
  return this.commandService.executeCommandWithArgs({
574
538
  command: 'npx',
575
539
  args: ['@solidxai/solidctl@latest', 'generate', 'module', `--name=${module.name}`],