@nest-omni/core 4.1.3-1 → 4.1.3-10
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.
- package/audit/audit.module.d.ts +10 -0
- package/audit/audit.module.js +15 -0
- package/audit/controllers/audit.controller.d.ts +24 -0
- package/audit/controllers/audit.controller.js +24 -0
- package/audit/decorators/audit-controller.decorator.d.ts +8 -0
- package/audit/decorators/audit-controller.decorator.js +9 -0
- package/audit/decorators/audit-operation.decorator.d.ts +45 -0
- package/audit/decorators/audit-operation.decorator.js +49 -0
- package/audit/decorators/entity-audit.decorator.d.ts +8 -0
- package/audit/decorators/entity-audit.decorator.js +9 -0
- package/audit/dto/audit-log-query.dto.d.ts +3 -0
- package/audit/dto/audit-log-query.dto.js +3 -0
- package/audit/dto/begin-transaction.dto.d.ts +3 -0
- package/audit/dto/begin-transaction.dto.js +3 -0
- package/audit/dto/compare-entities.dto.d.ts +3 -0
- package/audit/dto/compare-entities.dto.js +3 -0
- package/audit/dto/pre-check-restore.dto.d.ts +3 -0
- package/audit/dto/pre-check-restore.dto.js +3 -0
- package/audit/dto/restore-entity.dto.d.ts +3 -0
- package/audit/dto/restore-entity.dto.js +3 -0
- package/audit/entities/entity-audit-log.entity.d.ts +3 -0
- package/audit/entities/entity-audit-log.entity.js +3 -0
- package/audit/entities/entity-transaction.entity.d.ts +3 -0
- package/audit/entities/entity-transaction.entity.js +3 -0
- package/audit/entities/manual-operation-log.entity.d.ts +4 -0
- package/audit/entities/manual-operation-log.entity.js +4 -0
- package/audit/entities/operation-template.entity.d.ts +4 -0
- package/audit/entities/operation-template.entity.js +4 -0
- package/audit/enums/audit.enums.d.ts +17 -2
- package/audit/enums/audit.enums.js +15 -0
- package/audit/index.js +10 -0
- package/audit/interceptors/audit.interceptor.d.ts +15 -0
- package/audit/interceptors/audit.interceptor.js +23 -1
- package/audit/interfaces/audit.interfaces.d.ts +42 -0
- package/audit/services/audit-context.service.d.ts +15 -0
- package/audit/services/audit-context.service.js +15 -0
- package/audit/services/audit-strategy.service.d.ts +6 -0
- package/audit/services/audit-strategy.service.js +13 -0
- package/audit/services/entity-audit.service.d.ts +57 -0
- package/audit/services/entity-audit.service.js +91 -0
- package/audit/services/manual-audit-log.service.d.ts +124 -0
- package/audit/services/manual-audit-log.service.js +138 -0
- package/audit/services/multi-database.service.d.ts +12 -0
- package/audit/services/multi-database.service.js +12 -0
- package/audit/services/operation-description.service.d.ts +59 -0
- package/audit/services/operation-description.service.js +76 -2
- package/audit/services/transaction-audit.service.d.ts +30 -0
- package/audit/services/transaction-audit.service.js +47 -0
- package/audit/subscribers/entity-audit.subscriber.d.ts +15 -0
- package/audit/subscribers/entity-audit.subscriber.js +29 -1
- package/cache/cache-metrics.service.d.ts +67 -0
- package/cache/cache-metrics.service.js +68 -4
- package/cache/cache-serialization.service.d.ts +31 -0
- package/cache/cache-serialization.service.js +25 -0
- package/cache/cache.constants.d.ts +9 -0
- package/cache/cache.constants.js +9 -0
- package/cache/cache.health.d.ts +26 -0
- package/cache/cache.health.js +30 -0
- package/cache/cache.module.d.ts +86 -0
- package/cache/cache.module.js +71 -0
- package/cache/cache.service.d.ts +140 -0
- package/cache/cache.service.js +157 -0
- package/cache/cache.warmup.service.d.ts +39 -0
- package/cache/cache.warmup.service.js +32 -0
- package/cache/decorators/cache-evict.decorator.d.ts +47 -0
- package/cache/decorators/cache-evict.decorator.js +56 -0
- package/cache/decorators/cache-put.decorator.d.ts +34 -0
- package/cache/decorators/cache-put.decorator.js +39 -0
- package/cache/decorators/cacheable.decorator.d.ts +40 -0
- package/cache/decorators/cacheable.decorator.js +55 -0
- package/cache/dependencies/callback.dependency.d.ts +33 -0
- package/cache/dependencies/callback.dependency.js +39 -1
- package/cache/dependencies/chain.dependency.d.ts +28 -0
- package/cache/dependencies/chain.dependency.js +34 -0
- package/cache/dependencies/db.dependency.d.ts +45 -0
- package/cache/dependencies/db.dependency.js +48 -1
- package/cache/dependencies/file.dependency.d.ts +32 -0
- package/cache/dependencies/file.dependency.js +34 -0
- package/cache/dependencies/tag.dependency.d.ts +36 -0
- package/cache/dependencies/tag.dependency.js +36 -0
- package/cache/dependencies/time.dependency.d.ts +43 -0
- package/cache/dependencies/time.dependency.js +43 -0
- package/cache/examples/basic-usage.d.ts +15 -0
- package/cache/examples/basic-usage.js +62 -8
- package/cache/index.js +9 -0
- package/cache/interfaces/cache-dependency.interface.d.ts +53 -0
- package/cache/interfaces/cache-options.interface.d.ts +81 -0
- package/cache/interfaces/cache-options.interface.js +6 -0
- package/cache/interfaces/cache-provider.interface.d.ts +78 -0
- package/cache/providers/base-cache.provider.d.ts +14 -0
- package/cache/providers/base-cache.provider.js +16 -0
- package/cache/providers/cls-cache.provider.d.ts +20 -0
- package/cache/providers/cls-cache.provider.js +28 -0
- package/cache/providers/memory-cache.provider.d.ts +23 -0
- package/cache/providers/memory-cache.provider.js +26 -0
- package/cache/providers/redis-cache.provider.d.ts +26 -0
- package/cache/providers/redis-cache.provider.js +29 -0
- package/cache/utils/dependency-manager.util.d.ts +52 -0
- package/cache/utils/dependency-manager.util.js +59 -0
- package/cache/utils/key-generator.util.d.ts +42 -0
- package/cache/utils/key-generator.util.js +53 -1
- package/common/abstract.entity.d.ts +14 -0
- package/common/abstract.entity.js +14 -0
- package/common/boilerplate.polyfill.d.ts +142 -4
- package/common/boilerplate.polyfill.js +24 -100
- package/common/dto/dto-container.d.ts +16 -0
- package/common/dto/dto-container.js +20 -0
- package/common/dto/dto-decorators.d.ts +18 -0
- package/common/dto/dto-decorators.js +14 -0
- package/common/dto/dto-extensions.d.ts +11 -0
- package/common/dto/dto-extensions.js +9 -0
- package/common/dto/dto-service-accessor.d.ts +17 -0
- package/common/dto/dto-service-accessor.js +18 -0
- package/common/dto/dto-transformer.d.ts +12 -0
- package/common/dto/dto-transformer.js +9 -0
- package/common/dto/index.js +2 -0
- package/common/examples/paginate-and-map.example.d.ts +6 -0
- package/common/examples/paginate-and-map.example.js +26 -0
- package/common/utils.d.ts +15 -0
- package/common/utils.js +15 -0
- package/constants/language-code.js +1 -0
- package/decorators/field.decorators.js +8 -1
- package/decorators/property.decorators.js +1 -0
- package/decorators/public-route.decorator.js +1 -0
- package/decorators/transform.decorators.d.ts +27 -0
- package/decorators/transform.decorators.js +29 -0
- package/decorators/translate.decorator.js +1 -0
- package/decorators/user.decorator.js +1 -0
- package/decorators/validator.decorators.d.ts +8 -18
- package/decorators/validator.decorators.js +22 -190
- package/filters/constraint-errors.js +1 -0
- package/helpers/common.helper.d.ts +13 -0
- package/helpers/common.helper.js +13 -0
- package/http-client/config/http-client.config.d.ts +15 -0
- package/http-client/config/http-client.config.js +25 -9
- package/http-client/decorators/http-client.decorators.d.ts +63 -0
- package/http-client/decorators/http-client.decorators.js +71 -3
- package/http-client/entities/http-log.entity.d.ts +229 -0
- package/http-client/entities/http-log.entity.js +6 -1
- package/http-client/errors/http-client.errors.d.ts +57 -0
- package/http-client/errors/http-client.errors.js +58 -0
- package/http-client/examples/advanced-usage.example.d.ts +41 -0
- package/http-client/examples/advanced-usage.example.js +68 -24
- package/http-client/examples/auth-with-waiting-lock.example.d.ts +31 -0
- package/http-client/examples/auth-with-waiting-lock.example.js +52 -5
- package/http-client/examples/basic-usage.example.d.ts +60 -0
- package/http-client/examples/basic-usage.example.js +60 -0
- package/http-client/examples/multi-api-configuration.example.d.ts +60 -0
- package/http-client/examples/multi-api-configuration.example.js +76 -5
- package/http-client/http-client.module.d.ts +13 -0
- package/http-client/http-client.module.js +19 -0
- package/http-client/index.js +8 -0
- package/http-client/interfaces/api-client-config.interface.d.ts +125 -0
- package/http-client/interfaces/api-client-config.interface.js +3 -0
- package/http-client/interfaces/http-client-config.interface.d.ts +60 -0
- package/http-client/services/api-client-registry.service.d.ts +57 -0
- package/http-client/services/api-client-registry.service.js +84 -1
- package/http-client/services/cache.service.d.ts +52 -0
- package/http-client/services/cache.service.js +72 -3
- package/http-client/services/circuit-breaker.service.d.ts +46 -0
- package/http-client/services/circuit-breaker.service.js +52 -0
- package/http-client/services/http-client.service.d.ts +67 -0
- package/http-client/services/http-client.service.js +105 -4
- package/http-client/services/http-log-query.service.d.ts +83 -0
- package/http-client/services/http-log-query.service.js +122 -1
- package/http-client/services/http-replay.service.d.ts +101 -0
- package/http-client/services/http-replay.service.js +86 -0
- package/http-client/services/log-cleanup.service.d.ts +63 -0
- package/http-client/services/log-cleanup.service.js +54 -2
- package/http-client/services/logging.service.d.ts +40 -0
- package/http-client/services/logging.service.js +53 -0
- package/http-client/utils/call-stack-extractor.util.d.ts +37 -0
- package/http-client/utils/call-stack-extractor.util.js +48 -0
- package/http-client/utils/context-extractor.util.d.ts +49 -0
- package/http-client/utils/context-extractor.util.js +52 -0
- package/http-client/utils/curl-generator.util.d.ts +21 -0
- package/http-client/utils/curl-generator.util.js +44 -3
- package/http-client/utils/request-id.util.d.ts +18 -0
- package/http-client/utils/request-id.util.js +20 -0
- package/http-client/utils/retry-recorder.util.d.ts +42 -0
- package/http-client/utils/retry-recorder.util.js +44 -0
- package/i18n/en_US/validation.json +2 -1
- package/i18n/zh_CN/validation.json +2 -1
- package/index.js +8 -0
- package/interceptors/translation-interceptor.service.js +5 -0
- package/package.json +1 -1
- package/providers/context.provider.js +2 -0
- package/providers/generator.provider.d.ts +4 -0
- package/providers/generator.provider.js +4 -0
- package/redis-lock/comprehensive-lock-cleanup.service.d.ts +94 -0
- package/redis-lock/comprehensive-lock-cleanup.service.js +253 -0
- package/redis-lock/examples/lock-strategy.examples.d.ts +89 -0
- package/redis-lock/examples/lock-strategy.examples.js +130 -15
- package/redis-lock/index.d.ts +2 -0
- package/redis-lock/index.js +8 -1
- package/redis-lock/lock-heartbeat.service.d.ts +78 -0
- package/redis-lock/lock-heartbeat.service.js +222 -0
- package/redis-lock/redis-lock.decorator.d.ts +101 -0
- package/redis-lock/redis-lock.decorator.js +120 -0
- package/redis-lock/redis-lock.module.d.ts +66 -0
- package/redis-lock/redis-lock.module.js +175 -70
- package/redis-lock/redis-lock.service.d.ts +260 -0
- package/redis-lock/redis-lock.service.js +244 -4
- package/setup/bootstrap.setup.js +20 -0
- package/setup/mode.setup.d.ts +44 -0
- package/setup/mode.setup.js +44 -0
- package/setup/schedule.decorator.d.ts +227 -0
- package/setup/schedule.decorator.js +219 -6
- package/setup/worker.decorator.d.ts +86 -0
- package/setup/worker.decorator.js +88 -0
- package/shared/serviceRegistryModule.js +9 -1
- package/shared/services/api-config.service.d.ts +3 -0
- package/shared/services/api-config.service.js +20 -9
- package/validator-json/decorators.d.ts +17 -0
- package/validator-json/decorators.js +17 -2
- package/validator-json/default.d.ts +6 -0
- package/validator-json/default.js +30 -2
- package/validator-json/defaultConverters.js +1 -0
- package/validator-json/options.d.ts +23 -0
- package/validators/common-validators.d.ts +143 -0
- package/validators/common-validators.js +249 -0
- package/validators/custom-validate.examples.d.ts +96 -0
- package/validators/custom-validate.examples.js +400 -0
- package/validators/custom-validate.validator.d.ts +134 -0
- package/validators/custom-validate.validator.js +214 -0
- package/validators/index.d.ts +2 -0
- package/validators/index.js +2 -0
- package/validators/is-exists.validator.d.ts +18 -4
- package/validators/is-exists.validator.js +67 -6
- package/validators/is-unique.validator.d.ts +32 -5
- package/validators/is-unique.validator.js +99 -17
- package/validators/skip-empty.validator.d.ts +5 -0
- package/validators/skip-empty.validator.js +5 -0
- package/vault/interfaces/vault-options.interface.d.ts +9 -0
- package/vault/vault-config.loader.d.ts +30 -0
- package/vault/vault-config.loader.js +48 -1
- package/vault/vault-config.service.d.ts +53 -0
- package/vault/vault-config.service.js +57 -0
- package/vault/vault.module.d.ts +4 -0
- package/vault/vault.module.js +4 -0
- package/decorators/examples/validation-decorators.example.d.ts +0 -69
- package/decorators/examples/validation-decorators.example.js +0 -331
|
@@ -32,6 +32,9 @@ const audit_context_service_1 = require("./audit-context.service");
|
|
|
32
32
|
const audit_strategy_service_1 = require("./audit-strategy.service");
|
|
33
33
|
const multi_database_service_1 = require("./multi-database.service");
|
|
34
34
|
const dto_1 = require("../../common/dto");
|
|
35
|
+
/**
|
|
36
|
+
* 实体审计服务
|
|
37
|
+
*/
|
|
35
38
|
let EntityAuditService = class EntityAuditService {
|
|
36
39
|
constructor(auditLogRepository, transactionRepository, entityManager, contextService, multiDbService, auditStrategy = new audit_strategy_service_1.DefaultAuditStrategy(), config, auditConnectionName) {
|
|
37
40
|
this.auditLogRepository = auditLogRepository;
|
|
@@ -43,22 +46,32 @@ let EntityAuditService = class EntityAuditService {
|
|
|
43
46
|
this.config = config;
|
|
44
47
|
this.auditConnectionName = auditConnectionName || 'default';
|
|
45
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* 记录实体变更
|
|
51
|
+
*/
|
|
46
52
|
logEntityChange(entityType_1, entityId_1, operation_1, oldValue_1, newValue_1) {
|
|
47
53
|
return __awaiter(this, arguments, void 0, function* (entityType, entityId, operation, oldValue, newValue, metadata = {}) {
|
|
48
54
|
var _a, _b;
|
|
55
|
+
// 检查是否应该记录
|
|
49
56
|
if (!this.auditStrategy.shouldRecord(entityType, operation)) {
|
|
50
57
|
return null;
|
|
51
58
|
}
|
|
59
|
+
// 获取记录策略
|
|
52
60
|
const recordStrategy = this.auditStrategy.getRecordStrategy(entityType, operation);
|
|
53
61
|
if (recordStrategy === enums_1.RecordStrategy.DISABLED) {
|
|
54
62
|
return null;
|
|
55
63
|
}
|
|
64
|
+
// 获取字段过滤器
|
|
56
65
|
const fieldFilter = this.auditStrategy.getFieldFilter(entityType);
|
|
66
|
+
// 过滤和脱敏字段
|
|
57
67
|
const filteredOldValue = this.filterAndMaskFields(oldValue, fieldFilter);
|
|
58
68
|
const filteredNewValue = this.filterAndMaskFields(newValue, fieldFilter);
|
|
69
|
+
// 计算变更字段
|
|
59
70
|
const changedFields = this.calculateChangedFields(filteredOldValue, filteredNewValue);
|
|
60
71
|
const changedFieldPaths = this.calculateChangedFieldPaths(filteredOldValue, filteredNewValue);
|
|
72
|
+
// 获取上下文信息
|
|
61
73
|
const context = yield this.contextService.getCurrentContext();
|
|
74
|
+
// 创建审计日志
|
|
62
75
|
const auditLog = this.auditLogRepository.create({
|
|
63
76
|
entityType,
|
|
64
77
|
entityId,
|
|
@@ -77,17 +90,23 @@ let EntityAuditService = class EntityAuditService {
|
|
|
77
90
|
? yield this.generateHashChain(entityType, entityId, filteredNewValue)
|
|
78
91
|
: undefined,
|
|
79
92
|
});
|
|
93
|
+
// 保存变更日志
|
|
80
94
|
const savedLog = yield this.auditLogRepository.save(auditLog);
|
|
81
95
|
return savedLog;
|
|
82
96
|
});
|
|
83
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* 查询审计日志
|
|
100
|
+
*/
|
|
84
101
|
getAuditLogs(query) {
|
|
85
102
|
return __awaiter(this, void 0, void 0, function* () {
|
|
103
|
+
// 应用默认值
|
|
86
104
|
const page = query.page || 1;
|
|
87
105
|
const limit = query.limit || 20;
|
|
88
106
|
const sortBy = query.sortBy || 'createdAt';
|
|
89
107
|
const sortOrder = query.sortOrder || 'DESC';
|
|
90
108
|
const queryBuilder = this.auditLogRepository.createQueryBuilder('log');
|
|
109
|
+
// 应用过滤条件
|
|
91
110
|
if (query.entityType) {
|
|
92
111
|
queryBuilder.andWhere('log.entityType = :entityType', { entityType: query.entityType });
|
|
93
112
|
}
|
|
@@ -111,7 +130,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
111
130
|
search: `%${query.search}%`,
|
|
112
131
|
});
|
|
113
132
|
}
|
|
133
|
+
// 应用排序
|
|
114
134
|
queryBuilder.orderBy(`log.${sortBy}`, sortOrder);
|
|
135
|
+
// 应用分页
|
|
115
136
|
const skip = (page - 1) * limit;
|
|
116
137
|
queryBuilder.skip(skip).take(limit);
|
|
117
138
|
const [data, total] = yield queryBuilder.getManyAndCount();
|
|
@@ -124,6 +145,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
124
145
|
return new dto_1.PageDto(data, pageMetaDto);
|
|
125
146
|
});
|
|
126
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* 比较实体差异
|
|
150
|
+
*/
|
|
127
151
|
compareEntities(entityType, entityId, fromLogId, toLogId) {
|
|
128
152
|
return __awaiter(this, void 0, void 0, function* () {
|
|
129
153
|
let fromData = {};
|
|
@@ -137,6 +161,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
137
161
|
toData = (toLog === null || toLog === void 0 ? void 0 : toLog.newValue) || {};
|
|
138
162
|
}
|
|
139
163
|
else {
|
|
164
|
+
// 获取最新的日志
|
|
140
165
|
const latestLog = yield this.auditLogRepository.findOne({
|
|
141
166
|
where: { entityType, entityId },
|
|
142
167
|
order: { createdAt: 'DESC' },
|
|
@@ -146,6 +171,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
146
171
|
return this.compareSnapshotData(fromData, toData);
|
|
147
172
|
});
|
|
148
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* 预检查恢复操作
|
|
176
|
+
*/
|
|
149
177
|
preCheckRestore(entityType, entityId, auditLogId) {
|
|
150
178
|
return __awaiter(this, void 0, void 0, function* () {
|
|
151
179
|
const auditLog = yield this.auditLogRepository.findOne({ where: { id: auditLogId } });
|
|
@@ -163,6 +191,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
163
191
|
warnings: [],
|
|
164
192
|
};
|
|
165
193
|
}
|
|
194
|
+
// 获取当前实体状态
|
|
166
195
|
const repository = this.entityManager.getRepository(entityType);
|
|
167
196
|
const currentEntity = yield repository.findOne({ where: { id: entityId } });
|
|
168
197
|
if (!currentEntity) {
|
|
@@ -179,6 +208,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
179
208
|
warnings: [],
|
|
180
209
|
};
|
|
181
210
|
}
|
|
211
|
+
// 检查冲突
|
|
182
212
|
const conflicts = this.detectConflicts(currentEntity, auditLog.oldValue);
|
|
183
213
|
return {
|
|
184
214
|
canRestore: conflicts.length === 0,
|
|
@@ -187,6 +217,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
187
217
|
};
|
|
188
218
|
});
|
|
189
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* 恢复实体
|
|
222
|
+
*/
|
|
190
223
|
restoreEntity(entityType_1, entityId_1, auditLogId_1) {
|
|
191
224
|
return __awaiter(this, arguments, void 0, function* (entityType, entityId, auditLogId, options = {}) {
|
|
192
225
|
const auditLog = yield this.auditLogRepository.findOne({ where: { id: auditLogId } });
|
|
@@ -196,6 +229,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
196
229
|
message: '审计日志不存在',
|
|
197
230
|
};
|
|
198
231
|
}
|
|
232
|
+
// 预检查
|
|
199
233
|
const preCheckResult = yield this.preCheckRestore(entityType, entityId, auditLogId);
|
|
200
234
|
if (!preCheckResult.canRestore && !options.force) {
|
|
201
235
|
return {
|
|
@@ -205,10 +239,13 @@ let EntityAuditService = class EntityAuditService {
|
|
|
205
239
|
};
|
|
206
240
|
}
|
|
207
241
|
try {
|
|
242
|
+
// 获取指定的数据库连接
|
|
208
243
|
const connectionName = options.connectionName || 'default';
|
|
209
244
|
const dataSource = yield this.multiDbService.getDataSource(connectionName);
|
|
210
245
|
const repository = dataSource.getRepository(entityType);
|
|
246
|
+
// 恢复实体
|
|
211
247
|
const restoreData = Object.assign({}, auditLog.oldValue);
|
|
248
|
+
// 应用字段过滤
|
|
212
249
|
if (options.includeFields && options.includeFields.length > 0) {
|
|
213
250
|
Object.keys(restoreData).forEach((key) => {
|
|
214
251
|
if (!options.includeFields.includes(key)) {
|
|
@@ -221,8 +258,10 @@ let EntityAuditService = class EntityAuditService {
|
|
|
221
258
|
delete restoreData[field];
|
|
222
259
|
});
|
|
223
260
|
}
|
|
261
|
+
// 执行恢复
|
|
224
262
|
if (!options.dryRun) {
|
|
225
263
|
yield repository.update({ id: entityId }, restoreData);
|
|
264
|
+
// 记录恢复操作
|
|
226
265
|
yield this.logEntityChange(entityType, entityId, enums_1.AuditOperation.RESTORE, auditLog.newValue, restoreData);
|
|
227
266
|
}
|
|
228
267
|
return {
|
|
@@ -239,9 +278,14 @@ let EntityAuditService = class EntityAuditService {
|
|
|
239
278
|
}
|
|
240
279
|
});
|
|
241
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* 计算变更字段
|
|
283
|
+
*/
|
|
242
284
|
calculateChangedFields(oldValue, newValue) {
|
|
243
285
|
const changedFields = [];
|
|
286
|
+
// 获取所有字段
|
|
244
287
|
const allFields = new Set([...Object.keys(oldValue || {}), ...Object.keys(newValue || {})]);
|
|
288
|
+
// 比较每个字段
|
|
245
289
|
for (const field of allFields) {
|
|
246
290
|
const oldVal = oldValue === null || oldValue === void 0 ? void 0 : oldValue[field];
|
|
247
291
|
const newVal = newValue === null || newValue === void 0 ? void 0 : newValue[field];
|
|
@@ -251,14 +295,22 @@ let EntityAuditService = class EntityAuditService {
|
|
|
251
295
|
}
|
|
252
296
|
return changedFields;
|
|
253
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* 计算变更字段路径
|
|
300
|
+
*/
|
|
254
301
|
calculateChangedFieldPaths(oldValue, newValue) {
|
|
255
302
|
const changedPaths = [];
|
|
303
|
+
// 使用深度比较获取变更路径
|
|
256
304
|
const diff = this.deepDiff(oldValue, newValue);
|
|
305
|
+
// 提取路径
|
|
257
306
|
for (const change of diff) {
|
|
258
307
|
changedPaths.push(change.path.join('.'));
|
|
259
308
|
}
|
|
260
309
|
return changedPaths;
|
|
261
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* 深度比较对象
|
|
313
|
+
*/
|
|
262
314
|
deepEqual(a, b) {
|
|
263
315
|
if (a === b)
|
|
264
316
|
return true;
|
|
@@ -282,13 +334,18 @@ let EntityAuditService = class EntityAuditService {
|
|
|
282
334
|
}
|
|
283
335
|
return true;
|
|
284
336
|
}
|
|
337
|
+
/**
|
|
338
|
+
* 深度差异比较
|
|
339
|
+
*/
|
|
285
340
|
deepDiff(oldObj, newObj, path = []) {
|
|
286
341
|
var _a;
|
|
287
342
|
const changes = [];
|
|
288
343
|
const maxDepth = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxDiffDepth) || 5;
|
|
344
|
+
// 防止过深
|
|
289
345
|
if (path.length > maxDepth) {
|
|
290
346
|
return changes;
|
|
291
347
|
}
|
|
348
|
+
// 处理基本类型
|
|
292
349
|
if (typeof oldObj !== 'object' || oldObj === null) {
|
|
293
350
|
if (oldObj !== newObj) {
|
|
294
351
|
changes.push({
|
|
@@ -300,6 +357,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
300
357
|
}
|
|
301
358
|
return changes;
|
|
302
359
|
}
|
|
360
|
+
// 处理数组
|
|
303
361
|
if (Array.isArray(oldObj)) {
|
|
304
362
|
if (!Array.isArray(newObj)) {
|
|
305
363
|
changes.push({
|
|
@@ -324,6 +382,7 @@ let EntityAuditService = class EntityAuditService {
|
|
|
324
382
|
}
|
|
325
383
|
return changes;
|
|
326
384
|
}
|
|
385
|
+
// 处理对象
|
|
327
386
|
const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]);
|
|
328
387
|
for (const key of allKeys) {
|
|
329
388
|
const oldVal = oldObj[key];
|
|
@@ -350,6 +409,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
350
409
|
}
|
|
351
410
|
return changes;
|
|
352
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* 比较快照数据
|
|
414
|
+
*/
|
|
353
415
|
compareSnapshotData(fromData, toData) {
|
|
354
416
|
const changes = this.deepDiff(fromData, toData);
|
|
355
417
|
return {
|
|
@@ -361,6 +423,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
361
423
|
},
|
|
362
424
|
};
|
|
363
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* 过滤和脱敏字段
|
|
428
|
+
*/
|
|
364
429
|
filterAndMaskFields(data, fieldFilter, path = []) {
|
|
365
430
|
if (typeof data !== 'object' || data === null) {
|
|
366
431
|
return data;
|
|
@@ -368,14 +433,17 @@ let EntityAuditService = class EntityAuditService {
|
|
|
368
433
|
const result = {};
|
|
369
434
|
for (const [key, value] of Object.entries(data)) {
|
|
370
435
|
const currentPath = [...path, key];
|
|
436
|
+
// 检查是否应该包含此字段
|
|
371
437
|
if (!fieldFilter.shouldIncludeField(key, currentPath)) {
|
|
372
438
|
continue;
|
|
373
439
|
}
|
|
440
|
+
// 检查是否应该脱敏此字段
|
|
374
441
|
if (fieldFilter.shouldMaskField(key, currentPath)) {
|
|
375
442
|
const maskingStrategy = fieldFilter.getMaskingStrategy(key, currentPath);
|
|
376
443
|
result[key] = this.applyMasking(value, maskingStrategy);
|
|
377
444
|
}
|
|
378
445
|
else if (typeof value === 'object' && value !== null) {
|
|
446
|
+
// 递归处理嵌套对象
|
|
379
447
|
result[key] = this.filterAndMaskFields(value, fieldFilter, currentPath);
|
|
380
448
|
}
|
|
381
449
|
else {
|
|
@@ -384,6 +452,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
384
452
|
}
|
|
385
453
|
return result;
|
|
386
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* 应用脱敏策略
|
|
457
|
+
*/
|
|
387
458
|
applyMasking(value, strategy) {
|
|
388
459
|
if (value == null)
|
|
389
460
|
return value;
|
|
@@ -400,14 +471,23 @@ let EntityAuditService = class EntityAuditService {
|
|
|
400
471
|
return '***MASKED***';
|
|
401
472
|
}
|
|
402
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* 哈希值
|
|
476
|
+
*/
|
|
403
477
|
hashValue(value) {
|
|
404
478
|
const strValue = String(value);
|
|
405
479
|
return (0, crypto_1.createHash)('sha256').update(strValue).digest('hex');
|
|
406
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* 掩码值
|
|
483
|
+
*/
|
|
407
484
|
maskValue(value) {
|
|
408
485
|
const strValue = String(value);
|
|
409
486
|
return '*'.repeat(strValue.length);
|
|
410
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
* 部分掩码值
|
|
490
|
+
*/
|
|
411
491
|
partialMaskValue(value) {
|
|
412
492
|
const strValue = String(value);
|
|
413
493
|
if (strValue.length <= 4) {
|
|
@@ -417,14 +497,19 @@ let EntityAuditService = class EntityAuditService {
|
|
|
417
497
|
'*'.repeat(strValue.length - 4) +
|
|
418
498
|
strValue.substring(strValue.length - 2));
|
|
419
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* 生成哈希链
|
|
502
|
+
*/
|
|
420
503
|
generateHashChain(entityType, entityId, data) {
|
|
421
504
|
return __awaiter(this, void 0, void 0, function* () {
|
|
422
505
|
var _a, _b, _c;
|
|
506
|
+
// 获取上一个审计记录的哈希
|
|
423
507
|
const lastLog = yield this.auditLogRepository.findOne({
|
|
424
508
|
where: { entityType, entityId },
|
|
425
509
|
order: { createdAt: 'DESC' },
|
|
426
510
|
});
|
|
427
511
|
const previousHash = ((_a = lastLog === null || lastLog === void 0 ? void 0 : lastLog.hashChain) === null || _a === void 0 ? void 0 : _a.currentHash) || '';
|
|
512
|
+
// 计算当前数据的哈希
|
|
428
513
|
const currentData = JSON.stringify(data);
|
|
429
514
|
const hashAlgorithm = ((_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.security) === null || _c === void 0 ? void 0 : _c.hashAlgorithm) || 'sha256';
|
|
430
515
|
const currentHash = (0, crypto_1.createHash)(hashAlgorithm).update(currentData + previousHash).digest('hex');
|
|
@@ -435,6 +520,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
435
520
|
};
|
|
436
521
|
});
|
|
437
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* 生成描述
|
|
525
|
+
*/
|
|
438
526
|
generateDescription(operation, entityType, entityId, changedFields) {
|
|
439
527
|
const operationText = {
|
|
440
528
|
[enums_1.AuditOperation.CREATE]: '创建',
|
|
@@ -448,6 +536,9 @@ let EntityAuditService = class EntityAuditService {
|
|
|
448
536
|
}
|
|
449
537
|
return `${text} ${entityType}(${entityId})`;
|
|
450
538
|
}
|
|
539
|
+
/**
|
|
540
|
+
* 检测冲突
|
|
541
|
+
*/
|
|
451
542
|
detectConflicts(currentEntity, targetValue) {
|
|
452
543
|
const conflicts = [];
|
|
453
544
|
for (const [key, targetVal] of Object.entries(targetValue)) {
|
|
@@ -2,6 +2,11 @@ import { Repository, DataSource } from 'typeorm';
|
|
|
2
2
|
import { ManualOperationLogEntity, EntityTransactionEntity } from '../entities';
|
|
3
3
|
import { AuditContextService } from './audit-context.service';
|
|
4
4
|
import { ManualLogOptions } from '../interfaces';
|
|
5
|
+
/**
|
|
6
|
+
* 手动审计日志服务
|
|
7
|
+
*
|
|
8
|
+
* 提供全局静态方法,在任意地方手动记录操作日志
|
|
9
|
+
*/
|
|
5
10
|
export declare class ManualAuditLogService {
|
|
6
11
|
private readonly manualLogRepository;
|
|
7
12
|
private readonly transactionRepository;
|
|
@@ -9,15 +14,134 @@ export declare class ManualAuditLogService {
|
|
|
9
14
|
private readonly dataSource;
|
|
10
15
|
private static instance;
|
|
11
16
|
constructor(manualLogRepository: Repository<ManualOperationLogEntity>, transactionRepository: Repository<EntityTransactionEntity>, contextService: AuditContextService, dataSource: DataSource);
|
|
17
|
+
/**
|
|
18
|
+
* 全局静态方法:记录操作日志
|
|
19
|
+
*
|
|
20
|
+
* @description
|
|
21
|
+
* 支持三种记录模式:
|
|
22
|
+
* 1. 模板键模式:从数据库查找模板
|
|
23
|
+
* 2. 直接描述模式:直接传入字符串或多语言描述
|
|
24
|
+
* 3. 内联模板模式:传入多语言模板 + 参数
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // 模式1:模板键模式
|
|
28
|
+
* await ManualAuditLogService.log({
|
|
29
|
+
* templateKey: 'user.login',
|
|
30
|
+
* descriptionParams: {
|
|
31
|
+
* username: 'john.doe',
|
|
32
|
+
* loginTime: new Date().toISOString(),
|
|
33
|
+
* },
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // 模式2:直接描述模式(字符串)
|
|
38
|
+
* await ManualAuditLogService.log({
|
|
39
|
+
* description: '用户登录系统',
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* // 模式2:直接描述模式(多语言)
|
|
44
|
+
* await ManualAuditLogService.log({
|
|
45
|
+
* description: {
|
|
46
|
+
* zh: '用户登录系统',
|
|
47
|
+
* en: 'User logged in',
|
|
48
|
+
* },
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // 模式3:内联模板模式
|
|
53
|
+
* await ManualAuditLogService.log({
|
|
54
|
+
* descriptionTemplate: {
|
|
55
|
+
* zh: '用户 {username} 在 {time} 登录了系统',
|
|
56
|
+
* en: 'User {username} logged in at {time}',
|
|
57
|
+
* },
|
|
58
|
+
* descriptionParams: {
|
|
59
|
+
* username: 'john.doe',
|
|
60
|
+
* time: new Date().toISOString(),
|
|
61
|
+
* },
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
12
64
|
static log(options: ManualLogOptions): Promise<ManualOperationLogEntity>;
|
|
65
|
+
/**
|
|
66
|
+
* 实例方法:记录操作日志
|
|
67
|
+
*/
|
|
13
68
|
logOperation(options: ManualLogOptions): Promise<ManualOperationLogEntity>;
|
|
69
|
+
/**
|
|
70
|
+
* 静态方法:带事务记录
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const txId = await ManualAuditLogService.beginTransaction('user-123', 'John Doe');
|
|
75
|
+
*
|
|
76
|
+
* await ManualAuditLogService.log({
|
|
77
|
+
* templateKey: 'order.create',
|
|
78
|
+
* descriptionParams: { orderId: 'order-1' },
|
|
79
|
+
* transactionId: txId,
|
|
80
|
+
* autoCreateTransaction: false,
|
|
81
|
+
* });
|
|
82
|
+
*
|
|
83
|
+
* await ManualAuditLogService.log({
|
|
84
|
+
* templateKey: 'payment.process',
|
|
85
|
+
* descriptionParams: { paymentId: 'pay-1' },
|
|
86
|
+
* transactionId: txId,
|
|
87
|
+
* autoCreateTransaction: false,
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* await ManualAuditLogService.commitTransaction(txId);
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
14
93
|
static beginTransaction(userId?: string, username?: string): Promise<string>;
|
|
94
|
+
/**
|
|
95
|
+
* 静态方法:提交事务
|
|
96
|
+
*/
|
|
15
97
|
static commitTransaction(transactionId: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* 静态方法:回滚事务
|
|
100
|
+
*/
|
|
16
101
|
static rollbackTransaction(transactionId: string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* 创建事务
|
|
104
|
+
*/
|
|
17
105
|
private createTransaction;
|
|
106
|
+
/**
|
|
107
|
+
* 更新事务状态
|
|
108
|
+
*/
|
|
18
109
|
private updateTransactionStatus;
|
|
110
|
+
/**
|
|
111
|
+
* 生成事务ID
|
|
112
|
+
*/
|
|
19
113
|
private generateTransactionId;
|
|
114
|
+
/**
|
|
115
|
+
* 批量记录操作日志
|
|
116
|
+
*
|
|
117
|
+
* @description
|
|
118
|
+
* 批量记录多个操作,支持所有三种记录模式
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // 混合使用多种模式
|
|
123
|
+
* await ManualAuditLogService.logBatch([
|
|
124
|
+
* {
|
|
125
|
+
* templateKey: 'product.update',
|
|
126
|
+
* descriptionParams: { productId: 'p1', field: 'price' },
|
|
127
|
+
* },
|
|
128
|
+
* {
|
|
129
|
+
* description: '批量更新库存',
|
|
130
|
+
* },
|
|
131
|
+
* {
|
|
132
|
+
* descriptionTemplate: {
|
|
133
|
+
* zh: '更新产品 {productId} 的 {field}',
|
|
134
|
+
* en: 'Update {field} of product {productId}',
|
|
135
|
+
* },
|
|
136
|
+
* descriptionParams: { productId: 'p3', field: 'stock' },
|
|
137
|
+
* },
|
|
138
|
+
* ]);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
20
141
|
static logBatch(operations: ManualLogOptions[], sharedTransactionId?: string): Promise<ManualOperationLogEntity[]>;
|
|
142
|
+
/**
|
|
143
|
+
* 查询操作日志
|
|
144
|
+
*/
|
|
21
145
|
static findLogs(options: {
|
|
22
146
|
templateKey?: string;
|
|
23
147
|
userId?: string;
|