From f236d86ff3b4c0b23e777c4d6cd9939fef91097d Mon Sep 17 00:00:00 2001 From: sunlei Date: Wed, 13 May 2026 13:52:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E5=85=A8=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=B3=A8=E9=87=8A,=20=E5=AE=9E=E7=8E=B0minio?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 5 +- .env.prod | 3 +- API.md | 295 +++++++++++++ package.json | 34 +- pnpm-lock.yaml | 595 +++++++------------------- src/app.controller.ts | 5 + src/app.module.ts | 3 + src/common/swagger-response.ts | 181 ++++++++ src/component/component.controller.ts | 61 ++- src/dict/dict.controller.ts | 55 ++- src/dict/dict.dto.ts | 13 + src/minio/minio.controller.ts | 214 ++++++++- src/minio/minio.dto.ts | 67 +++ src/minio/minio.module.ts | 6 +- src/minio/minio.service.ts | 174 +++++++- src/utils/constant.ts | 7 - 16 files changed, 1207 insertions(+), 511 deletions(-) create mode 100644 API.md create mode 100644 src/common/swagger-response.ts create mode 100644 src/dict/dict.dto.ts create mode 100644 src/minio/minio.dto.ts diff --git a/.env b/.env index fbd9e7b..a24376b 100644 --- a/.env +++ b/.env @@ -5,7 +5,8 @@ DB_PASSWORD=qwqvqaqeq2333KT DB_DATABASE=shy_template DB_SYNC=true -MINIO_ENDPOINT=192.168.1.206 +MINIO_ENDPOINT=localhost MINIO_PORT=9000 MINIO_ACCESS_KEY=minioadmin -MINIO_SECRET_KEY=minioadmin \ No newline at end of file +MINIO_SECRET_KEY=minioadmin +MINIO_BUCKET=kt-template-online diff --git a/.env.prod b/.env.prod index f0a5083..d4913ca 100644 --- a/.env.prod +++ b/.env.prod @@ -8,4 +8,5 @@ DB_SYNC=false MINIO_ENDPOINT=192.168.1.206 MINIO_PORT=9000 MINIO_ACCESS_KEY=minioadmin -MINIO_SECRET_KEY=minioadmin \ No newline at end of file +MINIO_SECRET_KEY=minioadmin +MINIO_BUCKET=kt-template-online diff --git a/API.md b/API.md new file mode 100644 index 0000000..ec9df83 --- /dev/null +++ b/API.md @@ -0,0 +1,295 @@ +# KT Template Online API + +后端服务默认监听 `48085`,Swagger 地址为 `/api`,OpenAPI JSON 地址为 `/api-json`。接口除文件下载外,统一返回 `{ code, msg, data }`。 + +## 通用响应 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": {} +} +``` + +失败时仍使用相同结构,常见为: + +```json +{ + "code": 400, + "msg": "操作失败", + "data": null +} +``` + +## Root + +### GET `/` + +重定向到 Swagger 文档页 `/api#/`,HTTP 状态码为 `301`。 + +## 数据结构 + +### Component + +| 字段 | 类型 | 说明 | +| ---------------- | ------- | ---------------------------- | +| id | string | 组件 ID,新增时由后端生成 | +| name | string | 组件名称 | +| type | number | 一级类型,`1` 图表,`2` 组件 | +| componentType | number | 二级类型 | +| typeMsg | string | 一级类型文本,列表接口返回 | +| componentTypeMsg | string | 二级类型文本,列表接口返回 | +| image | string | 封面图 | +| template | string | playground 序列化模板内容 | +| createTime | string | 创建时间 | +| updateTime | string | 更新时间 | +| is_deleted | boolean | 逻辑删除标记 | + +### 字典 + +`COMPONENT_TYPE`: + +| label | value | +| ----- | ----- | +| 图表 | 1 | +| 组件 | 2 | + +`CHART`:`未分类(-1)`、`折线图(1)`、`柱状图(2)`、`饼图(3)`、`散点图(4)`、`地图(5)`、`K线图(6)`、`雷达图(7)`、`盒须图(8)`、`热力图(9)`、`关系图(10)`、`路径图(11)`、`树图(12)`、`矩树图(13)`、`旭日图(14)`、`平行坐标系(15)`、`桑基图(16)`、`漏斗图(17)`、`仪表盘(18)`、`象形图(19)`、`河流图(20)`、`水球(21)`、`词云(22)`。 + +`COMPONENT`:`未分类(-1)`、`表格(23)`、`表单(24)`、`容器(25)`。 + +## Component + +### GET `/component/allList` + +获取全部组件。 + +响应示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "id": "1d8d3dd2-99f0-4d10-9a44-0cf9566b37c9", + "name": "基础折线图", + "type": 1, + "componentType": 1, + "typeMsg": "图表", + "componentTypeMsg": "折线图", + "image": "", + "template": "%7B%22version%22%3A%221.0%22%7D", + "createTime": "2026-05-13T02:30:00.000Z", + "updateTime": "2026-05-13T02:30:00.000Z", + "is_deleted": false + } + ] +} +``` + +### GET `/component/list` + +分页获取组件列表。 + +Query: + +| 参数 | 类型 | 必填 | 说明 | +| ------------- | ------ | ---- | ------------ | +| pageNo | number | 是 | 页码 | +| pageSize | number | 是 | 每页条数 | +| name | string | 否 | 名称模糊搜索 | +| type | number | 否 | 一级类型 | +| componentType | number | 否 | 二级类型 | + +响应 `data`:`{ list: Component[], total: number }`。 + +### GET `/component/detail` + +获取组件详情。 + +Query: + +| 参数 | 类型 | 必填 | 说明 | +| ---- | ------ | ---- | ------- | +| id | string | 是 | 组件 ID | + +响应 `data`:`Component`。 + +### POST `/component/save` + +新增组件。`SaveMiddleware` 会删除 body 中的 `id`,新增时不需要传 `id`。 + +Body: + +```json +{ + "name": "基础折线图", + "type": 1, + "componentType": 1, + "image": "", + "template": "%7B%22version%22%3A%221.0%22%7D" +} +``` + +响应示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": "1d8d3dd2-99f0-4d10-9a44-0cf9566b37c9" +} +``` + +### POST `/component/update` + +编辑组件。 + +Body: + +```json +{ + "id": "1d8d3dd2-99f0-4d10-9a44-0cf9566b37c9", + "name": "基础折线图", + "type": 1, + "componentType": 1, + "image": "", + "template": "%7B%22version%22%3A%221.0%22%7D" +} +``` + +响应 `data`:`true` 表示更新成功。 + +### POST `/component/remove` + +逻辑删除组件。 + +Query: + +| 参数 | 类型 | 必填 | 说明 | +| ---- | ------ | ---- | ------- | +| id | string | 是 | 组件 ID | + +响应 `data`:`true` 表示删除成功。 + +## Dict + +### GET `/dict/getDictByKey` + +根据字典 key 获取字典。 + +Query: + +| 参数 | 类型 | 必填 | 可选值 | +| ------- | ------ | ---- | -------------------------------------- | +| dictKey | string | 是 | `COMPONENT_TYPE`、`CHART`、`COMPONENT` | + +响应示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "label": "图表", + "value": 1 + }, + { + "label": "组件", + "value": 2 + } + ] +} +``` + +### GET `/dict/getComponentDictByType` + +根据一级类型获取二级类型字典。 + +Query: + +| 参数 | 类型 | 必填 | 说明 | +| ---- | ------ | ---- | ------------------ | +| type | number | 是 | `1` 图表,`2` 组件 | + +响应 `data`:`Array<{ label: string; value: number }>`。 + +## MinIO + +### GET `/minio/check` + +检查 MinIO 连接和 bucket 状态。 + +Query:`bucketName?: string` + +响应 `data`:`{ bucketName: string; exists: boolean }`。 + +### POST `/minio/bucket` + +创建 bucket,已存在时跳过。 + +Query:`bucketName?: string` + +响应 `data`:bucket 名称。 + +### POST `/minio/upload` + +上传文件,请求类型为 `multipart/form-data`。 + +Body: + +| 参数 | 类型 | 必填 | 说明 | +| ---------- | ------ | ---- | ---------------------- | +| file | File | 是 | 文件 | +| bucketName | string | 否 | bucket 名称 | +| objectName | string | 否 | 对象名,不传时自动生成 | + +响应示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "bucketName": "kt-template-online", + "objectName": "uploads/1715580000000-a1b2c3-demo.png", + "etag": "9b2cf535f27731c974343645a3985328", + "size": 2048, + "mimeType": "image/png", + "url": "http://127.0.0.1:9000/kt-template-online/uploads/demo.png" + } +} +``` + +### GET `/minio/list` + +获取文件列表。 + +Query:`bucketName?: string`、`prefix?: string`、`recursive?: string` + +响应 `data`:MinIO 对象数组,常见字段为 `name`、`size`、`etag`、`lastModified`。 + +### GET `/minio/url` + +获取文件临时访问地址。 + +Query:`objectName: string`、`bucketName?: string`、`expiry?: string` + +响应 `data`:临时访问 URL。 + +### GET `/minio/download` + +下载文件,直接返回文件流。 + +Query:`objectName: string`、`bucketName?: string` + +### DELETE `/minio/remove` + +删除文件。 + +Query:`objectName: string`、`bucketName?: string` + +响应 `data`:`true` 表示删除成功。 diff --git a/package.json b/package.json index ed9d836..df9ad0b 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,24 @@ { "name": "kt-template-online-api", "version": "0.0.1", - "description": "", + "description": "kt-template-online server API", "author": "", "private": true, "license": "UNLICENSED", "scripts": { "build": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", - "start:prod": "nest build && NODE_ENV=prod node dist/main", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "start:prod": "nest build && cross-env NODE_ENV=prod node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"", + "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "test": "jest", "test:watch": "jest --watch", "test:cov": "jest --coverage", + "test:ci": "jest --runInBand --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json" }, @@ -23,29 +26,14 @@ "@nestjs/common": "^9.4.3", "@nestjs/config": "^2.3.4", "@nestjs/core": "^9.4.3", - "@nestjs/jwt": "^10.2.0", - "@nestjs/mapped-types": "^2.1.1", - "@nestjs/passport": "^9.0.3", "@nestjs/platform-express": "^9.4.3", "@nestjs/swagger": "^7.4.2", "@nestjs/typeorm": "^9.0.1", - "@types/dotenv": "^8.2.3", - "@types/lodash": "^4.17.24", - "@types/lodash-es": "^4.17.12", - "@types/multer": "^1.4.13", "cross-env": "^7.0.3", - "dotenv": "^16.6.1", - "express-session": "^1.19.0", - "lodash": "^4.18.1", - "minio": "^8.0.7", - "mssql": "^9.3.2", - "multer": "1.4.5-lts.1", + "lodash": "^4.17.21", "mysql2": "^3.22.3", - "nestjs-knife4j-plus": "^1.0.7", + "nestjs-knife4j-plus": "^1.0.8", "nestjs-minio-client": "^2.2.0", - "passport": "^0.6.0", - "passport-jwt": "^4.0.1", - "passport-local": "^1.0.0", "reflect-metadata": "^0.1.14", "rxjs": "^7.8.2", "svg-captcha": "^1.4.0", @@ -56,11 +44,9 @@ "@nestjs/schematics": "^9.2.0", "@nestjs/testing": "^9.4.3", "@types/express": "^4.17.25", - "@types/express-session": "^1.19.0", "@types/jest": "29.2.4", + "@types/lodash": "^4.17.24", "@types/node": "18.11.18", - "@types/passport-jwt": "^3.0.13", - "@types/passport-local": "^1.0.38", "@types/supertest": "^2.0.16", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", @@ -95,4 +81,4 @@ "coverageDirectory": "../coverage", "testEnvironment": "node" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f207914..f3213a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,15 +17,6 @@ importers: '@nestjs/core': specifier: ^9.4.3 version: 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/platform-express@9.4.3)(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@nestjs/jwt': - specifier: ^10.2.0 - version: 10.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2)) - '@nestjs/mapped-types': - specifier: ^2.1.1 - version: 2.1.1(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14) - '@nestjs/passport': - specifier: ^9.0.3 - version: 9.0.3(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.6.0) '@nestjs/platform-express': specifier: ^9.4.3 version: 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3) @@ -35,57 +26,21 @@ importers: '@nestjs/typeorm': specifier: ^9.0.1 version: 9.0.1(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3)(reflect-metadata@0.1.14)(rxjs@7.8.2)(typeorm@0.3.28(mssql@9.3.2(@azure/core-client@1.10.1))(mysql2@3.22.3(@types/node@18.11.18))(ts-node@10.9.2(@types/node@18.11.18)(typescript@4.9.5))) - '@types/dotenv': - specifier: ^8.2.3 - version: 8.2.3 - '@types/lodash': - specifier: ^4.17.24 - version: 4.17.24 - '@types/lodash-es': - specifier: ^4.17.12 - version: 4.17.12 - '@types/multer': - specifier: ^1.4.13 - version: 1.4.13 cross-env: specifier: ^7.0.3 version: 7.0.3 - dotenv: - specifier: ^16.6.1 - version: 16.6.1 - express-session: - specifier: ^1.19.0 - version: 1.19.0 lodash: - specifier: ^4.18.1 - version: 4.18.1 - minio: - specifier: ^8.0.7 - version: 8.0.7 - mssql: - specifier: ^9.3.2 - version: 9.3.2(@azure/core-client@1.10.1) - multer: - specifier: 1.4.5-lts.1 - version: 1.4.5-lts.1 + specifier: ^4.17.21 + version: 4.17.21 mysql2: specifier: ^3.22.3 version: 3.22.3(@types/node@18.11.18) nestjs-knife4j-plus: - specifier: ^1.0.7 - version: 1.0.7(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2) + specifier: ^1.0.8 + version: 1.0.8(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2) nestjs-minio-client: specifier: ^2.2.0 version: 2.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3) - passport: - specifier: ^0.6.0 - version: 0.6.0 - passport-jwt: - specifier: ^4.0.1 - version: 4.0.1 - passport-local: - specifier: ^1.0.0 - version: 1.0.0 reflect-metadata: specifier: ^0.1.14 version: 0.1.14 @@ -111,21 +66,15 @@ importers: '@types/express': specifier: ^4.17.25 version: 4.17.25 - '@types/express-session': - specifier: ^1.19.0 - version: 1.19.0 '@types/jest': specifier: 29.2.4 version: 29.2.4 + '@types/lodash': + specifier: ^4.17.24 + version: 4.17.24 '@types/node': specifier: 18.11.18 version: 18.11.18 - '@types/passport-jwt': - specifier: ^3.0.13 - version: 3.0.13 - '@types/passport-local': - specifier: ^1.0.38 - version: 1.0.38 '@types/supertest': specifier: ^2.0.16 version: 2.0.16 @@ -638,11 +587,6 @@ packages: '@nestjs/websockets': optional: true - '@nestjs/jwt@10.2.0': - resolution: {integrity: sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==} - peerDependencies: - '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 - '@nestjs/mapped-types@2.0.5': resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==} peerDependencies: @@ -656,25 +600,6 @@ packages: class-validator: optional: true - '@nestjs/mapped-types@2.1.1': - resolution: {integrity: sha512-SCCoMEJ6jdeI5h/N+KCVF1+pmg/hmEkNA5nHTS8Gvww7T/LCl4o1gFLinw2iQ60w7slFkszHcGLKGdazVI4F8A==} - peerDependencies: - '@nestjs/common': ^10.0.0 || ^11.0.0 - class-transformer: ^0.4.0 || ^0.5.0 - class-validator: ^0.13.0 || ^0.14.0 || ^0.15.0 - reflect-metadata: ^0.1.12 || ^0.2.0 - peerDependenciesMeta: - class-transformer: - optional: true - class-validator: - optional: true - - '@nestjs/passport@9.0.3': - resolution: {integrity: sha512-HplSJaimEAz1IOZEu+pdJHHJhQyBOPAYWXYHfAPQvRqWtw4FJF1VXl1Qtk9dcXQX1eKytDtH+qBzNQc19GWNEg==} - peerDependencies: - '@nestjs/common': ^8.0.0 || ^9.0.0 - passport: ^0.4.0 || ^0.5.0 || ^0.6.0 - '@nestjs/platform-express@9.4.3': resolution: {integrity: sha512-FpdczWoRSC0zz2dNL9u2AQLXKXRVtq4HgHklAhbL59X0uy+mcxhlSThG7DHzDMkoSnuuHY8ojDVf7mDxk+GtCw==} peerDependencies: @@ -729,9 +654,6 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@nodable/entities@2.1.0': - resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} - '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -804,10 +726,6 @@ packages: '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - '@types/dotenv@8.2.3': - resolution: {integrity: sha512-g2FXjlDX/cYuc5CiQvyU/6kkbP1JtmGzh0obW50zD7OKeILVL0NSpPWLXVfqoAGQjom2/SLLx9zHq0KXvD6mbw==} - deprecated: This is a stub types definition. dotenv provides its own type definitions, so you do not need this installed. - '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -820,9 +738,6 @@ packages: '@types/express-serve-static-core@4.19.8': resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} - '@types/express-session@1.19.0': - resolution: {integrity: sha512-GbypG0bog68UbOq2tSAp7SclvCUm3ha1uDi58OPRGK1NfRvCIu7Gz0M7fTGtpNG1T9a29GpuurQj9zEcT/lMXQ==} - '@types/express@4.17.25': resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} @@ -847,15 +762,6 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/jsonwebtoken@9.0.10': - resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} - - '@types/jsonwebtoken@9.0.5': - resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==} - - '@types/lodash-es@4.17.12': - resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} - '@types/lodash@4.17.24': resolution: {integrity: sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==} @@ -865,30 +771,12 @@ packages: '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/multer@1.4.13': - resolution: {integrity: sha512-bhhdtPw7JqCiEfC9Jimx5LqX9BDIPJEh2q/fQ4bqbBPtyEZYr3cvF22NwG0DmPZNYA0CAf2CnqDB4KIGGpJcaw==} - '@types/node@18.11.18': resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/passport-jwt@3.0.13': - resolution: {integrity: sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==} - - '@types/passport-local@1.0.38': - resolution: {integrity: sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==} - - '@types/passport-strategy@0.2.38': - resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==} - - '@types/passport@1.0.17': - resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} - '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -1269,10 +1157,6 @@ packages: buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-crc32@1.0.0: - resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} - engines: {node: '>=8.0.0'} - buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -1426,17 +1310,10 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - cookie-signature@1.0.7: - resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} - cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -1747,9 +1624,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eventemitter3@5.0.4: - resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -1770,10 +1644,6 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - express-session@1.19.0: - resolution: {integrity: sha512-0csaMkGq+vaiZTmSMMGkfdCOabYv192VbytFypcvI0MANrp+4i/7yEkJ0sbAEhycQjntaKGzYfjfXQyVb7BHMA==} - engines: {node: '>= 0.8.0'} - express@4.18.2: resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} engines: {node: '>= 0.10.0'} @@ -1804,17 +1674,10 @@ packages: fast-uri@3.1.2: resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - fast-xml-builder@1.1.9: - resolution: {integrity: sha512-jcyKVSEX13iseJqg7n/KWw+xnu/7fdrZ333Fac54KjHDIELVCfDDJXYIm6DTJ0Su4gSzrhqiK0DzY/wZbF40mw==} - fast-xml-parser@4.5.6: resolution: {integrity: sha512-Yd4vkROfJf8AuJrDIVMVmYfULKmIJszVsMv7Vo71aocsKgFxpdlpSHXSaInvyYfgw2PRuObQSW2GFpVMUjxu9A==} hasBin: true - fast-xml-parser@5.7.3: - resolution: {integrity: sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==} - hasBin: true - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -2485,23 +2348,13 @@ packages: jsonfile@6.2.1: resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} - engines: {node: '>=12', npm: '>=6'} - jsonwebtoken@9.0.3: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} - jwa@1.4.2: - resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==} - jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - jws@3.2.3: - resolution: {integrity: sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==} - jws@4.0.1: resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} @@ -2673,10 +2526,6 @@ packages: resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==} engines: {node: ^16 || ^18 || >=20} - minio@8.0.7: - resolution: {integrity: sha512-E737MgufW8CeQAsTAtnEMrxZ9scMSf29kkhZoXzDTKj/Jszzo2SfeZUH9wbDQH2Rsq6TCtl/yQL0+XdVKZansQ==} - engines: {node: ^16 || ^18 || >=20} - minipass@4.2.8: resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} engines: {node: '>=8'} @@ -2705,11 +2554,6 @@ packages: engines: {node: '>= 6.0.0'} deprecated: Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version. - multer@1.4.5-lts.1: - resolution: {integrity: sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==} - engines: {node: '>= 6.0.0'} - deprecated: Multer 1.x is impacted by a number of vulnerabilities, which have been patched in 2.x. You should upgrade to the latest 2.x version. - mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} @@ -2739,8 +2583,8 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - nestjs-knife4j-plus@1.0.7: - resolution: {integrity: sha512-YM1ecJGSDDUZdbNLVl/OJus3gZDjMt3cwx7Ymp8vSnQpXA8xwd+l0MVZEh7lJ5Rt45xhq4QwgaW/WIpw/MOCXA==} + nestjs-knife4j-plus@1.0.8: + resolution: {integrity: sha512-oXUBQwrEzeuOyqei32I/zIHGo1V8icL0pJaX2dOJSqi0VKXy63pXXJhZ/hVD/XX3Rg/dvLqg5IHgnm7nRksesw==} peerDependencies: '@fastify/static': '*' '@nestjs/common': '*' @@ -2807,10 +2651,6 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -2881,29 +2721,10 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - passport-jwt@4.0.1: - resolution: {integrity: sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==} - - passport-local@1.0.0: - resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==} - engines: {node: '>= 0.4.0'} - - passport-strategy@1.0.0: - resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==} - engines: {node: '>= 0.4.0'} - - passport@0.6.0: - resolution: {integrity: sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==} - engines: {node: '>= 0.4.0'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-expression-matcher@1.5.0: - resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} - engines: {node: '>=14.0.0'} - path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -2932,9 +2753,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - pause@0.0.1: - resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3011,10 +2829,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - random-bytes@1.0.0: - resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==} - engines: {node: '>= 0.8'} - range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -3168,6 +2982,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -3291,12 +3110,6 @@ packages: resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} engines: {node: '>=4', npm: '>=6'} - stream-chain@2.2.5: - resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} - - stream-json@1.9.1: - resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} - streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -3362,9 +3175,6 @@ packages: strnum@1.1.2: resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} - strnum@2.2.3: - resolution: {integrity: sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==} - superagent@8.1.2: resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} engines: {node: '>=6.4.0 <13 || >=14'} @@ -3641,10 +3451,6 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - uid-safe@2.1.5: - resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==} - engines: {node: '>= 0.8'} - uid@2.0.2: resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} engines: {node: '>=8'} @@ -3790,10 +3596,6 @@ packages: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} - xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} - xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} @@ -3875,14 +3677,17 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/abort-controller@1.1.0': dependencies: tslib: 2.8.1 + optional: true '@azure/abort-controller@2.1.2': dependencies: tslib: 2.8.1 + optional: true '@azure/core-auth@1.10.1': dependencies: @@ -3891,6 +3696,7 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/core-client@1.10.1': dependencies: @@ -3903,12 +3709,14 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/core-http-compat@2.4.0(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.23.0)': dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-client': 1.10.1 '@azure/core-rest-pipeline': 1.23.0 + optional: true '@azure/core-lro@2.7.2': dependencies: @@ -3918,10 +3726,12 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/core-paging@1.6.2': dependencies: tslib: 2.8.1 + optional: true '@azure/core-rest-pipeline@1.23.0': dependencies: @@ -3934,10 +3744,12 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/core-tracing@1.3.1': dependencies: tslib: 2.8.1 + optional: true '@azure/core-util@1.13.1': dependencies: @@ -3946,6 +3758,7 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/identity@2.1.0': dependencies: @@ -3967,6 +3780,7 @@ snapshots: uuid: 8.3.2 transitivePeerDependencies: - supports-color + optional: true '@azure/keyvault-common@2.1.0': dependencies: @@ -3980,6 +3794,7 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/keyvault-keys@4.10.0(@azure/core-client@1.10.1)': dependencies: @@ -3998,6 +3813,7 @@ snapshots: transitivePeerDependencies: - '@azure/core-client' - supports-color + optional: true '@azure/logger@1.3.0': dependencies: @@ -4005,22 +3821,28 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@azure/msal-browser@2.39.0': dependencies: '@azure/msal-common': 13.3.3 + optional: true - '@azure/msal-common@13.3.1': {} + '@azure/msal-common@13.3.1': + optional: true - '@azure/msal-common@13.3.3': {} + '@azure/msal-common@13.3.3': + optional: true - '@azure/msal-common@7.6.0': {} + '@azure/msal-common@7.6.0': + optional: true '@azure/msal-node@1.18.4': dependencies: '@azure/msal-common': 13.3.1 jsonwebtoken: 9.0.3 uuid: 8.3.2 + optional: true '@babel/code-frame@7.29.0': dependencies: @@ -4463,7 +4285,8 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@js-joda/core@5.7.0': {} + '@js-joda/core@5.7.0': + optional: true '@lukeed/csprng@1.1.0': {} @@ -4533,27 +4356,11 @@ snapshots: transitivePeerDependencies: - encoding - '@nestjs/jwt@10.2.0(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))': - dependencies: - '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) - '@types/jsonwebtoken': 9.0.5 - jsonwebtoken: 9.0.2 - '@nestjs/mapped-types@2.0.5(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)': dependencies: '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) reflect-metadata: 0.1.14 - '@nestjs/mapped-types@2.1.1(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(reflect-metadata@0.1.14)': - dependencies: - '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) - reflect-metadata: 0.1.14 - - '@nestjs/passport@9.0.3(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(passport@0.6.0)': - dependencies: - '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) - passport: 0.6.0 - '@nestjs/platform-express@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(@nestjs/core@9.4.3)': dependencies: '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) @@ -4607,8 +4414,6 @@ snapshots: '@noble/hashes@1.8.0': {} - '@nodable/entities@2.1.0': {} - '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4648,7 +4453,8 @@ snapshots: '@sqltools/formatter@1.2.5': {} - '@tediousjs/connection-string@0.5.0': {} + '@tediousjs/connection-string@0.5.0': + optional: true '@tsconfig/node10@1.0.12': {} @@ -4690,10 +4496,6 @@ snapshots: '@types/cookiejar@2.1.5': {} - '@types/dotenv@8.2.3': - dependencies: - dotenv: 16.6.1 - '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -4713,10 +4515,6 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 1.2.1 - '@types/express-session@1.19.0': - dependencies: - '@types/express': 4.17.25 - '@types/express@4.17.25': dependencies: '@types/body-parser': 1.19.6 @@ -4747,56 +4545,16 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/jsonwebtoken@9.0.10': - dependencies: - '@types/ms': 2.1.0 - '@types/node': 18.11.18 - - '@types/jsonwebtoken@9.0.5': - dependencies: - '@types/node': 18.11.18 - - '@types/lodash-es@4.17.12': - dependencies: - '@types/lodash': 4.17.24 - '@types/lodash@4.17.24': {} '@types/methods@1.1.4': {} '@types/mime@1.3.5': {} - '@types/ms@2.1.0': {} - - '@types/multer@1.4.13': - dependencies: - '@types/express': 4.17.25 - '@types/node@18.11.18': {} '@types/parse-json@4.0.2': {} - '@types/passport-jwt@3.0.13': - dependencies: - '@types/express': 4.17.25 - '@types/jsonwebtoken': 9.0.10 - '@types/passport-strategy': 0.2.38 - - '@types/passport-local@1.0.38': - dependencies: - '@types/express': 4.17.25 - '@types/passport': 1.0.17 - '@types/passport-strategy': 0.2.38 - - '@types/passport-strategy@0.2.38': - dependencies: - '@types/express': 4.17.25 - '@types/passport': 1.0.17 - - '@types/passport@1.0.17': - dependencies: - '@types/express': 4.17.25 - '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -4928,6 +4686,7 @@ snapshots: tslib: 2.8.1 transitivePeerDependencies: - supports-color + optional: true '@ungap/structured-clone@1.3.1': {} @@ -5033,7 +4792,8 @@ snapshots: acorn@8.16.0: {} - agent-base@7.1.4: {} + agent-base@7.1.4: + optional: true ajv-formats@2.1.1(ajv@8.12.0): optionalDependencies: @@ -5114,6 +4874,7 @@ snapshots: dependencies: call-bound: 1.0.4 is-array-buffer: 3.0.5 + optional: true array-flatten@1.1.1: {} @@ -5128,10 +4889,12 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + optional: true asap@2.0.6: {} - async-function@1.0.0: {} + async-function@1.0.0: + optional: true async@3.2.6: {} @@ -5217,6 +4980,7 @@ snapshots: buffer: 6.0.3 inherits: 2.0.4 readable-stream: 3.6.2 + optional: true block-stream2@2.1.0: dependencies: @@ -5289,9 +5053,8 @@ snapshots: buffer-crc32@0.2.13: {} - buffer-crc32@1.0.0: {} - - buffer-equal-constant-time@1.0.1: {} + buffer-equal-constant-time@1.0.1: + optional: true buffer-from@1.1.2: {} @@ -5399,7 +5162,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@11.1.0: {} + commander@11.1.0: + optional: true commander@2.20.3: {} @@ -5428,12 +5192,8 @@ snapshots: cookie-signature@1.0.6: {} - cookie-signature@1.0.7: {} - cookie@0.5.0: {} - cookie@0.7.2: {} - cookiejar@2.1.4: {} core-util-is@1.0.3: {} @@ -5483,18 +5243,21 @@ snapshots: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 + optional: true data-view-byte-length@1.0.2: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 + optional: true data-view-byte-offset@1.0.1: dependencies: call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 + optional: true dayjs@1.11.20: {} @@ -5524,13 +5287,15 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - define-lazy-prop@2.0.0: {} + define-lazy-prop@2.0.0: + optional: true define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + optional: true delayed-stream@1.0.0: {} @@ -5576,6 +5341,7 @@ snapshots: ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 + optional: true ee-first@1.1.1: {} @@ -5658,6 +5424,7 @@ snapshots: typed-array-length: 1.0.7 unbox-primitive: 1.1.0 which-typed-array: 1.1.20 + optional: true es-aggregate-error@1.0.14: dependencies: @@ -5669,6 +5436,7 @@ snapshots: globalthis: 1.0.4 has-property-descriptors: 1.0.2 set-function-name: 2.0.2 + optional: true es-define-property@1.0.1: {} @@ -5692,6 +5460,7 @@ snapshots: is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 + optional: true escalade@3.2.0: {} @@ -5798,8 +5567,6 @@ snapshots: etag@1.8.1: {} - eventemitter3@5.0.4: {} - events@3.3.0: {} execa@4.1.0: @@ -5836,19 +5603,6 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - express-session@1.19.0: - dependencies: - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9 - depd: 2.0.0 - on-headers: 1.1.0 - parseurl: 1.3.3 - safe-buffer: 5.2.1 - uid-safe: 2.1.5 - transitivePeerDependencies: - - supports-color - express@4.18.2: dependencies: accepts: 1.3.8 @@ -5911,21 +5665,10 @@ snapshots: fast-uri@3.1.2: {} - fast-xml-builder@1.1.9: - dependencies: - path-expression-matcher: 1.5.0 - fast-xml-parser@4.5.6: dependencies: strnum: 1.1.2 - fast-xml-parser@5.7.3: - dependencies: - '@nodable/entities': 2.1.0 - fast-xml-builder: 1.1.9 - path-expression-matcher: 1.5.0 - strnum: 2.2.3 - fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -6046,8 +5789,10 @@ snapshots: functions-have-names: 1.2.3 hasown: 2.0.3 is-callable: 1.2.7 + optional: true - functions-have-names@1.2.3: {} + functions-have-names@1.2.3: + optional: true generate-function@2.3.1: dependencies: @@ -6090,6 +5835,7 @@ snapshots: call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 + optional: true glob-parent@5.1.2: dependencies: @@ -6134,6 +5880,7 @@ snapshots: dependencies: define-properties: 1.2.1 gopd: 1.2.0 + optional: true globby@11.1.0: dependencies: @@ -6150,7 +5897,8 @@ snapshots: graphemer@1.4.0: {} - has-bigints@1.1.0: {} + has-bigints@1.1.0: + optional: true has-flag@4.0.0: {} @@ -6161,6 +5909,7 @@ snapshots: has-proto@1.2.0: dependencies: dunder-proto: 1.0.1 + optional: true has-symbols@1.1.0: {} @@ -6188,6 +5937,7 @@ snapshots: debug: 4.4.3 transitivePeerDependencies: - supports-color + optional: true https-proxy-agent@7.0.6: dependencies: @@ -6195,6 +5945,7 @@ snapshots: debug: 4.4.3 transitivePeerDependencies: - supports-color + optional: true human-signals@1.1.1: {} @@ -6207,6 +5958,7 @@ snapshots: iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 + optional: true iconv-lite@0.7.2: dependencies: @@ -6276,6 +6028,7 @@ snapshots: es-errors: 1.3.0 hasown: 2.0.3 side-channel: 1.1.0 + optional: true interpret@1.4.0: {} @@ -6293,6 +6046,7 @@ snapshots: call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 + optional: true is-arrayish@0.2.1: {} @@ -6303,10 +6057,12 @@ snapshots: get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 + optional: true is-bigint@1.1.0: dependencies: has-bigints: 1.1.0 + optional: true is-binary-path@2.1.0: dependencies: @@ -6316,6 +6072,7 @@ snapshots: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 + optional: true is-callable@1.2.7: {} @@ -6328,19 +6085,23 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 is-typed-array: 1.1.15 + optional: true is-date-object@1.1.0: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 + optional: true - is-docker@2.2.1: {} + is-docker@2.2.1: + optional: true is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: dependencies: call-bound: 1.0.4 + optional: true is-fullwidth-code-point@3.0.0: {} @@ -6360,14 +6121,17 @@ snapshots: is-interactive@1.0.0: {} - is-map@2.0.3: {} + is-map@2.0.3: + optional: true - is-negative-zero@2.0.3: {} + is-negative-zero@2.0.3: + optional: true is-number-object@1.1.1: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 + optional: true is-number@7.0.0: {} @@ -6382,11 +6146,13 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.3 - is-set@2.0.3: {} + is-set@2.0.3: + optional: true is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 + optional: true is-stream@2.0.1: {} @@ -6394,12 +6160,14 @@ snapshots: dependencies: call-bound: 1.0.4 has-tostringtag: 1.0.2 + optional: true is-symbol@1.1.1: dependencies: call-bound: 1.0.4 has-symbols: 1.1.0 safe-regex-test: 1.1.0 + optional: true is-typed-array@1.1.15: dependencies: @@ -6407,20 +6175,24 @@ snapshots: is-unicode-supported@0.1.0: {} - is-weakmap@2.0.2: {} + is-weakmap@2.0.2: + optional: true is-weakref@1.1.1: dependencies: call-bound: 1.0.4 + optional: true is-weakset@2.0.4: dependencies: call-bound: 1.0.4 get-intrinsic: 1.3.0 + optional: true is-wsl@2.2.0: dependencies: is-docker: 2.2.1 + optional: true isarray@1.0.0: {} @@ -6792,7 +6564,8 @@ snapshots: - supports-color - ts-node - js-md4@0.3.2: {} + js-md4@0.3.2: + optional: true js-tokens@4.0.0: {} @@ -6809,7 +6582,8 @@ snapshots: dependencies: argparse: 2.0.1 - jsbi@4.3.2: {} + jsbi@4.3.2: + optional: true jsesc@3.1.0: {} @@ -6835,19 +6609,6 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonwebtoken@9.0.2: - dependencies: - jws: 3.2.3 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.7.4 - jsonwebtoken@9.0.3: dependencies: jws: 4.0.1 @@ -6859,29 +6620,21 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.7.4 - - jwa@1.4.2: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 + semver: 7.8.0 + optional: true jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - - jws@3.2.3: - dependencies: - jwa: 1.4.2 - safe-buffer: 5.2.1 + optional: true jws@4.0.1: dependencies: jwa: 2.0.1 safe-buffer: 5.2.1 + optional: true keyv@4.5.4: dependencies: @@ -6908,23 +6661,30 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash.includes@4.3.0: {} + lodash.includes@4.3.0: + optional: true - lodash.isboolean@3.0.3: {} + lodash.isboolean@3.0.3: + optional: true - lodash.isinteger@4.0.4: {} + lodash.isinteger@4.0.4: + optional: true - lodash.isnumber@3.0.3: {} + lodash.isnumber@3.0.3: + optional: true - lodash.isplainobject@4.0.6: {} + lodash.isplainobject@4.0.6: + optional: true - lodash.isstring@4.0.1: {} + lodash.isstring@4.0.1: + optional: true lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} - lodash.once@4.1.1: {} + lodash.once@4.1.1: + optional: true lodash@4.17.21: {} @@ -7025,22 +6785,6 @@ snapshots: xml: 1.0.1 xml2js: 0.5.0 - minio@8.0.7: - dependencies: - async: 3.2.6 - block-stream2: 2.1.0 - browser-or-node: 2.1.1 - buffer-crc32: 1.0.0 - eventemitter3: 5.0.4 - fast-xml-parser: 5.7.3 - ipaddr.js: 2.4.0 - lodash: 4.18.1 - mime-types: 2.1.35 - query-string: 7.1.3 - stream-json: 1.9.1 - through2: 4.0.2 - xml2js: 0.6.2 - minipass@4.2.8: {} minipass@7.1.3: {} @@ -7064,6 +6808,7 @@ snapshots: transitivePeerDependencies: - '@azure/core-client' - supports-color + optional: true multer@1.4.4-lts.1: dependencies: @@ -7075,16 +6820,6 @@ snapshots: type-is: 1.6.18 xtend: 4.0.2 - multer@1.4.5-lts.1: - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - concat-stream: 1.6.2 - mkdirp: 0.5.6 - object-assign: 4.1.1 - type-is: 1.6.18 - xtend: 4.0.2 - mute-stream@0.0.8: {} mysql2@3.22.3(@types/node@18.11.18): @@ -7103,7 +6838,8 @@ snapshots: dependencies: lru.min: 1.1.4 - native-duplexpair@1.0.0: {} + native-duplexpair@1.0.0: + optional: true natural-compare-lite@1.4.0: {} @@ -7113,7 +6849,7 @@ snapshots: neo-async@2.6.2: {} - nestjs-knife4j-plus@1.0.7(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2): + nestjs-knife4j-plus@1.0.8(@nestjs/common@9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2))(express@4.18.2): dependencies: '@nestjs/common': 9.4.3(reflect-metadata@0.1.14)(rxjs@7.8.2) express: 4.18.2 @@ -7150,7 +6886,8 @@ snapshots: object-inspect@1.13.4: {} - object-keys@1.1.1: {} + object-keys@1.1.1: + optional: true object.assign@4.1.7: dependencies: @@ -7160,13 +6897,12 @@ snapshots: es-object-atoms: 1.1.1 has-symbols: 1.1.0 object-keys: 1.1.1 + optional: true on-finished@2.4.1: dependencies: ee-first: 1.1.1 - on-headers@1.1.0: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -7180,6 +6916,7 @@ snapshots: define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 + optional: true opentype.js@0.7.3: dependencies: @@ -7218,6 +6955,7 @@ snapshots: get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 + optional: true p-limit@2.3.0: dependencies: @@ -7252,27 +6990,8 @@ snapshots: parseurl@1.3.3: {} - passport-jwt@4.0.1: - dependencies: - jsonwebtoken: 9.0.3 - passport-strategy: 1.0.0 - - passport-local@1.0.0: - dependencies: - passport-strategy: 1.0.0 - - passport-strategy@1.0.0: {} - - passport@0.6.0: - dependencies: - passport-strategy: 1.0.0 - pause: 0.0.1 - utils-merge: 1.0.1 - path-exists@4.0.0: {} - path-expression-matcher@1.5.0: {} - path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -7292,8 +7011,6 @@ snapshots: path-type@4.0.0: {} - pause@0.0.1: {} - picocolors@1.1.1: {} picomatch@2.3.2: {} @@ -7360,8 +7077,6 @@ snapshots: queue-microtask@1.2.3: {} - random-bytes@1.0.0: {} - range-parser@1.2.1: {} raw-body@2.5.1: @@ -7418,6 +7133,7 @@ snapshots: get-intrinsic: 1.3.0 get-proto: 1.0.1 which-builtin-type: 1.2.1 + optional: true regexp.prototype.flags@1.5.4: dependencies: @@ -7427,6 +7143,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 set-function-name: 2.0.2 + optional: true require-directory@2.1.1: {} @@ -7458,7 +7175,8 @@ snapshots: reusify@1.1.0: {} - rfdc@1.4.1: {} + rfdc@1.4.1: + optional: true rimraf@3.0.2: dependencies: @@ -7489,6 +7207,7 @@ snapshots: get-intrinsic: 1.3.0 has-symbols: 1.1.0 isarray: 2.0.5 + optional: true safe-buffer@5.1.2: {} @@ -7498,6 +7217,7 @@ snapshots: dependencies: es-errors: 1.3.0 isarray: 2.0.5 + optional: true safe-regex-test@1.1.0: dependencies: @@ -7526,6 +7246,9 @@ snapshots: semver@7.7.4: {} + semver@7.8.0: + optional: true + send@0.18.0: dependencies: debug: 2.6.9 @@ -7568,12 +7291,14 @@ snapshots: es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + optional: true set-proto@1.0.0: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 + optional: true setprototypeof@1.2.0: {} @@ -7651,7 +7376,8 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.3: {} + sprintf-js@1.1.3: + optional: true sql-escaper@1.3.3: {} @@ -7667,14 +7393,10 @@ snapshots: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 + optional: true - stoppable@1.1.0: {} - - stream-chain@2.2.5: {} - - stream-json@1.9.1: - dependencies: - stream-chain: 2.2.5 + stoppable@1.1.0: + optional: true streamsearch@1.1.0: {} @@ -7706,6 +7428,7 @@ snapshots: es-abstract: 1.24.2 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 + optional: true string.prototype.trimend@1.0.9: dependencies: @@ -7713,12 +7436,14 @@ snapshots: call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 + optional: true string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.9 define-properties: 1.2.1 es-object-atoms: 1.1.1 + optional: true string_decoder@1.1.1: dependencies: @@ -7746,8 +7471,6 @@ snapshots: strnum@1.1.2: {} - strnum@2.2.3: {} - superagent@8.1.2: dependencies: component-emitter: 1.3.1 @@ -7790,7 +7513,8 @@ snapshots: tapable@2.3.3: {} - tarn@3.0.2: {} + tarn@3.0.2: + optional: true tedious@15.1.3(@azure/core-client@1.10.1): dependencies: @@ -7809,6 +7533,7 @@ snapshots: transitivePeerDependencies: - '@azure/core-client' - supports-color + optional: true terser-webpack-plugin@5.5.0(webpack@5.82.1): dependencies: @@ -7965,6 +7690,7 @@ snapshots: gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 + optional: true typed-array-byte-offset@1.0.4: dependencies: @@ -7975,6 +7701,7 @@ snapshots: has-proto: 1.2.0 is-typed-array: 1.1.15 reflect.getprototypeof: 1.0.10 + optional: true typed-array-length@1.0.7: dependencies: @@ -7984,6 +7711,7 @@ snapshots: is-typed-array: 1.1.15 possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + optional: true typedarray@0.0.6: {} @@ -8014,10 +7742,6 @@ snapshots: typescript@4.9.5: {} - uid-safe@2.1.5: - dependencies: - random-bytes: 1.0.0 - uid@2.0.2: dependencies: '@lukeed/csprng': 1.1.0 @@ -8028,6 +7752,7 @@ snapshots: has-bigints: 1.1.0 has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + optional: true universalify@2.0.1: {} @@ -8139,6 +7864,7 @@ snapshots: is-number-object: 1.1.1 is-string: 1.1.1 is-symbol: 1.1.1 + optional: true which-builtin-type@1.2.1: dependencies: @@ -8155,6 +7881,7 @@ snapshots: which-boxed-primitive: 1.1.1 which-collection: 1.0.2 which-typed-array: 1.1.20 + optional: true which-collection@1.0.2: dependencies: @@ -8162,6 +7889,7 @@ snapshots: is-set: 2.0.3 is-weakmap: 2.0.2 is-weakset: 2.0.4 + optional: true which-typed-array@1.1.20: dependencies: @@ -8207,11 +7935,6 @@ snapshots: sax: 1.6.0 xmlbuilder: 11.0.1 - xml2js@0.6.2: - dependencies: - sax: 1.6.0 - xmlbuilder: 11.0.1 - xml@1.0.1: {} xmlbuilder@11.0.1: {} diff --git a/src/app.controller.ts b/src/app.controller.ts index 0a4fb27..b02cd1c 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,4 +1,5 @@ import { Controller, Get, Redirect } from '@nestjs/common'; +import { ApiMovedPermanentlyResponse, ApiOperation } from '@nestjs/swagger'; import { AppService } from './app.service'; @Controller() @@ -7,6 +8,10 @@ export class AppController { @Get() @Redirect('/api#/', 301) + @ApiOperation({ summary: '重定向到Swagger文档' }) + @ApiMovedPermanentlyResponse({ + description: '重定向到 /api#/', + }) getHome() { return { url: '/api#/' }; } diff --git a/src/app.module.ts b/src/app.module.ts index 3823a24..5d341e5 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,11 +6,13 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { MinioModule } from 'nestjs-minio-client'; import { ComponentModule } from './component/component.module'; import { DictModule } from './dict/dict.module'; +import { MinioClientModule } from './minio/minio.module'; import { SaveMiddleware } from './middleware/save.middleware'; @Module({ imports: [ ConfigModule.forRoot({ + isGlobal: true, envFilePath: `.env${ process.env.NODE_ENV ? `.${process.env.NODE_ENV}` : '' }`, @@ -47,6 +49,7 @@ import { SaveMiddleware } from './middleware/save.middleware'; }), ComponentModule, DictModule, + MinioClientModule, ], providers: [AppService, ConfigService], }) diff --git a/src/common/swagger-response.ts b/src/common/swagger-response.ts new file mode 100644 index 0000000..a02a84d --- /dev/null +++ b/src/common/swagger-response.ts @@ -0,0 +1,181 @@ +import { applyDecorators, Type } from '@nestjs/common'; +import { ApiExtraModels, ApiOkResponse, ApiProperty } from '@nestjs/swagger'; + +type SwaggerSchema = Record; + +type ApiResponseOptions = { + description?: string; + schema?: SwaggerSchema; + example: any; +}; + +const primitiveTypeMap = { + string: String, + number: Number, + boolean: Boolean, +}; + +const setClassName = (target: Type, name: string) => { + Object.defineProperty(target, 'name', { + value: name, + }); + + return target; +}; + +export class PaginatedDto { + @ApiProperty() + total: number; + + @ApiProperty({ + type: Array, + }) + list: TData[]; +} + +export class ApiResponseDto { + @ApiProperty({ + example: 200, + }) + code: number; + + @ApiProperty({ + example: '操作成功', + }) + msg: string; + + @ApiProperty() + data: TData; +} + +const getResponseExample = (example: any) => ({ + code: 200, + msg: '操作成功', + data: example, +}); + +export const ApiSuccessResponse = ({ + description = '操作成功', + schema, + example, +}: ApiResponseOptions) => { + const primitiveType = primitiveTypeMap[schema?.type] || Object; + + class ApiSuccessResponseDto extends ApiResponseDto { + @ApiProperty({ + type: primitiveType, + description: schema?.description, + }) + declare data: any; + } + + setClassName(ApiSuccessResponseDto, `ApiResponseOf${primitiveType.name}`); + + return applyDecorators( + ApiExtraModels(ApiSuccessResponseDto), + ApiOkResponse({ + description, + type: ApiSuccessResponseDto, + example: getResponseExample(example), + }), + ); +}; + +export const ApiModelResponse = >( + model: TModel, + example: any, + description?: string, +) => { + class ApiModelResponseDto extends ApiResponseDto { + @ApiProperty({ + type: model, + }) + declare data: TModel; + } + + setClassName(ApiModelResponseDto, `ApiResponseOf${model.name}`); + + return applyDecorators( + ApiExtraModels(ApiModelResponseDto, model), + ApiOkResponse({ + description: description || '操作成功', + type: ApiModelResponseDto, + example: getResponseExample(example), + }), + ); +}; + +export const ApiArrayResponse = >( + model: TModel, + example: any[], + description?: string, +) => { + class ApiArrayResponseDto extends ApiResponseDto { + @ApiProperty({ + type: [model], + }) + declare data: TModel[]; + } + + setClassName(ApiArrayResponseDto, `ApiResponseOf${model.name}Array`); + + return applyDecorators( + ApiExtraModels(ApiArrayResponseDto, model), + ApiOkResponse({ + description: description || '操作成功', + type: ApiArrayResponseDto, + example: getResponseExample(example), + }), + ); +}; + +export const ApiPageResponse = >( + model: TModel, + example: any[], + total = 1, + description?: string, +) => { + class PageResponseDto extends PaginatedDto { + @ApiProperty({ + type: [model], + }) + declare list: TModel[]; + } + + class ApiPageResponseDto extends ApiResponseDto { + @ApiProperty({ + type: PageResponseDto, + }) + declare data: PageResponseDto; + } + + setClassName(PageResponseDto, `PaginatedResponseOf${model.name}`); + setClassName(ApiPageResponseDto, `ApiResponseOfPaginated${model.name}`); + + return applyDecorators( + ApiExtraModels(ApiPageResponseDto, PageResponseDto, PaginatedDto, model), + ApiOkResponse({ + description: description || '操作成功', + type: ApiPageResponseDto, + example: getResponseExample({ + list: example, + total, + }), + }), + ); +}; + +export const ApiFileDownloadResponse = (description = '文件下载成功') => + applyDecorators( + ApiOkResponse({ + description, + content: { + 'application/octet-stream': { + schema: { + type: 'string', + format: 'binary', + }, + }, + }, + }), + ); diff --git a/src/component/component.controller.ts b/src/component/component.controller.ts index 0cac56e..52e6228 100644 --- a/src/component/component.controller.ts +++ b/src/component/component.controller.ts @@ -10,7 +10,6 @@ import { } from '@nestjs/common'; import { ApiExtraModels, - ApiOkResponse, ApiOperation, ApiProperty, ApiQuery, @@ -20,8 +19,28 @@ import { import { ToolsService } from '@/utils/tool.service'; import { ComponentService } from './component.service'; import { Component } from './component.entity'; -import { PaginatedDto } from '@/utils/constant'; import { ComponentDto } from './component.dto'; +import { + PaginatedDto, + ApiArrayResponse, + ApiModelResponse, + ApiPageResponse, + ApiSuccessResponse, +} from '@/common/swagger-response'; + +const componentExample = { + id: '1d8d3dd2-99f0-4d10-9a44-0cf9566b37c9', + name: '基础折线图', + type: 1, + componentType: 1, + typeMsg: '图表', + componentTypeMsg: '折线图', + image: '', + template: '%7B%22version%22%3A%221.0%22%7D', + createTime: '2026-05-13T02:30:00.000Z', + updateTime: '2026-05-13T02:30:00.000Z', + is_deleted: false, +}; class CompPageDto extends PartialType(Component) @@ -39,16 +58,9 @@ class CompPageDto pageSize: number; } -class CompPageResDto extends PaginatedDto { - @ApiProperty({ - type: [ComponentDto], - }) - list: ComponentDto[]; -} - @Controller('component') @ApiTags('component') -@ApiExtraModels(PaginatedDto, ComponentDto) +@ApiExtraModels(PaginatedDto) export class ComponentController { constructor( private readonly toolsService: ToolsService, @@ -57,7 +69,7 @@ export class ComponentController { @Get('allList') @ApiOperation({ summary: '获取组件列表' }) - @ApiOkResponse({ type: [ComponentDto] }) + @ApiArrayResponse(ComponentDto, [componentExample]) async getAllList(@Res() res) { const list = await this.componentService.all(); res.send(this.toolsService.res(HttpStatus.OK, '操作成功', list)); @@ -66,13 +78,11 @@ export class ComponentController { @Get('list') @ApiOperation({ summary: '获取组件列表分页' }) @ApiQuery({ type: [CompPageDto] }) - @ApiOkResponse({ - type: CompPageResDto, - }) + @ApiPageResponse(ComponentDto, [componentExample], 1) async getList( @Res() res, @Query() { pageNo, pageSize, ...args }: PageParams, - ): Promise { + ): Promise> { const list = await this.componentService.page({ pageNo, pageSize, @@ -85,6 +95,13 @@ export class ComponentController { @Post('save') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: '保存组件' }) + @ApiSuccessResponse({ + schema: { + type: 'string', + description: '新增组件ID', + }, + example: '1d8d3dd2-99f0-4d10-9a44-0cf9566b37c9', + }) async save(@Res() res, @Body() component: Component) { const save = await this.componentService.save(component); @@ -101,6 +118,12 @@ export class ComponentController { @HttpCode(HttpStatus.OK) @ApiOperation({ summary: '删除组件' }) @ApiQuery({ name: 'id', type: String }) + @ApiSuccessResponse({ + schema: { + type: 'boolean', + }, + example: true, + }) async remove(@Res() res, @Query('id') id) { const remove = await this.componentService.remove(id); @@ -118,6 +141,12 @@ export class ComponentController { @Post('update') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: '编辑组件' }) + @ApiSuccessResponse({ + schema: { + type: 'boolean', + }, + example: true, + }) async update(@Res() res, @Body() component: Component) { const update = await this.componentService.update(component); @@ -135,7 +164,7 @@ export class ComponentController { @Get('detail') @ApiOperation({ summary: '组件详情' }) @ApiQuery({ name: 'id', type: String }) - @ApiOkResponse({ type: ComponentDto }) + @ApiModelResponse(ComponentDto, componentExample) async detail(@Res() res, @Query('id') id) { const detail = await this.componentService.find(id); diff --git a/src/dict/dict.controller.ts b/src/dict/dict.controller.ts index 256a135..164afe3 100644 --- a/src/dict/dict.controller.ts +++ b/src/dict/dict.controller.ts @@ -1,8 +1,39 @@ -import { Controller, Get, HttpStatus, ParseIntPipe, Query, Res } from '@nestjs/common'; +import { + Controller, + Get, + HttpStatus, + ParseIntPipe, + Query, + Res, +} from '@nestjs/common'; import { ToolsService } from '@/utils/tool.service'; import { DictService } from './dict.service'; import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger'; import { ComponentTypeEnum, DictKeyEnum, DictKeyType } from '@/utils/constant'; +import { ApiArrayResponse } from '@/common/swagger-response'; +import { DictDto } from './dict.dto'; + +const componentTypeDictExample = [ + { + label: '图表', + value: 1, + }, + { + label: '组件', + value: 2, + }, +]; + +const chartDictExample = [ + { + label: '未分类', + value: -1, + }, + { + label: '折线图', + value: 1, + }, +]; @ApiTags('dict') @Controller('dict') @@ -14,31 +45,21 @@ export class DictController { @ApiOperation({ summary: '根据key获取字典' }) @ApiQuery({ name: 'dictKey', enum: DictKeyEnum }) + @ApiArrayResponse(DictDto, componentTypeDictExample) @Get('getDictByKey') async getDictByKey(@Res() res, @Query('dictKey') dictKey: DictKeyType) { - const dict = this.toolsService.getDictByKey(dictKey) + const dict = this.toolsService.getDictByKey(dictKey); - return res.send( - this.toolsService.res( - HttpStatus.OK, - '操作成功', - dict, - ), - ); + return res.send(this.toolsService.res(HttpStatus.OK, '操作成功', dict)); } @ApiOperation({ summary: '根据组件类型获取组件字典' }) @ApiQuery({ name: 'type', enum: ComponentTypeEnum }) + @ApiArrayResponse(DictDto, chartDictExample) @Get('getComponentDictByType') async getComponentDictByType(@Res() res, @Query('type', ParseIntPipe) type) { - const dict = await this.dictService.getComponentDictByType(type) + const dict = await this.dictService.getComponentDictByType(type); - return res.send( - this.toolsService.res( - HttpStatus.OK, - '操作成功', - dict, - ), - ); + return res.send(this.toolsService.res(HttpStatus.OK, '操作成功', dict)); } } diff --git a/src/dict/dict.dto.ts b/src/dict/dict.dto.ts new file mode 100644 index 0000000..f5a6b39 --- /dev/null +++ b/src/dict/dict.dto.ts @@ -0,0 +1,13 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class DictDto { + @ApiProperty({ + example: '图表', + }) + label: string; + + @ApiProperty({ + example: 1, + }) + value: number; +} diff --git a/src/minio/minio.controller.ts b/src/minio/minio.controller.ts index e73ccf9..604b8d5 100644 --- a/src/minio/minio.controller.ts +++ b/src/minio/minio.controller.ts @@ -1,16 +1,226 @@ import { Controller, - + Body, + Delete, + Get, + HttpStatus, + Post, + Query, + Res, + UploadedFile, + UseInterceptors, } from '@nestjs/common'; -import { ToolsService } from 'src/utils/tool.service'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { + ApiBody, + ApiConsumes, + ApiOperation, + ApiQuery, + ApiTags, +} from '@nestjs/swagger'; +import { Response } from 'express'; +import { ToolsService } from '@/utils/tool.service'; import { MinioClientService } from './minio.service'; +import type { MinioUploadFile } from './minio.service'; +import { + ApiFileDownloadResponse, + ApiArrayResponse, + ApiModelResponse, + ApiSuccessResponse, +} from '@/common/swagger-response'; +import { + MinioBucketStatusDto, + MinioObjectDto, + MinioUploadResultDto, +} from './minio.dto'; @Controller('minio') +@ApiTags('minio') export class MinioClientController { constructor( private readonly toolsService: ToolsService, private readonly minioClientService: MinioClientService, ) {} //注入服务 + @Get('check') + @ApiOperation({ summary: '检查MinIO连接和Bucket状态' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiModelResponse(MinioBucketStatusDto, { + bucketName: 'kt-template-online', + exists: true, + }) + async check(@Res() res, @Query('bucketName') bucketName?: string) { + const result = await this.minioClientService.checkConnection(bucketName); + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } + + @Post('bucket') + @ApiOperation({ summary: '创建Bucket(存在则跳过)' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiSuccessResponse({ + schema: { + type: 'string', + description: 'Bucket名称', + }, + example: 'kt-template-online', + }) + async createBucket(@Res() res, @Query('bucketName') bucketName?: string) { + const result = await this.minioClientService.ensureBucket(bucketName); + + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } + + @Post('upload') + @UseInterceptors(FileInterceptor('file')) + @ApiOperation({ summary: '上传文件到MinIO' }) + @ApiConsumes('multipart/form-data') + @ApiModelResponse(MinioUploadResultDto, { + bucketName: 'kt-template-online', + objectName: 'uploads/1715580000000-a1b2c3-demo.png', + etag: '9b2cf535f27731c974343645a3985328', + size: 2048, + mimeType: 'image/png', + url: 'http://127.0.0.1:9000/kt-template-online/uploads/demo.png', + }) + @ApiBody({ + schema: { + type: 'object', + properties: { + file: { + type: 'string', + format: 'binary', + }, + bucketName: { + type: 'string', + }, + objectName: { + type: 'string', + }, + }, + required: ['file'], + }, + }) + async upload( + @Res() res, + @UploadedFile() file: MinioUploadFile, + @Body('bucketName') bucketName?: string, + @Body('objectName') objectName?: string, + ) { + const result = await this.minioClientService.uploadObject({ + bucketName, + objectName, + file, + }); + + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } + + @Get('list') + @ApiOperation({ summary: '获取MinIO文件列表' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiQuery({ name: 'prefix', required: false }) + @ApiQuery({ name: 'recursive', required: false }) + @ApiArrayResponse(MinioObjectDto, [ + { + name: 'uploads/demo.png', + size: 2048, + etag: '9b2cf535f27731c974343645a3985328', + lastModified: '2026-05-13T02:30:00.000Z', + }, + ]) + async list( + @Res() res, + @Query('bucketName') bucketName?: string, + @Query('prefix') prefix?: string, + @Query('recursive') recursive?: string, + ) { + const result = await this.minioClientService.listObjects({ + bucketName, + prefix, + recursive: recursive !== 'false', + }); + + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } + + @Get('url') + @ApiOperation({ summary: '获取文件临时访问地址' }) + @ApiQuery({ name: 'objectName' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiQuery({ name: 'expiry', required: false }) + @ApiSuccessResponse({ + schema: { + type: 'string', + description: '文件临时访问地址', + }, + example: + 'http://127.0.0.1:9000/kt-template-online/uploads/demo.png?X-Amz-Algorithm=AWS4-HMAC-SHA256', + }) + async getUrl( + @Res() res, + @Query('objectName') objectName: string, + @Query('bucketName') bucketName?: string, + @Query('expiry') expiry?: string, + ) { + const result = await this.minioClientService.getPresignedUrl( + objectName, + bucketName, + expiry ? Number(expiry) : undefined, + ); + + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } + + @Get('download') + @ApiOperation({ summary: '下载MinIO文件' }) + @ApiQuery({ name: 'objectName' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiFileDownloadResponse() + async download( + @Res() res: Response, + @Query('objectName') objectName: string, + @Query('bucketName') bucketName?: string, + ) { + const { stream, stat } = await this.minioClientService.getObject( + objectName, + bucketName, + ); + + res.setHeader( + 'Content-Type', + stat.metaData?.['content-type'] || 'application/octet-stream', + ); + res.setHeader( + 'Content-Disposition', + `attachment; filename="${encodeURIComponent( + objectName.split('/').pop(), + )}"`, + ); + + stream.pipe(res); + } + + @Delete('remove') + @ApiOperation({ summary: '删除MinIO文件' }) + @ApiQuery({ name: 'objectName' }) + @ApiQuery({ name: 'bucketName', required: false }) + @ApiSuccessResponse({ + schema: { + type: 'boolean', + }, + example: true, + }) + async remove( + @Res() res, + @Query('objectName') objectName: string, + @Query('bucketName') bucketName?: string, + ) { + const result = await this.minioClientService.removeObject( + objectName, + bucketName, + ); + + res.send(this.toolsService.res(HttpStatus.OK, '操作成功', result)); + } } diff --git a/src/minio/minio.dto.ts b/src/minio/minio.dto.ts new file mode 100644 index 0000000..86c1dcf --- /dev/null +++ b/src/minio/minio.dto.ts @@ -0,0 +1,67 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class MinioBucketStatusDto { + @ApiProperty({ + example: 'kt-template-online', + }) + bucketName: string; + + @ApiProperty({ + example: true, + }) + exists: boolean; +} + +export class MinioUploadResultDto { + @ApiProperty({ + example: 'kt-template-online', + }) + bucketName: string; + + @ApiProperty({ + example: 'uploads/1715580000000-a1b2c3-demo.png', + }) + objectName: string; + + @ApiProperty({ + example: '9b2cf535f27731c974343645a3985328', + }) + etag: string; + + @ApiProperty({ + example: 2048, + }) + size: number; + + @ApiProperty({ + example: 'image/png', + }) + mimeType: string; + + @ApiProperty({ + example: 'http://127.0.0.1:9000/kt-template-online/uploads/demo.png', + }) + url: string; +} + +export class MinioObjectDto { + @ApiProperty({ + example: 'uploads/demo.png', + }) + name: string; + + @ApiProperty({ + example: 2048, + }) + size: number; + + @ApiProperty({ + example: '9b2cf535f27731c974343645a3985328', + }) + etag: string; + + @ApiProperty({ + example: '2026-05-13T02:30:00.000Z', + }) + lastModified: string; +} diff --git a/src/minio/minio.module.ts b/src/minio/minio.module.ts index 9bc04f1..c1334d7 100644 --- a/src/minio/minio.module.ts +++ b/src/minio/minio.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; import { MinioClientController } from './minio.controller'; import { MinioClientService } from './minio.service'; -import { ToolsService } from 'src/utils/tool.service'; -import { MinioModule } from 'nestjs-minio-client'; +import { ToolsService } from '@/utils/tool.service'; @Module({ - imports: [MinioModule], + imports: [ConfigModule], controllers: [MinioClientController], providers: [MinioClientService, ToolsService], exports: [MinioClientService], diff --git a/src/minio/minio.service.ts b/src/minio/minio.service.ts index 9db6c1d..e04e71f 100644 --- a/src/minio/minio.service.ts +++ b/src/minio/minio.service.ts @@ -1,11 +1,179 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { MinioService } from 'nestjs-minio-client'; +import type { Readable } from 'stream'; + +export type MinioUploadFile = { + originalname: string; + mimetype: string; + size: number; + buffer: Buffer; +}; + +type UploadObjectOptions = { + bucketName?: string; + objectName?: string; + file: MinioUploadFile; +}; + +type ListObjectOptions = { + bucketName?: string; + prefix?: string; + recursive?: boolean; +}; + +type MinioObjectResult = { + stream: Readable; + stat: { + size: number; + etag: string; + lastModified: Date; + metaData: Record; + versionId?: string | null; + }; + bucketName: string; + objectName: string; +}; -import { ToolsService } from 'src/utils/tool.service'; @Injectable() export class MinioClientService { constructor( - private readonly toolsService: ToolsService, + private readonly minioService: MinioService, + private readonly configService: ConfigService, ) {} + private get client() { + return this.minioService.client; + } + getDefaultBucket(): string { + return this.configService.get('MINIO_BUCKET') || 'kt-template-online'; + } + + getBucketName(bucketName?: string): string { + return bucketName || this.getDefaultBucket(); + } + + async checkConnection(bucketName?: string) { + const targetBucket = this.getBucketName(bucketName); + const exists = await this.client.bucketExists(targetBucket); + + return { + bucketName: targetBucket, + exists, + }; + } + + async ensureBucket(bucketName?: string): Promise { + const targetBucket = this.getBucketName(bucketName); + const exists = await this.client.bucketExists(targetBucket); + + if (!exists) { + await this.client.makeBucket(targetBucket, 'us-east-1'); + } + + return targetBucket; + } + + async uploadObject({ bucketName, objectName, file }: UploadObjectOptions) { + if (!file) { + throw new BadRequestException('请选择要上传的文件'); + } + + const targetBucket = await this.ensureBucket(bucketName); + const targetObjectName = objectName || this.createObjectName(file.originalname); + + const result = await this.client.putObject( + targetBucket, + targetObjectName, + file.buffer, + file.size, + { + 'Content-Type': file.mimetype, + }, + ); + + return { + bucketName: targetBucket, + objectName: targetObjectName, + etag: result.etag, + size: file.size, + mimeType: file.mimetype, + url: await this.getPresignedUrl(targetObjectName, targetBucket), + }; + } + + async listObjects({ + bucketName, + prefix = '', + recursive = true, + }: ListObjectOptions) { + const targetBucket = this.getBucketName(bucketName); + const exists = await this.client.bucketExists(targetBucket); + + if (!exists) { + return []; + } + + return new Promise((resolve, reject) => { + const objects = []; + const stream = this.client.listObjectsV2(targetBucket, prefix, recursive); + + stream.on('data', (object) => objects.push(object)); + stream.on('error', reject); + stream.on('end', () => resolve(objects)); + }); + } + + async getObject( + objectName: string, + bucketName?: string, + ): Promise { + if (!objectName) { + throw new BadRequestException('objectName不能为空'); + } + + const targetBucket = this.getBucketName(bucketName); + const objectStat = await this.client.statObject(targetBucket, objectName); + const stream = await this.client.getObject(targetBucket, objectName); + + return { + stream, + stat: objectStat, + bucketName: targetBucket, + objectName, + }; + } + + async getPresignedUrl( + objectName: string, + bucketName?: string, + expiry = 24 * 60 * 60, + ): Promise { + if (!objectName) { + throw new BadRequestException('objectName不能为空'); + } + + return this.client.presignedGetObject( + this.getBucketName(bucketName), + objectName, + expiry, + ); + } + + async removeObject(objectName: string, bucketName?: string): Promise { + if (!objectName) { + throw new BadRequestException('objectName不能为空'); + } + + await this.client.removeObject(this.getBucketName(bucketName), objectName); + return true; + } + + private createObjectName(originalName: string): string { + const safeName = originalName.replace(/[\\/]/g, '_'); + const random = Math.random().toString(36).slice(2, 8); + + return `uploads/${Date.now()}-${random}-${safeName}`; + } } diff --git a/src/utils/constant.ts b/src/utils/constant.ts index 429aa8d..c9f7b3b 100644 --- a/src/utils/constant.ts +++ b/src/utils/constant.ts @@ -1,10 +1,3 @@ -import { ApiProperty } from '@nestjs/swagger'; - -export class PaginatedDto { - @ApiProperty() - total: number; -} - export enum ComponentTypeEnum { CHART = 1, COMPONENT = 2,