@nest-omni/core 4.1.3-10 → 4.1.3-12

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 (183) hide show
  1. package/audit/audit.module.js +42 -2
  2. package/audit/controllers/audit.controller.d.ts +64 -0
  3. package/audit/controllers/audit.controller.js +50 -0
  4. package/audit/decorators/audit-action.decorator.d.ts +74 -0
  5. package/audit/decorators/audit-action.decorator.js +42 -0
  6. package/audit/decorators/audit-controller.decorator.d.ts +1 -1
  7. package/audit/decorators/audit-controller.decorator.js +2 -2
  8. package/audit/decorators/entity-audit.decorator.d.ts +78 -2
  9. package/audit/decorators/entity-audit.decorator.js +145 -4
  10. package/audit/decorators/index.d.ts +2 -0
  11. package/audit/decorators/index.js +2 -0
  12. package/audit/entities/audit-action-summary.entity.d.ts +23 -0
  13. package/audit/entities/audit-action-summary.entity.js +101 -0
  14. package/audit/entities/entity-audit-log.entity.d.ts +8 -0
  15. package/audit/entities/entity-audit-log.entity.js +54 -2
  16. package/audit/entities/entity-transaction.entity.d.ts +8 -2
  17. package/audit/entities/entity-transaction.entity.js +39 -3
  18. package/audit/entities/index.d.ts +3 -0
  19. package/audit/entities/index.js +3 -0
  20. package/audit/entities/manual-operation-log.entity.js +8 -1
  21. package/audit/enums/audit.enums.d.ts +22 -6
  22. package/audit/enums/audit.enums.js +27 -9
  23. package/audit/index.d.ts +4 -1
  24. package/audit/index.js +25 -2
  25. package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
  26. package/audit/interceptors/audit-action.interceptor.js +215 -0
  27. package/audit/interceptors/index.d.ts +1 -0
  28. package/audit/interceptors/index.js +1 -0
  29. package/audit/interfaces/audit.interfaces.d.ts +145 -2
  30. package/audit/services/audit-action.service.d.ts +141 -0
  31. package/audit/services/audit-action.service.js +244 -0
  32. package/audit/services/audit-context.service.d.ts +82 -0
  33. package/audit/services/audit-context.service.js +170 -0
  34. package/audit/services/entity-audit.service.d.ts +174 -4
  35. package/audit/services/entity-audit.service.js +515 -14
  36. package/audit/services/index.d.ts +3 -0
  37. package/audit/services/index.js +3 -0
  38. package/audit/services/manual-audit-log.service.d.ts +24 -23
  39. package/audit/services/manual-audit-log.service.js +32 -53
  40. package/audit/services/operation-description.service.d.ts +13 -3
  41. package/audit/services/operation-description.service.js +161 -24
  42. package/audit/services/transaction-audit.service.js +3 -3
  43. package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
  44. package/audit/subscribers/entity-audit.subscriber.js +47 -0
  45. package/file-upload/controllers/file-access.controller.d.ts +23 -0
  46. package/file-upload/controllers/file-access.controller.js +128 -0
  47. package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
  48. package/file-upload/decorators/csv-data.decorator.js +131 -0
  49. package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
  50. package/file-upload/decorators/excel-data.decorator.js +125 -0
  51. package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
  52. package/file-upload/decorators/file-upload.decorator.js +172 -0
  53. package/file-upload/decorators/index.d.ts +4 -0
  54. package/file-upload/decorators/index.js +20 -0
  55. package/file-upload/decorators/process.decorator.d.ts +40 -0
  56. package/file-upload/decorators/process.decorator.js +52 -0
  57. package/file-upload/dto/create-file.dto.d.ts +24 -0
  58. package/file-upload/dto/create-file.dto.js +112 -0
  59. package/file-upload/dto/find-files.dto.d.ts +15 -0
  60. package/file-upload/dto/find-files.dto.js +76 -0
  61. package/file-upload/dto/index.d.ts +4 -0
  62. package/file-upload/dto/index.js +20 -0
  63. package/file-upload/dto/pagination.dto.d.ts +7 -0
  64. package/file-upload/dto/pagination.dto.js +39 -0
  65. package/file-upload/dto/update-file.dto.d.ts +16 -0
  66. package/file-upload/dto/update-file.dto.js +71 -0
  67. package/file-upload/entities/file-metadata.entity.d.ts +22 -0
  68. package/file-upload/entities/file-metadata.entity.js +84 -0
  69. package/file-upload/entities/file.entity.d.ts +129 -0
  70. package/file-upload/entities/file.entity.js +384 -0
  71. package/file-upload/entities/index.d.ts +2 -0
  72. package/file-upload/entities/index.js +18 -0
  73. package/file-upload/enums/file-type.enum.d.ts +72 -0
  74. package/file-upload/enums/file-type.enum.js +212 -0
  75. package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
  76. package/file-upload/exceptions/file-upload.exception.js +120 -0
  77. package/file-upload/exceptions/index.d.ts +1 -0
  78. package/file-upload/exceptions/index.js +17 -0
  79. package/file-upload/file-upload.module.d.ts +89 -0
  80. package/file-upload/file-upload.module.js +264 -0
  81. package/file-upload/index.d.ts +26 -0
  82. package/file-upload/index.js +59 -0
  83. package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
  84. package/file-upload/interceptors/file-upload.interceptor.js +434 -0
  85. package/file-upload/interceptors/index.d.ts +1 -0
  86. package/file-upload/interceptors/index.js +17 -0
  87. package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
  88. package/file-upload/interfaces/custom-file-type.interface.js +2 -0
  89. package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
  90. package/file-upload/interfaces/file-buffer.interface.js +2 -0
  91. package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
  92. package/file-upload/interfaces/file-entity.interface.js +28 -0
  93. package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
  94. package/file-upload/interfaces/file-metadata.interface.js +2 -0
  95. package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
  96. package/file-upload/interfaces/file-upload-options.interface.js +2 -0
  97. package/file-upload/interfaces/index.d.ts +7 -0
  98. package/file-upload/interfaces/index.js +24 -0
  99. package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
  100. package/file-upload/interfaces/storage-provider.interface.js +2 -0
  101. package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
  102. package/file-upload/interfaces/upload-options.interface.js +2 -0
  103. package/file-upload/providers/index.d.ts +2 -0
  104. package/file-upload/providers/index.js +18 -0
  105. package/file-upload/providers/local-storage.provider.d.ts +98 -0
  106. package/file-upload/providers/local-storage.provider.js +484 -0
  107. package/file-upload/providers/s3-storage.provider.d.ts +87 -0
  108. package/file-upload/providers/s3-storage.provider.js +455 -0
  109. package/file-upload/services/file-signature-validator.service.d.ts +118 -0
  110. package/file-upload/services/file-signature-validator.service.js +376 -0
  111. package/file-upload/services/file.service.d.ts +190 -0
  112. package/file-upload/services/file.service.js +609 -0
  113. package/file-upload/services/index.d.ts +4 -0
  114. package/file-upload/services/index.js +20 -0
  115. package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
  116. package/file-upload/services/malicious-file-detector.service.js +1035 -0
  117. package/file-upload/services/mime-registry.service.d.ts +47 -0
  118. package/file-upload/services/mime-registry.service.js +167 -0
  119. package/file-upload/utils/checksum.util.d.ts +28 -0
  120. package/file-upload/utils/checksum.util.js +65 -0
  121. package/file-upload/utils/dynamic-import.util.d.ts +50 -0
  122. package/file-upload/utils/dynamic-import.util.js +144 -0
  123. package/file-upload/utils/filename.util.d.ts +59 -0
  124. package/file-upload/utils/filename.util.js +184 -0
  125. package/file-upload/utils/filepath.util.d.ts +70 -0
  126. package/file-upload/utils/filepath.util.js +152 -0
  127. package/file-upload/utils/index.d.ts +4 -0
  128. package/file-upload/utils/index.js +20 -0
  129. package/http-client/http-client.module.js +1 -5
  130. package/index.d.ts +3 -1
  131. package/index.js +4 -1
  132. package/package.json +4 -5
  133. package/redis-lock/lock-heartbeat.service.d.ts +2 -2
  134. package/redis-lock/lock-heartbeat.service.js +4 -4
  135. package/redis-lock/redis-lock.service.d.ts +18 -0
  136. package/redis-lock/redis-lock.service.js +38 -8
  137. package/setup/bootstrap.setup.d.ts +1 -0
  138. package/setup/bootstrap.setup.js +1 -0
  139. package/setup/schedule.decorator.js +18 -8
  140. package/shared/index.d.ts +1 -1
  141. package/shared/index.js +1 -1
  142. package/shared/{serviceRegistryModule.js → service-registry.module.js} +9 -16
  143. package/shared/services/index.d.ts +0 -1
  144. package/shared/services/index.js +0 -1
  145. package/transaction/__tests__/mocks.d.ts +9 -0
  146. package/transaction/__tests__/mocks.js +33 -0
  147. package/transaction/base-service-transaction.d.ts +99 -0
  148. package/transaction/base-service-transaction.js +286 -0
  149. package/transaction/cls-compatibility.service.d.ts +55 -0
  150. package/transaction/cls-compatibility.service.js +127 -0
  151. package/transaction/data-source-registry.d.ts +91 -0
  152. package/transaction/data-source-registry.js +349 -0
  153. package/transaction/database-adapter.d.ts +44 -0
  154. package/transaction/database-adapter.js +240 -0
  155. package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
  156. package/transaction/decorators/entity-datasource.decorator.js +105 -0
  157. package/transaction/index.d.ts +14 -0
  158. package/transaction/index.js +57 -0
  159. package/transaction/logging-transactional.interceptor.d.ts +18 -0
  160. package/transaction/logging-transactional.interceptor.js +163 -0
  161. package/transaction/transaction-context.service.d.ts +137 -0
  162. package/transaction/transaction-context.service.js +411 -0
  163. package/transaction/transaction-manager.d.ts +230 -0
  164. package/transaction/transaction-manager.js +1001 -0
  165. package/transaction/transaction-synchronization.d.ts +171 -0
  166. package/transaction/transaction-synchronization.js +380 -0
  167. package/transaction/transaction.errors.d.ts +91 -0
  168. package/transaction/transaction.errors.js +206 -0
  169. package/transaction/transaction.module.d.ts +30 -0
  170. package/transaction/transaction.module.js +98 -0
  171. package/transaction/transactional.decorator.d.ts +82 -0
  172. package/transaction/transactional.decorator.js +319 -0
  173. package/transaction/typeorm-module-wrapper.d.ts +96 -0
  174. package/transaction/typeorm-module-wrapper.js +197 -0
  175. package/validators/file-mimetype.validator.d.ts +0 -2
  176. package/validators/file-mimetype.validator.js +4 -6
  177. package/validators/is-exists.validator.d.ts +2 -5
  178. package/validators/is-exists.validator.js +4 -6
  179. package/validators/is-unique.validator.d.ts +2 -5
  180. package/validators/is-unique.validator.js +6 -11
  181. package/shared/services/validator.service.d.ts +0 -3
  182. package/shared/services/validator.service.js +0 -20
  183. /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
