@nest-omni/core 4.1.3-11 → 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 (175) hide show
  1. package/audit/audit.module.js +17 -0
  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/entity-audit.decorator.d.ts +10 -1
  7. package/audit/decorators/entity-audit.decorator.js +34 -16
  8. package/audit/decorators/index.d.ts +1 -0
  9. package/audit/decorators/index.js +1 -0
  10. package/audit/entities/audit-action-summary.entity.d.ts +23 -0
  11. package/audit/entities/audit-action-summary.entity.js +101 -0
  12. package/audit/entities/entity-audit-log.entity.d.ts +3 -0
  13. package/audit/entities/entity-audit-log.entity.js +25 -2
  14. package/audit/entities/entity-transaction.entity.d.ts +3 -4
  15. package/audit/entities/entity-transaction.entity.js +10 -3
  16. package/audit/entities/index.d.ts +1 -0
  17. package/audit/entities/index.js +1 -0
  18. package/audit/entities/manual-operation-log.entity.js +8 -1
  19. package/audit/enums/audit.enums.d.ts +1 -10
  20. package/audit/enums/audit.enums.js +7 -17
  21. package/audit/index.d.ts +2 -1
  22. package/audit/index.js +5 -1
  23. package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
  24. package/audit/interceptors/audit-action.interceptor.js +215 -0
  25. package/audit/interceptors/index.d.ts +1 -0
  26. package/audit/interceptors/index.js +1 -0
  27. package/audit/interfaces/audit.interfaces.d.ts +10 -5
  28. package/audit/services/audit-action.service.d.ts +141 -0
  29. package/audit/services/audit-action.service.js +244 -0
  30. package/audit/services/audit-context.service.d.ts +82 -0
  31. package/audit/services/audit-context.service.js +170 -0
  32. package/audit/services/entity-audit.service.d.ts +104 -3
  33. package/audit/services/entity-audit.service.js +306 -9
  34. package/audit/services/index.d.ts +1 -0
  35. package/audit/services/index.js +1 -0
  36. package/audit/services/manual-audit-log.service.d.ts +24 -23
  37. package/audit/services/manual-audit-log.service.js +32 -53
  38. package/audit/services/operation-description.service.d.ts +13 -3
  39. package/audit/services/operation-description.service.js +161 -24
  40. package/audit/services/transaction-audit.service.js +3 -3
  41. package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
  42. package/audit/subscribers/entity-audit.subscriber.js +47 -0
  43. package/file-upload/controllers/file-access.controller.d.ts +23 -0
  44. package/file-upload/controllers/file-access.controller.js +128 -0
  45. package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
  46. package/file-upload/decorators/csv-data.decorator.js +131 -0
  47. package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
  48. package/file-upload/decorators/excel-data.decorator.js +125 -0
  49. package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
  50. package/file-upload/decorators/file-upload.decorator.js +172 -0
  51. package/file-upload/decorators/index.d.ts +4 -0
  52. package/file-upload/decorators/index.js +20 -0
  53. package/file-upload/decorators/process.decorator.d.ts +40 -0
  54. package/file-upload/decorators/process.decorator.js +52 -0
  55. package/file-upload/dto/create-file.dto.d.ts +24 -0
  56. package/file-upload/dto/create-file.dto.js +112 -0
  57. package/file-upload/dto/find-files.dto.d.ts +15 -0
  58. package/file-upload/dto/find-files.dto.js +76 -0
  59. package/file-upload/dto/index.d.ts +4 -0
  60. package/file-upload/dto/index.js +20 -0
  61. package/file-upload/dto/pagination.dto.d.ts +7 -0
  62. package/file-upload/dto/pagination.dto.js +39 -0
  63. package/file-upload/dto/update-file.dto.d.ts +16 -0
  64. package/file-upload/dto/update-file.dto.js +71 -0
  65. package/file-upload/entities/file-metadata.entity.d.ts +22 -0
  66. package/file-upload/entities/file-metadata.entity.js +84 -0
  67. package/file-upload/entities/file.entity.d.ts +129 -0
  68. package/file-upload/entities/file.entity.js +384 -0
  69. package/file-upload/entities/index.d.ts +2 -0
  70. package/file-upload/entities/index.js +18 -0
  71. package/file-upload/enums/file-type.enum.d.ts +72 -0
  72. package/file-upload/enums/file-type.enum.js +212 -0
  73. package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
  74. package/file-upload/exceptions/file-upload.exception.js +120 -0
  75. package/file-upload/exceptions/index.d.ts +1 -0
  76. package/file-upload/exceptions/index.js +17 -0
  77. package/file-upload/file-upload.module.d.ts +89 -0
  78. package/file-upload/file-upload.module.js +264 -0
  79. package/file-upload/index.d.ts +26 -0
  80. package/file-upload/index.js +59 -0
  81. package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
  82. package/file-upload/interceptors/file-upload.interceptor.js +434 -0
  83. package/file-upload/interceptors/index.d.ts +1 -0
  84. package/file-upload/interceptors/index.js +17 -0
  85. package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
  86. package/file-upload/interfaces/custom-file-type.interface.js +2 -0
  87. package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
  88. package/file-upload/interfaces/file-buffer.interface.js +2 -0
  89. package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
  90. package/file-upload/interfaces/file-entity.interface.js +28 -0
  91. package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
  92. package/file-upload/interfaces/file-metadata.interface.js +2 -0
  93. package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
  94. package/file-upload/interfaces/file-upload-options.interface.js +2 -0
  95. package/file-upload/interfaces/index.d.ts +7 -0
  96. package/file-upload/interfaces/index.js +24 -0
  97. package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
  98. package/file-upload/interfaces/storage-provider.interface.js +2 -0
  99. package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
  100. package/file-upload/interfaces/upload-options.interface.js +2 -0
  101. package/file-upload/providers/index.d.ts +2 -0
  102. package/file-upload/providers/index.js +18 -0
  103. package/file-upload/providers/local-storage.provider.d.ts +98 -0
  104. package/file-upload/providers/local-storage.provider.js +484 -0
  105. package/file-upload/providers/s3-storage.provider.d.ts +87 -0
  106. package/file-upload/providers/s3-storage.provider.js +455 -0
  107. package/file-upload/services/file-signature-validator.service.d.ts +118 -0
  108. package/file-upload/services/file-signature-validator.service.js +376 -0
  109. package/file-upload/services/file.service.d.ts +190 -0
  110. package/file-upload/services/file.service.js +609 -0
  111. package/file-upload/services/index.d.ts +4 -0
  112. package/file-upload/services/index.js +20 -0
  113. package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
  114. package/file-upload/services/malicious-file-detector.service.js +1035 -0
  115. package/file-upload/services/mime-registry.service.d.ts +47 -0
  116. package/file-upload/services/mime-registry.service.js +167 -0
  117. package/file-upload/utils/checksum.util.d.ts +28 -0
  118. package/file-upload/utils/checksum.util.js +65 -0
  119. package/file-upload/utils/dynamic-import.util.d.ts +50 -0
  120. package/file-upload/utils/dynamic-import.util.js +144 -0
  121. package/file-upload/utils/filename.util.d.ts +59 -0
  122. package/file-upload/utils/filename.util.js +184 -0
  123. package/file-upload/utils/filepath.util.d.ts +70 -0
  124. package/file-upload/utils/filepath.util.js +152 -0
  125. package/file-upload/utils/index.d.ts +4 -0
  126. package/file-upload/utils/index.js +20 -0
  127. package/index.d.ts +3 -1
  128. package/index.js +4 -1
  129. package/package.json +4 -5
  130. package/setup/bootstrap.setup.d.ts +1 -0
  131. package/setup/bootstrap.setup.js +1 -0
  132. package/shared/index.d.ts +1 -1
  133. package/shared/index.js +1 -1
  134. package/shared/{serviceRegistryModule.js → service-registry.module.js} +0 -12
  135. package/shared/services/index.d.ts +0 -1
  136. package/shared/services/index.js +0 -1
  137. package/transaction/__tests__/mocks.d.ts +9 -0
  138. package/transaction/__tests__/mocks.js +33 -0
  139. package/transaction/base-service-transaction.d.ts +99 -0
  140. package/transaction/base-service-transaction.js +286 -0
  141. package/transaction/cls-compatibility.service.d.ts +55 -0
  142. package/transaction/cls-compatibility.service.js +127 -0
  143. package/transaction/data-source-registry.d.ts +91 -0
  144. package/transaction/data-source-registry.js +349 -0
  145. package/transaction/database-adapter.d.ts +44 -0
  146. package/transaction/database-adapter.js +240 -0
  147. package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
  148. package/transaction/decorators/entity-datasource.decorator.js +105 -0
  149. package/transaction/index.d.ts +14 -0
  150. package/transaction/index.js +57 -0
  151. package/transaction/logging-transactional.interceptor.d.ts +18 -0
  152. package/transaction/logging-transactional.interceptor.js +163 -0
  153. package/transaction/transaction-context.service.d.ts +137 -0
  154. package/transaction/transaction-context.service.js +411 -0
  155. package/transaction/transaction-manager.d.ts +230 -0
  156. package/transaction/transaction-manager.js +1001 -0
  157. package/transaction/transaction-synchronization.d.ts +171 -0
  158. package/transaction/transaction-synchronization.js +380 -0
  159. package/transaction/transaction.errors.d.ts +91 -0
  160. package/transaction/transaction.errors.js +206 -0
  161. package/transaction/transaction.module.d.ts +30 -0
  162. package/transaction/transaction.module.js +98 -0
  163. package/transaction/transactional.decorator.d.ts +82 -0
  164. package/transaction/transactional.decorator.js +319 -0
  165. package/transaction/typeorm-module-wrapper.d.ts +96 -0
  166. package/transaction/typeorm-module-wrapper.js +197 -0
  167. package/validators/file-mimetype.validator.d.ts +0 -2
  168. package/validators/file-mimetype.validator.js +4 -6
  169. package/validators/is-exists.validator.d.ts +2 -5
  170. package/validators/is-exists.validator.js +4 -6
  171. package/validators/is-unique.validator.d.ts +2 -5
  172. package/validators/is-unique.validator.js +6 -11
  173. package/shared/services/validator.service.d.ts +0 -3
  174. package/shared/services/validator.service.js +0 -20
  175. /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
