From 090b91e72d600f438f193423450e3d60e06d608b Mon Sep 17 00:00:00 2001 From: richarjiang Date: Fri, 12 Sep 2025 14:23:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 11 ++++ package.json | 1 + src/users/cos.service.ts | 90 +++++++++++++++++++++++++++---- src/users/dto/upload-image.dto.ts | 27 ++++++++++ src/users/users.controller.ts | 47 ++++++++++++++++ yarn.lock | 73 +++++++++++++------------ 6 files changed, 207 insertions(+), 42 deletions(-) create mode 100644 src/users/dto/upload-image.dto.ts diff --git a/package-lock.json b/package-lock.json index aecdd5c..8492f71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "@swc/core": "^1.10.7", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", + "@types/multer": "^2.0.0", "@types/node": "^22.10.7", "@types/sequelize": "^4.28.20", "@types/supertest": "^6.0.2", @@ -3385,6 +3386,16 @@ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", "license": "MIT" }, + "node_modules/@types/multer": { + "version": "2.0.0", + "resolved": "https://mirrors.tencent.com/npm/@types/multer/-/multer-2.0.0.tgz", + "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { "version": "22.13.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz", diff --git a/package.json b/package.json index 5f9d25e..4f83ada 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@swc/core": "^1.10.7", "@types/express": "^5.0.0", "@types/jest": "^29.5.14", + "@types/multer": "^2.0.0", "@types/node": "^22.10.7", "@types/sequelize": "^4.28.20", "@types/supertest": "^6.0.2", diff --git a/src/users/cos.service.ts b/src/users/cos.service.ts index 53887bc..d8f170a 100644 --- a/src/users/cos.service.ts +++ b/src/users/cos.service.ts @@ -1,6 +1,7 @@ import { Injectable, Logger, BadRequestException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as STS from 'qcloud-cos-sts'; +import * as COS from 'cos-nodejs-sdk-v5'; import { v4 as uuidv4 } from 'uuid'; @Injectable() @@ -10,20 +11,25 @@ export class CosService { private readonly secretKey: string; private readonly bucket: string; private readonly region: string; - private readonly cdnDomain: string; private readonly allowPrefix: string; + private readonly cosClient: COS; constructor(private configService: ConfigService) { this.secretId = this.configService.get('TENCENT_SECRET_ID') || ''; this.secretKey = this.configService.get('TENCENT_SECRET_KEY') || ''; this.bucket = this.configService.get('COS_BUCKET') || ''; this.region = this.configService.get('COS_REGION') || 'ap-guangzhou'; - this.cdnDomain = this.configService.get('COS_CDN_DOMAIN') || 'https://cdn.richarjiang.com'; this.allowPrefix = this.configService.get('COS_ALLOW_PREFIX') || 'uploads/*'; if (!this.secretId || !this.secretKey || !this.bucket) { throw new Error('腾讯云COS配置缺失:TENCENT_SECRET_ID, TENCENT_SECRET_KEY, COS_BUCKET 是必需的'); } + + // 初始化COS客户端 + this.cosClient = new COS({ + SecretId: this.secretId, + SecretKey: this.secretKey, + }); } /** @@ -53,7 +59,6 @@ export class CosService { bucket: this.bucket, region: this.region, prefix: prefix, - cdnDomain: this.cdnDomain, }; this.logger.log(`临时密钥获取成功,用户ID: ${userId}, 有效期至: ${new Date(stsResult.expiredTime * 1000)}`); @@ -172,12 +177,8 @@ export class CosService { /** * 生成文件访问URL */ - private generateFileUrl(fileKey: string): string { - if (this.cdnDomain) { - return `${this.cdnDomain}/${fileKey}`; - } else { - return `https://${this.bucket}.cos.${this.region}.myqcloud.com/${fileKey}`; - } + private generateFileUrl(uploadResult: COS.UploadFileResult): string { + return `https://${uploadResult.Location}` } /** @@ -225,4 +226,75 @@ export class CosService { return limits[fileType as keyof typeof limits] || 10 * 1024 * 1024; } + + /** + * 直接上传图片到COS + */ + async uploadImage(userId: string, file: Express.Multer.File): Promise { + try { + this.logger.log(`开始上传图片,用户ID: ${userId}, 原始文件名: ${file.originalname}`); + + // 验证文件类型 + const fileExtension = this.getFileExtension(file.originalname); + if (!this.validateFileType('image', fileExtension)) { + throw new BadRequestException('不支持的图片格式'); + } + + // 验证文件大小 + const sizeLimit = this.getFileSizeLimit('image'); + if (file.size > sizeLimit) { + throw new BadRequestException(`图片文件大小超过限制 (${sizeLimit / 1024 / 1024}MB)`); + } + + // 生成唯一文件名 + const uniqueFileName = this.generateUniqueFileName(file.originalname, fileExtension); + const fileKey = `uploads/images/${uniqueFileName}`; + + // 上传到COS + const uploadResult = await this.uploadToCos(fileKey, file.buffer, file.mimetype); + + // 生成文件访问URL + const fileUrl = this.generateFileUrl(uploadResult); + + const response = { + fileUrl, + fileKey, + originalName: file.originalname, + fileSize: file.size, + fileType: 'image', + mimeType: file.mimetype, + uploadTime: new Date(), + etag: uploadResult.ETag, + }; + + this.logger.log(`图片上传成功,用户ID: ${userId}, 文件URL: ${fileUrl}`); + return response; + + } catch (error) { + this.logger.error(`上传图片失败: ${error.message}`, error.stack); + throw new BadRequestException(`上传图片失败: ${error.message}`); + } + } + + /** + * 上传文件到COS + */ + private async uploadToCos(key: string, body: Buffer, contentType?: string): Promise { + return new Promise((resolve, reject) => { + this.cosClient.putObject({ + Bucket: this.bucket, + Region: this.region, + Key: key, + Body: body, + ContentType: contentType, + ContentLength: body.length, + }, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); + } } \ No newline at end of file diff --git a/src/users/dto/upload-image.dto.ts b/src/users/dto/upload-image.dto.ts new file mode 100644 index 0000000..f1fc9c6 --- /dev/null +++ b/src/users/dto/upload-image.dto.ts @@ -0,0 +1,27 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class UploadImageResponseDto { + @ApiProperty({ description: '文件访问URL', example: 'https://cdn.richarjiang.com/uploads/images/1673123456789-abc123.jpg' }) + fileUrl: string; + + @ApiProperty({ description: '文件存储键', example: 'uploads/images/1673123456789-abc123.jpg' }) + fileKey: string; + + @ApiProperty({ description: '原始文件名', example: 'photo.jpg' }) + originalName: string; + + @ApiProperty({ description: '文件大小(字节)', example: 1024000 }) + fileSize: number; + + @ApiProperty({ description: '文件类型', example: 'image' }) + fileType: string; + + @ApiProperty({ description: 'MIME类型', example: 'image/jpeg' }) + mimeType: string; + + @ApiProperty({ description: '上传时间', example: '2024-01-08T10:30:45.123Z' }) + uploadTime: Date; + + @ApiProperty({ description: 'COS ETag', example: '"abc123def456"' }) + etag: string; +} \ No newline at end of file diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 4b52ce4..fac1f0a 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -14,11 +14,15 @@ import { Inject, Req, NotFoundException, + UseInterceptors, + UploadedFile, } from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; import { Request } from 'express'; import { WINSTON_MODULE_PROVIDER } from 'nest-winston'; import { Logger as WinstonLogger } from 'winston'; import { UsersService } from './users.service'; +import { UploadImageResponseDto } from './dto/upload-image.dto'; import { CreateUserDto } from './dto/create-user.dto'; import { UserResponseDto } from './dto/user-response.dto'; import { ApiOperation, ApiBody, ApiResponse, ApiTags, ApiQuery } from '@nestjs/swagger'; @@ -193,6 +197,49 @@ export class UsersController { } } + // 上传图片到COS + @UseGuards(JwtAuthGuard) + @Post('cos/upload-image') + @HttpCode(HttpStatus.OK) + @UseInterceptors(FileInterceptor('file')) + @ApiOperation({ summary: '上传图片到COS' }) + @ApiResponse({ + status: 200, + description: '图片上传成功', + type: UploadImageResponseDto, + }) + @ApiResponse({ + status: 400, + description: '上传失败:文件格式不支持或文件过大', + }) + async uploadImageToCos( + @CurrentUser() user: AccessTokenPayload, + @UploadedFile() file: Express.Multer.File, + ) { + try { + if (!file) { + return { code: ResponseCode.ERROR, message: '请选择要上传的图片文件' }; + } + + + this.winstonLogger.log(`file: ${file}`, { + context: 'UsersController', + userId: user?.sub, + }) + + const data = await this.cosService.uploadImage(user.sub, file); + return data; + } catch (error) { + this.winstonLogger.error('上传图片失败', { + context: 'UsersController', + userId: user?.sub, + error: (error as Error).message, + stack: (error as Error).stack, + }); + return { code: ResponseCode.ERROR, message: (error as Error).message }; + } + } + // App Store 服务器通知接收接口 @Public() @Post('app-store-notifications') diff --git a/yarn.lock b/yarn.lock index 780d236..f517ac2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -879,12 +879,12 @@ "@napi-rs/nice-android-arm-eabi@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz#9a0cba12706ff56500df127d6f4caf28ddb94936" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.0.1.tgz#9a0cba12706ff56500df127d6f4caf28ddb94936" integrity sha512-5qpvOu5IGwDo7MEKVqqyAxF90I6aLj4n07OzpARdgDRfz8UbBztTByBp0RC59r3J1Ij8uzYi6jI7r5Lws7nn6w== "@napi-rs/nice-android-arm64@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz#32fc32e9649bd759d2a39ad745e95766f6759d2f" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.0.1.tgz#32fc32e9649bd759d2a39ad745e95766f6759d2f" integrity sha512-GqvXL0P8fZ+mQqG1g0o4AO9hJjQaeYG84FRfZaYjyJtZZZcMjXW5TwkL8Y8UApheJgyE13TQ4YNUssQaTgTyvA== "@napi-rs/nice-darwin-arm64@1.0.1": @@ -894,67 +894,67 @@ "@napi-rs/nice-darwin-x64@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz#f1b1365a8370c6a6957e90085a9b4873d0e6a957" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.0.1.tgz#f1b1365a8370c6a6957e90085a9b4873d0e6a957" integrity sha512-jXnMleYSIR/+TAN/p5u+NkCA7yidgswx5ftqzXdD5wgy/hNR92oerTXHc0jrlBisbd7DpzoaGY4cFD7Sm5GlgQ== "@napi-rs/nice-freebsd-x64@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz#4280f081efbe0b46c5165fdaea8b286e55a8f89e" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.0.1.tgz#4280f081efbe0b46c5165fdaea8b286e55a8f89e" integrity sha512-j+iJ/ezONXRQsVIB/FJfwjeQXX7A2tf3gEXs4WUGFrJjpe/z2KB7sOv6zpkm08PofF36C9S7wTNuzHZ/Iiccfw== "@napi-rs/nice-linux-arm-gnueabihf@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz#07aec23a9467ed35eb7602af5e63d42c5d7bd473" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.0.1.tgz#07aec23a9467ed35eb7602af5e63d42c5d7bd473" integrity sha512-G8RgJ8FYXYkkSGQwywAUh84m946UTn6l03/vmEXBYNJxQJcD+I3B3k5jmjFG/OPiU8DfvxutOP8bi+F89MCV7Q== "@napi-rs/nice-linux-arm64-gnu@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz#038a77134cc6df3c48059d5a5e199d6f50fb9a90" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.0.1.tgz#038a77134cc6df3c48059d5a5e199d6f50fb9a90" integrity sha512-IMDak59/W5JSab1oZvmNbrms3mHqcreaCeClUjwlwDr0m3BoR09ZiN8cKFBzuSlXgRdZ4PNqCYNeGQv7YMTjuA== "@napi-rs/nice-linux-arm64-musl@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz#715d0906582ba0cff025109f42e5b84ea68c2bcc" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.0.1.tgz#715d0906582ba0cff025109f42e5b84ea68c2bcc" integrity sha512-wG8fa2VKuWM4CfjOjjRX9YLIbysSVV1S3Kgm2Fnc67ap/soHBeYZa6AGMeR5BJAylYRjnoVOzV19Cmkco3QEPw== "@napi-rs/nice-linux-ppc64-gnu@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz#ac1c8f781c67b0559fa7a1cd4ae3ca2299dc3d06" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.0.1.tgz#ac1c8f781c67b0559fa7a1cd4ae3ca2299dc3d06" integrity sha512-lxQ9WrBf0IlNTCA9oS2jg/iAjQyTI6JHzABV664LLrLA/SIdD+I1i3Mjf7TsnoUbgopBcCuDztVLfJ0q9ubf6Q== "@napi-rs/nice-linux-riscv64-gnu@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz#b0a430549acfd3920ffd28ce544e2fe17833d263" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.0.1.tgz#b0a430549acfd3920ffd28ce544e2fe17833d263" integrity sha512-3xs69dO8WSWBb13KBVex+yvxmUeEsdWexxibqskzoKaWx9AIqkMbWmE2npkazJoopPKX2ULKd8Fm9veEn0g4Ig== "@napi-rs/nice-linux-s390x-gnu@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz#5b95caf411ad72a965885217db378c4d09733e97" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.0.1.tgz#5b95caf411ad72a965885217db378c4d09733e97" integrity sha512-lMFI3i9rlW7hgToyAzTaEybQYGbQHDrpRkg+1gJWEpH0PLAQoZ8jiY0IzakLfNWnVda1eTYYlxxFYzW8Rqczkg== "@napi-rs/nice-linux-x64-gnu@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz#a98cdef517549f8c17a83f0236a69418a90e77b7" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.0.1.tgz#a98cdef517549f8c17a83f0236a69418a90e77b7" integrity sha512-XQAJs7DRN2GpLN6Fb+ZdGFeYZDdGl2Fn3TmFlqEL5JorgWKrQGRUrpGKbgZ25UeZPILuTKJ+OowG2avN8mThBA== "@napi-rs/nice-linux-x64-musl@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz#5e26843eafa940138aed437c870cca751c8a8957" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.0.1.tgz#5e26843eafa940138aed437c870cca751c8a8957" integrity sha512-/rodHpRSgiI9o1faq9SZOp/o2QkKQg7T+DK0R5AkbnI/YxvAIEHf2cngjYzLMQSQgUhxym+LFr+UGZx4vK4QdQ== "@napi-rs/nice-win32-arm64-msvc@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz#bd62617d02f04aa30ab1e9081363856715f84cd8" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.0.1.tgz#bd62617d02f04aa30ab1e9081363856715f84cd8" integrity sha512-rEcz9vZymaCB3OqEXoHnp9YViLct8ugF+6uO5McifTedjq4QMQs3DHz35xBEGhH3gJWEsXMUbzazkz5KNM5YUg== "@napi-rs/nice-win32-ia32-msvc@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz#b8b7aad552a24836027473d9b9f16edaeabecf18" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.0.1.tgz#b8b7aad552a24836027473d9b9f16edaeabecf18" integrity sha512-t7eBAyPUrWL8su3gDxw9xxxqNwZzAqKo0Szv3IjVQd1GpXXVkb6vBBQUuxfIYaXMzZLwlxRQ7uzM2vdUE9ULGw== "@napi-rs/nice-win32-x64-msvc@1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz#37d8718b8f722f49067713e9f1e85540c9a3dd09" + resolved "https://mirrors.tencent.com/npm/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.0.1.tgz#37d8718b8f722f49067713e9f1e85540c9a3dd09" integrity sha512-JlF+uDcatt3St2ntBG8H02F1mM45i5SF9W+bIKiReVE6wiy3o16oBP/yxt+RZ+N6LbCImJXJ6bXNO2kn9AXicg== "@napi-rs/nice@^1.0.1": @@ -1232,47 +1232,47 @@ "@swc/core-darwin-x64@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.11.13.tgz#9cad870d48ebff805e8946ddcbe3d8312182f70b" + resolved "https://mirrors.tencent.com/npm/@swc/core-darwin-x64/-/core-darwin-x64-1.11.13.tgz#9cad870d48ebff805e8946ddcbe3d8312182f70b" integrity sha512-uSA4UwgsDCIysUPfPS8OrQTH2h9spO7IYFd+1NB6dJlVGUuR6jLKuMBOP1IeLeax4cGHayvkcwSJ3OvxHwgcZQ== "@swc/core-linux-arm-gnueabihf@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.13.tgz#51839e5a850bfa300e2c838fee8379e4dba1de78" + resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.13.tgz#51839e5a850bfa300e2c838fee8379e4dba1de78" integrity sha512-boVtyJzS8g30iQfe8Q46W5QE/cmhKRln/7NMz/5sBP/am2Lce9NL0d05NnFwEWJp1e2AMGHFOdRr3Xg1cDiPKw== "@swc/core-linux-arm64-gnu@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.13.tgz#4145f1e504bdfa92604aee883d777bc8c4fba5d7" + resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.13.tgz#4145f1e504bdfa92604aee883d777bc8c4fba5d7" integrity sha512-+IK0jZ84zHUaKtwpV+T+wT0qIUBnK9v2xXD03vARubKF+eUqCsIvcVHXmLpFuap62dClMrhCiwW10X3RbXNlHw== "@swc/core-linux-arm64-musl@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.13.tgz#b1813ae2e99e386ca16fff5af6601ac45ef57c5b" + resolved "https://mirrors.tencent.com/npm/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.13.tgz#b1813ae2e99e386ca16fff5af6601ac45ef57c5b" integrity sha512-+ukuB8RHD5BHPCUjQwuLP98z+VRfu+NkKQVBcLJGgp0/+w7y0IkaxLY/aKmrAS5ofCNEGqKL+AOVyRpX1aw+XA== "@swc/core-linux-x64-gnu@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.13.tgz#13b89a0194c4033c01400e9c65d9c21c56a4a6cd" + resolved "https://mirrors.tencent.com/npm/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.13.tgz#13b89a0194c4033c01400e9c65d9c21c56a4a6cd" integrity sha512-q9H3WI3U3dfJ34tdv60zc8oTuWvSd5fOxytyAO9Pc5M82Hic3jjWaf2xBekUg07ubnMZpyfnv+MlD+EbUI3Llw== "@swc/core-linux-x64-musl@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.13.tgz#0d0e5aa889dd4da69723e2287c3c1714d9bfd8aa" + resolved "https://mirrors.tencent.com/npm/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.13.tgz#0d0e5aa889dd4da69723e2287c3c1714d9bfd8aa" integrity sha512-9aaZnnq2pLdTbAzTSzy/q8dr7Woy3aYIcQISmw1+Q2/xHJg5y80ZzbWSWKYca/hKonDMjIbGR6dp299I5J0aeA== "@swc/core-win32-arm64-msvc@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.13.tgz#ad7281f9467e3de09f52615afe2276a8ef738a9d" + resolved "https://mirrors.tencent.com/npm/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.13.tgz#ad7281f9467e3de09f52615afe2276a8ef738a9d" integrity sha512-n3QZmDewkHANcoHvtwvA6yJbmS4XJf0MBMmwLZoKDZ2dOnC9D/jHiXw7JOohEuzYcpLoL5tgbqmjxa3XNo9Oow== "@swc/core-win32-ia32-msvc@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.13.tgz#046f6dbddb5b69a29bbaa98de104090a46088b74" + resolved "https://mirrors.tencent.com/npm/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.13.tgz#046f6dbddb5b69a29bbaa98de104090a46088b74" integrity sha512-wM+Nt4lc6YSJFthCx3W2dz0EwFNf++j0/2TQ0Js9QLJuIxUQAgukhNDVCDdq8TNcT0zuA399ALYbvj5lfIqG6g== "@swc/core-win32-x64-msvc@1.11.13": version "1.11.13" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.13.tgz#0412620d8594a7d3e482d3e79d9e89d80f9a14c0" + resolved "https://mirrors.tencent.com/npm/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.13.tgz#0412620d8594a7d3e482d3e79d9e89d80f9a14c0" integrity sha512-+X5/uW3s1L5gK7wAo0E27YaAoidJDo51dnfKSfU7gF3mlEUuWH8H1bAy5OTt2mU4eXtfsdUMEVXSwhDlLtQkuA== "@swc/core@^1.10.7": @@ -1456,6 +1456,15 @@ "@types/range-parser" "*" "@types/send" "*" +"@types/express@*", "@types/express@^5.0.0": + version "5.0.1" + resolved "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz" + integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/serve-static" "*" + "@types/express@^4.17.20": version "4.17.23" resolved "https://mirrors.tencent.com/npm/@types/express/-/express-4.17.23.tgz" @@ -1466,15 +1475,6 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/express@^5.0.0": - version "5.0.1" - resolved "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz" - integrity sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^5.0.0" - "@types/serve-static" "*" - "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" @@ -1559,6 +1559,13 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== +"@types/multer@^2.0.0": + version "2.0.0" + resolved "https://mirrors.tencent.com/npm/@types/multer/-/multer-2.0.0.tgz" + integrity sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw== + dependencies: + "@types/express" "*" + "@types/node-fetch@^2.6.4": version "2.6.12" resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz"