From dff4fcac00939cf5a9b2077eba4cadcfe47c72eb Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Wed, 4 Jun 2025 23:11:34 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20fix:=20Apply=20Mongoose=20Plugin?= =?UTF-8?q?=20at=20Model=20Creation=20(#7749)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: apply mongoMeili when models are created to use main runtime mongoose * chore: update @librechat/data-schemas version to 0.0.8 * refactor: remove unused useDebounceCodeBlock * fix: ensure setter function is stable and handle numeric conversion in useDebouncedInput * refactor: replace useCallback with useMemo for stable debounced function in useDebouncedInput --- .../Artifacts/useDebounceCodeBlock.ts | 37 ------------------- .../hooks/Conversations/useDebouncedInput.ts | 15 ++++---- package-lock.json | 4 +- packages/data-schemas/package.json | 2 +- packages/data-schemas/src/models/convo.ts | 11 ++++++ packages/data-schemas/src/models/message.ts | 13 ++++++- .../src/models/plugins/mongoMeili.ts | 10 +++-- packages/data-schemas/src/schema/convo.ts | 11 ------ packages/data-schemas/src/schema/message.ts | 10 ----- 9 files changed, 40 insertions(+), 73 deletions(-) delete mode 100644 client/src/components/Artifacts/useDebounceCodeBlock.ts diff --git a/client/src/components/Artifacts/useDebounceCodeBlock.ts b/client/src/components/Artifacts/useDebounceCodeBlock.ts deleted file mode 100644 index 27aaf5bc83..0000000000 --- a/client/src/components/Artifacts/useDebounceCodeBlock.ts +++ /dev/null @@ -1,37 +0,0 @@ -// client/src/hooks/useDebounceCodeBlock.ts -import { useCallback, useEffect } from 'react'; -import debounce from 'lodash/debounce'; -import { useSetRecoilState } from 'recoil'; -import { codeBlocksState, codeBlockIdsState } from '~/store/artifacts'; -import type { CodeBlock } from '~/common'; - -export function useDebounceCodeBlock() { - const setCodeBlocks = useSetRecoilState(codeBlocksState); - const setCodeBlockIds = useSetRecoilState(codeBlockIdsState); - - const updateCodeBlock = useCallback((codeBlock: CodeBlock) => { - console.log('Updating code block:', codeBlock); - setCodeBlocks((prev) => ({ - ...prev, - [codeBlock.id]: codeBlock, - })); - setCodeBlockIds((prev) => - prev.includes(codeBlock.id) ? prev : [...prev, codeBlock.id], - ); - }, [setCodeBlocks, setCodeBlockIds]); - - const debouncedUpdateCodeBlock = useCallback( - debounce((codeBlock: CodeBlock) => { - updateCodeBlock(codeBlock); - }, 25), - [updateCodeBlock], - ); - - useEffect(() => { - return () => { - debouncedUpdateCodeBlock.cancel(); - }; - }, [debouncedUpdateCodeBlock]); - - return debouncedUpdateCodeBlock; -} diff --git a/client/src/hooks/Conversations/useDebouncedInput.ts b/client/src/hooks/Conversations/useDebouncedInput.ts index 56584769ce..73fbb66723 100644 --- a/client/src/hooks/Conversations/useDebouncedInput.ts +++ b/client/src/hooks/Conversations/useDebouncedInput.ts @@ -1,5 +1,5 @@ import debounce from 'lodash/debounce'; -import React, { useState, useCallback } from 'react'; +import React, { useState, useCallback, useMemo } from 'react'; import type { SetterOrUpdater } from 'recoil'; import type { TSetOption } from '~/common'; import { defaultDebouncedDelay } from '~/common'; @@ -29,10 +29,10 @@ function useDebouncedInput({ /** A debounced function to call the passed setOption with the optionKey and new value. * - Note: We use useCallback to ensure our debounced function is stable across renders. */ - const setDebouncedOption = useCallback( - debounce(setOption && optionKey ? setOption(optionKey) : setter, delay), - [], + Note: We use useMemo to ensure our debounced function is stable across renders and properly typed. */ + const setDebouncedOption = useMemo( + () => debounce(setOption && optionKey ? setOption(optionKey) : setter || (() => {}), delay), + [setOption, optionKey, setter, delay], ); /** An onChange handler that updates the local state and the debounced option */ @@ -42,8 +42,9 @@ function useDebouncedInput({ typeof e !== 'object' ? e : ((e as React.ChangeEvent).target - .value as unknown as T); - if (numeric === true) { + .value as unknown as T); + // Handle numeric conversion only if value is not undefined and not empty string + if (numeric === true && newValue !== undefined && newValue !== '') { newValue = Number(newValue) as unknown as T; } setValue(newValue); diff --git a/package-lock.json b/package-lock.json index af0d6dbc9d..f53d7389ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46018,7 +46018,7 @@ "passport-facebook": "^3.0.0" }, "devDependencies": { - "@librechat/data-schemas": "^0.0.7", + "@librechat/data-schemas": "^0.0.8", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^25.0.2", "@rollup/plugin-json": "^6.1.0", @@ -46186,7 +46186,7 @@ }, "packages/data-schemas": { "name": "@librechat/data-schemas", - "version": "0.0.7", + "version": "0.0.8", "license": "MIT", "devDependencies": { "@rollup/plugin-alias": "^5.1.0", diff --git a/packages/data-schemas/package.json b/packages/data-schemas/package.json index 9c2dddf0b5..8d625fa835 100644 --- a/packages/data-schemas/package.json +++ b/packages/data-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@librechat/data-schemas", - "version": "0.0.7", + "version": "0.0.8", "description": "Mongoose schemas and models for LibreChat", "type": "module", "main": "dist/index.cjs", diff --git a/packages/data-schemas/src/models/convo.ts b/packages/data-schemas/src/models/convo.ts index 13a36e2069..da0a8c68cf 100644 --- a/packages/data-schemas/src/models/convo.ts +++ b/packages/data-schemas/src/models/convo.ts @@ -1,10 +1,21 @@ import type * as t from '~/types'; +import mongoMeili from '~/models/plugins/mongoMeili'; import convoSchema from '~/schema/convo'; /** * Creates or returns the Conversation model using the provided mongoose instance and schema */ export function createConversationModel(mongoose: typeof import('mongoose')) { + if (process.env.MEILI_HOST && process.env.MEILI_MASTER_KEY) { + convoSchema.plugin(mongoMeili, { + mongoose, + host: process.env.MEILI_HOST, + apiKey: process.env.MEILI_MASTER_KEY, + /** Note: Will get created automatically if it doesn't exist already */ + indexName: 'convos', + primaryKey: 'conversationId', + }); + } return ( mongoose.models.Conversation || mongoose.model('Conversation', convoSchema) ); diff --git a/packages/data-schemas/src/models/message.ts b/packages/data-schemas/src/models/message.ts index cb5bd9e7d3..3a81211e68 100644 --- a/packages/data-schemas/src/models/message.ts +++ b/packages/data-schemas/src/models/message.ts @@ -1,9 +1,20 @@ -import messageSchema from '~/schema/message'; import type * as t from '~/types'; +import mongoMeili from '~/models/plugins/mongoMeili'; +import messageSchema from '~/schema/message'; /** * Creates or returns the Message model using the provided mongoose instance and schema */ export function createMessageModel(mongoose: typeof import('mongoose')) { + if (process.env.MEILI_HOST && process.env.MEILI_MASTER_KEY) { + messageSchema.plugin(mongoMeili, { + mongoose, + host: process.env.MEILI_HOST, + apiKey: process.env.MEILI_MASTER_KEY, + indexName: 'messages', + primaryKey: 'messageId', + }); + } + return mongoose.models.Message || mongoose.model('Message', messageSchema); } diff --git a/packages/data-schemas/src/models/plugins/mongoMeili.ts b/packages/data-schemas/src/models/plugins/mongoMeili.ts index 111f9e0bba..1956be9f30 100644 --- a/packages/data-schemas/src/models/plugins/mongoMeili.ts +++ b/packages/data-schemas/src/models/plugins/mongoMeili.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { MeiliSearch, Index } from 'meilisearch'; -import mongoose, { Schema, Document, Model, Query } from 'mongoose'; +import type { FilterQuery, Types, Schema, Document, Model, Query } from 'mongoose'; import logger from '~/config/meiliLogger'; interface MongoMeiliOptions { @@ -8,6 +8,7 @@ interface MongoMeiliOptions { apiKey: string; indexName: string; primaryKey: string; + mongoose: typeof import('mongoose'); } interface MeiliIndexable { @@ -314,7 +315,7 @@ const createMeiliMongooseModel = ({ } await this.collection.updateMany( - { _id: this._id as mongoose.Types.ObjectId }, + { _id: this._id as Types.ObjectId }, { $set: { _meiliIndex: true } }, ); } @@ -398,6 +399,7 @@ const createMeiliMongooseModel = ({ * @param options.primaryKey - The primary key field for indexing. */ export default function mongoMeili(schema: Schema, options: MongoMeiliOptions): void { + const mongoose = options.mongoose; validateOptions(options); // Add _meiliIndex field to the schema to track if a document has been indexed in MeiliSearch. @@ -452,7 +454,7 @@ export default function mongoMeili(schema: Schema, options: MongoMeiliOptions): const convoIndex = client.index('convos'); const deletedConvos = await mongoose .model('Conversation') - .find(conditions as mongoose.FilterQuery) + .find(conditions as FilterQuery) .lean(); const promises = deletedConvos.map((convo: Record) => convoIndex.deleteDocument(convo.conversationId as string), @@ -464,7 +466,7 @@ export default function mongoMeili(schema: Schema, options: MongoMeiliOptions): const messageIndex = client.index('messages'); const deletedMessages = await mongoose .model('Message') - .find(conditions as mongoose.FilterQuery) + .find(conditions as FilterQuery) .lean(); const promises = deletedMessages.map((message: Record) => messageIndex.deleteDocument(message.messageId as string), diff --git a/packages/data-schemas/src/schema/convo.ts b/packages/data-schemas/src/schema/convo.ts index 8b0eb5b5c7..9680a49d9e 100644 --- a/packages/data-schemas/src/schema/convo.ts +++ b/packages/data-schemas/src/schema/convo.ts @@ -1,5 +1,4 @@ import { Schema } from 'mongoose'; -import mongoMeili from '~/models/plugins/mongoMeili'; import { conversationPreset } from './defaults'; import { IConversation } from '~/types'; @@ -48,14 +47,4 @@ convoSchema.index({ expiredAt: 1 }, { expireAfterSeconds: 0 }); convoSchema.index({ createdAt: 1, updatedAt: 1 }); convoSchema.index({ conversationId: 1, user: 1 }, { unique: true }); -if (process.env.MEILI_HOST && process.env.MEILI_MASTER_KEY) { - convoSchema.plugin(mongoMeili, { - host: process.env.MEILI_HOST, - apiKey: process.env.MEILI_MASTER_KEY, - /** Note: Will get created automatically if it doesn't exist already */ - indexName: 'convos', - primaryKey: 'conversationId', - }); -} - export default convoSchema; diff --git a/packages/data-schemas/src/schema/message.ts b/packages/data-schemas/src/schema/message.ts index 4946d1e449..15a80ae80e 100644 --- a/packages/data-schemas/src/schema/message.ts +++ b/packages/data-schemas/src/schema/message.ts @@ -1,6 +1,5 @@ import mongoose, { Schema } from 'mongoose'; import type { IMessage } from '~/types/message'; -import mongoMeili from '~/models/plugins/mongoMeili'; const messageSchema: Schema = new Schema( { @@ -166,13 +165,4 @@ messageSchema.index({ expiredAt: 1 }, { expireAfterSeconds: 0 }); messageSchema.index({ createdAt: 1 }); messageSchema.index({ messageId: 1, user: 1 }, { unique: true }); -if (process.env.MEILI_HOST && process.env.MEILI_MASTER_KEY) { - messageSchema.plugin(mongoMeili, { - host: process.env.MEILI_HOST, - apiKey: process.env.MEILI_MASTER_KEY, - indexName: 'messages', - primaryKey: 'messageId', - }); -} - export default messageSchema;