@@ -0,0 +1,455 @@
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ var S3StorageProvider_1;
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.S3StorageProvider = void 0;
23
+ const common_1 = require("@nestjs/common");
24
+ const dynamic_import_util_1 = require("../utils/dynamic-import.util");
25
+ /**
26
+ * AWS S3 存储提供者
27
+ * 使用动态导入,只在实际使用时加载 AWS SDK
28
+ */
29
+ let S3StorageProvider = S3StorageProvider_1 = class S3StorageProvider {
30
+ constructor(options) {
31
+ this.options = options;
32
+ this.name = 's3';
33
+ this.logger = new common_1.Logger(S3StorageProvider_1.name);
34
+ this.initialized = false;
35
+ }
36
+ /**
37
+ * 初始化存储配置
38
+ * 动态导入 AWS S3 SDK
39
+ */
40
+ initialize() {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ if (this.initialized) {
43
+ return;
44
+ }
45
+ try {
46
+ // 动态导入 AWS S3 SDK
47
+ const { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand, DeleteObjectsCommand, HeadObjectCommand, CopyObjectCommand, ListObjectsV2Command, getSignedUrl, } = yield dynamic_import_util_1.DynamicImportUtil.importAwsS3Sdk();
48
+ this.S3Commands = {
49
+ PutObjectCommand,
50
+ GetObjectCommand,
51
+ DeleteObjectCommand,
52
+ DeleteObjectsCommand,
53
+ HeadObjectCommand,
54
+ CopyObjectCommand,
55
+ ListObjectsV2Command,
56
+ };
57
+ this.s3GetSignedUrl = getSignedUrl;
58
+ // 创建 S3 客户端
59
+ const clientConfig = {
60
+ region: this.options.region,
61
+ credentials: {
62
+ accessKeyId: this.options.accessKeyId,
63
+ secretAccessKey: this.options.secretAccessKey,
64
+ },
65
+ };
66
+ // 自定义端点(用于 MinIO 或其他 S3 兼容服务)
67
+ if (this.options.endpoint) {
68
+ clientConfig.endpoint = this.options.endpoint;
69
+ }
70
+ // 强制路径样式访问(某些 S3 兼容服务需要)
71
+ if (this.options.forcePathStyle) {
72
+ clientConfig.forcePathStyle = true;
73
+ }
74
+ this.s3Client = new S3Client(clientConfig);
75
+ this.initialized = true;
76
+ this.logger.log(`S3 storage initialized: bucket=${this.options.bucket}, region=${this.options.region}`);
77
+ }
78
+ catch (error) {
79
+ this.logger.error('Failed to initialize S3 storage', error);
80
+ throw error;
81
+ }
82
+ });
83
+ }
84
+ /**
85
+ * 上传文件
86
+ */
87
+ upload(file, options) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ yield this.ensureInitialized();
90
+ const key = this.generateKey(file, options);
91
+ const command = new this.S3Commands.PutObjectCommand({
92
+ Bucket: this.options.bucket,
93
+ Key: key,
94
+ Body: file.buffer,
95
+ ContentType: file.mimeType,
96
+ Metadata: options.metadata || {},
97
+ ACL: options.acl || this.options.acl,
98
+ ServerSideEncryption: this.options.serverSideEncryption,
99
+ StorageClass: this.options.storageClass,
100
+ });
101
+ const response = yield this.s3Client.send(command);
102
+ const url = this.getFileUrl(key);
103
+ return {
104
+ key,
105
+ url,
106
+ etag: response.ETag,
107
+ versionId: response.VersionId,
108
+ size: file.size,
109
+ uploadedAt: new Date(),
110
+ metadata: {
111
+ originalName: file.originalName,
112
+ mimeType: file.mimeType,
113
+ bucket: this.options.bucket,
114
+ },
115
+ };
116
+ });
117
+ }
118
+ /**
119
+ * 下载文件
120
+ */
121
+ download(key) {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ var _a;
124
+ yield this.ensureInitialized();
125
+ const command = new this.S3Commands.GetObjectCommand({
126
+ Bucket: this.options.bucket,
127
+ Key: key,
128
+ });
129
+ const response = yield this.s3Client.send(command);
130
+ // 将流转换为 Buffer
131
+ const buffer = yield this.streamToBuffer(response.Body);
132
+ return {
133
+ buffer,
134
+ size: buffer.length,
135
+ mimeType: response.ContentType || 'application/octet-stream',
136
+ originalName: key.split('/').pop() || key,
137
+ hash: (_a = response.ETag) === null || _a === void 0 ? void 0 : _a.replace(/"/g, ''),
138
+ };
139
+ });
140
+ }
141
+ /**
142
+ * 删除文件
143
+ */
144
+ delete(key) {
145
+ return __awaiter(this, void 0, void 0, function* () {
146
+ yield this.ensureInitialized();
147
+ const command = new this.S3Commands.DeleteObjectCommand({
148
+ Bucket: this.options.bucket,
149
+ Key: key,
150
+ });
151
+ yield this.s3Client.send(command);
152
+ this.logger.log(`File deleted from S3: ${key}`);
153
+ });
154
+ }
155
+ /**
156
+ * 批量删除
157
+ */
158
+ deleteBatch(keys) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ var _a, _b;
161
+ yield this.ensureInitialized();
162
+ const command = new this.S3Commands.DeleteObjectsCommand({
163
+ Bucket: this.options.bucket,
164
+ Delete: {
165
+ Objects: keys.map((key) => ({ Key: key })),
166
+ Quiet: false,
167
+ },
168
+ });
169
+ const response = yield this.s3Client.send(command);
170
+ const deleted = ((_a = response.Deleted) === null || _a === void 0 ? void 0 : _a.map((item) => item.Key)) || [];
171
+ const failed = ((_b = response.Errors) === null || _b === void 0 ? void 0 : _b.map((item) => ({
172
+ path: item.Key,
173
+ error: item.Message,
174
+ }))) || [];
175
+ return {
176
+ deleted,
177
+ failed,
178
+ total: keys.length,
179
+ };
180
+ });
181
+ }
182
+ /**
183
+ * 检查文件是否存在
184
+ */
185
+ exists(key) {
186
+ return __awaiter(this, void 0, void 0, function* () {
187
+ var _a;
188
+ yield this.ensureInitialized();
189
+ try {
190
+ const command = new this.S3Commands.HeadObjectCommand({
191
+ Bucket: this.options.bucket,
192
+ Key: key,
193
+ });
194
+ yield this.s3Client.send(command);
195
+ return true;
196
+ }
197
+ catch (error) {
198
+ if (error.name === 'NotFound' ||
199
+ ((_a = error.$metadata) === null || _a === void 0 ? void 0 : _a.httpStatusCode) === 404) {
200
+ return false;
201
+ }
202
+ throw error;
203
+ }
204
+ });
205
+ }
206
+ /**
207
+ * 获取文件元数据
208
+ */
209
+ getMetadata(key) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ var _a;
212
+ yield this.ensureInitialized();
213
+ const command = new this.S3Commands.HeadObjectCommand({
214
+ Bucket: this.options.bucket,
215
+ Key: key,
216
+ });
217
+ const response = yield this.s3Client.send(command);
218
+ return {
219
+ size: response.ContentLength || 0,
220
+ mimeType: response.ContentType || 'application/octet-stream',
221
+ lastModified: response.LastModified || new Date(),
222
+ etag: (_a = response.ETag) === null || _a === void 0 ? void 0 : _a.replace(/"/g, ''),
223
+ metadata: response.Metadata,
224
+ };
225
+ });
226
+ }
227
+ /**
228
+ * 获取预签名URL(下载)
229
+ */
230
+ getSignedUrl(key_1) {
231
+ return __awaiter(this, arguments, void 0, function* (key, expiresIn = 3600) {
232
+ yield this.ensureInitialized();
233
+ const command = new this.S3Commands.GetObjectCommand({
234
+ Bucket: this.options.bucket,
235
+ Key: key,
236
+ });
237
+ return yield this.s3GetSignedUrl(this.s3Client, command, { expiresIn });
238
+ });
239
+ }
240
+ /**
241
+ * 获取预签名上传URL
242
+ */
243
+ getSignedUploadUrl(key_1) {
244
+ return __awaiter(this, arguments, void 0, function* (key, expiresIn = 3600, contentType) {
245
+ yield this.ensureInitialized();
246
+ const command = new this.S3Commands.PutObjectCommand({
247
+ Bucket: this.options.bucket,
248
+ Key: key,
249
+ ContentType: contentType,
250
+ });
251
+ const url = yield this.s3GetSignedUrl(this.s3Client, command, {
252
+ expiresIn,
253
+ });
254
+ return {
255
+ url,
256
+ method: 'PUT',
257
+ headers: contentType ? { 'Content-Type': contentType } : {},
258
+ expiresAt: new Date(Date.now() + expiresIn * 1000),
259
+ };
260
+ });
261
+ }
262
+ /**
263
+ * 复制文件
264
+ */
265
+ copy(sourceKey, destinationKey) {
266
+ return __awaiter(this, void 0, void 0, function* () {
267
+ var _a, _b;
268
+ yield this.ensureInitialized();
269
+ const command = new this.S3Commands.CopyObjectCommand({
270
+ Bucket: this.options.bucket,
271
+ CopySource: `${this.options.bucket}/${sourceKey}`,
272
+ Key: destinationKey,
273
+ });
274
+ const response = yield this.s3Client.send(command);
275
+ // 获取目标文件元数据
276
+ const metadata = yield this.getMetadata(destinationKey);
277
+ return {
278
+ destinationPath: destinationKey,
279
+ size: metadata.size,
280
+ copiedAt: new Date(),
281
+ etag: (_b = (_a = response.CopyObjectResult) === null || _a === void 0 ? void 0 : _a.ETag) === null || _b === void 0 ? void 0 : _b.replace(/"/g, ''),
282
+ };
283
+ });
284
+ }
285
+ /**
286
+ * 移动文件(复制后删除)
287
+ */
288
+ move(sourceKey, destinationKey) {
289
+ return __awaiter(this, void 0, void 0, function* () {
290
+ yield this.ensureInitialized();
291
+ // 先复制
292
+ const copyResult = yield this.copy(sourceKey, destinationKey);
293
+ // 再删除源文件
294
+ yield this.delete(sourceKey);
295
+ return {
296
+ destinationPath: destinationKey,
297
+ size: copyResult.size,
298
+ movedAt: new Date(),
299
+ etag: copyResult.etag,
300
+ };
301
+ });
302
+ }
303
+ /**
304
+ * 列出文件
305
+ */
306
+ list(prefix_1) {
307
+ return __awaiter(this, arguments, void 0, function* (prefix, limit = 1000) {
308
+ var _a;
309
+ yield this.ensureInitialized();
310
+ const command = new this.S3Commands.ListObjectsV2Command({
311
+ Bucket: this.options.bucket,
312
+ Prefix: prefix,
313
+ MaxKeys: limit,
314
+ });
315
+ const response = yield this.s3Client.send(command);
316
+ const files = ((_a = response.Contents) === null || _a === void 0 ? void 0 : _a.map((item) => {
317
+ var _a;
318
+ return ({
319
+ key: item.Key,
320
+ size: item.Size,
321
+ lastModified: item.LastModified,
322
+ etag: (_a = item.ETag) === null || _a === void 0 ? void 0 : _a.replace(/"/g, ''),
323
+ });
324
+ })) || [];
325
+ return {
326
+ files,
327
+ hasMore: response.IsTruncated || false,
328
+ nextMarker: response.NextContinuationToken,
329
+ totalCount: response.KeyCount,
330
+ };
331
+ });
332
+ }
333
+ /**
334
+ * 健康检查
335
+ */
336
+ healthCheck() {
337
+ return __awaiter(this, void 0, void 0, function* () {
338
+ const startTime = Date.now();
339
+ try {
340
+ yield this.ensureInitialized();
341
+ // 尝试列出存储桶中的对象
342
+ const command = new this.S3Commands.ListObjectsV2Command({
343
+ Bucket: this.options.bucket,
344
+ MaxKeys: 1,
345
+ });
346
+ yield this.s3Client.send(command);
347
+ return {
348
+ healthy: true,
349
+ responseTime: Date.now() - startTime,
350
+ details: {
351
+ bucket: this.options.bucket,
352
+ region: this.options.region,
353
+ accessible: true,
354
+ },
355
+ };
356
+ }
357
+ catch (error) {
358
+ return {
359
+ healthy: false,
360
+ responseTime: Date.now() - startTime,
361
+ error: error.message,
362
+ details: {
363
+ bucket: this.options.bucket,
364
+ region: this.options.region,
365
+ accessible: false,
366
+ },
367
+ };
368
+ }
369
+ });
370
+ }
371
+ /**
372
+ * 生成文件 Key
373
+ */
374
+ generateKey(file, options) {
375
+ const timestamp = Date.now();
376
+ const random = Math.random().toString(36).substring(2, 8);
377
+ const ext = file.originalName.split('.').pop();
378
+ let filename;
379
+ if (options.filename) {
380
+ filename = options.filename;
381
+ }
382
+ else {
383
+ filename = `${timestamp}-${random}.${ext}`;
384
+ }
385
+ // 添加路径前缀
386
+ if (options.path) {
387
+ return `${options.path}/${filename}`;
388
+ }
389
+ return filename;
390
+ }
391
+ /**
392
+ * 获取文件访问 URL
393
+ */
394
+ getFileUrl(key) {
395
+ // 如果启用了 CDN
396
+ if (this.options.cdnEnabled && this.options.cdnDomain) {
397
+ return `https://${this.options.cdnDomain}/${key}`;
398
+ }
399
+ // 标准 S3 URL
400
+ if (this.options.forcePathStyle || this.options.endpoint) {
401
+ return `${this.options.endpoint || `https://s3.${this.options.region}.amazonaws.com`}/${this.options.bucket}/${key}`;
402
+ }
403
+ // 虚拟主机样式
404
+ return `https://${this.options.bucket}.s3.${this.options.region}.amazonaws.com/${key}`;
405
+ }
406
+ /**
407
+ * 将流转换为 Buffer(带超时和大小限制)
408
+ */
409
+ streamToBuffer(stream) {
410
+ return __awaiter(this, void 0, void 0, function* () {
411
+ return new Promise((resolve, reject) => {
412
+ const chunks = [];
413
+ const MAX_SIZE = 100 * 1024 * 1024; // 100MB
414
+ const TIMEOUT = 30000; // 30s
415
+ let totalSize = 0;
416
+ const timeout = setTimeout(() => {
417
+ stream.destroy();
418
+ reject(new Error('Stream timeout after 30s'));
419
+ }, TIMEOUT);
420
+ stream.on('data', (chunk) => {
421
+ chunks.push(chunk);
422
+ totalSize += chunk.length;
423
+ if (totalSize > MAX_SIZE) {
424
+ stream.destroy();
425
+ clearTimeout(timeout);
426
+ reject(new Error(`Stream exceeds maximum size: ${MAX_SIZE} bytes`));
427
+ }
428
+ });
429
+ stream.on('error', (err) => {
430
+ clearTimeout(timeout);
431
+ reject(err);
432
+ });
433
+ stream.on('end', () => {
434
+ clearTimeout(timeout);
435
+ resolve(Buffer.concat(chunks));
436
+ });
437
+ });
438
+ });
439
+ }
440
+ /**
441
+ * 确保已初始化
442
+ */
443
+ ensureInitialized() {
444
+ return __awaiter(this, void 0, void 0, function* () {
445
+ if (!this.initialized) {
446
+ yield this.initialize();
447
+ }
448
+ });
449
+ }
450
+ };
451
+ exports.S3StorageProvider = S3StorageProvider;
452
+ exports.S3StorageProvider = S3StorageProvider = S3StorageProvider_1 = __decorate([
453
+ (0, common_1.Injectable)(),
454
+ __metadata("design:paramtypes", [Object])
455
+ ], S3StorageProvider);
@@ -0,0 +1,118 @@
1
+ import { CustomFileTypes, FileSignature } from '../interfaces/custom-file-type.interface';
2
+ import { MimeRegistryService } from './mime-registry.service';
3
+ /**
4
+ * 检测到的文件类型
5
+ */
6
+ export interface DetectedType {
7
+ /** 类型名称 */
8
+ type: string;
9
+ /** 签名 */
10
+ signature: FileSignature;
11
+ /** 置信度 0-1 */
12
+ confidence: number;
13
+ /** 是否为自定义类型 */
14
+ isCustom?: boolean;
15
+ }
16
+ /**
17
+ * 文件完整性检查结果
18
+ */
19
+ export interface IntegrityResult {
20
+ /** 是否完整 */
21
+ valid: boolean;
22
+ /** 错误列表 */
23
+ errors: string[];
24
+ }
25
+ /**
26
+ * 签名验证选项
27
+ */
28
+ export interface SignatureValidationOptions {
29
+ /** 读取的最大字节数 */
30
+ maxReadBytes?: number;
31
+ /** 是否严格验证 */
32
+ strict?: boolean;
33
+ /** 容差范围 */
34
+ tolerance?: number;
35
+ }
36
+ /**
37
+ * 验证结果
38
+ */
39
+ export interface ValidationResult {
40
+ /** 验证是否通过 */
41
+ valid: boolean;
42
+ /** 检测到的类型 */
43
+ detectedTypes: DetectedType[];
44
+ /** 期望的类型 */
45
+ expectedTypes: string[];
46
+ /** 错误列表 */
47
+ errors: string[];
48
+ /** 元数据 */
49
+ metadata: {
50
+ fileSize: number;
51
+ confidence: number;
52
+ signatures: Array<{
53
+ type: string;
54
+ signature: FileSignature;
55
+ }>;
56
+ };
57
+ }
58
+ /**
59
+ * 文件签名验证服务
60
+ */
61
+ export declare class FileSignatureValidator {
62
+ private readonly mimeRegistry;
63
+ private readonly logger;
64
+ private readonly defaultSignatures;
65
+ constructor(mimeRegistry: MimeRegistryService, customTypes?: CustomFileTypes);
66
+ /**
67
+ * 验证文件签名
68
+ */
69
+ validateFileSignature(filePath: string, expectedTypes: string[], options?: SignatureValidationOptions): Promise<ValidationResult>;
70
+ /**
71
+ * 检测文件类型
72
+ */
73
+ detectFileTypes(buffer: Buffer): Promise<DetectedType[]>;
74
+ /**
75
+ * 注册自定义签名
76
+ */
77
+ registerCustomSignatures(customTypes: CustomFileTypes): void;
78
+ /**
79
+ * 检查签名是否匹配
80
+ */
81
+ private matchesSignature;
82
+ /**
83
+ * 检查类型是否匹配
84
+ */
85
+ private matchesType;
86
+ /**
87
+ * 规范化签名字节
88
+ */
89
+ private normalizeSignatureBytes;
90
+ /**
91
+ * 读取文件缓冲区
92
+ */
93
+ private readFileBuffer;
94
+ /**
95
+ * 检查文件完整性
96
+ */
97
+ private checkFileIntegrity;
98
+ /**
99
+ * 读取文件尾部
100
+ */
101
+ private readFileTail;
102
+ /**
103
+ * 计算签名置信度
104
+ */
105
+ private calculateSignatureConfidence;
106
+ /**
107
+ * 计算总体置信度
108
+ */
109
+ private calculateConfidence;
110
+ /**
111
+ * 获取验证错误信息
112
+ */
113
+ private getValidationError;
114
+ /**
115
+ * 初始化默认签名
116
+ */
117
+ private initializeDefaultSignatures;
118
+ }