@nest-omni/core 4.1.3-12 → 4.1.3-14
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/cache/dependencies/db.dependency.d.ts +55 -6
- package/cache/dependencies/db.dependency.js +64 -13
- package/common/boilerplate.polyfill.js +1 -1
- package/file-upload/decorators/column.decorator.d.ts +151 -0
- package/file-upload/decorators/column.decorator.js +273 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +17 -31
- package/file-upload/decorators/csv-data.decorator.js +45 -91
- package/file-upload/decorators/csv-import.decorator.d.ts +34 -0
- package/file-upload/decorators/csv-import.decorator.js +24 -0
- package/file-upload/decorators/examples/column-mapping.example.d.ts +76 -0
- package/file-upload/decorators/examples/column-mapping.example.js +122 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +15 -29
- package/file-upload/decorators/excel-data.decorator.js +42 -82
- package/file-upload/decorators/index.d.ts +3 -2
- package/file-upload/decorators/index.js +20 -2
- package/file-upload/decorators/validate-data.decorator.d.ts +91 -0
- package/file-upload/decorators/validate-data.decorator.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +0 -1
- package/file-upload/dto/update-file.dto.js +0 -4
- package/file-upload/entities/file-metadata.entity.d.ts +6 -3
- package/file-upload/entities/file-metadata.entity.js +2 -10
- package/file-upload/entities/file.entity.d.ts +3 -18
- package/file-upload/entities/file.entity.js +0 -34
- package/file-upload/file-upload.module.d.ts +1 -1
- package/file-upload/file-upload.module.js +44 -16
- package/file-upload/index.d.ts +13 -2
- package/file-upload/index.js +21 -3
- package/file-upload/interceptors/file-upload.interceptor.d.ts +61 -8
- package/file-upload/interceptors/file-upload.interceptor.js +417 -257
- package/file-upload/interfaces/file-processor.interface.d.ts +93 -0
- package/file-upload/interfaces/file-processor.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +3 -46
- package/file-upload/interfaces/file-upload-options.interface.js +3 -0
- package/file-upload/interfaces/processor-options.interface.d.ts +102 -0
- package/file-upload/interfaces/processor-options.interface.js +2 -0
- package/file-upload/processors/csv.processor.d.ts +98 -0
- package/file-upload/processors/csv.processor.js +391 -0
- package/file-upload/processors/excel.processor.d.ts +130 -0
- package/file-upload/processors/excel.processor.js +547 -0
- package/file-upload/processors/image.processor.d.ts +199 -0
- package/file-upload/processors/image.processor.js +377 -0
- package/file-upload/services/file.service.d.ts +3 -0
- package/file-upload/services/file.service.js +39 -10
- package/file-upload/services/malicious-file-detector.service.d.ts +29 -3
- package/file-upload/services/malicious-file-detector.service.js +256 -57
- package/file-upload/utils/dynamic-import.util.d.ts +6 -2
- package/file-upload/utils/dynamic-import.util.js +17 -5
- package/http-client/decorators/http-client.decorators.d.ts +4 -2
- package/http-client/decorators/http-client.decorators.js +2 -1
- package/http-client/entities/http-log.entity.js +1 -9
- package/http-client/examples/proxy-from-environment.example.d.ts +133 -0
- package/http-client/examples/proxy-from-environment.example.js +410 -0
- package/http-client/http-client.module.js +65 -6
- package/http-client/interfaces/http-client-config.interface.d.ts +6 -0
- package/http-client/services/http-client.service.d.ts +8 -0
- package/http-client/services/http-client.service.js +61 -17
- package/http-client/services/logging.service.d.ts +1 -1
- package/http-client/services/logging.service.js +74 -58
- package/http-client/utils/index.d.ts +1 -0
- package/http-client/utils/index.js +1 -0
- package/http-client/utils/proxy-environment.util.d.ts +42 -0
- package/http-client/utils/proxy-environment.util.js +148 -0
- package/package.json +9 -5
- package/shared/service-registry.module.js +18 -0
- package/transaction/data-source.util.d.ts +142 -0
- package/transaction/data-source.util.js +330 -0
- package/transaction/index.d.ts +1 -0
- package/transaction/index.js +12 -1
- package/validators/is-exists.validator.d.ts +19 -2
- package/validators/is-exists.validator.js +27 -2
- package/validators/is-unique.validator.d.ts +12 -1
- package/validators/is-unique.validator.js +26 -1
|
@@ -9,117 +9,77 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.ExcelData = exports.EXCEL_COLUMN_METADATA = void 0;
|
|
13
12
|
exports.ExcelColumn = ExcelColumn;
|
|
14
13
|
exports.getExcelColumnMapping = getExcelColumnMapping;
|
|
15
14
|
exports.parseAndValidateExcelData = parseAndValidateExcelData;
|
|
16
|
-
|
|
15
|
+
require("reflect-metadata");
|
|
17
16
|
const class_transformer_1 = require("class-transformer");
|
|
18
17
|
const class_validator_1 = require("class-validator");
|
|
18
|
+
const EXCEL_COLUMN_METADATA_KEY = Symbol('excel:column');
|
|
19
19
|
/**
|
|
20
|
-
* Excel
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Excel 列名映射装饰器
|
|
20
|
+
* Excel 列映射装饰器
|
|
21
|
+
* 用于标记 DTO 类的属性对应的 Excel 列名
|
|
22
|
+
*
|
|
25
23
|
* @example
|
|
26
24
|
* ```typescript
|
|
27
|
-
*
|
|
25
|
+
* class UserDto {
|
|
28
26
|
* @ExcelColumn('姓名')
|
|
29
|
-
* @IsString()
|
|
30
27
|
* name: string;
|
|
28
|
+
*
|
|
29
|
+
* @ExcelColumn('邮箱')
|
|
30
|
+
* email: string;
|
|
31
31
|
* }
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
function ExcelColumn(columnName) {
|
|
35
35
|
return (target, propertyKey) => {
|
|
36
|
-
Reflect.
|
|
36
|
+
const existingColumns = Reflect.getMetadata(EXCEL_COLUMN_METADATA_KEY, target.constructor) || {};
|
|
37
|
+
existingColumns[columnName] = propertyKey;
|
|
38
|
+
Reflect.defineMetadata(EXCEL_COLUMN_METADATA_KEY, existingColumns, target.constructor);
|
|
37
39
|
};
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
|
-
* Excel
|
|
41
|
-
* @example
|
|
42
|
-
* ```typescript
|
|
43
|
-
* @Post('import/excel')
|
|
44
|
-
* @FileUpload({ types: [FileType.Excel] })
|
|
45
|
-
* async importExcel(@ExcelData(UserImportDto) users: UserImportDto[]) {
|
|
46
|
-
* await this.userService.batchCreate(users);
|
|
47
|
-
* return { count: users.length };
|
|
48
|
-
* }
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
exports.ExcelData = (0, common_1.createParamDecorator)((data, ctx) => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
-
const request = ctx.switchToHttp().getRequest();
|
|
53
|
-
const file = request.file;
|
|
54
|
-
if (!file) {
|
|
55
|
-
throw new Error('No file uploaded');
|
|
56
|
-
}
|
|
57
|
-
// 这里将在 interceptor 中处理 Excel 解析
|
|
58
|
-
// 当前只返回文件信息,实际解析逻辑在 FileUploadInterceptor 中
|
|
59
|
-
return {
|
|
60
|
-
_excelData: true,
|
|
61
|
-
dto: data,
|
|
62
|
-
file,
|
|
63
|
-
options: data === null || data === void 0 ? void 0 : data['options'],
|
|
64
|
-
};
|
|
65
|
-
}));
|
|
66
|
-
/**
|
|
67
|
-
* 辅助函数:获取 DTO 的 Excel 列映射
|
|
42
|
+
* 获取 Excel 列映射
|
|
68
43
|
*/
|
|
69
44
|
function getExcelColumnMapping(dto) {
|
|
70
|
-
|
|
71
|
-
const prototype = dto.prototype;
|
|
72
|
-
if (!prototype) {
|
|
73
|
-
return mapping;
|
|
74
|
-
}
|
|
75
|
-
const propertyKeys = Object.getOwnPropertyNames(prototype);
|
|
76
|
-
for (const propertyKey of propertyKeys) {
|
|
77
|
-
const columnName = Reflect.getMetadata(exports.EXCEL_COLUMN_METADATA, prototype, propertyKey);
|
|
78
|
-
if (columnName) {
|
|
79
|
-
mapping.set(columnName, propertyKey);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return mapping;
|
|
45
|
+
return Reflect.getMetadata(EXCEL_COLUMN_METADATA_KEY, dto) || {};
|
|
83
46
|
}
|
|
84
47
|
/**
|
|
85
|
-
*
|
|
48
|
+
* 解析并验证 Excel 数据
|
|
86
49
|
*/
|
|
87
|
-
function parseAndValidateExcelData(
|
|
88
|
-
return __awaiter(this,
|
|
89
|
-
const
|
|
90
|
-
const
|
|
50
|
+
function parseAndValidateExcelData(data, dto, options) {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
const columnMapping = getExcelColumnMapping(dto);
|
|
53
|
+
const results = [];
|
|
91
54
|
const errors = [];
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// 映射列名到属性名
|
|
101
|
-
for (const [columnName, propertyKey] of mapping.entries()) {
|
|
102
|
-
obj[propertyKey] = row[columnName];
|
|
55
|
+
for (let i = 0; i < data.length; i++) {
|
|
56
|
+
const row = data[i];
|
|
57
|
+
const mappedData = {};
|
|
58
|
+
// 映射列名
|
|
59
|
+
for (const [excelColumn, dtoProperty] of Object.entries(columnMapping)) {
|
|
60
|
+
if (row.hasOwnProperty(excelColumn)) {
|
|
61
|
+
mappedData[dtoProperty] = row[excelColumn];
|
|
62
|
+
}
|
|
103
63
|
}
|
|
104
64
|
// 转换为 DTO 实例
|
|
105
|
-
const instance = (0, class_transformer_1.plainToInstance)(
|
|
65
|
+
const instance = (0, class_transformer_1.plainToInstance)(dto, mappedData);
|
|
106
66
|
// 验证
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
67
|
+
if (!(options === null || options === void 0 ? void 0 : options.skipValidation)) {
|
|
68
|
+
const validationErrors = yield (0, class_validator_1.validate)(instance);
|
|
69
|
+
if (validationErrors.length > 0) {
|
|
70
|
+
errors.push({
|
|
71
|
+
row: i + 1,
|
|
72
|
+
data: row,
|
|
73
|
+
errors: validationErrors.map((e) => ({
|
|
74
|
+
property: e.property,
|
|
75
|
+
constraints: e.constraints,
|
|
76
|
+
})),
|
|
77
|
+
});
|
|
78
|
+
continue;
|
|
116
79
|
}
|
|
117
80
|
}
|
|
118
|
-
|
|
119
|
-
data.push(instance);
|
|
120
|
-
}
|
|
121
|
-
rowsProcessed++;
|
|
81
|
+
results.push(instance);
|
|
122
82
|
}
|
|
123
|
-
return { data, errors };
|
|
83
|
+
return { data: results, errors };
|
|
124
84
|
});
|
|
125
85
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from './file-upload.decorator';
|
|
2
|
-
export
|
|
3
|
-
export
|
|
2
|
+
export { ExcelColumn as ExcelColumnDecorator, getExcelColumnMapping as getExcelColumnMappingLegacy, parseAndValidateExcelData } from './excel-data.decorator';
|
|
3
|
+
export { CsvColumn as CsvColumnDecorator, getCsvColumnMapping as getCsvColumnMappingLegacy, parseAndValidateCsvData } from './csv-data.decorator';
|
|
4
|
+
export { CSVColumn, ExcelColumn, getCsvColumnMapping, getExcelColumnMapping, processRowWithMapping, excelColumnToNumber, numberToExcelColumn, ColumnIdentifier } from './column.decorator';
|
|
4
5
|
export * from './process.decorator';
|
|
@@ -14,7 +14,25 @@ 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
|
+
exports.numberToExcelColumn = exports.excelColumnToNumber = exports.processRowWithMapping = exports.getExcelColumnMapping = exports.getCsvColumnMapping = exports.ExcelColumn = exports.CSVColumn = exports.parseAndValidateCsvData = exports.getCsvColumnMappingLegacy = exports.CsvColumnDecorator = exports.parseAndValidateExcelData = exports.getExcelColumnMappingLegacy = exports.ExcelColumnDecorator = void 0;
|
|
17
18
|
__exportStar(require("./file-upload.decorator"), exports);
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
// Excel/CSV 列映射装饰器(字段级别)
|
|
20
|
+
var excel_data_decorator_1 = require("./excel-data.decorator");
|
|
21
|
+
Object.defineProperty(exports, "ExcelColumnDecorator", { enumerable: true, get: function () { return excel_data_decorator_1.ExcelColumn; } });
|
|
22
|
+
Object.defineProperty(exports, "getExcelColumnMappingLegacy", { enumerable: true, get: function () { return excel_data_decorator_1.getExcelColumnMapping; } });
|
|
23
|
+
Object.defineProperty(exports, "parseAndValidateExcelData", { enumerable: true, get: function () { return excel_data_decorator_1.parseAndValidateExcelData; } });
|
|
24
|
+
var csv_data_decorator_1 = require("./csv-data.decorator");
|
|
25
|
+
Object.defineProperty(exports, "CsvColumnDecorator", { enumerable: true, get: function () { return csv_data_decorator_1.CsvColumn; } });
|
|
26
|
+
Object.defineProperty(exports, "getCsvColumnMappingLegacy", { enumerable: true, get: function () { return csv_data_decorator_1.getCsvColumnMapping; } });
|
|
27
|
+
Object.defineProperty(exports, "parseAndValidateCsvData", { enumerable: true, get: function () { return csv_data_decorator_1.parseAndValidateCsvData; } });
|
|
28
|
+
// 列装饰器和相关辅助函数(推荐使用)
|
|
29
|
+
var column_decorator_1 = require("./column.decorator");
|
|
30
|
+
Object.defineProperty(exports, "CSVColumn", { enumerable: true, get: function () { return column_decorator_1.CSVColumn; } });
|
|
31
|
+
Object.defineProperty(exports, "ExcelColumn", { enumerable: true, get: function () { return column_decorator_1.ExcelColumn; } });
|
|
32
|
+
Object.defineProperty(exports, "getCsvColumnMapping", { enumerable: true, get: function () { return column_decorator_1.getCsvColumnMapping; } });
|
|
33
|
+
Object.defineProperty(exports, "getExcelColumnMapping", { enumerable: true, get: function () { return column_decorator_1.getExcelColumnMapping; } });
|
|
34
|
+
Object.defineProperty(exports, "processRowWithMapping", { enumerable: true, get: function () { return column_decorator_1.processRowWithMapping; } });
|
|
35
|
+
Object.defineProperty(exports, "excelColumnToNumber", { enumerable: true, get: function () { return column_decorator_1.excelColumnToNumber; } });
|
|
36
|
+
Object.defineProperty(exports, "numberToExcelColumn", { enumerable: true, get: function () { return column_decorator_1.numberToExcelColumn; } });
|
|
37
|
+
// NOTE: @ExcelDataParam 和 @CsvDataParam 参数装饰器已废弃并移除
|
|
20
38
|
__exportStar(require("./process.decorator"), exports);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 验证装饰器元数据键
|
|
3
|
+
*/
|
|
4
|
+
export declare const VALIDATE_DATA_KEY = "validate:data";
|
|
5
|
+
/**
|
|
6
|
+
* 数据验证配置
|
|
7
|
+
*/
|
|
8
|
+
export interface ValidateDataOptions {
|
|
9
|
+
/** 验证类 */
|
|
10
|
+
validateClass?: any;
|
|
11
|
+
/** 是否验证数组 */
|
|
12
|
+
isArray?: boolean;
|
|
13
|
+
/** 验证组 */
|
|
14
|
+
groups?: string[];
|
|
15
|
+
/** 是否跳过缺失属性 */
|
|
16
|
+
skipMissingProperties?: boolean;
|
|
17
|
+
/** 是否跳过未装饰的属性 */
|
|
18
|
+
skipUndefinedProperties?: boolean;
|
|
19
|
+
/** 自定义验证器 */
|
|
20
|
+
customValidators?: Array<{
|
|
21
|
+
property: string;
|
|
22
|
+
validator: (value: any) => boolean | string;
|
|
23
|
+
}>;
|
|
24
|
+
/** 转换器 */
|
|
25
|
+
transformers?: Array<{
|
|
26
|
+
property: string;
|
|
27
|
+
transformer: (value: any) => any;
|
|
28
|
+
}>;
|
|
29
|
+
/** 错误处理策略 */
|
|
30
|
+
onError?: 'stop' | 'collect' | 'skip';
|
|
31
|
+
/** 是否启用自动类型转换 */
|
|
32
|
+
autoTransform?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 数据验证装饰器
|
|
36
|
+
* 用于在控制器方法上启用数据验证
|
|
37
|
+
*/
|
|
38
|
+
export declare const ValidateData: (options?: ValidateDataOptions) => import("@nestjs/common").CustomDecorator<string>;
|
|
39
|
+
/**
|
|
40
|
+
* 批量数据验证装饰器
|
|
41
|
+
* 用于验证数组数据
|
|
42
|
+
*/
|
|
43
|
+
export declare const ValidateArray: (validateClass: any, options?: Omit<ValidateDataOptions, "isArray" | "validateClass">) => import("@nestjs/common").CustomDecorator<string>;
|
|
44
|
+
/**
|
|
45
|
+
* 自动验证转换装饰器
|
|
46
|
+
* 自动应用 class-transformer 的转换
|
|
47
|
+
*/
|
|
48
|
+
export declare const AutoTransform: (options?: {
|
|
49
|
+
excludeExtraneousValues?: boolean;
|
|
50
|
+
}) => import("@nestjs/common").CustomDecorator<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Excel/CSV 行数据验证基类
|
|
53
|
+
* 使用 class-validator 定义验证规则
|
|
54
|
+
*/
|
|
55
|
+
export declare abstract class BaseRowData {
|
|
56
|
+
/**
|
|
57
|
+
* 验证行数据
|
|
58
|
+
* 子类应该使用 class-validator 装饰器定义验证规则
|
|
59
|
+
*/
|
|
60
|
+
abstract validate(): Promise<string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* 转换行数据
|
|
63
|
+
* 子类可以重写此方法进行数据转换
|
|
64
|
+
*/
|
|
65
|
+
transform?(): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* 清理数据
|
|
68
|
+
* 子类可以重写此方法进行数据清理
|
|
69
|
+
*/
|
|
70
|
+
clean?(): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 验证结果
|
|
74
|
+
*/
|
|
75
|
+
export interface ValidationResult {
|
|
76
|
+
/** 是否通过验证 */
|
|
77
|
+
isValid: boolean;
|
|
78
|
+
/** 错误列表 */
|
|
79
|
+
errors: Array<{
|
|
80
|
+
row?: number;
|
|
81
|
+
field: string;
|
|
82
|
+
message: string;
|
|
83
|
+
value: any;
|
|
84
|
+
property: string;
|
|
85
|
+
constraints?: Record<string, string>;
|
|
86
|
+
}>;
|
|
87
|
+
/** 转换后的数据 */
|
|
88
|
+
data?: any;
|
|
89
|
+
/** 警告信息 */
|
|
90
|
+
warnings?: string[];
|
|
91
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseRowData = exports.AutoTransform = exports.ValidateArray = exports.ValidateData = exports.VALIDATE_DATA_KEY = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
/**
|
|
6
|
+
* 验证装饰器元数据键
|
|
7
|
+
*/
|
|
8
|
+
exports.VALIDATE_DATA_KEY = 'validate:data';
|
|
9
|
+
/**
|
|
10
|
+
* 数据验证装饰器
|
|
11
|
+
* 用于在控制器方法上启用数据验证
|
|
12
|
+
*/
|
|
13
|
+
const ValidateData = (options = {}) => {
|
|
14
|
+
return (0, common_1.SetMetadata)(exports.VALIDATE_DATA_KEY, options);
|
|
15
|
+
};
|
|
16
|
+
exports.ValidateData = ValidateData;
|
|
17
|
+
/**
|
|
18
|
+
* 批量数据验证装饰器
|
|
19
|
+
* 用于验证数组数据
|
|
20
|
+
*/
|
|
21
|
+
const ValidateArray = (validateClass, options = {}) => {
|
|
22
|
+
return (0, common_1.SetMetadata)(exports.VALIDATE_DATA_KEY, Object.assign(Object.assign({}, options), { validateClass, isArray: true }));
|
|
23
|
+
};
|
|
24
|
+
exports.ValidateArray = ValidateArray;
|
|
25
|
+
/**
|
|
26
|
+
* 自动验证转换装饰器
|
|
27
|
+
* 自动应用 class-transformer 的转换
|
|
28
|
+
*/
|
|
29
|
+
const AutoTransform = (options = {}) => {
|
|
30
|
+
return (0, common_1.SetMetadata)('auto:transform', options);
|
|
31
|
+
};
|
|
32
|
+
exports.AutoTransform = AutoTransform;
|
|
33
|
+
/**
|
|
34
|
+
* Excel/CSV 行数据验证基类
|
|
35
|
+
* 使用 class-validator 定义验证规则
|
|
36
|
+
*/
|
|
37
|
+
class BaseRowData {
|
|
38
|
+
}
|
|
39
|
+
exports.BaseRowData = BaseRowData;
|
|
@@ -65,7 +65,3 @@ __decorate([
|
|
|
65
65
|
(0, class_validator_1.IsOptional)(),
|
|
66
66
|
__metadata("design:type", Object)
|
|
67
67
|
], UpdateFileDto.prototype, "validationData", void 0);
|
|
68
|
-
__decorate([
|
|
69
|
-
(0, class_validator_1.IsOptional)(),
|
|
70
|
-
__metadata("design:type", Object)
|
|
71
|
-
], UpdateFileDto.prototype, "processingData", void 0);
|
|
@@ -6,17 +6,20 @@ export declare class FileMetadataEntity {
|
|
|
6
6
|
id: string;
|
|
7
7
|
fileId: string;
|
|
8
8
|
key: string;
|
|
9
|
+
/**
|
|
10
|
+
* 元数据值(JSON 字符串)
|
|
11
|
+
* 支持存储任何 JSON 可序列化的数据
|
|
12
|
+
*/
|
|
9
13
|
value: string;
|
|
10
|
-
jsonData: any;
|
|
11
14
|
isPublic: boolean;
|
|
12
15
|
createdAt: Date;
|
|
13
16
|
file: FileEntity;
|
|
14
17
|
/**
|
|
15
|
-
*
|
|
18
|
+
* 获取值(自动解析 JSON)
|
|
16
19
|
*/
|
|
17
20
|
getValue<T = any>(): T;
|
|
18
21
|
/**
|
|
19
|
-
*
|
|
22
|
+
* 设置值(自动序列化为 JSON 字符串)
|
|
20
23
|
*/
|
|
21
24
|
setValue(value: any): void;
|
|
22
25
|
}
|
|
@@ -18,12 +18,9 @@ const file_entity_1 = require("./file.entity");
|
|
|
18
18
|
let FileMetadataEntity = class FileMetadataEntity {
|
|
19
19
|
// ========== 便捷方法 ==========
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* 获取值(自动解析 JSON)
|
|
22
22
|
*/
|
|
23
23
|
getValue() {
|
|
24
|
-
if (this.jsonData !== null && this.jsonData !== undefined) {
|
|
25
|
-
return this.jsonData;
|
|
26
|
-
}
|
|
27
24
|
if (this.value) {
|
|
28
25
|
try {
|
|
29
26
|
return JSON.parse(this.value);
|
|
@@ -35,10 +32,9 @@ let FileMetadataEntity = class FileMetadataEntity {
|
|
|
35
32
|
return null;
|
|
36
33
|
}
|
|
37
34
|
/**
|
|
38
|
-
*
|
|
35
|
+
* 设置值(自动序列化为 JSON 字符串)
|
|
39
36
|
*/
|
|
40
37
|
setValue(value) {
|
|
41
|
-
this.jsonData = value;
|
|
42
38
|
this.value = typeof value === 'string' ? value : JSON.stringify(value);
|
|
43
39
|
}
|
|
44
40
|
};
|
|
@@ -59,10 +55,6 @@ __decorate([
|
|
|
59
55
|
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
|
60
56
|
__metadata("design:type", String)
|
|
61
57
|
], FileMetadataEntity.prototype, "value", void 0);
|
|
62
|
-
__decorate([
|
|
63
|
-
(0, typeorm_1.Column)({ type: 'json', nullable: true }),
|
|
64
|
-
__metadata("design:type", Object)
|
|
65
|
-
], FileMetadataEntity.prototype, "jsonData", void 0);
|
|
66
58
|
__decorate([
|
|
67
59
|
(0, typeorm_1.Column)({ default: false }),
|
|
68
60
|
__metadata("design:type", Boolean)
|
|
@@ -21,6 +21,9 @@ export declare class FileEntity {
|
|
|
21
21
|
tempPath: string;
|
|
22
22
|
status: 'processing' | 'completed' | 'failed' | 'deleted';
|
|
23
23
|
errorMessage: string;
|
|
24
|
+
/**
|
|
25
|
+
* 验证数据(文件签名检测、类型检测等)
|
|
26
|
+
*/
|
|
24
27
|
validationData: {
|
|
25
28
|
detectedTypes: Array<{
|
|
26
29
|
type: string;
|
|
@@ -34,16 +37,6 @@ export declare class FileEntity {
|
|
|
34
37
|
}>;
|
|
35
38
|
integrityChecks: string[];
|
|
36
39
|
};
|
|
37
|
-
processingData: {
|
|
38
|
-
processors: Array<{
|
|
39
|
-
name: string;
|
|
40
|
-
startTime: Date;
|
|
41
|
-
endTime?: Date;
|
|
42
|
-
status: 'pending' | 'completed' | 'failed';
|
|
43
|
-
result?: any;
|
|
44
|
-
error?: string;
|
|
45
|
-
}>;
|
|
46
|
-
};
|
|
47
40
|
createdAt: Date;
|
|
48
41
|
updatedAt: Date;
|
|
49
42
|
deletedAt: Date;
|
|
@@ -118,12 +111,4 @@ export declare class FileEntity {
|
|
|
118
111
|
* 添加验证数据
|
|
119
112
|
*/
|
|
120
113
|
addValidationData(data: Partial<FileEntity['validationData']>): void;
|
|
121
|
-
/**
|
|
122
|
-
* 添加处理步骤
|
|
123
|
-
*/
|
|
124
|
-
addProcessingStep(processor: string): void;
|
|
125
|
-
/**
|
|
126
|
-
* 更新处理步骤
|
|
127
|
-
*/
|
|
128
|
-
updateProcessingStep(processor: string, status: 'completed' | 'failed', result?: any, error?: string): void;
|
|
129
114
|
}
|
|
@@ -223,36 +223,6 @@ let FileEntity = FileEntity_1 = class FileEntity {
|
|
|
223
223
|
}
|
|
224
224
|
this.validationData = Object.assign(Object.assign({}, this.validationData), data);
|
|
225
225
|
}
|
|
226
|
-
/**
|
|
227
|
-
* 添加处理步骤
|
|
228
|
-
*/
|
|
229
|
-
addProcessingStep(processor) {
|
|
230
|
-
if (!this.processingData) {
|
|
231
|
-
this.processingData = { processors: [] };
|
|
232
|
-
}
|
|
233
|
-
this.processingData.processors.push({
|
|
234
|
-
name: processor,
|
|
235
|
-
startTime: new Date(),
|
|
236
|
-
status: 'pending',
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* 更新处理步骤
|
|
241
|
-
*/
|
|
242
|
-
updateProcessingStep(processor, status, result, error) {
|
|
243
|
-
var _a;
|
|
244
|
-
if (!((_a = this.processingData) === null || _a === void 0 ? void 0 : _a.processors))
|
|
245
|
-
return;
|
|
246
|
-
const step = this.processingData.processors.find((p) => p.name === processor);
|
|
247
|
-
if (step) {
|
|
248
|
-
step.status = status;
|
|
249
|
-
step.endTime = new Date();
|
|
250
|
-
if (result !== undefined)
|
|
251
|
-
step.result = result;
|
|
252
|
-
if (error)
|
|
253
|
-
step.error = error;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
226
|
};
|
|
257
227
|
exports.FileEntity = FileEntity;
|
|
258
228
|
__decorate([
|
|
@@ -356,10 +326,6 @@ __decorate([
|
|
|
356
326
|
(0, typeorm_1.Column)({ type: 'json', nullable: true }),
|
|
357
327
|
__metadata("design:type", Object)
|
|
358
328
|
], FileEntity.prototype, "validationData", void 0);
|
|
359
|
-
__decorate([
|
|
360
|
-
(0, typeorm_1.Column)({ type: 'json', nullable: true }),
|
|
361
|
-
__metadata("design:type", Object)
|
|
362
|
-
], FileEntity.prototype, "processingData", void 0);
|
|
363
329
|
__decorate([
|
|
364
330
|
(0, typeorm_1.CreateDateColumn)(),
|
|
365
331
|
__metadata("design:type", Date)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DynamicModule } from '@nestjs/common';
|
|
2
|
-
import { IFileProcessor } from './interfaces/file-
|
|
2
|
+
import { IFileProcessor } from './interfaces/file-processor.interface';
|
|
3
3
|
import { LocalStorageOptions, S3StorageOptions } from './interfaces/storage-provider.interface';
|
|
4
4
|
import { CustomFileTypes } from './interfaces/custom-file-type.interface';
|
|
5
5
|
import { MaliciousDetectorOptions } from './services/malicious-file-detector.service';
|
|
@@ -28,6 +28,9 @@ const file_service_1 = require("./services/file.service");
|
|
|
28
28
|
const file_entity_1 = require("./entities/file.entity");
|
|
29
29
|
const file_metadata_entity_1 = require("./entities/file-metadata.entity");
|
|
30
30
|
const file_access_controller_1 = require("./controllers/file-access.controller");
|
|
31
|
+
const csv_processor_1 = require("./processors/csv.processor");
|
|
32
|
+
const excel_processor_1 = require("./processors/excel.processor");
|
|
33
|
+
const image_processor_1 = require("./processors/image.processor");
|
|
31
34
|
/**
|
|
32
35
|
* 文件上传模块(增强版)
|
|
33
36
|
*/
|
|
@@ -71,18 +74,32 @@ let FileUploadModule = FileUploadModule_1 = class FileUploadModule {
|
|
|
71
74
|
inject: [mime_registry_service_1.MimeRegistryService],
|
|
72
75
|
});
|
|
73
76
|
}
|
|
74
|
-
//
|
|
77
|
+
// 注册处理器(内置处理器 + 自定义处理器)
|
|
78
|
+
const processorMap = new Map();
|
|
79
|
+
// 自动注册内置处理器
|
|
80
|
+
try {
|
|
81
|
+
const csvProcessor = new csv_processor_1.CsvProcessor();
|
|
82
|
+
const excelProcessor = new excel_processor_1.ExcelProcessor();
|
|
83
|
+
const imageProcessor = new image_processor_1.ImageProcessor();
|
|
84
|
+
processorMap.set(csvProcessor.name, csvProcessor);
|
|
85
|
+
processorMap.set(excelProcessor.name, excelProcessor);
|
|
86
|
+
processorMap.set(imageProcessor.name, imageProcessor);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
// 内置处理器加载失败,忽略(可能是依赖未安装)
|
|
90
|
+
}
|
|
91
|
+
// 添加用户自定义处理器
|
|
75
92
|
if (options.processors && options.processors.length > 0) {
|
|
76
|
-
const processorMap = new Map();
|
|
77
93
|
for (const ProcessorClass of options.processors) {
|
|
78
94
|
const processor = new ProcessorClass();
|
|
79
95
|
processorMap.set(processor.name, processor);
|
|
80
96
|
}
|
|
81
|
-
providers.push({
|
|
82
|
-
provide: 'FILE_PROCESSORS',
|
|
83
|
-
useValue: processorMap,
|
|
84
|
-
});
|
|
85
97
|
}
|
|
98
|
+
// 始终提供 FILE_PROCESSORS(即使为空Map)
|
|
99
|
+
providers.push({
|
|
100
|
+
provide: 'FILE_PROCESSORS',
|
|
101
|
+
useValue: processorMap,
|
|
102
|
+
});
|
|
86
103
|
// 注册存储提供者
|
|
87
104
|
if (options.storage) {
|
|
88
105
|
const storageProviders = this.createStorageProviders(options.storage);
|
|
@@ -106,9 +123,8 @@ let FileUploadModule = FileUploadModule_1 = class FileUploadModule {
|
|
|
106
123
|
if (databaseEnabled) {
|
|
107
124
|
exports.push(file_service_1.FileService);
|
|
108
125
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
126
|
+
// 始终导出 FILE_PROCESSORS
|
|
127
|
+
exports.push('FILE_PROCESSORS');
|
|
112
128
|
if (((_b = options.storage) === null || _b === void 0 ? void 0 : _b.local) ||
|
|
113
129
|
!((_c = options.storage) === null || _c === void 0 ? void 0 : _c.default) ||
|
|
114
130
|
((_d = options.storage) === null || _d === void 0 ? void 0 : _d.default) === 'local') {
|
|
@@ -157,18 +173,30 @@ let FileUploadModule = FileUploadModule_1 = class FileUploadModule {
|
|
|
157
173
|
useFactory: asyncOptions.useFactory,
|
|
158
174
|
inject: asyncOptions.inject || [],
|
|
159
175
|
},
|
|
160
|
-
//
|
|
176
|
+
// 异步处理器注册(内置 + 自定义)
|
|
161
177
|
{
|
|
162
178
|
provide: 'FILE_PROCESSORS',
|
|
163
179
|
useFactory: (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
164
180
|
const options = yield asyncOptions.useFactory(...args);
|
|
165
|
-
if (!options.processors || options.processors.length === 0) {
|
|
166
|
-
return new Map();
|
|
167
|
-
}
|
|
168
181
|
const processorMap = new Map();
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
182
|
+
// 自动注册内置处理器
|
|
183
|
+
try {
|
|
184
|
+
const csvProcessor = new csv_processor_1.CsvProcessor();
|
|
185
|
+
const excelProcessor = new excel_processor_1.ExcelProcessor();
|
|
186
|
+
const imageProcessor = new image_processor_1.ImageProcessor();
|
|
187
|
+
processorMap.set(csvProcessor.name, csvProcessor);
|
|
188
|
+
processorMap.set(excelProcessor.name, excelProcessor);
|
|
189
|
+
processorMap.set(imageProcessor.name, imageProcessor);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
// 内置处理器加载失败,忽略
|
|
193
|
+
}
|
|
194
|
+
// 添加用户自定义处理器
|
|
195
|
+
if (options.processors && options.processors.length > 0) {
|
|
196
|
+
for (const ProcessorClass of options.processors) {
|
|
197
|
+
const processor = new ProcessorClass();
|
|
198
|
+
processorMap.set(processor.name, processor);
|
|
199
|
+
}
|
|
172
200
|
}
|
|
173
201
|
return processorMap;
|
|
174
202
|
}),
|
package/file-upload/index.d.ts
CHANGED
|
@@ -6,9 +6,17 @@ export * from './interfaces/file-buffer.interface';
|
|
|
6
6
|
export * from './interfaces/file-metadata.interface';
|
|
7
7
|
export * from './interfaces/upload-options.interface';
|
|
8
8
|
export * from './interfaces/custom-file-type.interface';
|
|
9
|
+
export * from './interfaces/file-processor.interface';
|
|
10
|
+
import { ProcessResult as _ProcessResult } from './interfaces/processor-options.interface';
|
|
11
|
+
import { ValidationResult as _ValidationResult } from './decorators/validate-data.decorator';
|
|
12
|
+
export { _ProcessResult as ProcessResult };
|
|
9
13
|
export * from './decorators/file-upload.decorator';
|
|
10
|
-
export
|
|
11
|
-
export
|
|
14
|
+
export { ExcelColumn, getExcelColumnMapping, parseAndValidateExcelData } from './decorators/excel-data.decorator';
|
|
15
|
+
export { CsvColumn, getCsvColumnMapping, parseAndValidateCsvData } from './decorators/csv-data.decorator';
|
|
16
|
+
export * from './decorators/csv-import.decorator';
|
|
17
|
+
export { BaseRowData, ValidationResult as ValidationResultType } from './decorators/validate-data.decorator';
|
|
18
|
+
export { _ValidationResult as ValidationResult };
|
|
19
|
+
export * from './decorators/validate-data.decorator';
|
|
12
20
|
export * from './decorators/process.decorator';
|
|
13
21
|
export * from './interceptors/file-upload.interceptor';
|
|
14
22
|
export * from './controllers/file-access.controller';
|
|
@@ -17,6 +25,9 @@ export * from './services/mime-registry.service';
|
|
|
17
25
|
export * from './services/file-signature-validator.service';
|
|
18
26
|
export * from './services/malicious-file-detector.service';
|
|
19
27
|
export * from './services/file.service';
|
|
28
|
+
export * from './processors/excel.processor';
|
|
29
|
+
export * from './processors/csv.processor';
|
|
30
|
+
export * from './processors/image.processor';
|
|
20
31
|
export * from './entities/file.entity';
|
|
21
32
|
export * from './entities/file-metadata.entity';
|
|
22
33
|
export * from './dto/create-file.dto';
|