feat: add redis cache
This commit is contained in:
parent
827c1a431b
commit
9d183e1d36
@ -37,6 +37,7 @@
|
|||||||
"@teacinema/common": "^1.1.6",
|
"@teacinema/common": "^1.1.6",
|
||||||
"@teacinema/contracts": "^1.2.1",
|
"@teacinema/contracts": "^1.2.1",
|
||||||
"drizzle-orm": "^0.45.2",
|
"drizzle-orm": "^0.45.2",
|
||||||
|
"ioredis": "^5.10.1",
|
||||||
"pg": "^8.20.0",
|
"pg": "^8.20.0",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1"
|
"rxjs": "^7.8.1"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'
|
|||||||
import { ConfigModule } from '@nestjs/config'
|
import { ConfigModule } from '@nestjs/config'
|
||||||
import { DatabaseModule } from 'src/infra/database/database.module'
|
import { DatabaseModule } from 'src/infra/database/database.module'
|
||||||
|
|
||||||
|
import { RedisModule } from '../infra/redis/redis.module'
|
||||||
import { CategoryModule } from '../modules/category/category.module'
|
import { CategoryModule } from '../modules/category/category.module'
|
||||||
import { MovieModule } from '../modules/movie/movie.module'
|
import { MovieModule } from '../modules/movie/movie.module'
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import { MovieModule } from '../modules/movie/movie.module'
|
|||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({ isGlobal: true }),
|
ConfigModule.forRoot({ isGlobal: true }),
|
||||||
DatabaseModule,
|
DatabaseModule,
|
||||||
|
RedisModule,
|
||||||
MovieModule,
|
MovieModule,
|
||||||
CategoryModule
|
CategoryModule
|
||||||
]
|
]
|
||||||
|
|||||||
10
src/infra/redis/redis.module.ts
Normal file
10
src/infra/redis/redis.module.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { Global, Module } from '@nestjs/common'
|
||||||
|
|
||||||
|
import { RedisService } from './redis.service'
|
||||||
|
|
||||||
|
@Global()
|
||||||
|
@Module({
|
||||||
|
providers: [RedisService],
|
||||||
|
exports: [RedisService]
|
||||||
|
})
|
||||||
|
export class RedisModule {}
|
||||||
81
src/infra/redis/redis.service.ts
Normal file
81
src/infra/redis/redis.service.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import {
|
||||||
|
Injectable,
|
||||||
|
Logger,
|
||||||
|
OnModuleDestroy,
|
||||||
|
OnModuleInit
|
||||||
|
} from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
import Redis from 'ioredis'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RedisService
|
||||||
|
extends Redis
|
||||||
|
implements OnModuleInit, OnModuleDestroy
|
||||||
|
{
|
||||||
|
private readonly logger = new Logger(RedisService.name)
|
||||||
|
|
||||||
|
public constructor(private readonly configService: ConfigService) {
|
||||||
|
super({
|
||||||
|
username: configService.getOrThrow<string>('REDIS_USERNAME'),
|
||||||
|
host: configService.getOrThrow('REDIS_HOST'),
|
||||||
|
port: configService.getOrThrow('REDIS_PORT'),
|
||||||
|
password: configService.getOrThrow('REDIS_PASSWORD'),
|
||||||
|
db: parseInt(configService.getOrThrow('REDIS_DB')),
|
||||||
|
maxRetriesPerRequest: 5,
|
||||||
|
enableOfflineQueue: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public onModuleInit() {
|
||||||
|
const start = Date.now()
|
||||||
|
|
||||||
|
this.on('connect', () => {
|
||||||
|
this.logger.log('Redis connecting...')
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('ready', () => {
|
||||||
|
this.logger.log(`Redis connected in ${Date.now() - start}ms`)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('error', e => {
|
||||||
|
this.logger.error('Redis connection error', {
|
||||||
|
error: e.message || e
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('close', () => {
|
||||||
|
this.logger.warn('Redis connection closed')
|
||||||
|
})
|
||||||
|
|
||||||
|
this.on('reconnecting', () => {
|
||||||
|
this.logger.log('Redis reconnecting')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onModuleDestroy() {
|
||||||
|
this.logger.log('Redis disconnecting...')
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.quit()
|
||||||
|
this.logger.log('Redis disconnected')
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error('Redis disconnecting error', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getJson<T>(key: string): Promise<T | null> {
|
||||||
|
const value = await this.get(key)
|
||||||
|
|
||||||
|
return value ? (JSON.parse(value) as T) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
public async setJson(key: string, value: unknown, ttl?: number) {
|
||||||
|
const payload = JSON.stringify(value)
|
||||||
|
|
||||||
|
if (ttl) {
|
||||||
|
await this.set(key, payload, 'EX', ttl)
|
||||||
|
} else {
|
||||||
|
await this.set(key, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/modules/movie/movie.cache.keys.ts
Normal file
12
src/modules/movie/movie.cache.keys.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export const MovieCacheKeys = {
|
||||||
|
all: (params: { category?: string; random?: boolean; limit?: number }) =>
|
||||||
|
[
|
||||||
|
'movies',
|
||||||
|
'list',
|
||||||
|
params.category ?? 'all',
|
||||||
|
params.random ? 'random' : 'ordered',
|
||||||
|
params.limit ?? 'nolimit'
|
||||||
|
].join(':'),
|
||||||
|
bySlug: (slug: string) => `movies:slug:${slug}`,
|
||||||
|
byId: (id: string) => `movies:id:${id}`
|
||||||
|
}
|
||||||
45
src/modules/movie/movie.cache.service.ts
Normal file
45
src/modules/movie/movie.cache.service.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
import { ConfigService } from '@nestjs/config'
|
||||||
|
|
||||||
|
import { RedisService } from '../../infra/redis/redis.service'
|
||||||
|
|
||||||
|
import { MovieCacheKeys } from './movie.cache.keys'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MovieCacheService {
|
||||||
|
private readonly CACHE_TTL: number
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
private readonly redisService: RedisService
|
||||||
|
) {
|
||||||
|
this.CACHE_TTL = this.configService.getOrThrow<number>('CACHE_TTL')
|
||||||
|
}
|
||||||
|
|
||||||
|
public get<T>(key: string): Promise<T | null> {
|
||||||
|
return this.redisService.getJson<T>(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(key: string, value: unknown): Promise<void> {
|
||||||
|
return this.redisService.setJson(key, value, this.CACHE_TTL)
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAll<T>(params: {
|
||||||
|
category?: string
|
||||||
|
random?: boolean
|
||||||
|
limit?: number
|
||||||
|
}): Promise<T | null> {
|
||||||
|
return this.get<T>(MovieCacheKeys.all(params))
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAll(
|
||||||
|
params: {
|
||||||
|
category?: string
|
||||||
|
random?: boolean
|
||||||
|
limit?: number
|
||||||
|
},
|
||||||
|
value: unknown
|
||||||
|
) {
|
||||||
|
return this.set(MovieCacheKeys.all(params), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'
|
|||||||
|
|
||||||
import { DatabaseModule } from '../../infra/database/database.module'
|
import { DatabaseModule } from '../../infra/database/database.module'
|
||||||
|
|
||||||
|
import { MovieCacheService } from './movie.cache.service'
|
||||||
import { MovieController } from './movie.controller'
|
import { MovieController } from './movie.controller'
|
||||||
import { MovieRepository } from './movie.repository'
|
import { MovieRepository } from './movie.repository'
|
||||||
import { MovieService } from './movie.service'
|
import { MovieService } from './movie.service'
|
||||||
@ -9,6 +10,6 @@ import { MovieService } from './movie.service'
|
|||||||
@Module({
|
@Module({
|
||||||
imports: [DatabaseModule],
|
imports: [DatabaseModule],
|
||||||
controllers: [MovieController],
|
controllers: [MovieController],
|
||||||
providers: [MovieService, MovieRepository]
|
providers: [MovieService, MovieRepository, MovieCacheService]
|
||||||
})
|
})
|
||||||
export class MovieModule {}
|
export class MovieModule {}
|
||||||
|
|||||||
@ -3,33 +3,60 @@ import { RpcException } from '@nestjs/microservices'
|
|||||||
import { RpcStatus } from '@teacinema/common'
|
import { RpcStatus } from '@teacinema/common'
|
||||||
import {
|
import {
|
||||||
GetMovieRequest,
|
GetMovieRequest,
|
||||||
|
type GetMovieResponse,
|
||||||
ListMovieRequest,
|
ListMovieRequest,
|
||||||
|
type ListMovieResponse,
|
||||||
Movie,
|
Movie,
|
||||||
MovieDetails
|
MovieDetails
|
||||||
} from '@teacinema/contracts/gen/ts/movie'
|
} from '@teacinema/contracts/gen/ts/movie'
|
||||||
|
|
||||||
|
import { MovieCacheKeys } from './movie.cache.keys'
|
||||||
|
import { MovieCacheService } from './movie.cache.service'
|
||||||
import { MovieMapper } from './movie.mapper'
|
import { MovieMapper } from './movie.mapper'
|
||||||
import { MovieRepository } from './movie.repository'
|
import { MovieRepository } from './movie.repository'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MovieService {
|
export class MovieService {
|
||||||
public constructor(private readonly movieRepository: MovieRepository) {}
|
public constructor(
|
||||||
|
private readonly movieRepository: MovieRepository,
|
||||||
|
private readonly movieCacheService: MovieCacheService
|
||||||
|
) {}
|
||||||
|
|
||||||
public async getAll(data: ListMovieRequest) {
|
public async getAll(data: ListMovieRequest): Promise<ListMovieResponse> {
|
||||||
const filter = {
|
const filter = {
|
||||||
category: data.category ?? undefined,
|
category: data.category ?? undefined,
|
||||||
random: data.random === true,
|
random: data.random === true,
|
||||||
limit: data.limit > 0 ? data.limit : undefined
|
limit: data.limit > 0 ? data.limit : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cached =
|
||||||
|
await this.movieCacheService.getAll<ListMovieResponse['movies']>(filter)
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
return { movies: cached }
|
||||||
|
}
|
||||||
|
|
||||||
const movies = await this.movieRepository.findAll(filter)
|
const movies = await this.movieRepository.findAll(filter)
|
||||||
|
const mapped = movies.map(movie => MovieMapper.toMovie<Movie>(movie))
|
||||||
|
|
||||||
|
await this.movieCacheService.setAll(filter, mapped)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
movies: movies.map(movie => MovieMapper.toMovie<Movie>(movie))
|
movies: mapped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getOne(data: GetMovieRequest) {
|
public async getOne(data: GetMovieRequest): Promise<GetMovieResponse> {
|
||||||
|
const cacheKey = data.id
|
||||||
|
? MovieCacheKeys.byId(data.id)
|
||||||
|
: MovieCacheKeys.bySlug(data.slug)
|
||||||
|
const cached =
|
||||||
|
await this.movieCacheService.get<GetMovieResponse['movie']>(cacheKey)
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
return { movie: cached }
|
||||||
|
}
|
||||||
|
|
||||||
const movie = data.id
|
const movie = data.id
|
||||||
? await this.movieRepository.findById(data.id)
|
? await this.movieRepository.findById(data.id)
|
||||||
: await this.movieRepository.findBySlug(data.slug)
|
: await this.movieRepository.findBySlug(data.slug)
|
||||||
@ -41,6 +68,9 @@ export class MovieService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return { movie: MovieMapper.toMovie<MovieDetails>(movie) }
|
const mapped = MovieMapper.toMovie<MovieDetails>(movie)
|
||||||
|
await this.movieCacheService.set(cacheKey, mapped)
|
||||||
|
|
||||||
|
return { movie: mapped }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
59
yarn.lock
59
yarn.lock
@ -1033,6 +1033,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.10.tgz#11ed564ec78432a200ea2601a212d24af8150d50"
|
resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-3.0.10.tgz#11ed564ec78432a200ea2601a212d24af8150d50"
|
||||||
integrity sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==
|
integrity sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==
|
||||||
|
|
||||||
|
"@ioredis/commands@1.5.1":
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.5.1.tgz#a0a3449993b10c7aeb91ecb0d5f1a23692297e51"
|
||||||
|
integrity sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==
|
||||||
|
|
||||||
"@isaacs/cliui@^8.0.2":
|
"@isaacs/cliui@^8.0.2":
|
||||||
version "8.0.2"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
||||||
@ -2652,6 +2657,11 @@ clone@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||||
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
|
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
|
||||||
|
|
||||||
|
cluster-key-slot@^1.1.0:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
|
||||||
|
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==
|
||||||
|
|
||||||
co@^4.6.0:
|
co@^4.6.0:
|
||||||
version "4.6.0"
|
version "4.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||||
@ -2786,7 +2796,7 @@ cross-spawn@^7.0.3, cross-spawn@^7.0.6:
|
|||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.7, debug@^4.4.0, debug@^4.4.3:
|
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0, debug@^4.4.3:
|
||||||
version "4.4.3"
|
version "4.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
|
||||||
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
|
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
|
||||||
@ -2820,6 +2830,11 @@ delayed-stream@~1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||||
|
|
||||||
|
denque@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
|
||||||
|
integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
|
||||||
|
|
||||||
depd@^2.0.0, depd@~2.0.0:
|
depd@^2.0.0, depd@~2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
|
||||||
@ -3714,6 +3729,21 @@ inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4:
|
|||||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||||
|
|
||||||
|
ioredis@^5.10.1:
|
||||||
|
version "5.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.10.1.tgz#6082781d8aec8d51ee4936bf81d0610404db1e3d"
|
||||||
|
integrity sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==
|
||||||
|
dependencies:
|
||||||
|
"@ioredis/commands" "1.5.1"
|
||||||
|
cluster-key-slot "^1.1.0"
|
||||||
|
debug "^4.3.4"
|
||||||
|
denque "^2.1.0"
|
||||||
|
lodash.defaults "^4.2.0"
|
||||||
|
lodash.isarguments "^3.1.0"
|
||||||
|
redis-errors "^1.2.0"
|
||||||
|
redis-parser "^3.0.0"
|
||||||
|
standard-as-callback "^2.1.0"
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||||
@ -4324,6 +4354,16 @@ lodash.camelcase@^4.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
|
||||||
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
|
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
|
||||||
|
|
||||||
|
lodash.defaults@^4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||||
|
integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==
|
||||||
|
|
||||||
|
lodash.isarguments@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
|
||||||
|
integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==
|
||||||
|
|
||||||
lodash.memoize@^4.1.2:
|
lodash.memoize@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
@ -4966,6 +5006,18 @@ readdirp@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
|
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d"
|
||||||
integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
|
integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==
|
||||||
|
|
||||||
|
redis-errors@^1.0.0, redis-errors@^1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
|
||||||
|
integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==
|
||||||
|
|
||||||
|
redis-parser@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
|
||||||
|
integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==
|
||||||
|
dependencies:
|
||||||
|
redis-errors "^1.0.0"
|
||||||
|
|
||||||
reflect-metadata@^0.2.2:
|
reflect-metadata@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b"
|
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b"
|
||||||
@ -5222,6 +5274,11 @@ stack-utils@^2.0.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
escape-string-regexp "^2.0.0"
|
escape-string-regexp "^2.0.0"
|
||||||
|
|
||||||
|
standard-as-callback@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
|
||||||
|
integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
|
||||||
|
|
||||||
statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2:
|
statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382"
|
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user