diff --git a/client/src/http/BaseModel.ts b/client/src/http/BaseModel.ts index a74be639..ae05925c 100644 --- a/client/src/http/BaseModel.ts +++ b/client/src/http/BaseModel.ts @@ -50,6 +50,8 @@ export default class BaseModel { } as any; if (timeout) httpConfig.timeout = timeout; const res = await http(httpConfig); + // conflict with collection view data structure, status is useless, so delete here. + delete res.data.data.status; return new this(res.data.data || {}) as T; } diff --git a/client/src/http/Collection.ts b/client/src/http/Collection.ts index 04a01f10..63e5295d 100644 --- a/client/src/http/Collection.ts +++ b/client/src/http/Collection.ts @@ -42,13 +42,20 @@ export class Collection extends BaseModel implements CollectionData { return super.findAll({ path: this.COLLECTIONS_URL, params: data || {} }); } - static getCollection(name: string) { + static getCollectionWithIndexInfo(name: string) { return super.search({ path: `${this.COLLECTIONS_URL}/${name}`, params: {}, }); } + static getCollectionInfo(collectionName: string) { + return super.search({ + path: `${this.COLLECTIONS_URL}/${collectionName}/info`, + params: {}, + }); + } + static createCollection(data: any) { return super.create({ path: this.COLLECTIONS_URL, data }); } diff --git a/client/src/http/MilvusIndex.ts b/client/src/http/MilvusIndex.ts index 2528afa3..37deb50d 100644 --- a/client/src/http/MilvusIndex.ts +++ b/client/src/http/MilvusIndex.ts @@ -49,6 +49,12 @@ export class MilvusIndex extends BaseModel { return super.batchDelete({ path, data: { ...param, type } }); } + static async flush() { + const path = `${this.BASE_URL}/flush`; + + return super.query({ path, data: {} }); + } + get indexType() { return this.params.find(p => p.key === 'index_type')?.value || ''; } diff --git a/client/src/pages/collections/Collections.tsx b/client/src/pages/collections/Collections.tsx index ca0e6665..b93d240a 100644 --- a/client/src/pages/collections/Collections.tsx +++ b/client/src/pages/collections/Collections.tsx @@ -9,7 +9,7 @@ import { dataContext, webSocketContext, } from '@/context'; -import { Collection, MilvusService, DataService } from '@/http'; +import { Collection, MilvusService, DataService, MilvusIndex } from '@/http'; import { useNavigationHook, usePaginationHook } from '@/hooks'; import { ALL_ROUTER_TYPES } from '@/router/Types'; import AttuGrid from '@/components/grid/Grid'; @@ -123,6 +123,10 @@ const Collections = () => { } }, [setCollections, checkCollectionStatus]); + const clearIndexCache = useCallback(async () => { + await MilvusIndex.flush(); + }, []); + useEffect(() => { fetchData(); }, [fetchData, database]); @@ -412,6 +416,7 @@ const Collections = () => { { type: 'iconBtn', onClick: () => { + clearIndexCache(); fetchData(); }, label: collectionTrans('delete'), diff --git a/client/src/pages/partitions/Partitions.tsx b/client/src/pages/partitions/Partitions.tsx index 4a388443..352f4d2d 100644 --- a/client/src/pages/partitions/Partitions.tsx +++ b/client/src/pages/partitions/Partitions.tsx @@ -81,7 +81,7 @@ const Partitions: FC<{ }; const fetchCollectionDetail = async (name: string) => { - const res = await Collection.getCollection(name); + const res = await Collection.getCollectionInfo(name); return res; }; diff --git a/client/src/pages/preview/Preview.tsx b/client/src/pages/preview/Preview.tsx index 6089ff01..1738fd34 100644 --- a/client/src/pages/preview/Preview.tsx +++ b/client/src/pages/preview/Preview.tsx @@ -45,7 +45,7 @@ const Preview: FC<{ const loadData = async (collectionName: string) => { // get schema list - const collection = await Collection.getCollection(collectionName); + const collection = await Collection.getCollectionInfo(collectionName); const schemaList = collection.fields!; let nameList = schemaList.map(v => ({ diff --git a/client/src/pages/query/Query.tsx b/client/src/pages/query/Query.tsx index 74f623c5..2827a37c 100644 --- a/client/src/pages/query/Query.tsx +++ b/client/src/pages/query/Query.tsx @@ -66,7 +66,7 @@ const Query: FC<{ }; const getFields = async (collectionName: string) => { - const collection = await Collection.getCollection(collectionName); + const collection = await Collection.getCollectionInfo(collectionName); const schemaList = collection.fields; const nameList = schemaList.map(v => ({ diff --git a/client/src/pages/schema/Schema.tsx b/client/src/pages/schema/Schema.tsx index 87862f93..57dcd35f 100644 --- a/client/src/pages/schema/Schema.tsx +++ b/client/src/pages/schema/Schema.tsx @@ -85,7 +85,9 @@ const Schema: FC<{ const KeyIcon = icons.key; try { - const collection = await Collection.getCollection(collectionName); + const collection = await Collection.getCollectionWithIndexInfo( + collectionName + ); const fields = collection.fieldWithIndexInfo.map(f => Object.assign(f, { _fieldNameElement: ( diff --git a/client/src/pages/search/VectorSearch.tsx b/client/src/pages/search/VectorSearch.tsx index 58535dee..2826b79a 100644 --- a/client/src/pages/search/VectorSearch.tsx +++ b/client/src/pages/search/VectorSearch.tsx @@ -15,7 +15,7 @@ import SimpleMenu from '@/components/menu/SimpleMenu'; import { Option } from '@/components/customSelector/Types'; import Filter from '@/components/advancedSearch'; import { Field } from '@/components/advancedSearch/Types'; -import { Collection, MilvusIndex } from '@/http'; +import { Collection } from '@/http'; import { parseValue, parseLocationSearch, @@ -253,15 +253,17 @@ const VectorSearch = () => { const fetchFieldsWithIndex = useCallback( async (collectionName: string, collections: Collection[]) => { - const fields = - collections.find(c => c.collectionName === collectionName)?.fields || - []; - const indexes = await MilvusIndex.getIndexInfo(collectionName); + const col = collections.find(c => c.collectionName === collectionName); + + const fields = col?.fields ?? []; const { vectorFields, nonVectorFields } = classifyFields(fields); // only vector type fields can be select - const fieldOptions = getVectorFieldOptions(vectorFields, indexes); + const fieldOptions = getVectorFieldOptions( + vectorFields, + col?.indexes ?? [] + ); setFieldOptions(fieldOptions); if (fieldOptions.length > 0) { // set first option value as default field value @@ -351,10 +353,7 @@ const VectorSearch = () => { setTableLoading(true); try { - const res = await Collection.vectorSearchData( - selectedCollection, - params - ); + const res = await Collection.vectorSearchData(selectedCollection, params); setTableLoading(false); setSearchResult(res.results); setLatency(res.latency); diff --git a/client/src/pages/segments/Segments.tsx b/client/src/pages/segments/Segments.tsx index e5fa93a4..07960bcc 100644 --- a/client/src/pages/segments/Segments.tsx +++ b/client/src/pages/segments/Segments.tsx @@ -28,7 +28,8 @@ const Segments: FC<{ const qsegments = (await Segement.getQSegments(collectionName)) || {}; const combinedArray = psegments.infos.map(p => { - const q = qsegments.infos.find(q => q.segmentID === p.segmentID)! as any; + const q: any = + qsegments.infos.find(q => q.segmentID === p.segmentID)! || {}; return { ...p, ...Object.keys(q).reduce((acc, key) => { diff --git a/package.json b/package.json index 08359b1f..d5f1ef47 100644 --- a/package.json +++ b/package.json @@ -14,5 +14,8 @@ "private": true, "dependencies": { "react-router-dom": "^6.20.0" + }, + "devDependencies": { + "@types/lru-cache": "^7.10.10" } } diff --git a/server/package.json b/server/package.json index c8ef92a3..64d8b752 100644 --- a/server/package.json +++ b/server/package.json @@ -26,7 +26,7 @@ "glob": "^7.2.0", "helmet": "^7.0.0", "http-errors": "^2.0.0", - "lru-cache": "^6.0.0", + "lru-cache": "^10.1.0", "morgan": "^1.10.0", "node-cron": "^3.0.2", "rimraf": "^5.0.1", @@ -55,7 +55,7 @@ "@types/glob": "^8.1.0", "@types/http-errors": "^2.0.1", "@types/jest": "^29.5.3", - "@types/lru-cache": "^5.1.1", + "@types/lru-cache": "^7.10.10", "@types/morgan": "^1.9.4", "@types/node": "^20.4.2", "@types/node-cron": "^3.0.8", diff --git a/server/src/app.ts b/server/src/app.ts index f7b649db..24c13515 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -3,7 +3,7 @@ import cors from 'cors'; import helmet from 'helmet'; import * as http from 'http'; import { Server, Socket } from 'socket.io'; -import LruCache from 'lru-cache'; +import { LRUCache } from 'lru-cache'; import * as path from 'path'; import chalk from 'chalk'; import { router as connectRouter } from './milvus'; @@ -21,15 +21,21 @@ import { ErrorMiddleware, ReqHeaderMiddleware, } from './middleware'; -import { EXPIRED_TIME, CACHE_KEY } from './utils'; +import { CLIENT_TTL, INDEX_TTL } from './utils'; import { getIp } from './utils/Network'; +import { DescribeIndexResponse, MilvusClient } from './types'; // initialize express app export const app = express(); // initialize cache store -const cache = new LruCache({ - maxAge: EXPIRED_TIME, - updateAgeOnGet: true, +export const clientCache = new LRUCache({ + ttl: CLIENT_TTL, + ttlAutopurge: true, +}); + +export const indexCache = new LRUCache({ + ttl: INDEX_TTL, + ttlAutopurge: true, }); // initialize express router @@ -52,9 +58,8 @@ router.get('/healthy', (req, res, next) => { const server = http.createServer(app); // default port 3000 const PORT = 3000; + // setup middlewares -// use cache -app.set(CACHE_KEY, cache); // use cors https://expressjs.com/en/resources/middleware/cors.html app.use(cors()); // use helmet https://github.com/helmetjs/helmet diff --git a/server/src/collections/collections.controller.ts b/server/src/collections/collections.controller.ts index d3c1c1c3..ba06a55d 100644 --- a/server/src/collections/collections.controller.ts +++ b/server/src/collections/collections.controller.ts @@ -50,7 +50,10 @@ export class CollectionController { this.renameCollection.bind(this) ); this.router.delete('/:name/alias/:alias', this.dropAlias.bind(this)); + // collection with index info this.router.get('/:name', this.describeCollection.bind(this)); + // just collection info + this.router.get('/:name/info', this.getCollectionInfo.bind(this)); this.router.get('/:name/count', this.count.bind(this)); // load / release @@ -164,6 +167,18 @@ export class CollectionController { } } + async getCollectionInfo(req: Request, res: Response, next: NextFunction) { + const name = req.params?.name; + try { + const result = await this.collectionsService.describeCollection({ + collection_name: name, + }); + res.send(result); + } catch (error) { + next(error); + } + } + async getCollectionStatistics( req: Request, res: Response, diff --git a/server/src/collections/collections.service.ts b/server/src/collections/collections.service.ts index 9608c1c1..3ee2e9d4 100644 --- a/server/src/collections/collections.service.ts +++ b/server/src/collections/collections.service.ts @@ -4,7 +4,6 @@ import { DescribeCollectionReq, DropCollectionReq, GetCollectionStatisticsReq, - GetIndexStateReq, InsertReq, LoadCollectionReq, ReleaseLoadCollectionReq, @@ -27,9 +26,14 @@ import { Parser } from '@json2csv/plainjs'; import { throwErrorFromSDK, findKeyValue, genRows, ROW_COUNT } from '../utils'; import { QueryDto, ImportSampleDto, GetReplicasDto } from './dto'; import { CollectionData } from '../types'; +import { SchemaService } from '../schema/schema.service'; export class CollectionsService { - constructor(private milvusService: MilvusService) {} + private schemaService: SchemaService; + + constructor(private milvusService: MilvusService) { + this.schemaService = new SchemaService(milvusService); + } async getCollections(data?: ShowCollectionsReq) { const res = await this.milvusService.client.showCollections(data); @@ -151,18 +155,6 @@ export class CollectionsService { return res; } - /** - * We do not throw error for this. - * Because if collection dont have index, it will throw error. - * We need wait for milvus error code. - * @param data - * @returns - */ - async getIndexInfo(data: GetIndexStateReq) { - const res = await this.milvusService.client.describeIndex(data); - return res; - } - /** * Get all collections meta data * @returns {id:string, collection_name:string, schema:Field[], autoID:boolean, rowCount: string, consistency_level:string} @@ -190,7 +182,7 @@ export class CollectionsService { }); // get index info for collections - const indexRes = await this.getIndexInfo({ + const indexRes = await this.schemaService.describeIndex({ collection_name: item.name, }); @@ -295,7 +287,7 @@ export class CollectionsService { const res = await this.getCollections(); if (res.data.length > 0) { for (const item of res.data) { - const indexRes = await this.getIndexInfo({ + const indexRes = await this.schemaService.describeIndex({ collection_name: item.name, }); data.push({ diff --git a/server/src/middleware/index.ts b/server/src/middleware/index.ts index 43725eb6..8a0cd4e2 100644 --- a/server/src/middleware/index.ts +++ b/server/src/middleware/index.ts @@ -2,16 +2,16 @@ import { Request, Response, NextFunction } from 'express'; import morgan from 'morgan'; import chalk from 'chalk'; import { MilvusService } from '../milvus/milvus.service'; -import { CACHE_KEY, MILVUS_ADDRESS, HTTP_STATUS_CODE } from '../utils'; +import { MILVUS_ADDRESS, HTTP_STATUS_CODE } from '../utils'; import { HttpError } from 'http-errors'; import HttpErrors from 'http-errors'; +import { clientCache } from '../app'; export const ReqHeaderMiddleware = ( req: Request, res: Response, next: NextFunction ) => { - const cache = req.app.get(CACHE_KEY); // all ape requests need set milvus address in header. // server will set active address in milvus service. const milvusAddress = (req.headers[MILVUS_ADDRESS] as string) || ''; @@ -20,10 +20,10 @@ export const ReqHeaderMiddleware = ( // only api request has MILVUS_ADDRESS. // When client run in express, we dont need static files like: xx.js run this logic. // Otherwise will cause 401 error. - if (milvusAddress && cache.has(milvusAddress)) { + if (milvusAddress && clientCache.has(milvusAddress)) { MilvusService.activeAddress = milvusAddress; // insight cache will update expire time when use insightCache.get - MilvusService.activeMilvusClient = cache.get(milvusAddress); + MilvusService.activeMilvusClient = clientCache.get(milvusAddress); } const CONNECT_URL = `/api/v1/milvus/connect`; diff --git a/server/src/milvus/milvus.controller.ts b/server/src/milvus/milvus.controller.ts index b8935085..46699007 100644 --- a/server/src/milvus/milvus.controller.ts +++ b/server/src/milvus/milvus.controller.ts @@ -2,7 +2,6 @@ import { NextFunction, Request, Response, Router } from 'express'; import { dtoValidationMiddleware } from '../middleware/validation'; import { MilvusService } from './milvus.service'; import { ConnectMilvusDto, FlushDto, UseDatabaseDto } from './dto'; -import { CACHE_KEY } from '../utils'; import packageJson from '../../package.json'; export class MilvusController { @@ -44,12 +43,13 @@ export class MilvusController { async connectMilvus(req: Request, res: Response, next: NextFunction) { const { address, username, password, database } = req.body; - const cache = req.app.get(CACHE_KEY); try { - const result = await this.milvusService.connectMilvus( - { address, username, password, database }, - cache - ); + const result = await this.milvusService.connectMilvus({ + address, + username, + password, + database, + }); res.send(result); } catch (error) { @@ -60,10 +60,9 @@ export class MilvusController { async checkConnect(req: Request, res: Response, next: NextFunction) { const address = '' + req.query?.address; - const cache = req.app.get(CACHE_KEY); try { - const result = await this.milvusService.checkConnect(address, cache); + const result = await this.milvusService.checkConnect(address); res.send(result); } catch (error) { next(error); diff --git a/server/src/milvus/milvus.service.ts b/server/src/milvus/milvus.service.ts index c3539dbd..b6687b62 100644 --- a/server/src/milvus/milvus.service.ts +++ b/server/src/milvus/milvus.service.ts @@ -4,11 +4,11 @@ import { GetMetricsResponse, } from '@zilliz/milvus2-sdk-node'; import HttpErrors from 'http-errors'; -import LruCache from 'lru-cache'; import { HTTP_STATUS_CODE } from '../utils/Const'; import { DEFAULT_MILVUS_PORT } from '../utils'; import { connectivityState } from '@grpc/grpc-js'; import { DatabasesService } from '../database/databases.service'; +import { clientCache } from '../app'; export class MilvusService { private databaseService: DatabasesService; @@ -40,23 +40,17 @@ export class MilvusService { HTTP_STATUS_CODE.FORBIDDEN, 'Can not find your connection, please check your connection settings.' ); - - // throw new Error('Please connect milvus first'); } } - async connectMilvus( - data: { - address: string; - username?: string; - password?: string; - database?: string; - }, - cache: LruCache - ) { + async connectMilvus(data: { + address: string; + username?: string; + password?: string; + database?: string; + }) { // Destructure the data object to get the connection details const { address, username, password, database } = data; - // Format the address to remove the http prefix const milvusAddress = MilvusService.formatAddress(address); @@ -76,7 +70,7 @@ export class MilvusService { await milvusClient.connectPromise; } catch (error) { // If the connection fails, clear the cache and throw an error - cache.dump(); + clientCache.dump(); throw new Error('Failed to connect to Milvus: ' + error); } @@ -90,7 +84,7 @@ export class MilvusService { // If the server is healthy, set the active address and add the client to the cache MilvusService.activeAddress = address; - cache.set(address, milvusClient); + clientCache.set(address, milvusClient); // Create a new database service and check if the specified database exists let hasDatabase = false; @@ -109,14 +103,14 @@ export class MilvusService { return { address, database: hasDatabase ? database : 'default' }; } catch (error) { // If any error occurs, clear the cache and throw the error - cache.dump(); + clientCache.dump(); throw error; } } - async checkConnect(address: string, cache: LruCache) { + async checkConnect(address: string) { const milvusAddress = MilvusService.formatAddress(address); - return { connected: cache.has(milvusAddress) }; + return { connected: clientCache.has(milvusAddress) }; } async flush(data: FlushReq) { diff --git a/server/src/schema/schema.controller.ts b/server/src/schema/schema.controller.ts index 3ea3b250..763923bb 100644 --- a/server/src/schema/schema.controller.ts +++ b/server/src/schema/schema.controller.ts @@ -2,7 +2,6 @@ import { NextFunction, Request, Response, Router } from 'express'; import { dtoValidationMiddleware } from '../middleware/validation'; import { SchemaService } from './schema.service'; import { milvusService } from '../milvus'; - import { ManageIndexDto } from './dto'; export class SchemaController { @@ -22,6 +21,7 @@ export class SchemaController { ); this.router.get('/index', this.describeIndex.bind(this)); + this.router.post('/index/flush', this.clearCache.bind(this)); return this.router; } @@ -60,4 +60,13 @@ export class SchemaController { next(error); } } + + async clearCache(req: Request, res: Response, next: NextFunction) { + try { + const result = await this.schemaService.clearCache(); + res.send(result); + } catch (error) { + next(error); + } + } } diff --git a/server/src/schema/schema.service.ts b/server/src/schema/schema.service.ts index a7cff0d6..eb4c40ca 100644 --- a/server/src/schema/schema.service.ts +++ b/server/src/schema/schema.service.ts @@ -2,33 +2,76 @@ import { CreateIndexReq, DescribeIndexReq, DropIndexReq, - GetIndexBuildProgressReq, - GetIndexStateReq, + DescribeIndexResponse, } from '@zilliz/milvus2-sdk-node'; import { throwErrorFromSDK } from '../utils/Error'; import { MilvusService } from '../milvus/milvus.service'; +import { indexCache } from '../app'; export class SchemaService { constructor(private milvusService: MilvusService) {} async createIndex(data: CreateIndexReq) { const res = await this.milvusService.client.createIndex(data); + const key = data.collection_name; + + // clear cache; + indexCache.delete(key); throwErrorFromSDK(res); return res; } + /** + * This function is used to describe an index in Milvus. + * It first checks if the index description is cached, if so, it returns the cached value. + * If not, it calls the Milvus SDK's describeIndex function to get the index description. + * If the index is finished building, it caches the index description for future use. + * If the index is not finished building, it deletes any cached value for this index. + * @param data - The request data for describing an index. It contains the collection name. + * @returns - The response from the Milvus SDK's describeIndex function or the cached index description. + */ async describeIndex(data: DescribeIndexReq) { - const res = await this.milvusService.client.describeIndex(data); - if (res.status.error_code === 'IndexNotExist') { + // Get the collection name from the request data + const key = data.collection_name; + + // Try to get the index description from the cache + const value: DescribeIndexResponse = indexCache.get(key); + + // If the index description is in the cache, return it + if (value) { + return value; + } else { + // If the index description is not in the cache, call the Milvus SDK's describeIndex function + const res = await this.milvusService.client.describeIndex(data); + + // If the index is finished building and there is at least one index description, + // cache the index description for future use + if ( + res.index_descriptions?.length > 0 && + res.index_descriptions.every(i => i.state === 'Finished') + ) { + indexCache.set(key, res); + } else { + // If the index is not finished building, delete any cached value for this index + indexCache.delete(key); + } + + // Return the response from the Milvus SDK's describeIndex function return res; } - throwErrorFromSDK(res.status); - return res; } async dropIndex(data: DropIndexReq) { const res = await this.milvusService.client.dropIndex(data); + const key = data.collection_name; + + // clear cache; + indexCache.delete(key); throwErrorFromSDK(res); return res; } + + async clearCache() { + return indexCache.clear(); + } } diff --git a/server/src/types/index.ts b/server/src/types/index.ts index a82c84bc..dbfadf48 100644 --- a/server/src/types/index.ts +++ b/server/src/types/index.ts @@ -9,6 +9,8 @@ export { QuerySegmentInfo, GePersistentSegmentInfoResponse, PersistentSegmentInfo, + DescribeIndexResponse, + MilvusClient } from '@zilliz/milvus2-sdk-node'; export * from './collections.type'; diff --git a/server/src/utils/Const.ts b/server/src/utils/Const.ts index 4726c9fd..c51d8951 100644 --- a/server/src/utils/Const.ts +++ b/server/src/utils/Const.ts @@ -5,8 +5,10 @@ export const ROW_COUNT = 'row_count'; export const MILVUS_ADDRESS = 'milvus-address'; // for lru cache -export const CACHE_KEY = 'insight_cache'; -export const EXPIRED_TIME = 1000 * 60 * 60 * 24; +export const CLIENT_CACHE = 'insight_cache'; +export const INDEX_CACHE = 'index_cache'; +export const CLIENT_TTL = 1000 * 60 * 60 * 24; +export const INDEX_TTL = 1000 * 60 * 60; export enum LOADING_STATE { LOADED, diff --git a/server/yarn.lock b/server/yarn.lock index 0b7c2d4b..c476a984 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -1073,10 +1073,12 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== -"@types/lru-cache@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" - integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== +"@types/lru-cache@^7.10.10": + version "7.10.10" + resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-7.10.10.tgz#3fa937c35ff4b3f6753d5737915c9bf8e693a713" + integrity sha512-nEpVRPWW9EBmx2SCfNn3ClYxPL7IktPX12HhIoSc/H5mMjdeW3+YsXIpseLQ2xF35+OcpwKQbEUw5VtqE4PDNA== + dependencies: + lru-cache "*" "@types/mime@^1": version "1.3.2" @@ -3491,6 +3493,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lru-cache@*, lru-cache@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" diff --git a/yarn.lock b/yarn.lock index e692d056..793dafb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,18 @@ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.13.0.tgz#7e29c4ee85176d9c08cb0f4456bff74d092c5065" integrity sha512-5dMOnVnefRsl4uRnAdoWjtVTdh8e6aZqgM4puy9nmEADH72ck+uXwzpJLEKE9Q6F8ZljNewLgmTfkxUrBdv4WA== +"@types/lru-cache@^7.10.10": + version "7.10.10" + resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-7.10.10.tgz#3fa937c35ff4b3f6753d5737915c9bf8e693a713" + integrity sha512-nEpVRPWW9EBmx2SCfNn3ClYxPL7IktPX12HhIoSc/H5mMjdeW3+YsXIpseLQ2xF35+OcpwKQbEUw5VtqE4PDNA== + dependencies: + lru-cache "*" + +lru-cache@*: + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== + react-router-dom@^6.20.0: version "6.20.0" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.20.0.tgz#7b9527a1e29c7fb90736a5f89d54ca01f40e264b"