@@ -72,13 +72,16 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
72
72
  this.redis = null;
73
73
  this.defaultOptions = {
74
74
  ttl: 300000, // 5 minutes
75
- retryCount: 0,
76
- retryDelay: 100,
75
+ retryCount: 3, // Increased from 0 to provide reasonable retry attempts
76
+ retryDelay: 500, // Increased from 100 to reduce retry frequency
77
77
  keyPrefix: 'lock',
78
78
  throwOnFailure: false,
79
79
  strategy: LockStrategy.SKIP,
80
80
  waitTimeout: undefined,
81
81
  autoExtend: 0, // No auto-extension by default
82
+ useExponentialBackoff: true, // Enable exponential backoff by default
83
+ maxRetryDelay: 30000, // Maximum retry delay of 30 seconds
84
+ retryJitter: 100, // Add random jitter to avoid synchronized retries
82
85
  };
83
86
  // Set global instance when created
84
87
  if (!RedisLockService_1.globalInstance) {
@@ -169,6 +172,7 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
169
172
  */
170
173
  acquireLock(key_1) {
171
174
  return __awaiter(this, arguments, void 0, function* (key, options = {}) {
175
+ var _a, _b, _c, _d, _e;
172
176
  const redis = yield this.getRedis();
173
177
  const opts = Object.assign(Object.assign({}, this.defaultOptions), options);
174
178
  // Handle backward compatibility: if throwOnFailure is true, use THROW strategy
@@ -229,16 +233,42 @@ let RedisLockService = RedisLockService_1 = class RedisLockService {
229
233
  }
230
234
  // Wait before next attempt (except for last attempt)
231
235
  if (attempts < maxAttempts) {
232
- yield this.sleep(opts.retryDelay);
236
+ // Add random jitter to avoid synchronized retries
237
+ const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
238
+ const totalDelay = opts.retryDelay + jitter;
239
+ yield this.sleep(totalDelay);
233
240
  }
234
241
  }
235
242
  catch (error) {
236
- const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
237
- this.logger.error(errorMessage, error.stack);
238
- if (opts.strategy === LockStrategy.THROW) {
239
- throw new Error(errorMessage);
243
+ // Enhanced error classification and handling
244
+ if (((_a = error.message) === null || _a === void 0 ? void 0 : _a.includes('ECONNREFUSED')) ||
245
+ ((_b = error.message) === null || _b === void 0 ? void 0 : _b.includes('ECONNRESET')) ||
246
+ error.code === 'ECONNREFUSED') {
247
+ // Connection error, will retry - log at debug level
248
+ this.logger.debug(`Redis connection error, will retry: ${error.message}`);
249
+ }
250
+ else if (((_c = error.message) === null || _c === void 0 ? void 0 : _c.includes('READONLY')) ||
251
+ ((_d = error.message) === null || _d === void 0 ? void 0 : _d.includes('LOADING')) ||
252
+ ((_e = error.message) === null || _e === void 0 ? void 0 : _e.includes('MASTERDOWN'))) {
253
+ // Redis server error, log at warn level
254
+ this.logger.warn(`Redis server error: ${error.message}`);
255
+ }
256
+ else {
257
+ // Other errors, log at error level
258
+ const errorMessage = `Error acquiring lock for ${lockKey}: ${error.message}`;
259
+ this.logger.error(errorMessage, error.stack);
260
+ if (opts.strategy === LockStrategy.THROW) {
261
+ throw new Error(errorMessage);
262
+ }
263
+ return { acquired: false, error: errorMessage };
264
+ }
265
+ // For retryable errors, continue with retry logic
266
+ attempts++;
267
+ if (attempts < maxAttempts) {
268
+ const jitter = opts.retryJitter ? Math.random() * opts.retryJitter : 0;
269
+ const totalDelay = opts.retryDelay + jitter;
270
+ yield this.sleep(totalDelay);
240
271
  }
241
- return { acquired: false, error: errorMessage };
242
272
  }
243
273
  }
244
274
  // Max attempts reached
@@ -1,2 +1,3 @@
1
+ import "../common/boilerplate.polyfill";
1
2
  import type { NestExpressApplication } from '@nestjs/platform-express';
2
3
  export declare function bootstrapSetup(AppModule: any, SetupSwagger: any): Promise<NestExpressApplication<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>>;
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.bootstrapSetup = bootstrapSetup;
13
+ require("../common/boilerplate.polyfill");
13
14
  const Sentry = require("@sentry/nestjs");
14
15
  const profiling_node_1 = require("@sentry/profiling-node");
15
16
  const dotenv = require("dotenv");
@@ -106,8 +106,18 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
106
106
  }
107
107
  // Get or create global instance - auto-configures from environment variables
108
108
  const lockService = redis_lock_1.RedisLockService.getOrCreateGlobalInstance();
109
- const { lockTtl = 3600000, // 1 hour default
110
- retryCount = 0, retryDelay = 1000, useExponentialBackoff = false, maxRetryDelay = 60000, logExecution = true, lockKeyPrefix = 'schedule', autoExtendLock = 0, onSuccess, onError, skipIfLocked = true, } = options;
109
+ const { lockTtl = 600000, // 10 minutes default (reduced from 1 hour)
110
+ retryCount = 3, retryDelay = 500, useExponentialBackoff = true, maxRetryDelay = 30000, logExecution = true, lockKeyPrefix = 'schedule', autoExtendLock = 0, onSuccess, onError, skipIfLocked = true, } = options;
111
+ // Configuration validation and adjustment
112
+ const validatedLockTtl = lockTtl >= 3600000
113
+ ? (logger.warn(`lockTtl (${lockTtl}ms) is quite long for a scheduled task, consider if this is appropriate for ${className}.${methodName}`), lockTtl)
114
+ : lockTtl;
115
+ const validatedRetryCount = retryCount > 10
116
+ ? (logger.warn(`retryCount (${retryCount}) is too high, limiting to 10 for task ${className}.${methodName}`), 10)
117
+ : retryCount;
118
+ const validatedRetryDelay = retryDelay < 100
119
+ ? (logger.warn(`retryDelay (${retryDelay}ms) is too low, setting to 100ms for task ${className}.${methodName}`), 100)
120
+ : retryDelay;
111
121
  const fullLockKey = `${lockKeyPrefix}:${resolvedLockKey}`;
112
122
  const startTime = Date.now();
113
123
  // Log task start
@@ -117,7 +127,7 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
117
127
  try {
118
128
  // Acquire lock
119
129
  const lockResult = yield lockService.acquireLock(resolvedLockKey, {
120
- ttl: lockTtl,
130
+ ttl: validatedLockTtl,
121
131
  keyPrefix: lockKeyPrefix,
122
132
  autoExtend: autoExtendLock,
123
133
  });
@@ -133,8 +143,8 @@ function createWorkerDecoratorWithLock(baseDecorator, decoratorName, lockKey, op
133
143
  try {
134
144
  // Execute with retry logic
135
145
  const result = yield executeWithRetry(() => originalMethod.apply(this, args), {
136
- retryCount,
137
- retryDelay,
146
+ retryCount: validatedRetryCount,
147
+ retryDelay: validatedRetryDelay,
138
148
  useExponentialBackoff,
139
149
  maxRetryDelay,
140
150
  logger,
@@ -309,11 +319,11 @@ function WorkerIntervalWithLock(timeout, lockKeyOrOptions, lockTtl) {
309
319
  let options;
310
320
  if (typeof lockKeyOrOptions === 'string') {
311
321
  lockKey = lockKeyOrOptions;
312
- options = { lockTtl: lockTtl || Math.floor(timeout * 0.8) };
322
+ options = { lockTtl: lockTtl || Math.max(Math.floor(timeout * 0.8), 10000) };
313
323
  }
314
324
  else {
315
325
  lockKey = generateLockKey(target.constructor.name, String(propertyKey));
316
- options = Object.assign({ lockTtl: Math.floor(timeout * 0.8) }, lockKeyOrOptions);
326
+ options = Object.assign({ lockTtl: Math.max(Math.floor(timeout * 0.8), 10000) }, lockKeyOrOptions);
317
327
  }
318
328
  return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalWithLock', lockKey, options)(target, propertyKey, descriptor);
319
329
  };
@@ -406,7 +416,7 @@ function WorkerCronSmart(cronTime, options = {}, cronOptions) {
406
416
  function WorkerIntervalSmart(timeout, options = {}) {
407
417
  return function (target, propertyKey, descriptor) {
408
418
  const lockKey = generateLockKey(target.constructor.name, String(propertyKey));
409
- return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalSmart', lockKey, Object.assign({ lockTtl: Math.floor(timeout * 0.8), logExecution: true }, options))(target, propertyKey, descriptor);
419
+ return createWorkerDecoratorWithLock((0, schedule_1.Interval)(timeout), 'WorkerIntervalSmart', lockKey, Object.assign({ lockTtl: Math.max(Math.floor(timeout * 0.8), 10000), logExecution: true }, options))(target, propertyKey, descriptor);
410
420
  };
411
421
  }
412
422
  /**
package/shared/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from './serviceRegistryModule';
1
+ export * from './service-registry.module';
2
2
  export * from './services';
package/shared/index.js CHANGED
@@ -14,5 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./serviceRegistryModule"), exports);
17
+ __exportStar(require("./service-registry.module"), exports);
18
18
  __exportStar(require("./services"), exports);
@@ -27,8 +27,6 @@ const typeorm_1 = require("@nestjs/typeorm");
27
27
  const schedule_1 = require("@nestjs/schedule");
28
28
  const setup_1 = require("@sentry/nestjs/setup");
29
29
  const cache_1 = require("../cache");
30
- const transactional_1 = require("@nestjs-cls/transactional");
31
- const transactional_adapter_typeorm_1 = require("@nestjs-cls/transactional-adapter-typeorm");
32
30
  const nestjs_i18n_1 = require("nestjs-i18n");
33
31
  const health_checker_1 = require("../health-checker");
34
32
  const nestjs_redis_1 = require("@songkeys/nestjs-redis");
@@ -40,7 +38,6 @@ const vault_1 = require("../vault");
40
38
  const validators_1 = require("../validators");
41
39
  const providers = [
42
40
  services_1.ApiConfigService,
43
- services_1.ValidatorService,
44
41
  services_1.GeneratorService,
45
42
  services_1.TranslationService,
46
43
  validators_1.IsExistsValidator,
@@ -61,19 +58,6 @@ const modules = [
61
58
  expandVariables: false,
62
59
  envFilePath: [process.env.ENV_FILE_PATH, process.env.BASE_ENV_FILE_PATH],
63
60
  }),
64
- nestjs_cls_1.ClsModule.forRoot({
65
- global: true,
66
- middleware: { mount: true, saveReq: true },
67
- plugins: [
68
- new transactional_1.ClsPluginTransactional({
69
- imports: [typeorm_1.TypeOrmModule],
70
- adapter: new transactional_adapter_typeorm_1.TransactionalAdapterTypeOrm({
71
- dataSourceToken: typeorm_2.DataSource,
72
- }),
73
- enableTransactionProxy: true,
74
- }),
75
- ],
76
- }),
77
61
  nestjs_pino_1.LoggerModule.forRootAsync({
78
62
  inject: [services_1.ApiConfigService],
79
63
  useFactory: (config) => config.pinoConfig,
@@ -105,6 +89,15 @@ if (services_1.ApiConfigService.toBoolean(process.env.DB_ENABLED, true)) {
105
89
  inject: [services_1.ApiConfigService],
106
90
  useFactory: (config) => config.typeormConfig,
107
91
  }));
92
+ modules.push(nestjs_cls_1.ClsModule.forRootAsync({
93
+ imports: [typeorm_1.TypeOrmModule],
94
+ useFactory(args) {
95
+ return {
96
+ middleware: { mount: true, saveReq: true },
97
+ };
98
+ },
99
+ global: true,
100
+ }));
108
101
  }
109
102
  if (services_1.ApiConfigService.toBoolean(process.env.BULL_ENABLED)) {
110
103
  modules.push(bull_1.BullModule.forRootAsync({
@@ -1,4 +1,3 @@
1
1
  export * from './api-config.service';
2
2
  export * from './generator.service';
3
3
  export * from './translation.service';
4
- export * from './validator.service';
@@ -17,4 +17,3 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./api-config.service"), exports);
18
18
  __exportStar(require("./generator.service"), exports);
19
19
  __exportStar(require("./translation.service"), exports);
20
- __exportStar(require("./validator.service"), exports);
@@ -0,0 +1,9 @@
1
+ import { TransactionStatus } from '../transaction-manager';
2
+ /**
3
+ * 创建 Mock TransactionStatus
4
+ */
5
+ export declare function createMockTransactionStatus(overrides?: Partial<TransactionStatus>): TransactionStatus;
6
+ /**
7
+ * 创建 Mock EntityManager
8
+ */
9
+ export declare function createMockEntityManager(): any;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMockTransactionStatus = createMockTransactionStatus;
4
+ exports.createMockEntityManager = createMockEntityManager;
5
+ /**
6
+ * 创建 Mock TransactionStatus
7
+ */
8
+ function createMockTransactionStatus(overrides) {
9
+ return Object.assign({ isCompleted: false, isRollbackOnly: false, isNewTransaction: false, dataSourceName: 'default', startTime: new Date(), definition: {
10
+ propagation: 0, // Propagation.REQUIRED
11
+ }, nestingLevel: 1 }, overrides);
12
+ }
13
+ /**
14
+ * 创建 Mock EntityManager
15
+ */
16
+ function createMockEntityManager() {
17
+ const mockEntityManager = {
18
+ save: jest.fn().mockResolvedValue({}),
19
+ find: jest.fn().mockResolvedValue([]),
20
+ findOne: jest.fn().mockResolvedValue(null),
21
+ update: jest.fn().mockResolvedValue(undefined),
22
+ delete: jest.fn().mockResolvedValue(undefined),
23
+ remove: jest.fn().mockResolvedValue({}),
24
+ count: jest.fn().mockResolvedValue(0),
25
+ query: jest.fn().mockResolvedValue([]),
26
+ createQueryBuilder: jest.fn().mockReturnValue({}),
27
+ getRepository: jest.fn().mockReturnValue({}),
28
+ queryRunner: {
29
+ isTransactionActive: false,
30
+ },
31
+ };
32
+ return mockEntityManager;
33
+ }
@@ -0,0 +1,99 @@
1
+ import { Logger } from '@nestjs/common';
2
+ import { Repository, EntityManager } from 'typeorm';
3
+ import { TransactionManager, Propagation, IsolationLevel, TransactionStatus } from './transaction-manager';
4
+ /**
5
+ * 事务感知的基础服务类
6
+ * 提供统一的数据操作接口,自动处理事务
7
+ */
8
+ export declare abstract class BaseService {
9
+ protected readonly transactionManager: TransactionManager;
10
+ protected readonly defaultDataSourceName: string;
11
+ protected readonly logger: Logger;
12
+ constructor(transactionManager: TransactionManager, defaultDataSourceName?: string);
13
+ /**
14
+ * 获取指定数据源的 EntityManager
15
+ */
16
+ protected getEntityManager(dataSourceName?: string): EntityManager;
17
+ /**
18
+ * 手动在事务中执行
19
+ */
20
+ protected executeInTransaction<T>(callback: (em: EntityManager) => Promise<T>, options?: {
21
+ propagation?: Propagation;
22
+ readOnly?: boolean;
23
+ isolation?: IsolationLevel;
24
+ dataSource?: string;
25
+ }): Promise<T>;
26
+ /**
27
+ * 保存实体
28
+ */
29
+ protected save<T>(entity: T, dataSourceName?: string): Promise<T>;
30
+ /**
31
+ * 批量保存实体
32
+ */
33
+ protected saveMany<T>(entities: T[], dataSourceName?: string): Promise<T[]>;
34
+ /**
35
+ * 更新实体
36
+ */
37
+ protected update<T>(entityClass: any, criteria: any, partialEntity: Partial<T>, dataSourceName?: string): Promise<void>;
38
+ /**
39
+ * 删除实体
40
+ */
41
+ protected remove<T>(entity: T, dataSourceName?: string): Promise<T>;
42
+ /**
43
+ * 根据 ID 删除实体
44
+ */
45
+ protected delete<T>(entityClass: any, id: string | number | (string | number)[], dataSourceName?: string): Promise<void>;
46
+ /**
47
+ * 查找实体
48
+ */
49
+ protected find<T>(entityClass: any, options?: any, dataSourceName?: string): Promise<T[]>;
50
+ /**
51
+ * 查找一个实体
52
+ */
53
+ protected findOne<T>(entityClass: any, options?: any, dataSourceName?: string): Promise<T | null>;
54
+ /**
55
+ * 根据 ID 查找实体
56
+ */
57
+ protected findById<T>(entityClass: any, id: string | number, dataSourceName?: string): Promise<T | null>;
58
+ /**
59
+ * 计数
60
+ */
61
+ protected count<T>(entityClass: any, options?: any, dataSourceName?: string): Promise<number>;
62
+ /**
63
+ * 执行原生 SQL
64
+ */
65
+ protected query<T = any>(query: string, parameters?: any[], dataSourceName?: string): Promise<T[]>;
66
+ /**
67
+ * 创建 Query Builder
68
+ */
69
+ protected createQueryBuilder<T>(entityClass: any, alias?: string, dataSourceName?: string): Promise<import("typeorm").SelectQueryBuilder<import("typeorm").ObjectLiteral>>;
70
+ /**
71
+ * 获取 Repository
72
+ */
73
+ protected getRepository<T>(entity: any, dataSourceName?: string): Promise<Repository<T>>;
74
+ /**
75
+ * 执行跨数据源操作
76
+ */
77
+ protected executeAcrossDataSources<T>(operations: Array<{
78
+ dataSourceName: string;
79
+ operation: (em: EntityManager) => Promise<any>;
80
+ }>, options?: {
81
+ rollbackOnError?: boolean;
82
+ }): Promise<T[]>;
83
+ /**
84
+ * 批量操作优化
85
+ */
86
+ protected batchOperation<T, R>(items: T[], batchSize: number, operation: (batch: T[], em: EntityManager) => Promise<R[]>, options?: {
87
+ continueOnError?: boolean;
88
+ isolation?: IsolationLevel;
89
+ dataSourceName?: string;
90
+ }): Promise<R[]>;
91
+ /**
92
+ * 检查是否在事务中
93
+ */
94
+ protected isInTransaction(dataSourceName?: string): boolean;
95
+ /**
96
+ * 获取当前事务状态
97
+ */
98
+ protected getCurrentTransactionStatus(dataSourceName?: string): TransactionStatus;
99
+ }
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
15
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
16
+ return new (P || (P = Promise))(function (resolve, reject) {
17
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
20
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
21
+ });
22
+ };
23
+ var BaseService_1;
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.BaseService = void 0;
26
+ const common_1 = require("@nestjs/common");
27
+ const transaction_manager_1 = require("./transaction-manager");
28
+ /**
29
+ * 事务感知的基础服务类
30
+ * 提供统一的数据操作接口,自动处理事务
31
+ */
32
+ let BaseService = BaseService_1 = class BaseService {
33
+ constructor(transactionManager, defaultDataSourceName = 'default') {
34
+ this.transactionManager = transactionManager;
35
+ this.defaultDataSourceName = defaultDataSourceName;
36
+ this.logger = new common_1.Logger(BaseService_1.name);
37
+ }
38
+ /**
39
+ * 获取指定数据源的 EntityManager
40
+ */
41
+ getEntityManager(dataSourceName) {
42
+ const dsName = dataSourceName || this.defaultDataSourceName;
43
+ const em = this.transactionManager.getCurrentEntityManager(dsName);
44
+ if (!em) {
45
+ throw new Error(`No active transaction for dataSource: ${dsName}. ` +
46
+ `Use @Transactional decorator to start a transaction.`);
47
+ }
48
+ return em;
49
+ }
50
+ /**
51
+ * 手动在事务中执行
52
+ */
53
+ executeInTransaction(callback, options) {
54
+ return __awaiter(this, void 0, void 0, function* () {
55
+ const status = yield this.transactionManager.getTransaction({
56
+ propagation: (options === null || options === void 0 ? void 0 : options.propagation) || transaction_manager_1.Propagation.REQUIRED,
57
+ readOnly: (options === null || options === void 0 ? void 0 : options.readOnly) || false,
58
+ isolationLevel: options === null || options === void 0 ? void 0 : options.isolation,
59
+ dataSourceName: (options === null || options === void 0 ? void 0 : options.dataSource) || this.defaultDataSourceName,
60
+ name: `executeInTransaction-${this.constructor.name}`,
61
+ });
62
+ try {
63
+ const em = this.getEntityManager(options === null || options === void 0 ? void 0 : options.dataSource);
64
+ const result = yield callback(em);
65
+ yield this.transactionManager.commit(status);
66
+ return result;
67
+ }
68
+ catch (error) {
69
+ yield this.transactionManager.rollback(status);
70
+ throw error;
71
+ }
72
+ });
73
+ }
74
+ /**
75
+ * 保存实体
76
+ */
77
+ save(entity, dataSourceName) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ const em = this.getEntityManager(dataSourceName);
80
+ return em.save(entity);
81
+ });
82
+ }
83
+ /**
84
+ * 批量保存实体
85
+ */
86
+ saveMany(entities, dataSourceName) {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ const em = this.getEntityManager(dataSourceName);
89
+ return em.save(entities);
90
+ });
91
+ }
92
+ /**
93
+ * 更新实体
94
+ */
95
+ update(entityClass, criteria, partialEntity, dataSourceName) {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ const em = this.getEntityManager(dataSourceName);
98
+ yield em.update(entityClass, criteria, partialEntity);
99
+ });
100
+ }
101
+ /**
102
+ * 删除实体
103
+ */
104
+ remove(entity, dataSourceName) {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ const em = this.getEntityManager(dataSourceName);
107
+ return em.remove(entity);
108
+ });
109
+ }
110
+ /**
111
+ * 根据 ID 删除实体
112
+ */
113
+ delete(entityClass, id, dataSourceName) {
114
+ return __awaiter(this, void 0, void 0, function* () {
115
+ const em = this.getEntityManager(dataSourceName);
116
+ yield em.delete(entityClass, id);
117
+ });
118
+ }
119
+ /**
120
+ * 查找实体
121
+ */
122
+ find(entityClass, options, dataSourceName) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const em = this.getEntityManager(dataSourceName);
125
+ return em.find(entityClass, options);
126
+ });
127
+ }
128
+ /**
129
+ * 查找一个实体
130
+ */
131
+ findOne(entityClass, options, dataSourceName) {
132
+ return __awaiter(this, void 0, void 0, function* () {
133
+ const em = this.getEntityManager(dataSourceName);
134
+ return em.findOne(entityClass, options);
135
+ });
136
+ }
137
+ /**
138
+ * 根据 ID 查找实体
139
+ */
140
+ findById(entityClass, id, dataSourceName) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ const em = this.getEntityManager(dataSourceName);
143
+ return em.findOne(entityClass, {
144
+ where: { id },
145
+ });
146
+ });
147
+ }
148
+ /**
149
+ * 计数
150
+ */
151
+ count(entityClass, options, dataSourceName) {
152
+ return __awaiter(this, void 0, void 0, function* () {
153
+ const em = this.getEntityManager(dataSourceName);
154
+ return em.count(entityClass, options);
155
+ });
156
+ }
157
+ /**
158
+ * 执行原生 SQL
159
+ */
160
+ query(query, parameters, dataSourceName) {
161
+ return __awaiter(this, void 0, void 0, function* () {
162
+ const em = this.getEntityManager(dataSourceName);
163
+ return em.query(query, parameters);
164
+ });
165
+ }
166
+ /**
167
+ * 创建 Query Builder
168
+ */
169
+ createQueryBuilder(entityClass, alias, dataSourceName) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ const em = this.getEntityManager(dataSourceName);
172
+ return em.createQueryBuilder(entityClass, alias || entityClass.name.toLowerCase());
173
+ });
174
+ }
175
+ /**
176
+ * 获取 Repository
177
+ */
178
+ getRepository(entity, dataSourceName) {
179
+ return __awaiter(this, void 0, void 0, function* () {
180
+ const em = this.getEntityManager(dataSourceName);
181
+ return em.getRepository(entity);
182
+ });
183
+ }
184
+ /**
185
+ * 执行跨数据源操作
186
+ */
187
+ executeAcrossDataSources(operations, options) {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ const results = [];
190
+ const startedTransactions = [];
191
+ try {
192
+ // 在每个数据源上开始事务
193
+ for (const op of operations) {
194
+ const status = yield this.transactionManager.getTransaction({
195
+ propagation: transaction_manager_1.Propagation.REQUIRED,
196
+ dataSourceName: op.dataSourceName,
197
+ });
198
+ startedTransactions.push(status);
199
+ }
200
+ // 执行所有操作
201
+ for (const op of operations) {
202
+ const em = this.getEntityManager(op.dataSourceName);
203
+ const result = yield op.operation(em);
204
+ results.push(result);
205
+ }
206
+ // 提交所有事务
207
+ for (const status of startedTransactions) {
208
+ yield this.transactionManager.commit(status);
209
+ }
210
+ return results;
211
+ }
212
+ catch (error) {
213
+ // 回滚所有事务
214
+ if ((options === null || options === void 0 ? void 0 : options.rollbackOnError) !== false) {
215
+ for (const status of startedTransactions.reverse()) {
216
+ try {
217
+ yield this.transactionManager.rollback(status);
218
+ }
219
+ catch (rollbackError) {
220
+ this.logger.error(`Failed to rollback transaction on ${status.dataSourceName}:`, rollbackError);
221
+ }
222
+ }
223
+ }
224
+ throw error;
225
+ }
226
+ });
227
+ }
228
+ /**
229
+ * 批量操作优化
230
+ */
231
+ batchOperation(items, batchSize, operation, options) {
232
+ return __awaiter(this, void 0, void 0, function* () {
233
+ const allResults = [];
234
+ let processedCount = 0;
235
+ return yield this.executeInTransaction((em) => __awaiter(this, void 0, void 0, function* () {
236
+ for (let i = 0; i < items.length; i += batchSize) {
237
+ const batch = items.slice(i, i + batchSize);
238
+ const batchNumber = Math.floor(i / batchSize) + 1;
239
+ try {
240
+ this.logger.log(`Processing batch ${batchNumber}/${Math.ceil(items.length / batchSize)}`);
241
+ const results = yield operation(batch, em);
242
+ allResults.push(...results);
243
+ processedCount += batch.length;
244
+ }
245
+ catch (error) {
246
+ this.logger.error(`Batch ${batchNumber} failed:`, error);
247
+ if (options === null || options === void 0 ? void 0 : options.continueOnError) {
248
+ // 记录失败但继续
249
+ processedCount += batch.length;
250
+ continue;
251
+ }
252
+ else {
253
+ throw new Error(`Batch operation failed at batch ${batchNumber}. Processed ${processedCount}/${items.length} items.`);
254
+ }
255
+ }
256
+ }
257
+ return allResults;
258
+ }), {
259
+ isolation: options === null || options === void 0 ? void 0 : options.isolation,
260
+ dataSource: options === null || options === void 0 ? void 0 : options.dataSourceName,
261
+ });
262
+ });
263
+ }
264
+ /**
265
+ * 检查是否在事务中
266
+ */
267
+ isInTransaction(dataSourceName) {
268
+ const dsName = dataSourceName || this.defaultDataSourceName;
269
+ const status = this.transactionManager.getCurrentTransaction(dsName);
270
+ return status !== null && !status.isCompleted;
271
+ }
272
+ /**
273
+ * 获取当前事务状态
274
+ */
275
+ getCurrentTransactionStatus(dataSourceName) {
276
+ const dsName = dataSourceName || this.defaultDataSourceName;
277
+ return this.transactionManager.getCurrentTransaction(dsName);
278
+ }
279
+ };
280
+ exports.BaseService = BaseService;
281
+ exports.BaseService = BaseService = BaseService_1 = __decorate([
282
+ (0, common_1.Injectable)(),
283
+ __param(1, (0, common_1.Optional)()),
284
+ __param(1, (0, common_1.Inject)('DEFAULT_DATA_SOURCE_NAME')),
285
+ __metadata("design:paramtypes", [transaction_manager_1.TransactionManager, String])
286
+ ], BaseService);