mirror of https://github.com/fantasticit/think.git
commit
aaa2b7acb9
|
@ -5,6 +5,7 @@ lib
|
|||
|
||||
**/.next/**
|
||||
**/dist/**
|
||||
**/static/**
|
||||
**/build/**
|
||||
**/public/**
|
||||
**/diagram.js
|
||||
|
|
|
@ -42,12 +42,26 @@ db:
|
|||
|
||||
# oss 文件存储服务
|
||||
oss:
|
||||
local:
|
||||
enable: true
|
||||
# 线上更改为服务端地址(如:https://api.codingit.cn)
|
||||
server: 'http://localhost:5002'
|
||||
# 以下为各厂商 sdk 配置,不要修改字段,填入值即可
|
||||
tencent:
|
||||
enable: false
|
||||
config:
|
||||
SecretId: ''
|
||||
SecretKey: ''
|
||||
Bucket: ''
|
||||
Region: ''
|
||||
aliyun:
|
||||
accessKeyId: ''
|
||||
accessKeySecret: ''
|
||||
bucket: ''
|
||||
https: true
|
||||
region: ''
|
||||
enable: false
|
||||
config:
|
||||
accessKeyId: ''
|
||||
accessKeySecret: ''
|
||||
bucket: ''
|
||||
https: true
|
||||
region: ''
|
||||
|
||||
# jwt 配置
|
||||
jwt:
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
"requestidlecallback-polyfill": "^1.0.2",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"scroll-into-view-if-needed": "^2.2.29",
|
||||
"spark-md5": "^3.0.2",
|
||||
"timeago.js": "^4.0.2",
|
||||
"tippy.js": "^6.3.7",
|
||||
"toggle-selection": "^1.0.6",
|
||||
|
|
|
@ -1,30 +1,139 @@
|
|||
import { FILE_CHUNK_SIZE, FileApiDefinition } from '@think/domains';
|
||||
import SparkMD5 from 'spark-md5';
|
||||
|
||||
import { HttpClient } from './http-client';
|
||||
|
||||
const ONE_MB = 1 * 1024 * 1024;
|
||||
|
||||
export const readFileAsDataURL = (file): Promise<string | ArrayBuffer> => {
|
||||
if (file.size > ONE_MB) {
|
||||
return Promise.reject(new Error('文件过大,请实现文件上传到存储服务!'));
|
||||
}
|
||||
|
||||
const splitBigFile = (file: File): Promise<{ chunks: File[]; md5: string }> => {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', (e) => resolve(e.target.result), { once: true });
|
||||
reader.readAsDataURL(file);
|
||||
const chunks = [];
|
||||
const len = Math.ceil(file.size / FILE_CHUNK_SIZE);
|
||||
const sparkWorker = new Worker(new URL('./spark-md5.js', import.meta.url));
|
||||
sparkWorker.onmessage = (evt) => {
|
||||
resolve({ md5: evt.data.md5, chunks });
|
||||
};
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const start = i * FILE_CHUNK_SIZE;
|
||||
const end = Math.min(start + FILE_CHUNK_SIZE, file.size);
|
||||
const chunk = file.slice(start, end);
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
sparkWorker.postMessage({ chunks });
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadFile = async (file: Blob): Promise<string | ArrayBuffer> => {
|
||||
if (!process.env.ENABLE_ALIYUN_OSS) {
|
||||
return readFileAsDataURL(file);
|
||||
}
|
||||
const uploadFileToServer = (arg: {
|
||||
filename: string;
|
||||
file: File;
|
||||
md5: string;
|
||||
isChunk?: boolean;
|
||||
chunkIndex?: number;
|
||||
onUploadProgress?: (progress: number) => void;
|
||||
}) => {
|
||||
const { filename, file, md5, isChunk, chunkIndex, onUploadProgress } = arg;
|
||||
const api = isChunk ? 'uploadChunk' : 'upload';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
return HttpClient.post('/file/upload', formData, {
|
||||
return HttpClient.request({
|
||||
method: FileApiDefinition[api].method,
|
||||
url: FileApiDefinition[api].client(),
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
params: {
|
||||
filename,
|
||||
md5,
|
||||
chunkIndex,
|
||||
},
|
||||
onUploadProgress: (progress) => {
|
||||
const percent = progress.loaded / progress.total;
|
||||
onUploadProgress && onUploadProgress(percent);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadFile = async (
|
||||
file: File,
|
||||
onUploadProgress?: (progress: number) => void,
|
||||
onTooLarge?: () => void
|
||||
) => {
|
||||
const wraponUploadProgress = (percent) => {
|
||||
return onUploadProgress && onUploadProgress(Math.ceil(percent * 100));
|
||||
};
|
||||
|
||||
const filename = file.name;
|
||||
|
||||
if (file.size > FILE_CHUNK_SIZE * 5) {
|
||||
onTooLarge && onTooLarge();
|
||||
}
|
||||
|
||||
if (file.size <= FILE_CHUNK_SIZE) {
|
||||
const spark = new SparkMD5.ArrayBuffer();
|
||||
spark.append(file);
|
||||
const md5 = spark.end();
|
||||
const url = await uploadFileToServer({ filename, file, md5, onUploadProgress: wraponUploadProgress });
|
||||
return url;
|
||||
} else {
|
||||
const { chunks, md5 } = await splitBigFile(file);
|
||||
const unitPercent = 1 / chunks.length;
|
||||
const progressMap = {};
|
||||
|
||||
/**
|
||||
* 先上传一块分块,如果文件已上传,即无需上传后续分块
|
||||
*/
|
||||
let url = await uploadFileToServer({
|
||||
filename,
|
||||
file: chunks[0],
|
||||
chunkIndex: 1,
|
||||
md5,
|
||||
isChunk: true,
|
||||
onUploadProgress: (progress) => {
|
||||
progressMap[1] = progress * unitPercent;
|
||||
wraponUploadProgress(
|
||||
Object.keys(progressMap).reduce((a, c) => {
|
||||
return (a += progressMap[c]);
|
||||
}, 0)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
if (!url) {
|
||||
await Promise.all(
|
||||
chunks.slice(1).map((chunk, index) => {
|
||||
const currentIndex = 1 + index + 1;
|
||||
return uploadFileToServer({
|
||||
filename,
|
||||
file: chunk,
|
||||
chunkIndex: currentIndex,
|
||||
md5,
|
||||
isChunk: true,
|
||||
onUploadProgress: (progress) => {
|
||||
progressMap[currentIndex] = progress * unitPercent;
|
||||
wraponUploadProgress(
|
||||
Object.keys(progressMap).reduce((a, c) => {
|
||||
return (a += progressMap[c]);
|
||||
}, 0)
|
||||
);
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
url = await HttpClient.request({
|
||||
method: FileApiDefinition.mergeChunk.method,
|
||||
url: FileApiDefinition.mergeChunk.client(),
|
||||
params: {
|
||||
filename,
|
||||
md5,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
wraponUploadProgress(1);
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ interface AxiosInstance extends Axios {
|
|||
|
||||
export const HttpClient = axios.create({
|
||||
baseURL: process.env.SERVER_API_URL,
|
||||
timeout: 10 * 1000,
|
||||
timeout: 10 * 60 * 1000,
|
||||
withCredentials: true,
|
||||
}) as AxiosInstance;
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import SparkMD5 from 'spark-md5';
|
||||
|
||||
addEventListener('message', (e) => {
|
||||
const chunks = e.data.chunks || [];
|
||||
|
||||
if (!chunks.length) return;
|
||||
|
||||
const spark = new SparkMD5.ArrayBuffer();
|
||||
const reader = new FileReader();
|
||||
let index = 0;
|
||||
|
||||
const load = () => {
|
||||
const chunk = chunks[index];
|
||||
reader.readAsArrayBuffer(chunk);
|
||||
};
|
||||
|
||||
reader.onload = (e) => {
|
||||
spark.append(e.target.result);
|
||||
|
||||
if (index === chunks.length - 1) {
|
||||
const md5 = spark.end();
|
||||
postMessage({ md5 });
|
||||
self.close();
|
||||
} else {
|
||||
index++;
|
||||
load();
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
});
|
|
@ -1,10 +1,11 @@
|
|||
import { IconClose, IconDownload, IconPlayCircle } from '@douyinfe/semi-icons';
|
||||
import { Button, Collapsible, Space, Spin, Typography } from '@douyinfe/semi-ui';
|
||||
import { Button, Collapsible, Progress, Space, Spin, Toast, Typography } from '@douyinfe/semi-ui';
|
||||
import { FILE_CHUNK_SIZE } from '@think/domains';
|
||||
import { NodeViewWrapper } from '@tiptap/react';
|
||||
import cls from 'classnames';
|
||||
import { Tooltip } from 'components/tooltip';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { uploadFile } from 'services/file';
|
||||
import { download, extractFileExtension, extractFilename, normalizeFileSize } from 'tiptap/prose-utils';
|
||||
|
||||
|
@ -20,6 +21,8 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
|||
const { hasTrigger, fileName, fileSize, fileExt, fileType, url, error } = node.attrs;
|
||||
const [loading, toggleLoading] = useToggle(false);
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
const [showProgress, toggleShowProgress] = useToggle(false);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
|
||||
const selectFile = useCallback(() => {
|
||||
if (!isEditable || url) return;
|
||||
|
@ -29,6 +32,7 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
|||
const handleFile = useCallback(
|
||||
async (e) => {
|
||||
const file = e.target.files && e.target.files[0];
|
||||
if (!file) return;
|
||||
const fileInfo = {
|
||||
fileName: extractFilename(file.name),
|
||||
fileSize: file.size,
|
||||
|
@ -36,16 +40,28 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
|||
fileExt: extractFileExtension(file.name),
|
||||
};
|
||||
toggleLoading(true);
|
||||
|
||||
if (file.size > FILE_CHUNK_SIZE) {
|
||||
toggleShowProgress(true);
|
||||
}
|
||||
|
||||
try {
|
||||
const url = await uploadFile(file);
|
||||
const url = await uploadFile(file, setUploadProgress, () => {
|
||||
Toast.info('文件较大,文件将在后台进行上传处理,您可继续其他操作');
|
||||
});
|
||||
updateAttributes({ ...fileInfo, url });
|
||||
toggleLoading(false);
|
||||
setUploadProgress(0);
|
||||
toggleShowProgress(false);
|
||||
} catch (error) {
|
||||
updateAttributes({ error: '文件上传失败:' + (error && error.message) || '未知错误' });
|
||||
toggleLoading(false);
|
||||
setUploadProgress(0);
|
||||
toggleShowProgress(false);
|
||||
$upload.current.value = '';
|
||||
}
|
||||
},
|
||||
[toggleLoading, updateAttributes]
|
||||
[toggleLoading, toggleShowProgress, updateAttributes]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -61,7 +77,21 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
|||
<div className={cls(styles.wrap, 'render-wrapper')}>
|
||||
<Spin spinning={loading}>
|
||||
<Text style={{ cursor: 'pointer' }} onClick={selectFile}>
|
||||
{loading ? '正在上传中' : '请选择文件'}
|
||||
{loading ? (
|
||||
showProgress ? (
|
||||
<Progress
|
||||
percent={uploadProgress}
|
||||
showInfo
|
||||
style={{
|
||||
margin: '10px 0',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
'正在上传中'
|
||||
)
|
||||
) : (
|
||||
'请选择文件'
|
||||
)}
|
||||
</Text>
|
||||
<input ref={$upload} type="file" hidden onChange={handleFile} />
|
||||
</Spin>
|
||||
|
|
|
@ -31,6 +31,6 @@
|
|||
"thirtypart/*": ["thirtypart/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx", "src/services/spark-md5.js"],
|
||||
"exclude": ["node_modules", "next.config.js"]
|
||||
}
|
||||
|
|
|
@ -7,4 +7,21 @@ export declare const FileApiDefinition: {
|
|||
server: "upload";
|
||||
client: () => string;
|
||||
};
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
uploadChunk: {
|
||||
method: "post";
|
||||
server: "upload/chunk";
|
||||
client: () => string;
|
||||
};
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
mergeChunk: {
|
||||
method: "post";
|
||||
server: "merge/chunk";
|
||||
client: () => string;
|
||||
};
|
||||
};
|
||||
export declare const FILE_CHUNK_SIZE: number;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.FileApiDefinition = void 0;
|
||||
exports.FILE_CHUNK_SIZE = exports.FileApiDefinition = void 0;
|
||||
exports.FileApiDefinition = {
|
||||
/**
|
||||
* 上传文件
|
||||
|
@ -9,5 +9,22 @@ exports.FileApiDefinition = {
|
|||
method: 'post',
|
||||
server: 'upload',
|
||||
client: function () { return '/file/upload'; }
|
||||
},
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
uploadChunk: {
|
||||
method: 'post',
|
||||
server: 'upload/chunk',
|
||||
client: function () { return '/file/upload/chunk'; }
|
||||
},
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
mergeChunk: {
|
||||
method: 'post',
|
||||
server: 'merge/chunk',
|
||||
client: function () { return '/file/merge/chunk'; }
|
||||
}
|
||||
};
|
||||
exports.FILE_CHUNK_SIZE = 2 * 1024 * 1024;
|
||||
|
|
|
@ -7,4 +7,24 @@ export const FileApiDefinition = {
|
|||
server: 'upload' as const,
|
||||
client: () => '/file/upload',
|
||||
},
|
||||
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
uploadChunk: {
|
||||
method: 'post' as const,
|
||||
server: 'upload/chunk' as const,
|
||||
client: () => '/file/upload/chunk',
|
||||
},
|
||||
|
||||
/**
|
||||
* 上传分块文件
|
||||
*/
|
||||
mergeChunk: {
|
||||
method: 'post' as const,
|
||||
server: 'merge/chunk' as const,
|
||||
client: () => '/file/merge/chunk',
|
||||
},
|
||||
};
|
||||
|
||||
export const FILE_CHUNK_SIZE = 2 * 1024 * 1024;
|
||||
|
|
|
@ -32,4 +32,7 @@ lerna-debug.log*
|
|||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# 静态文件
|
||||
/static
|
||||
|
|
|
@ -31,12 +31,14 @@
|
|||
"@think/config": "workspace:^1.0.0",
|
||||
"@think/constants": "workspace:^1.0.0",
|
||||
"@think/domains": "workspace:^1.0.0",
|
||||
"@types/multer": "^1.4.7",
|
||||
"ali-oss": "^6.16.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.13.2",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cos-nodejs-sdk-v5": "^2.11.9",
|
||||
"date-fns": "^2.28.0",
|
||||
"express": "^4.17.2",
|
||||
"express-rate-limit": "^6.2.0",
|
||||
|
|
|
@ -1,27 +1,55 @@
|
|||
import { JwtGuard } from '@guard/jwt.guard';
|
||||
import { Controller, Post, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { FileQuery } from '@helpers/file.helper/oss.client';
|
||||
import { Controller, Post, Query, UploadedFile, UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { FileService } from '@services/file.service';
|
||||
import { FileApiDefinition } from '@think/domains';
|
||||
import { FILE_CHUNK_SIZE, FileApiDefinition } from '@think/domains';
|
||||
|
||||
@Controller('file')
|
||||
export class FileController {
|
||||
constructor(private readonly fileService: FileService) {}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* 上传小文件
|
||||
* @param file
|
||||
*/
|
||||
@Post(FileApiDefinition.upload.server)
|
||||
@UseInterceptors(
|
||||
FileInterceptor('file', {
|
||||
limits: {
|
||||
fieldSize: 50 * 1024 * 1024,
|
||||
fieldSize: FILE_CHUNK_SIZE,
|
||||
},
|
||||
})
|
||||
)
|
||||
@UseGuards(JwtGuard)
|
||||
uploadFile(@UploadedFile() file) {
|
||||
return this.fileService.uploadFile(file);
|
||||
uploadFile(@UploadedFile() file: Express.Multer.File, @Query() query: FileQuery) {
|
||||
return this.fileService.uploadFile(file, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传分块文件
|
||||
* @param file
|
||||
*/
|
||||
@Post(FileApiDefinition.uploadChunk.server)
|
||||
@UseInterceptors(
|
||||
FileInterceptor('file', {
|
||||
limits: {
|
||||
fieldSize: FILE_CHUNK_SIZE,
|
||||
},
|
||||
})
|
||||
)
|
||||
@UseGuards(JwtGuard)
|
||||
uploadChunk(@UploadedFile() file: Express.Multer.File, @Query() query: FileQuery) {
|
||||
return this.fileService.uploadChunk(file, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并分块文件
|
||||
* @param file
|
||||
*/
|
||||
@Post(FileApiDefinition.mergeChunk.server)
|
||||
@UseGuards(JwtGuard)
|
||||
mergeChunk(@Query() query: FileQuery) {
|
||||
return this.fileService.mergeChunk(query);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
import { FILE_CHUNK_SIZE } from '@think/domains';
|
||||
import * as AliyunOSS from 'ali-oss';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import { pipeWriteStream } from './local.client';
|
||||
import { BaseOssClient, FileQuery } from './oss.client';
|
||||
|
||||
export class AliyunOssClient extends BaseOssClient {
|
||||
private client: AliyunOSS | null;
|
||||
|
||||
/**
|
||||
* 构建 ali-oss 客户端
|
||||
* @returns
|
||||
*/
|
||||
private ensureAliyunOssClient(): AliyunOSS {
|
||||
if (this.client) {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
const config = this.configService.get('oss.aliyun.config');
|
||||
|
||||
try {
|
||||
this.client = new AliyunOSS(config);
|
||||
return this.client;
|
||||
} catch (err) {
|
||||
console.log('无法启动阿里云存储服务,请检查阿里云 OSS 配置是否正确', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件名
|
||||
* @param md5
|
||||
* @param filename
|
||||
* @returns
|
||||
*/
|
||||
private getInOssFileName(md5, filename) {
|
||||
return `/think/${md5}/${filename}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否已存储到 oss
|
||||
* @param md5
|
||||
* @param filename
|
||||
* @returns
|
||||
*/
|
||||
private async checkIfAlreadyInOss(md5, filename) {
|
||||
this.ensureAliyunOssClient();
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
const ifExist = await this.client.head(inOssFileName).catch(() => false);
|
||||
|
||||
if (ifExist) {
|
||||
return ifExist.res.requestUrls[0];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件临时存储路径
|
||||
* @param md5
|
||||
* @returns
|
||||
*/
|
||||
private getStoreDir(md5: string) {
|
||||
const tmpdir = os.tmpdir();
|
||||
const dir = path.join(tmpdir, md5);
|
||||
fs.ensureDirSync(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传小文件
|
||||
* @param file
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string> {
|
||||
const client = this.ensureAliyunOssClient();
|
||||
const { filename, md5 } = query;
|
||||
|
||||
const maybeOssURL = await this.checkIfAlreadyInOss(md5, filename);
|
||||
if (maybeOssURL) {
|
||||
return maybeOssURL;
|
||||
}
|
||||
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
const res = await client.put(inOssFileName, file.buffer);
|
||||
return res.url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将切片临时存储到服务器
|
||||
* FIXME: 阿里云的文档没看懂,故做成这种服务器中转的蠢模式
|
||||
* @param file
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<string | void> {
|
||||
const { md5, filename, chunkIndex } = query;
|
||||
|
||||
if (!('chunkIndex' in query)) {
|
||||
throw new Error('请指定 chunkIndex');
|
||||
}
|
||||
|
||||
const maybeOssURL = await this.checkIfAlreadyInOss(md5, filename);
|
||||
if (maybeOssURL) {
|
||||
return maybeOssURL;
|
||||
}
|
||||
|
||||
const dir = this.getStoreDir(md5);
|
||||
const chunksDir = path.join(dir, 'chunks');
|
||||
fs.ensureDirSync(chunksDir);
|
||||
fs.writeFileSync(path.join(chunksDir, '' + chunkIndex), file.buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并切片后上传到阿里云
|
||||
* FIXME: 阿里云的文档没看懂,故做成这种服务器中转的蠢模式
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async mergeChunk(query: FileQuery): Promise<string> {
|
||||
const { filename, md5 } = query;
|
||||
|
||||
this.ensureAliyunOssClient();
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
|
||||
const dir = this.getStoreDir(md5);
|
||||
const absoluteFilepath = path.join(dir, filename);
|
||||
const chunksDir = path.join(dir, 'chunks');
|
||||
const chunks = fs.readdirSync(chunksDir);
|
||||
chunks.sort((a, b) => Number(a) - Number(b));
|
||||
|
||||
await Promise.all(
|
||||
chunks.map((chunk, index) => {
|
||||
return pipeWriteStream(
|
||||
path.join(chunksDir, chunk),
|
||||
fs.createWriteStream(absoluteFilepath, {
|
||||
start: index * FILE_CHUNK_SIZE,
|
||||
end: (index + 1) * FILE_CHUNK_SIZE,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
fs.removeSync(chunksDir);
|
||||
const ret = await this.client.multipartUpload(inOssFileName, absoluteFilepath);
|
||||
fs.removeSync(absoluteFilepath);
|
||||
return ret.res.requestUrls[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { AliyunOssClient } from './aliyun.client';
|
||||
import { LocalOssClient } from './local.client';
|
||||
import { OssClient } from './oss.client';
|
||||
import { TencentOssClient } from './tencent.client';
|
||||
|
||||
export { OssClient };
|
||||
|
||||
export const getOssClient = (configService: ConfigService): OssClient => {
|
||||
if (configService.get('oss.tencent.enable')) {
|
||||
return new TencentOssClient(configService);
|
||||
}
|
||||
|
||||
if (configService.get('oss.aliyun.enable')) {
|
||||
return new AliyunOssClient(configService);
|
||||
}
|
||||
|
||||
return new LocalOssClient(configService);
|
||||
};
|
|
@ -0,0 +1,129 @@
|
|||
import { FILE_CHUNK_SIZE } from '@think/domains';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
|
||||
import { BaseOssClient, FileQuery } from './oss.client';
|
||||
|
||||
export const FILE_DEST = '/' + 'static';
|
||||
export const FILE_ROOT_PATH = path.join(__dirname, '../../../', FILE_DEST);
|
||||
|
||||
export const pipeWriteStream = (filepath, writeStream): Promise<void> => {
|
||||
return new Promise((resolve) => {
|
||||
const readStream = fs.createReadStream(filepath);
|
||||
readStream.on('end', () => {
|
||||
fs.unlinkSync(filepath);
|
||||
resolve();
|
||||
});
|
||||
readStream.pipe(writeStream);
|
||||
});
|
||||
};
|
||||
|
||||
export class LocalOssClient extends BaseOssClient {
|
||||
/**
|
||||
* 文件存储路径
|
||||
* @param md5
|
||||
* @returns
|
||||
*/
|
||||
protected getStoreDir(md5: string): {
|
||||
relative: string;
|
||||
absolute: string;
|
||||
} {
|
||||
const filepath = path.join(FILE_ROOT_PATH, md5);
|
||||
fs.ensureDirSync(filepath);
|
||||
return { relative: filepath.replace(FILE_ROOT_PATH, FILE_DEST), absolute: filepath };
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件存储的相对路径拼接为可访问 URL
|
||||
* @param serverRoot
|
||||
* @param relativeFilePath
|
||||
* @returns
|
||||
*/
|
||||
protected serveFilePath(relativeFilePath: string) {
|
||||
const serverRoot = this.configService.get('oss.local.server');
|
||||
|
||||
if (!serverRoot) {
|
||||
throw new Error(`本地文件存储已启动,但未配置 oss.local.server,请在 config 完善!`);
|
||||
}
|
||||
|
||||
return new URL(relativeFilePath, serverRoot).href;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小文件上传
|
||||
* @param file
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string> {
|
||||
const { filename, md5 } = query;
|
||||
const { absolute, relative } = this.getStoreDir(md5);
|
||||
const absoluteFilepath = path.join(absolute, filename);
|
||||
const relativeFilePath = path.join(relative, filename);
|
||||
|
||||
if (!fs.existsSync(absoluteFilepath)) {
|
||||
fs.writeFileSync(absoluteFilepath, file.buffer);
|
||||
}
|
||||
|
||||
return this.serveFilePath(relativeFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件分块上传
|
||||
* @param file
|
||||
* @param query
|
||||
*/
|
||||
async uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<void | string> {
|
||||
const { filename, md5, chunkIndex } = query;
|
||||
|
||||
if (!('chunkIndex' in query)) {
|
||||
throw new Error('请指定 chunkIndex');
|
||||
}
|
||||
|
||||
const { absolute, relative } = this.getStoreDir(md5);
|
||||
const absoluteFilepath = path.join(absolute, filename);
|
||||
|
||||
if (fs.existsSync(absoluteFilepath)) {
|
||||
const relativeFilePath = path.join(relative, filename);
|
||||
return this.serveFilePath(relativeFilePath);
|
||||
}
|
||||
|
||||
const chunksDir = path.join(absolute, 'chunks');
|
||||
fs.ensureDirSync(chunksDir);
|
||||
fs.writeFileSync(path.join(chunksDir, '' + chunkIndex), file.buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并分块
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async mergeChunk(query: FileQuery): Promise<string> {
|
||||
const { filename, md5 } = query;
|
||||
const { absolute, relative } = this.getStoreDir(md5);
|
||||
const absoluteFilepath = path.join(absolute, filename);
|
||||
const relativeFilePath = path.join(relative, filename);
|
||||
|
||||
if (!fs.existsSync(absoluteFilepath)) {
|
||||
const chunksDir = path.join(absolute, 'chunks');
|
||||
const chunks = fs.readdirSync(chunksDir);
|
||||
chunks.sort((a, b) => Number(a) - Number(b));
|
||||
|
||||
await Promise.all(
|
||||
chunks.map((chunk, index) => {
|
||||
return pipeWriteStream(
|
||||
path.join(chunksDir, chunk),
|
||||
fs.createWriteStream(absoluteFilepath, {
|
||||
start: index * FILE_CHUNK_SIZE,
|
||||
end: (index + 1) * FILE_CHUNK_SIZE,
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
fs.removeSync(chunksDir);
|
||||
}
|
||||
|
||||
return this.serveFilePath(relativeFilePath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
export type FileQuery = {
|
||||
filename: string;
|
||||
md5: string;
|
||||
chunkIndex?: number;
|
||||
};
|
||||
|
||||
export abstract class OssClient {
|
||||
abstract uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string>;
|
||||
abstract uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<void | string>;
|
||||
abstract mergeChunk(query: FileQuery): Promise<string>;
|
||||
}
|
||||
|
||||
export class BaseOssClient implements OssClient {
|
||||
protected configService: ConfigService;
|
||||
|
||||
constructor(configService) {
|
||||
this.configService = configService;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<void | string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
mergeChunk(query: FileQuery): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
import * as TencentCos from 'cos-nodejs-sdk-v5';
|
||||
|
||||
import { BaseOssClient, FileQuery } from './oss.client';
|
||||
|
||||
export class TencentOssClient extends BaseOssClient {
|
||||
private client: TencentCos | null;
|
||||
private uploadIdMap: Map<string, string> = new Map();
|
||||
private uploadChunkEtagMap: Map<
|
||||
string,
|
||||
{
|
||||
PartNumber: number;
|
||||
ETag: string;
|
||||
}[]
|
||||
> = new Map();
|
||||
|
||||
/**
|
||||
* 构建客户端
|
||||
* @returns
|
||||
*/
|
||||
private ensureOssClient(): TencentCos {
|
||||
if (this.client) {
|
||||
return this.client;
|
||||
}
|
||||
|
||||
const config = this.configService.get('oss.tencent.config');
|
||||
|
||||
try {
|
||||
this.client = new TencentCos(config);
|
||||
return this.client;
|
||||
} catch (err) {
|
||||
console.log('无法启动腾讯云存储服务,请检查腾讯云 COS 配置是否正确', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传文件名
|
||||
* @param md5
|
||||
* @param filename
|
||||
* @returns
|
||||
*/
|
||||
private getInOssFileName(md5, filename) {
|
||||
return `/think/${md5}/${filename}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件是否已存储到 oss
|
||||
* @param md5
|
||||
* @param filename
|
||||
* @returns
|
||||
*/
|
||||
private async checkIfAlreadyInOss(inOssFileName): Promise<boolean | string> {
|
||||
const params = {
|
||||
Bucket: this.configService.get('oss.tencent.config.Bucket'),
|
||||
Region: this.configService.get('oss.tencent.config.Region'),
|
||||
Key: inOssFileName,
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ensureOssClient();
|
||||
this.client.headObject(params, (err) => {
|
||||
if (err) {
|
||||
resolve(false);
|
||||
} else {
|
||||
this.client.getObjectUrl(params, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data.Url);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传小文件到 oss
|
||||
* @param inOssFileName
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
private putObject(inOssFileName, file): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {
|
||||
Bucket: this.configService.get('oss.tencent.config.Bucket'),
|
||||
Region: this.configService.get('oss.tencent.config.Region'),
|
||||
Key: inOssFileName,
|
||||
};
|
||||
this.ensureOssClient();
|
||||
this.client.putObject(
|
||||
{
|
||||
...params,
|
||||
StorageClass: 'STANDARD',
|
||||
Body: file.buffer, // 上传文件对象
|
||||
},
|
||||
(err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
this.client.getObjectUrl(params, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data.Url);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化分块上传
|
||||
* @param inOssFileName
|
||||
* @returns
|
||||
*/
|
||||
private getUploadChunkId(inOssFileName): Promise<string> {
|
||||
if (this.uploadIdMap.has(inOssFileName)) {
|
||||
return Promise.resolve(this.uploadIdMap.get(inOssFileName));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {
|
||||
Bucket: this.configService.get('oss.tencent.config.Bucket'),
|
||||
Region: this.configService.get('oss.tencent.config.Region'),
|
||||
Key: inOssFileName,
|
||||
};
|
||||
this.ensureOssClient();
|
||||
this.client.multipartInit(params, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const uploadId = data.UploadId;
|
||||
this.uploadIdMap.set(inOssFileName, uploadId);
|
||||
resolve(uploadId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传分片
|
||||
* @param uploadId
|
||||
* @param inOssFileName
|
||||
* @param chunkIndex
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
private uploadChunkToCos(uploadId, inOssFileName, chunkIndex, file): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {
|
||||
Bucket: this.configService.get('oss.tencent.config.Bucket'),
|
||||
Region: this.configService.get('oss.tencent.config.Region'),
|
||||
Key: inOssFileName,
|
||||
UploadId: uploadId,
|
||||
PartNumber: chunkIndex,
|
||||
Body: file.buffer,
|
||||
};
|
||||
this.ensureOssClient();
|
||||
this.client.multipartUpload(params, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
if (!this.uploadChunkEtagMap.has(uploadId)) {
|
||||
this.uploadChunkEtagMap.set(uploadId, []);
|
||||
}
|
||||
this.uploadChunkEtagMap.get(uploadId).push({
|
||||
PartNumber: chunkIndex,
|
||||
ETag: data.ETag,
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成上传分片
|
||||
* @param uploadId
|
||||
* @param inOssFileName
|
||||
* @param chunkIndex
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
private completeUploadChunkToCos(uploadId, inOssFileName): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const params = {
|
||||
Bucket: this.configService.get('oss.tencent.config.Bucket'),
|
||||
Region: this.configService.get('oss.tencent.config.Region'),
|
||||
Key: inOssFileName,
|
||||
};
|
||||
this.ensureOssClient();
|
||||
const parts = this.uploadChunkEtagMap.get(uploadId);
|
||||
parts.sort((a, b) => a.PartNumber - b.PartNumber);
|
||||
|
||||
this.client.multipartComplete(
|
||||
{
|
||||
...params,
|
||||
UploadId: uploadId,
|
||||
Parts: parts,
|
||||
},
|
||||
(err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
this.client.getObjectUrl(params, (err, data) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data.Url);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传小文件
|
||||
* @param file
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async uploadFile(file: Express.Multer.File, query: FileQuery): Promise<string> {
|
||||
this.ensureOssClient();
|
||||
const { filename, md5 } = query;
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
|
||||
const maybeOssURL = await this.checkIfAlreadyInOss(inOssFileName);
|
||||
if (maybeOssURL) {
|
||||
return maybeOssURL as string;
|
||||
}
|
||||
|
||||
const res = await this.putObject(inOssFileName, file);
|
||||
return res as string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传分片
|
||||
* @param file
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async uploadChunk(file: Express.Multer.File, query: FileQuery): Promise<string | void> {
|
||||
const { md5, filename, chunkIndex } = query;
|
||||
|
||||
if (!('chunkIndex' in query)) {
|
||||
throw new Error('请指定 chunkIndex');
|
||||
}
|
||||
|
||||
this.ensureOssClient();
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
|
||||
const maybeOssURL = await this.checkIfAlreadyInOss(inOssFileName);
|
||||
if (maybeOssURL) {
|
||||
return maybeOssURL as string;
|
||||
}
|
||||
|
||||
const uploadId = await this.getUploadChunkId(inOssFileName);
|
||||
await this.uploadChunkToCos(uploadId, inOssFileName, chunkIndex, file);
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并分片
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
async mergeChunk(query: FileQuery): Promise<string> {
|
||||
const { filename, md5 } = query;
|
||||
const inOssFileName = this.getInOssFileName(md5, filename);
|
||||
const uploadId = await this.getUploadChunkId(inOssFileName);
|
||||
const data = await this.completeUploadChunkToCos(uploadId, inOssFileName);
|
||||
this.uploadIdMap.delete(inOssFileName);
|
||||
this.uploadChunkEtagMap.delete(uploadId);
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { HttpResponseExceptionFilter } from '@exceptions/http-response.exception';
|
||||
import { IS_PRODUCTION } from '@helpers/env.helper';
|
||||
import { FILE_DEST, FILE_ROOT_PATH } from '@helpers/file.helper/local.client';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { ValidationPipe } from '@pipes/validation.pipe';
|
||||
|
@ -31,6 +32,7 @@ async function bootstrap() {
|
|||
max: config.get('server.rateLimitMax'),
|
||||
})
|
||||
);
|
||||
|
||||
app.use(cookieParser());
|
||||
app.use(compression());
|
||||
app.use(helmet());
|
||||
|
@ -41,7 +43,16 @@ async function bootstrap() {
|
|||
app.useGlobalPipes(new ValidationPipe());
|
||||
app.setGlobalPrefix(config.get('server.prefix') || '/');
|
||||
|
||||
if (config.get('oss.local.enable')) {
|
||||
const serverStatic = express.static(FILE_ROOT_PATH);
|
||||
app.use(FILE_DEST, (req, res, next) => {
|
||||
res.header('Cross-Origin-Resource-Policy', 'cross-origin');
|
||||
return serverStatic(req, res, next);
|
||||
});
|
||||
}
|
||||
|
||||
await app.listen(port);
|
||||
|
||||
console.log(`[think] 主服务启动成功,端口:${port}`);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
import { AliyunOssClient } from '@helpers/aliyun.helper';
|
||||
import { dateFormat } from '@helpers/date.helper';
|
||||
import { uniqueid } from '@helpers/uniqueid.helper';
|
||||
import { getOssClient, OssClient } from '@helpers/file.helper';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class FileService {
|
||||
private ossClient: AliyunOssClient;
|
||||
private ossClient: OssClient;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.ossClient = new AliyunOssClient(this.configService);
|
||||
this.ossClient = getOssClient(this.configService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param file
|
||||
*/
|
||||
async uploadFile(file) {
|
||||
const { originalname, buffer } = file;
|
||||
const filename = `/${dateFormat(new Date(), 'yyyy-MM-dd')}/${uniqueid()}/${originalname}`;
|
||||
const url = await this.ossClient.putFile(filename, buffer);
|
||||
return url;
|
||||
async uploadFile(file, query) {
|
||||
return this.ossClient.uploadFile(file, query);
|
||||
}
|
||||
|
||||
async uploadChunk(file, query) {
|
||||
return this.ossClient.uploadChunk(file, query);
|
||||
}
|
||||
|
||||
async mergeChunk(query) {
|
||||
return this.ossClient.mergeChunk(query);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,5 +23,8 @@
|
|||
"@controllers/*": ["src/controllers/*"],
|
||||
"@modules/*": ["src/modules/*"]
|
||||
}
|
||||
},
|
||||
"watchOptions": {
|
||||
"excludeFiles": ["static"]
|
||||
}
|
||||
}
|
||||
|
|
349
pnpm-lock.yaml
349
pnpm-lock.yaml
|
@ -136,6 +136,7 @@ importers:
|
|||
requestidlecallback-polyfill: ^1.0.2
|
||||
resize-observer-polyfill: ^1.5.1
|
||||
scroll-into-view-if-needed: ^2.2.29
|
||||
spark-md5: ^3.0.2
|
||||
timeago.js: ^4.0.2
|
||||
tippy.js: ^6.3.7
|
||||
toggle-selection: ^1.0.6
|
||||
|
@ -226,6 +227,7 @@ importers:
|
|||
requestidlecallback-polyfill: 1.0.2
|
||||
resize-observer-polyfill: 1.5.1
|
||||
scroll-into-view-if-needed: 2.2.29
|
||||
spark-md5: 3.0.2
|
||||
timeago.js: 4.0.2
|
||||
tippy.js: 6.3.7
|
||||
toggle-selection: 1.0.6
|
||||
|
@ -289,6 +291,7 @@ importers:
|
|||
'@types/express': ^4.17.13
|
||||
'@types/jest': 27.0.2
|
||||
'@types/lodash': ^4.14.182
|
||||
'@types/multer': ^1.4.7
|
||||
'@types/node': ^16.0.0
|
||||
'@types/supertest': ^2.0.11
|
||||
'@typescript-eslint/eslint-plugin': ^5.21.0
|
||||
|
@ -299,6 +302,7 @@ importers:
|
|||
class-validator: ^0.13.2
|
||||
compression: ^1.7.4
|
||||
cookie-parser: ^1.4.6
|
||||
cos-nodejs-sdk-v5: ^2.11.9
|
||||
date-fns: ^2.28.0
|
||||
eslint: ^8.14.0
|
||||
eslint-config-prettier: ^8.5.0
|
||||
|
@ -350,12 +354,14 @@ importers:
|
|||
'@think/config': link:../config
|
||||
'@think/constants': link:../constants
|
||||
'@think/domains': link:../domains
|
||||
'@types/multer': 1.4.7
|
||||
ali-oss: 6.16.0
|
||||
bcryptjs: 2.4.3
|
||||
class-transformer: 0.5.1
|
||||
class-validator: 0.13.2
|
||||
compression: 1.7.4
|
||||
cookie-parser: 1.4.6
|
||||
cos-nodejs-sdk-v5: 2.11.9
|
||||
date-fns: 2.28.0
|
||||
express: 4.17.2
|
||||
express-rate-limit: 6.2.0_express@4.17.2
|
||||
|
@ -3103,13 +3109,11 @@ packages:
|
|||
dependencies:
|
||||
'@types/connect': 3.4.35
|
||||
'@types/node': 16.11.21
|
||||
dev: true
|
||||
|
||||
/@types/connect/3.4.35:
|
||||
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
|
||||
dependencies:
|
||||
'@types/node': 16.11.21
|
||||
dev: true
|
||||
|
||||
/@types/cookie-parser/1.4.3:
|
||||
resolution: {integrity: sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==}
|
||||
|
@ -3156,7 +3160,6 @@ packages:
|
|||
'@types/node': 16.11.21
|
||||
'@types/qs': 6.9.7
|
||||
'@types/range-parser': 1.2.4
|
||||
dev: true
|
||||
|
||||
/@types/express/4.17.13:
|
||||
resolution: {integrity: sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==}
|
||||
|
@ -3165,7 +3168,6 @@ packages:
|
|||
'@types/express-serve-static-core': 4.17.28
|
||||
'@types/qs': 6.9.7
|
||||
'@types/serve-static': 1.13.10
|
||||
dev: true
|
||||
|
||||
/@types/glob/7.2.0:
|
||||
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
|
||||
|
@ -3236,7 +3238,6 @@ packages:
|
|||
|
||||
/@types/mime/1.3.2:
|
||||
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
|
||||
dev: true
|
||||
|
||||
/@types/minimatch/3.0.5:
|
||||
resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
|
||||
|
@ -3246,6 +3247,12 @@ packages:
|
|||
resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
|
||||
dev: true
|
||||
|
||||
/@types/multer/1.4.7:
|
||||
resolution: {integrity: sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==}
|
||||
dependencies:
|
||||
'@types/express': 4.17.13
|
||||
dev: false
|
||||
|
||||
/@types/node/16.11.21:
|
||||
resolution: {integrity: sha512-Pf8M1XD9i1ksZEcCP8vuSNwooJ/bZapNmIzpmsMaL+jMI+8mEYU3PKvs+xDNuQcJWF/x24WzY4qxLtB0zNow9A==}
|
||||
|
||||
|
@ -3349,11 +3356,9 @@ packages:
|
|||
|
||||
/@types/qs/6.9.7:
|
||||
resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
|
||||
dev: true
|
||||
|
||||
/@types/range-parser/1.2.4:
|
||||
resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==}
|
||||
dev: true
|
||||
|
||||
/@types/react-window/1.8.5:
|
||||
resolution: {integrity: sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==}
|
||||
|
@ -3382,7 +3387,6 @@ packages:
|
|||
dependencies:
|
||||
'@types/mime': 1.3.2
|
||||
'@types/node': 16.11.21
|
||||
dev: true
|
||||
|
||||
/@types/stack-utils/2.0.1:
|
||||
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
|
||||
|
@ -3758,6 +3762,15 @@ packages:
|
|||
indent-string: 4.0.0
|
||||
dev: true
|
||||
|
||||
/ajv-formats/1.6.1:
|
||||
resolution: {integrity: sha512-4CjkH20If1lhR5CGtqkrVg3bbOtFEG80X9v6jDOIUhbzzbB+UzPBGy8GQhUNVZ0yvMHdMpawCOcy5ydGMsagGQ==}
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
dependencies:
|
||||
ajv: 7.2.4
|
||||
dev: false
|
||||
|
||||
/ajv-formats/2.1.1:
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependenciesMeta:
|
||||
|
@ -3791,6 +3804,15 @@ packages:
|
|||
json-schema-traverse: 0.4.1
|
||||
uri-js: 4.4.1
|
||||
|
||||
/ajv/7.2.4:
|
||||
resolution: {integrity: sha512-nBeQgg/ZZA3u3SYxyaDvpvDtgZ/EZPF547ARgZBrG9Bhu1vKDwAIjtIf+sDtJUKa2zOcEbmRLBRSyMraS/Oy1A==}
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
json-schema-traverse: 1.0.0
|
||||
require-from-string: 2.0.2
|
||||
uri-js: 4.4.1
|
||||
dev: false
|
||||
|
||||
/ajv/8.6.3:
|
||||
resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==}
|
||||
dependencies:
|
||||
|
@ -3988,6 +4010,17 @@ packages:
|
|||
resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=}
|
||||
dev: true
|
||||
|
||||
/asn1/0.2.6:
|
||||
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
|
||||
dependencies:
|
||||
safer-buffer: 2.1.2
|
||||
dev: false
|
||||
|
||||
/assert-plus/1.0.0:
|
||||
resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
|
||||
engines: {node: '>=0.8'}
|
||||
dev: false
|
||||
|
||||
/ast-types/0.13.4:
|
||||
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -4014,7 +4047,6 @@ packages:
|
|||
|
||||
/asynckit/0.4.0:
|
||||
resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=}
|
||||
dev: true
|
||||
|
||||
/at-least-node/1.0.0:
|
||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
||||
|
@ -4025,11 +4057,24 @@ packages:
|
|||
engines: {node: '>=8.0.0'}
|
||||
dev: false
|
||||
|
||||
/atomically/1.7.0:
|
||||
resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==}
|
||||
engines: {node: '>=10.12.0'}
|
||||
dev: false
|
||||
|
||||
/available-typed-arrays/1.0.5:
|
||||
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: false
|
||||
|
||||
/aws-sign2/0.7.0:
|
||||
resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
|
||||
dev: false
|
||||
|
||||
/aws4/1.11.0:
|
||||
resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==}
|
||||
dev: false
|
||||
|
||||
/axios/0.24.0:
|
||||
resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
|
||||
dependencies:
|
||||
|
@ -4184,6 +4229,12 @@ packages:
|
|||
/base64-js/1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
|
||||
/bcrypt-pbkdf/1.0.2:
|
||||
resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
|
||||
dependencies:
|
||||
tweetnacl: 0.14.5
|
||||
dev: false
|
||||
|
||||
/bcryptjs/2.4.3:
|
||||
resolution: {integrity: sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=}
|
||||
dev: false
|
||||
|
@ -4393,6 +4444,10 @@ packages:
|
|||
resolution: {integrity: sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==}
|
||||
dev: false
|
||||
|
||||
/caseless/0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
dev: false
|
||||
|
||||
/chalk/2.4.2:
|
||||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -4622,7 +4677,6 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
dev: true
|
||||
|
||||
/commander/2.20.3:
|
||||
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||
|
@ -4701,6 +4755,23 @@ packages:
|
|||
yargs: 16.2.0
|
||||
dev: false
|
||||
|
||||
/conf/9.0.2:
|
||||
resolution: {integrity: sha512-rLSiilO85qHgaTBIIHQpsv8z+NnVfZq3cKuYNCXN1AOqPzced0GWZEe/A517VldRLyQYXUMyV+vszavE2jSAqw==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ajv: 7.2.4
|
||||
ajv-formats: 1.6.1
|
||||
atomically: 1.7.0
|
||||
debounce-fn: 4.0.0
|
||||
dot-prop: 6.0.1
|
||||
env-paths: 2.2.1
|
||||
json-schema-typed: 7.0.3
|
||||
make-dir: 3.1.0
|
||||
onetime: 5.1.2
|
||||
pkg-up: 3.1.0
|
||||
semver: 7.3.5
|
||||
dev: false
|
||||
|
||||
/consola/2.15.3:
|
||||
resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
|
||||
dev: false
|
||||
|
@ -4778,6 +4849,10 @@ packages:
|
|||
requiresBuild: true
|
||||
dev: false
|
||||
|
||||
/core-util-is/1.0.2:
|
||||
resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
|
||||
dev: false
|
||||
|
||||
/core-util-is/1.0.3:
|
||||
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
|
||||
dev: false
|
||||
|
@ -4790,6 +4865,16 @@ packages:
|
|||
vary: 1.1.2
|
||||
dev: false
|
||||
|
||||
/cos-nodejs-sdk-v5/2.11.9:
|
||||
resolution: {integrity: sha512-szsUw/8hx1RWUfMNwgErzYcdPM3EwcmgbylqQf82HPZALMCAcaa7qCeAxVQHNvCumWYeQLy7EEloZjMUyjg7Ug==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
conf: 9.0.2
|
||||
mime-types: 2.1.34
|
||||
request: 2.88.2
|
||||
xml2js: 0.4.23
|
||||
dev: false
|
||||
|
||||
/cosmiconfig/6.0.0:
|
||||
resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -4891,6 +4976,13 @@ packages:
|
|||
/csstype/3.0.10:
|
||||
resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==}
|
||||
|
||||
/dashdash/1.14.1:
|
||||
resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
|
||||
engines: {node: '>=0.10'}
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
dev: false
|
||||
|
||||
/data-uri-to-buffer/3.0.1:
|
||||
resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -4926,6 +5018,13 @@ packages:
|
|||
resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==}
|
||||
dev: false
|
||||
|
||||
/debounce-fn/4.0.0:
|
||||
resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-fn: 3.1.0
|
||||
dev: false
|
||||
|
||||
/debug/2.6.9:
|
||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||
dependencies:
|
||||
|
@ -5065,7 +5164,6 @@ packages:
|
|||
/delayed-stream/1.0.0:
|
||||
resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: true
|
||||
|
||||
/denque/2.0.1:
|
||||
resolution: {integrity: sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==}
|
||||
|
@ -5153,6 +5251,13 @@ packages:
|
|||
resolution: {integrity: sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==}
|
||||
dev: false
|
||||
|
||||
/dot-prop/6.0.1:
|
||||
resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
is-obj: 2.0.0
|
||||
dev: false
|
||||
|
||||
/dotenv-expand/5.1.0:
|
||||
resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
|
||||
dev: false
|
||||
|
@ -5180,6 +5285,13 @@ packages:
|
|||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
dev: true
|
||||
|
||||
/ecc-jsbn/0.1.2:
|
||||
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
|
||||
dependencies:
|
||||
jsbn: 0.1.1
|
||||
safer-buffer: 2.1.2
|
||||
dev: false
|
||||
|
||||
/ecdsa-sig-formatter/1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
dependencies:
|
||||
|
@ -5248,6 +5360,11 @@ packages:
|
|||
resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==}
|
||||
dev: false
|
||||
|
||||
/env-paths/2.2.1:
|
||||
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/error-ex/1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
dependencies:
|
||||
|
@ -5726,6 +5843,10 @@ packages:
|
|||
is-extendable: 0.1.1
|
||||
dev: false
|
||||
|
||||
/extend/3.0.2:
|
||||
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
|
||||
dev: false
|
||||
|
||||
/external-editor/3.1.0:
|
||||
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -5735,6 +5856,11 @@ packages:
|
|||
tmp: 0.0.33
|
||||
dev: true
|
||||
|
||||
/extsprintf/1.3.0:
|
||||
resolution: {integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=}
|
||||
engines: {'0': node >=0.6.0}
|
||||
dev: false
|
||||
|
||||
/fast-deep-equal/3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
|
@ -5869,6 +5995,13 @@ packages:
|
|||
locate-path: 2.0.0
|
||||
dev: true
|
||||
|
||||
/find-up/3.0.0:
|
||||
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
locate-path: 3.0.0
|
||||
dev: false
|
||||
|
||||
/find-up/4.1.0:
|
||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -5902,6 +6035,10 @@ packages:
|
|||
resolution: {integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k=}
|
||||
dev: false
|
||||
|
||||
/forever-agent/0.6.1:
|
||||
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
|
||||
dev: false
|
||||
|
||||
/fork-ts-checker-webpack-plugin/6.5.0_787dd39517260957bc59f00cd4915d0b:
|
||||
resolution: {integrity: sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==}
|
||||
engines: {node: '>=10', yarn: '>=1.0.0'}
|
||||
|
@ -5934,6 +6071,15 @@ packages:
|
|||
webpack: 5.66.0
|
||||
dev: true
|
||||
|
||||
/form-data/2.3.3:
|
||||
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
|
||||
engines: {node: '>= 0.12'}
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.34
|
||||
dev: false
|
||||
|
||||
/form-data/3.0.1:
|
||||
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -6111,6 +6257,12 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/getpass/0.1.7:
|
||||
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
dev: false
|
||||
|
||||
/glob-parent/5.1.2:
|
||||
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -6205,6 +6357,20 @@ packages:
|
|||
/graceful-fs/4.2.9:
|
||||
resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==}
|
||||
|
||||
/har-schema/2.0.0:
|
||||
resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==}
|
||||
engines: {node: '>=4'}
|
||||
dev: false
|
||||
|
||||
/har-validator/5.1.5:
|
||||
resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
|
||||
engines: {node: '>=6'}
|
||||
deprecated: this library is no longer supported
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
har-schema: 2.0.0
|
||||
dev: false
|
||||
|
||||
/hard-rejection/2.1.0:
|
||||
resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -6308,6 +6474,15 @@ packages:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
/http-signature/1.2.0:
|
||||
resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
|
||||
engines: {node: '>=0.8', npm: '>=1.3.7'}
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
jsprim: 1.4.2
|
||||
sshpk: 1.17.0
|
||||
dev: false
|
||||
|
||||
/https-proxy-agent/5.0.0:
|
||||
resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -6615,6 +6790,11 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/is-obj/2.0.0:
|
||||
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/is-path-cwd/2.2.0:
|
||||
resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -6719,7 +6899,6 @@ packages:
|
|||
|
||||
/is-typedarray/1.0.0:
|
||||
resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=}
|
||||
dev: true
|
||||
|
||||
/is-unicode-supported/0.1.0:
|
||||
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
|
||||
|
@ -7331,6 +7510,10 @@ packages:
|
|||
dependencies:
|
||||
argparse: 2.0.1
|
||||
|
||||
/jsbn/0.1.1:
|
||||
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
|
||||
dev: false
|
||||
|
||||
/jsdom/16.7.0:
|
||||
resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -7397,6 +7580,10 @@ packages:
|
|||
/json-schema-traverse/1.0.0:
|
||||
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
|
||||
|
||||
/json-schema-typed/7.0.3:
|
||||
resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==}
|
||||
dev: false
|
||||
|
||||
/json-schema/0.4.0:
|
||||
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
|
||||
dev: false
|
||||
|
@ -7405,6 +7592,10 @@ packages:
|
|||
resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=}
|
||||
dev: true
|
||||
|
||||
/json-stringify-safe/5.0.1:
|
||||
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
|
||||
dev: false
|
||||
|
||||
/json5/1.0.1:
|
||||
resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
|
||||
hasBin: true
|
||||
|
@ -7457,6 +7648,16 @@ packages:
|
|||
semver: 5.7.1
|
||||
dev: false
|
||||
|
||||
/jsprim/1.4.2:
|
||||
resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
|
||||
engines: {node: '>=0.6.0'}
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
extsprintf: 1.3.0
|
||||
json-schema: 0.4.0
|
||||
verror: 1.10.0
|
||||
dev: false
|
||||
|
||||
/jstoxml/0.2.4:
|
||||
resolution: {integrity: sha1-/z+2eFaIOgMpU8fOjOdIYhD0hEc=}
|
||||
engines: {node: '>=0.2.0'}
|
||||
|
@ -7651,6 +7852,14 @@ packages:
|
|||
path-exists: 3.0.0
|
||||
dev: true
|
||||
|
||||
/locate-path/3.0.0:
|
||||
resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
p-locate: 3.0.0
|
||||
path-exists: 3.0.0
|
||||
dev: false
|
||||
|
||||
/locate-path/5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -7973,7 +8182,11 @@ packages:
|
|||
/mimic-fn/2.1.0:
|
||||
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/mimic-fn/3.1.0:
|
||||
resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/min-indent/1.0.1:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
|
@ -8274,6 +8487,10 @@ packages:
|
|||
resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==}
|
||||
dev: true
|
||||
|
||||
/oauth-sign/0.9.0:
|
||||
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
|
||||
dev: false
|
||||
|
||||
/object-assign/4.1.1:
|
||||
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -8371,7 +8588,6 @@ packages:
|
|||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
mimic-fn: 2.1.0
|
||||
dev: true
|
||||
|
||||
/optional/0.1.4:
|
||||
resolution: {integrity: sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==}
|
||||
|
@ -8469,6 +8685,13 @@ packages:
|
|||
p-limit: 1.3.0
|
||||
dev: true
|
||||
|
||||
/p-locate/3.0.0:
|
||||
resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
dev: false
|
||||
|
||||
/p-locate/4.1.0:
|
||||
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -8580,7 +8803,6 @@ packages:
|
|||
/path-exists/3.0.0:
|
||||
resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/path-exists/4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
|
@ -8632,6 +8854,10 @@ packages:
|
|||
optional: true
|
||||
dev: false
|
||||
|
||||
/performance-now/2.1.0:
|
||||
resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
|
||||
dev: false
|
||||
|
||||
/picocolors/0.2.1:
|
||||
resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==}
|
||||
dev: false
|
||||
|
@ -8742,6 +8968,13 @@ packages:
|
|||
dependencies:
|
||||
find-up: 4.1.0
|
||||
|
||||
/pkg-up/3.1.0:
|
||||
resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
find-up: 3.0.0
|
||||
dev: false
|
||||
|
||||
/platform/1.3.6:
|
||||
resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==}
|
||||
dev: false
|
||||
|
@ -9047,7 +9280,6 @@ packages:
|
|||
|
||||
/psl/1.8.0:
|
||||
resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
|
||||
dev: true
|
||||
|
||||
/pump/3.0.0:
|
||||
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
|
||||
|
@ -9069,6 +9301,11 @@ packages:
|
|||
dependencies:
|
||||
side-channel: 1.0.4
|
||||
|
||||
/qs/6.5.3:
|
||||
resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
|
||||
engines: {node: '>=0.6'}
|
||||
dev: false
|
||||
|
||||
/qs/6.9.3:
|
||||
resolution: {integrity: sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
@ -9449,6 +9686,33 @@ packages:
|
|||
resolution: {integrity: sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U=}
|
||||
dev: false
|
||||
|
||||
/request/2.88.2:
|
||||
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
|
||||
engines: {node: '>= 6'}
|
||||
deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
|
||||
dependencies:
|
||||
aws-sign2: 0.7.0
|
||||
aws4: 1.11.0
|
||||
caseless: 0.12.0
|
||||
combined-stream: 1.0.8
|
||||
extend: 3.0.2
|
||||
forever-agent: 0.6.1
|
||||
form-data: 2.3.3
|
||||
har-validator: 5.1.5
|
||||
http-signature: 1.2.0
|
||||
is-typedarray: 1.0.0
|
||||
isstream: 0.1.2
|
||||
json-stringify-safe: 5.0.1
|
||||
mime-types: 2.1.34
|
||||
oauth-sign: 0.9.0
|
||||
performance-now: 2.1.0
|
||||
qs: 6.5.3
|
||||
safe-buffer: 5.2.1
|
||||
tough-cookie: 2.5.0
|
||||
tunnel-agent: 0.6.0
|
||||
uuid: 3.4.0
|
||||
dev: false
|
||||
|
||||
/requestidlecallback-polyfill/1.0.2:
|
||||
resolution: {integrity: sha512-zzkRzvMe7UdV0M7AIU70vl2fh4rFnNYDL8U0ISwWiOX/5MowBV1ESYCWSQP/KsgJNUOC/AS6X3DApOmxoyE6MA==}
|
||||
dev: false
|
||||
|
@ -9920,6 +10184,10 @@ packages:
|
|||
/sourcemap-codec/1.4.8:
|
||||
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
|
||||
|
||||
/spark-md5/3.0.2:
|
||||
resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==}
|
||||
dev: false
|
||||
|
||||
/spawn-command/0.0.2-1:
|
||||
resolution: {integrity: sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=}
|
||||
dev: false
|
||||
|
@ -9965,6 +10233,22 @@ packages:
|
|||
engines: {node: '>= 0.6'}
|
||||
dev: false
|
||||
|
||||
/sshpk/1.17.0:
|
||||
resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
asn1: 0.2.6
|
||||
assert-plus: 1.0.0
|
||||
bcrypt-pbkdf: 1.0.2
|
||||
dashdash: 1.14.1
|
||||
ecc-jsbn: 0.1.2
|
||||
getpass: 0.1.7
|
||||
jsbn: 0.1.1
|
||||
safer-buffer: 2.1.2
|
||||
tweetnacl: 0.14.5
|
||||
dev: false
|
||||
|
||||
/stack-utils/2.0.5:
|
||||
resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -10614,6 +10898,14 @@ packages:
|
|||
engines: {node: '>=0.6'}
|
||||
dev: false
|
||||
|
||||
/tough-cookie/2.5.0:
|
||||
resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
|
||||
engines: {node: '>=0.8'}
|
||||
dependencies:
|
||||
psl: 1.8.0
|
||||
punycode: 2.1.1
|
||||
dev: false
|
||||
|
||||
/tough-cookie/4.0.0:
|
||||
resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -10769,6 +11061,16 @@ packages:
|
|||
typescript: 4.5.5
|
||||
dev: true
|
||||
|
||||
/tunnel-agent/0.6.0:
|
||||
resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/tweetnacl/0.14.5:
|
||||
resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=}
|
||||
dev: false
|
||||
|
||||
/type-check/0.3.2:
|
||||
resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -11066,6 +11368,12 @@ packages:
|
|||
engines: {node: '>= 0.4.0'}
|
||||
dev: false
|
||||
|
||||
/uuid/3.4.0:
|
||||
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
|
||||
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/uuid/8.3.2:
|
||||
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||
hasBin: true
|
||||
|
@ -11101,6 +11409,15 @@ packages:
|
|||
engines: {node: '>= 0.8'}
|
||||
dev: false
|
||||
|
||||
/verror/1.10.0:
|
||||
resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=}
|
||||
engines: {'0': node >=0.6.0}
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
core-util-is: 1.0.2
|
||||
extsprintf: 1.3.0
|
||||
dev: false
|
||||
|
||||
/viewerjs/1.10.4:
|
||||
resolution: {integrity: sha512-CjMt64yC9D+XUx2t3F0TPbh/Yt5+/ke8/s3IizXa6NtksdJUFDoCcNxi/KRZ9eiZPR/D77pHnnQzAtCoLDaGIw==}
|
||||
dev: false
|
||||
|
|
Loading…
Reference in New Issue