add some code
This commit is contained in:
parent
25637cac59
commit
ed9977cab8
201
src/modules/Base.ts
Normal file
201
src/modules/Base.ts
Normal file
@ -0,0 +1,201 @@
|
||||
import { FindOrCreate } from '@typegoose/typegoose/lib/defaultClasses'
|
||||
import { checkJson } from '../decorators/nojson'
|
||||
import { plugin, ReturnModelType } from '@typegoose/typegoose'
|
||||
|
||||
// @ts-ignore
|
||||
import findOrCreate from 'mongoose-findorcreate'
|
||||
import { Connection } from 'mongoose'
|
||||
import { ObjectId } from 'bson'
|
||||
import { isTrue } from '../utils/string.util'
|
||||
import { AnyParamConstructor } from '@typegoose/typegoose/lib/types'
|
||||
|
||||
const jsonExcludeKeys = ['updatedAt', '__v']
|
||||
const saveExcludeKeys = ['createdAt', 'updatedAt', '__v', '_id']
|
||||
|
||||
@plugin(findOrCreate)
|
||||
export abstract class BaseModule extends FindOrCreate {
|
||||
static db: Connection
|
||||
|
||||
public updateFromReq(data: any) {
|
||||
for (let key in data) {
|
||||
if (saveExcludeKeys.indexOf(key) == -1) {
|
||||
this[key] = data[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入或更新
|
||||
* @param condition
|
||||
* @param data
|
||||
*/
|
||||
public static insertOrUpdate<T extends BaseModule>(
|
||||
this: ReturnModelType<AnyParamConstructor<T>>,
|
||||
condition: any,
|
||||
data: any,
|
||||
) {
|
||||
return this.findOneAndUpdate(condition, data, { upsert: true, new: true, setDefaultsOnInsert: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 虚拟删除
|
||||
* @param {string[]} ids
|
||||
*/
|
||||
public static deleteVirtual<T extends BaseModule>(this: ReturnModelType<AnyParamConstructor<T>>, ids: string[]) {
|
||||
return this.updateMany(
|
||||
// @ts-ignore
|
||||
{
|
||||
_id: { $in: ids },
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
deleted: true,
|
||||
deleteTime: new Date(),
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义分页查询
|
||||
* @param data
|
||||
* @param {boolean} json
|
||||
*/
|
||||
public static async pageQuery<T extends BaseModule>(
|
||||
this: ReturnModelType<AnyParamConstructor<T>>,
|
||||
data: any,
|
||||
json: boolean = false,
|
||||
) {
|
||||
let { start, limit, page } = data
|
||||
limit = +limit || 10
|
||||
start = +start || (+page - 1) * limit || 0
|
||||
// @ts-ignore
|
||||
let { opt, sort } = this.parseQueryParam(data)
|
||||
let records = await this.find(opt).sort(sort).skip(start).limit(limit)
|
||||
let total = await this.countDocuments(opt)
|
||||
if (json) {
|
||||
records.map((o: T) => o.toJson())
|
||||
}
|
||||
return { records, total, start, limit }
|
||||
}
|
||||
|
||||
public toJson() {
|
||||
let result: any = {}
|
||||
// @ts-ignore
|
||||
for (let key in this._doc) {
|
||||
if (checkJson(this, key + '') && jsonExcludeKeys.indexOf(key) == -1) {
|
||||
result[key] = this[key]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用的查询条件拼接方法
|
||||
* @param {{}} params req.params
|
||||
* @param options
|
||||
* sort: 排序 比如: {createdAt: 1} 默认是 {_id: 1}
|
||||
* opt: 设置一些特殊的过滤条件, 比如{deleted: 0}
|
||||
* timeKey: 如果需要查询创建时间, 而且创建时间不为 createdAt, 可以用此字段设置
|
||||
* matchKey: 指定关键字查询的匹配字段, 可为string或[string]
|
||||
*
|
||||
* @return {{opt: any, sort: {_id: number}}}
|
||||
*/
|
||||
public static parseQueryParam(params: {}, options?: any) {
|
||||
const opt: any = { deleted: false }
|
||||
// @ts-ignore
|
||||
let obj = this.schema.paths
|
||||
for (let key in params) {
|
||||
if (key !== 'sort' && obj.hasOwnProperty(key)) {
|
||||
switch (obj[key].instance) {
|
||||
case 'String':
|
||||
opt[key] = { $regex: params[key], $options: 'i' }
|
||||
break
|
||||
case 'Number':
|
||||
opt[key] = params[key]
|
||||
break
|
||||
case 'Array':
|
||||
if (Array.isArray(params[key])) {
|
||||
opt[key] = { $in: params[key] }
|
||||
} else {
|
||||
opt[key] = params[key]
|
||||
}
|
||||
break
|
||||
case 'Date':
|
||||
// TODO:
|
||||
break
|
||||
case 'Boolean':
|
||||
opt[key] = isTrue(params[key])
|
||||
break
|
||||
case 'ObjectID':
|
||||
if (/^[0-9a-fA-F]{24}$/.test(params[key])) {
|
||||
opt[key] = new ObjectId(params[key])
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (params.hasOwnProperty('key') && params['key']) {
|
||||
let orArr = []
|
||||
if (options?.matchKey) {
|
||||
if (Array.isArray(options?.matchKey)) {
|
||||
for (let key in options?.matchKey) {
|
||||
let _tmp = {}
|
||||
_tmp[key] = { $regex: params['key'], $options: 'i' }
|
||||
orArr.push(_tmp)
|
||||
}
|
||||
} else {
|
||||
let _tmp = {}
|
||||
_tmp[options.matchKey] = { $regex: params['key'], $options: 'i' }
|
||||
orArr.push(_tmp)
|
||||
}
|
||||
} else {
|
||||
for (let key in obj) {
|
||||
if (obj[key].instance === 'String') {
|
||||
let _tmp = {}
|
||||
_tmp[key] = { $regex: params['key'], $options: 'i' }
|
||||
orArr.push(_tmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(opt, { $or: orArr })
|
||||
}
|
||||
let timeKey = options?.timeKey ? options.timeKey : 'createdAt'
|
||||
if (params.hasOwnProperty('timeBegin') && !params.hasOwnProperty('timeEnd')) {
|
||||
let timeBegin = params['timeBegin']
|
||||
if (!(timeBegin instanceof Date)) {
|
||||
timeBegin = new Date(parseInt(timeBegin))
|
||||
}
|
||||
opt[timeKey] = { $gte: timeBegin }
|
||||
} else if (params.hasOwnProperty('timeBegin') && params.hasOwnProperty('timeEnd')) {
|
||||
let timeBegin = params['timeBegin']
|
||||
if (!(timeBegin instanceof Date)) {
|
||||
timeBegin = new Date(parseInt(timeBegin))
|
||||
}
|
||||
let timeEnd = params['timeEnd']
|
||||
if (!(timeEnd instanceof Date)) {
|
||||
timeEnd = new Date(parseInt(timeEnd))
|
||||
}
|
||||
let tmpB = {}
|
||||
tmpB[timeKey] = { $gte: timeBegin }
|
||||
let tmpE = {}
|
||||
tmpE[timeKey] = { $lte: timeEnd }
|
||||
opt['$and'] = [tmpB, tmpE]
|
||||
} else if (!params.hasOwnProperty('timeBegin') && params.hasOwnProperty('timeEnd')) {
|
||||
let timeEnd = params['timeEnd']
|
||||
if (!(timeEnd instanceof Date)) {
|
||||
timeEnd = new Date(parseInt(timeEnd))
|
||||
}
|
||||
opt[timeKey] = { $lte: timeEnd }
|
||||
}
|
||||
if (options?.opt) {
|
||||
Object.assign(opt, options.opt)
|
||||
}
|
||||
let sort = { _id: 1 }
|
||||
if (params.hasOwnProperty('sort')) {
|
||||
sort = params['sort']
|
||||
}
|
||||
return { opt, sort }
|
||||
}
|
||||
}
|
116
src/utils/net.util.ts
Normal file
116
src/utils/net.util.ts
Normal file
@ -0,0 +1,116 @@
|
||||
const TIMEOUT_ERROR = new Error('timeout')
|
||||
|
||||
const hexRe = /^[0-9A-Fa-f]+$/gu
|
||||
|
||||
/**
|
||||
* Execute fetch and verify that the response was successful.
|
||||
*
|
||||
* @param request - Request information.
|
||||
* @param options - Fetch options.
|
||||
* @returns The fetch response.
|
||||
*/
|
||||
export async function successfulFetch(request: string, options?: RequestInit) {
|
||||
const response = await fetch(request, options)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Fetch failed with status '${response.status}' for request '${request}'`)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute fetch and return object response.
|
||||
*
|
||||
* @param request - The request information.
|
||||
* @param options - The fetch options.
|
||||
* @returns The fetch response JSON data.
|
||||
*/
|
||||
export async function handleFetch(request: string, options?: RequestInit) {
|
||||
const response = await successfulFetch(request, options)
|
||||
const object = await response.json()
|
||||
return object
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute fetch and return object response, log if known error thrown, otherwise rethrow error.
|
||||
*
|
||||
* @param request - the request options object
|
||||
* @param request.url - The request url to query.
|
||||
* @param request.options - The fetch options.
|
||||
* @param request.timeout - Timeout to fail request
|
||||
* @param request.errorCodesToCatch - array of error codes for errors we want to catch in a particular context
|
||||
* @returns The fetch response JSON data or undefined (if error occurs).
|
||||
*/
|
||||
export async function fetchWithErrorHandling({
|
||||
url,
|
||||
options,
|
||||
timeout,
|
||||
errorCodesToCatch,
|
||||
}: {
|
||||
url: string
|
||||
options?: RequestInit
|
||||
timeout?: number
|
||||
errorCodesToCatch?: number[]
|
||||
}) {
|
||||
let result
|
||||
try {
|
||||
if (timeout) {
|
||||
result = Promise.race([
|
||||
await handleFetch(url, options),
|
||||
new Promise<Response>((_, reject) =>
|
||||
setTimeout(() => {
|
||||
reject(TIMEOUT_ERROR)
|
||||
}, timeout),
|
||||
),
|
||||
])
|
||||
} else {
|
||||
result = await handleFetch(url, options)
|
||||
}
|
||||
} catch (e) {
|
||||
logOrRethrowError(e, errorCodesToCatch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch that fails after timeout.
|
||||
*
|
||||
* @param url - Url to fetch.
|
||||
* @param options - Options to send with the request.
|
||||
* @param timeout - Timeout to fail request.
|
||||
* @returns Promise resolving the request.
|
||||
*/
|
||||
export async function timeoutFetch(url: string, options?: RequestInit, timeout = 500): Promise<Response> {
|
||||
return Promise.race([
|
||||
successfulFetch(url, options),
|
||||
new Promise<Response>((_, reject) =>
|
||||
setTimeout(() => {
|
||||
reject(TIMEOUT_ERROR)
|
||||
}, timeout),
|
||||
),
|
||||
])
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to log if error is a common fetch error and otherwise rethrow it.
|
||||
*
|
||||
* @param error - Caught error that we should either rethrow or log to console
|
||||
* @param codesToCatch - array of error codes for errors we want to catch and log in a particular context
|
||||
*/
|
||||
function logOrRethrowError(error: any, codesToCatch: number[] = []) {
|
||||
if (!error) {
|
||||
return
|
||||
}
|
||||
|
||||
const includesErrorCodeToCatch = codesToCatch.some(code =>
|
||||
error.message.includes(`Fetch failed with status '${code}'`),
|
||||
)
|
||||
|
||||
if (
|
||||
error instanceof Error &&
|
||||
(includesErrorCodeToCatch || error.message.includes('Failed to fetch') || error === TIMEOUT_ERROR)
|
||||
) {
|
||||
console.error(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
47
src/utils/promise.util.ts
Normal file
47
src/utils/promise.util.ts
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
*
|
||||
* @param {Function} cb
|
||||
* @param {number} maxRetries
|
||||
* @param {any[]} errorWhiteList
|
||||
* @param {number} retries
|
||||
* @return {Promise<T>}
|
||||
*/
|
||||
export function retry<T = any>(cb: Function, maxRetries: number = 3, errorWhiteList: any[] = [], retries: number = 0) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
cb()
|
||||
.then(resolve)
|
||||
.catch(e => {
|
||||
if (errorWhiteList.indexOf(e.constructor) !== -1 && retries++ < maxRetries) {
|
||||
setTimeout(() => {
|
||||
retry<T>(cb, maxRetries, errorWhiteList, retries)
|
||||
.then(resolve)
|
||||
.catch(e2 => reject(e2))
|
||||
}, Math.floor(Math.random() * Math.pow(2, retries) * 400))
|
||||
} else {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export class Deferred<T = any> {
|
||||
public promise: Promise<T>
|
||||
|
||||
public resolve: Function
|
||||
public reject: Function
|
||||
|
||||
constructor() {
|
||||
this.promise = new Promise<T>((resolve, reject) => {
|
||||
this.resolve = resolve
|
||||
this.reject = reject
|
||||
})
|
||||
}
|
||||
|
||||
public then(func: (value: T) => any) {
|
||||
return this.promise.then.apply(this.promise, arguments)
|
||||
}
|
||||
|
||||
public catch(func: (value: any) => any) {
|
||||
return this.promise.catch(func)
|
||||
}
|
||||
}
|
106
src/utils/string.util.ts
Normal file
106
src/utils/string.util.ts
Normal file
@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 根据key升序生成 key1=val1&key2=val2的字符串
|
||||
* @param {object} data 需要处理的对象
|
||||
* @param {boolean} ignoreNull 是否过滤空值(空格或者null值不参与拼接)
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function generateKeyValStr(data: {}, ignoreNull = true, splitChar: string = '&', equalChar = '=') {
|
||||
const keys = Object.keys(data)
|
||||
keys.sort()
|
||||
let result = ''
|
||||
let i = 0
|
||||
for (let key of keys) {
|
||||
if (ignoreNull && !data[key]) {
|
||||
return
|
||||
}
|
||||
if (i++ > 0) result += splitChar
|
||||
result += `${key}${equalChar}${data[key]}`
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 将key1=val&key2=val的字符串组装成对象
|
||||
* @param str key1=val&key2=val的字符串
|
||||
* @param splitChar 连接的字符, 默认是&
|
||||
* @param equalChar =
|
||||
*/
|
||||
export function keyValToObject(str: string, splitChar: string = '&', equalChar = '='): {} {
|
||||
let result = {}
|
||||
if (!str) {
|
||||
return result
|
||||
}
|
||||
let arrs = str.split(splitChar)
|
||||
for (let sub of arrs) {
|
||||
let subArr = sub.split(equalChar)
|
||||
result[subArr[0]] = subArr[1]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断传入的值是否为true
|
||||
* @param {Object} obj 传入值为'true','TRUE',1,'1','on','ON','YES','yes'时,返回true,其他值均返回false
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isTrue(obj) {
|
||||
return (
|
||||
obj === 'true' ||
|
||||
obj === 'TRUE' ||
|
||||
obj === 'True' ||
|
||||
obj === 'on' ||
|
||||
obj === 'ON' ||
|
||||
obj === true ||
|
||||
obj === 1 ||
|
||||
obj === '1' ||
|
||||
obj === 'YES' ||
|
||||
obj === 'yes'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证ObjectId格式是否正确
|
||||
* @param {string} id
|
||||
* @return {boolean}
|
||||
*/
|
||||
export function isObjectId(id: string): boolean {
|
||||
//mongoose.Types.ObjectId.isValid(id)
|
||||
return /^[a-fA-F0-9]{24}$/.test(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 10进制 -> 62进制
|
||||
* @param {string | number} number
|
||||
* @return {string}
|
||||
*/
|
||||
export function string10to62(number: string | number) {
|
||||
const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'.split('')
|
||||
const radix = chars.length
|
||||
let qutient = +number
|
||||
const arr = []
|
||||
do {
|
||||
const mod = qutient % radix
|
||||
qutient = (qutient - mod) / radix
|
||||
arr.unshift(chars[mod])
|
||||
} while (qutient)
|
||||
return arr.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 62进制 -> 10 进制
|
||||
* @param {string} numberCode
|
||||
* @return {number}
|
||||
*/
|
||||
export function string62to10(numberCode: string) {
|
||||
const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'
|
||||
const radix = chars.length
|
||||
numberCode = numberCode + ''
|
||||
const len = numberCode.length
|
||||
let i = 0
|
||||
let originNumber = 0
|
||||
while (i < len) {
|
||||
originNumber += Math.pow(radix, i++) * (chars.indexOf(numberCode.charAt(len - i)) || 0)
|
||||
}
|
||||
return originNumber
|
||||
}
|
58
yarn.lock
58
yarn.lock
@ -148,6 +148,40 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@redis/bloom@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.0.2.tgz#42b82ec399a92db05e29fffcdfd9235a5fc15cdf"
|
||||
integrity sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==
|
||||
|
||||
"@redis/client@1.3.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmmirror.com/@redis/client/-/client-1.3.0.tgz#c62ccd707f16370a2dc2f9e158a28b7da049fa77"
|
||||
integrity sha512-XCFV60nloXAefDsPnYMjHGtvbtHR8fV5Om8cQ0JYqTNbWcQo/4AryzJ2luRj4blveWazRK/j40gES8M7Cp6cfQ==
|
||||
dependencies:
|
||||
cluster-key-slot "1.1.0"
|
||||
generic-pool "3.8.2"
|
||||
yallist "4.0.0"
|
||||
|
||||
"@redis/graph@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmmirror.com/@redis/graph/-/graph-1.0.1.tgz#eabc58ba99cd70d0c907169c02b55497e4ec8a99"
|
||||
integrity sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==
|
||||
|
||||
"@redis/json@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz#f372b5f93324e6ffb7f16aadcbcb4e5c3d39bda1"
|
||||
integrity sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==
|
||||
|
||||
"@redis/search@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmmirror.com/@redis/search/-/search-1.1.0.tgz#7abb18d431f27ceafe6bcb4dd83a3fa67e9ab4df"
|
||||
integrity sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==
|
||||
|
||||
"@redis/time-series@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.3.tgz#4cfca8e564228c0bddcdf4418cba60c20b224ac4"
|
||||
integrity sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
@ -529,6 +563,11 @@ chokidar@^3.5.1:
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
cluster-key-slot@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmmirror.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
|
||||
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
|
||||
|
||||
color-convert@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
|
||||
@ -991,6 +1030,11 @@ function-bind@^1.1.1:
|
||||
resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
generic-pool@3.8.2:
|
||||
version "3.8.2"
|
||||
resolved "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9"
|
||||
integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==
|
||||
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
@ -1551,6 +1595,18 @@ real-require@^0.2.0:
|
||||
resolved "https://registry.npmmirror.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78"
|
||||
integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==
|
||||
|
||||
redis@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.npmmirror.com/redis/-/redis-4.3.1.tgz#290532a0c22221e05e991162ac4dca1e1b2ff6da"
|
||||
integrity sha512-cM7yFU5CA6zyCF7N/+SSTcSJQSRMEKN0k0Whhu6J7n9mmXRoXugfWDBo5iOzGwABmsWKSwGPTU5J4Bxbl+0mrA==
|
||||
dependencies:
|
||||
"@redis/bloom" "1.0.2"
|
||||
"@redis/client" "1.3.0"
|
||||
"@redis/graph" "1.0.1"
|
||||
"@redis/json" "1.0.4"
|
||||
"@redis/search" "1.1.0"
|
||||
"@redis/time-series" "1.0.3"
|
||||
|
||||
reflect-metadata@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
|
||||
@ -1960,7 +2016,7 @@ xtend@^4.0.0, xtend@^4.0.2:
|
||||
resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
|
||||
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
|
||||
|
||||
yallist@^4.0.0:
|
||||
yallist@4.0.0, yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
|
||||
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
|
||||
|
Loading…
x
Reference in New Issue
Block a user