Compare commits
41 Commits
main
...
refactor/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
148052c473 | ||
|
|
331014cc98 | ||
|
|
9c0deed34a | ||
|
|
226bd90ede | ||
|
|
4fea3d4274 | ||
|
|
ad6716f6ef | ||
|
|
b2f7f5c904 | ||
|
|
4ae1d82a75 | ||
|
|
494c6d2596 | ||
|
|
6f4c8ef114 | ||
|
|
a4c6553695 | ||
|
|
edb977c1bc | ||
|
|
8ec7781672 | ||
|
|
99731e98dd | ||
|
|
f57d920bd5 | ||
|
|
3831ad8202 | ||
|
|
6e278f6932 | ||
|
|
90ac2b51cd | ||
|
|
20ad7d52f3 | ||
|
|
eb368fcb70 | ||
|
|
7cf3f98475 | ||
|
|
ab5450be8b | ||
|
|
c682d45fb2 | ||
|
|
5fb6b91e71 | ||
|
|
76e070048c | ||
|
|
728d19e361 | ||
|
|
2d492b932f | ||
|
|
c201d54cac | ||
|
|
a2a3f5c044 | ||
|
|
f9c0e9853f | ||
|
|
fa9177180f | ||
|
|
f6ca8caf7e | ||
|
|
30b8a1c6c4 | ||
|
|
848cb6f871 | ||
|
|
ea459749f9 | ||
|
|
63c56c8dd9 | ||
|
|
7caffda81a | ||
|
|
0cb5ed4063 | ||
|
|
85d0688f38 | ||
|
|
2c14fe1e9a | ||
|
|
4049b5572c |
@@ -1,7 +1,7 @@
|
||||
const { Constants } = require('librechat-data-provider');
|
||||
const { initializeFakeClient } = require('./FakeClient');
|
||||
|
||||
jest.mock('~/lib/db/connectDb');
|
||||
jest.mock('~/db/connect');
|
||||
jest.mock('~/models', () => ({
|
||||
User: jest.fn(),
|
||||
Key: jest.fn(),
|
||||
@@ -52,7 +52,7 @@ const messageHistory = [
|
||||
{
|
||||
role: 'user',
|
||||
isCreatedByUser: true,
|
||||
text: 'What\'s up',
|
||||
text: "What's up",
|
||||
messageId: '3',
|
||||
parentMessageId: '2',
|
||||
},
|
||||
@@ -456,7 +456,7 @@ describe('BaseClient', () => {
|
||||
|
||||
const chatMessages2 = await TestClient.loadHistory(conversationId, '3');
|
||||
expect(TestClient.currentMessages).toHaveLength(3);
|
||||
expect(chatMessages2[chatMessages2.length - 1].text).toEqual('What\'s up');
|
||||
expect(chatMessages2[chatMessages2.length - 1].text).toEqual("What's up");
|
||||
});
|
||||
|
||||
/* Most of the new sendMessage logic revolving around edited/continued AI messages
|
||||
|
||||
@@ -5,7 +5,7 @@ const getLogStores = require('~/cache/getLogStores');
|
||||
const OpenAIClient = require('../OpenAIClient');
|
||||
jest.mock('meilisearch');
|
||||
|
||||
jest.mock('~/lib/db/connectDb');
|
||||
jest.mock('~/db/connect');
|
||||
jest.mock('~/models', () => ({
|
||||
User: jest.fn(),
|
||||
Key: jest.fn(),
|
||||
@@ -462,17 +462,17 @@ describe('OpenAIClient', () => {
|
||||
role: 'system',
|
||||
name: 'example_user',
|
||||
content:
|
||||
'Let\'s circle back when we have more bandwidth to touch base on opportunities for increased leverage.',
|
||||
"Let's circle back when we have more bandwidth to touch base on opportunities for increased leverage.",
|
||||
},
|
||||
{
|
||||
role: 'system',
|
||||
name: 'example_assistant',
|
||||
content: 'Let\'s talk later when we\'re less busy about how to do better.',
|
||||
content: "Let's talk later when we're less busy about how to do better.",
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content:
|
||||
'This late pivot means we don\'t have time to boil the ocean for the client deliverable.',
|
||||
"This late pivot means we don't have time to boil the ocean for the client deliverable.",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const { Constants } = require('librechat-data-provider');
|
||||
const { HumanMessage, AIMessage } = require('@langchain/core/messages');
|
||||
const PluginsClient = require('../PluginsClient');
|
||||
|
||||
jest.mock('~/lib/db/connectDb');
|
||||
jest.mock('~/db/connect');
|
||||
jest.mock('~/models/Conversation', () => {
|
||||
return function () {
|
||||
return {
|
||||
|
||||
@@ -10,18 +10,24 @@ const mockPluginService = {
|
||||
getUserPluginAuthValue: jest.fn(),
|
||||
};
|
||||
|
||||
jest.mock('~/models/User', () => {
|
||||
return function () {
|
||||
return mockUser;
|
||||
const mockModels = {
|
||||
User: mockUser,
|
||||
};
|
||||
jest.mock('~/db/connect', () => {
|
||||
return {
|
||||
connectDb: jest.fn(),
|
||||
User: mockModels.mockUser,
|
||||
};
|
||||
});
|
||||
jest.mock('~/models/File', () => ({
|
||||
File: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('~/server/services/PluginService', () => mockPluginService);
|
||||
|
||||
const { BaseLLM } = require('@langchain/openai');
|
||||
const { Calculator } = require('@langchain/community/tools/calculator');
|
||||
|
||||
const User = require('~/models/User');
|
||||
const PluginService = require('~/server/services/PluginService');
|
||||
const { validateTools, loadTools, loadToolWithAuth } = require('./handleTools');
|
||||
const { StructuredSD, availableTools, DALLE3 } = require('../');
|
||||
@@ -52,7 +58,7 @@ describe('Tool Handlers', () => {
|
||||
},
|
||||
);
|
||||
|
||||
fakeUser = new User({
|
||||
fakeUser = await mockModels.User.createUser({
|
||||
name: 'Fake User',
|
||||
username: 'fakeuser',
|
||||
email: 'fakeuser@example.com',
|
||||
@@ -218,7 +224,6 @@ describe('Tool Handlers', () => {
|
||||
try {
|
||||
await loadTool2();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line jest/no-conditional-expect
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
4
api/cache/banViolation.js
vendored
4
api/cache/banViolation.js
vendored
@@ -1,8 +1,8 @@
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { ViolationTypes } = require('librechat-data-provider');
|
||||
const { isEnabled, math, removePorts } = require('~/server/utils');
|
||||
const { deleteAllUserSessions } = require('~/models');
|
||||
const getLogStores = require('./getLogStores');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const { BAN_VIOLATIONS, BAN_INTERVAL } = process.env ?? {};
|
||||
const interval = math(BAN_INTERVAL, 20);
|
||||
@@ -32,7 +32,6 @@ const banViolation = async (req, res, errorMessage) => {
|
||||
if (!isEnabled(BAN_VIOLATIONS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!errorMessage) {
|
||||
return;
|
||||
}
|
||||
@@ -51,7 +50,6 @@ const banViolation = async (req, res, errorMessage) => {
|
||||
|
||||
const banLogs = getLogStores(ViolationTypes.BAN);
|
||||
const duration = errorMessage.duration || banLogs.opts.ttl;
|
||||
|
||||
if (duration <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
23
api/cache/banViolation.spec.js
vendored
23
api/cache/banViolation.spec.js
vendored
@@ -1,7 +1,28 @@
|
||||
const banViolation = require('./banViolation');
|
||||
|
||||
const mockModels = {
|
||||
Session: {
|
||||
deleteAllUserSessions: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('~/db/connect', () => {
|
||||
return {
|
||||
connectDb: jest.fn(),
|
||||
get models() {
|
||||
return mockModels;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('~/server/utils', () => ({
|
||||
isEnabled: jest.fn(() => true), // default to false, override per test if needed
|
||||
math: jest.fn(() => 20), // default to false, override per test if needed
|
||||
removePorts: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('keyv');
|
||||
jest.mock('../models/Session');
|
||||
// jest.mock('../models/Session');
|
||||
// Mocking the getLogStores function
|
||||
jest.mock('./getLogStores', () => {
|
||||
return jest.fn().mockImplementation(() => {
|
||||
|
||||
@@ -39,7 +39,10 @@ async function connectDb() {
|
||||
});
|
||||
}
|
||||
cached.conn = await cached.promise;
|
||||
|
||||
return cached.conn;
|
||||
}
|
||||
|
||||
module.exports = connectDb;
|
||||
module.exports = {
|
||||
connectDb,
|
||||
};
|
||||
8
api/db/index.js
Normal file
8
api/db/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { createModels } = require('@librechat/data-schemas');
|
||||
const { connectDb } = require('./connect');
|
||||
const indexSync = require('./indexSync');
|
||||
|
||||
createModels(mongoose);
|
||||
|
||||
module.exports = { connectDb, indexSync };
|
||||
@@ -1,8 +1,11 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { MeiliSearch } = require('meilisearch');
|
||||
const { Conversation } = require('~/models/Conversation');
|
||||
const { Message } = require('~/models/Message');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Conversation = mongoose.models.Conversation;
|
||||
const Message = mongoose.models.Message;
|
||||
|
||||
const searchEnabled = isEnabled(process.env.SEARCH);
|
||||
const indexingDisabled = isEnabled(process.env.MEILI_NO_SYNC);
|
||||
@@ -29,7 +32,6 @@ async function indexSync() {
|
||||
if (!searchEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const client = MeiliSearchClient.getInstance();
|
||||
|
||||
5
api/db/models.js
Normal file
5
api/db/models.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { createModels } = require('@librechat/data-schemas');
|
||||
const models = createModels(mongoose);
|
||||
|
||||
module.exports = { ...models };
|
||||
@@ -1,4 +0,0 @@
|
||||
const connectDb = require('./connectDb');
|
||||
const indexSync = require('./indexSync');
|
||||
|
||||
module.exports = { connectDb, indexSync };
|
||||
@@ -1,7 +1,5 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { actionSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const Action = mongoose.model('action', actionSchema);
|
||||
const Action = require('~/db/models').Action;
|
||||
|
||||
/**
|
||||
* Update an action with new data without overwriting existing properties,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const mongoose = require('mongoose');
|
||||
const crypto = require('node:crypto');
|
||||
const { agentSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { SystemRoles, Tools, actionDelimiter } = require('librechat-data-provider');
|
||||
const { GLOBAL_PROJECT_NAME, EPHEMERAL_AGENT_ID, mcp_delimiter } =
|
||||
require('librechat-data-provider').Constants;
|
||||
@@ -13,9 +13,8 @@ const {
|
||||
} = require('./Project');
|
||||
const getLogStores = require('~/cache/getLogStores');
|
||||
const { getActions } = require('./Action');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Agent = mongoose.model('agent', agentSchema);
|
||||
const Agent = require('~/db/models').Agent;
|
||||
|
||||
/**
|
||||
* Create an agent with the provided data.
|
||||
@@ -481,7 +480,6 @@ const getListAgents = async (searchParameter) => {
|
||||
delete globalQuery.author;
|
||||
query = { $or: [globalQuery, query] };
|
||||
}
|
||||
|
||||
const agents = (
|
||||
await Agent.find(query, {
|
||||
id: 1,
|
||||
@@ -662,7 +660,6 @@ const generateActionMetadataHash = async (actionIds, actions) => {
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
Agent,
|
||||
getAgent,
|
||||
loadAgent,
|
||||
createAgent,
|
||||
|
||||
@@ -8,19 +8,21 @@ process.env.CREDS_IV = '0123456789abcdef';
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const {
|
||||
Agent,
|
||||
addAgentResourceFile,
|
||||
removeAgentResourceFiles,
|
||||
createAgent,
|
||||
updateAgent,
|
||||
getAgent,
|
||||
updateAgent,
|
||||
deleteAgent,
|
||||
createAgent,
|
||||
getListAgents,
|
||||
updateAgentProjects,
|
||||
addAgentResourceFile,
|
||||
removeAgentResourceFiles,
|
||||
} = require('./Agent');
|
||||
|
||||
const Agent = require('~/db/models').Agent;
|
||||
|
||||
describe('Agent Resource File Operations', () => {
|
||||
let mongoServer;
|
||||
|
||||
@@ -55,6 +57,7 @@ describe('Agent Resource File Operations', () => {
|
||||
|
||||
test('should add tool_resource to tools if missing', async () => {
|
||||
const agent = await createBasicAgent();
|
||||
|
||||
const fileId = uuidv4();
|
||||
const toolResource = 'file_search';
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { assistantSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const Assistant = mongoose.model('assistant', assistantSchema);
|
||||
const Assistant = require('~/db/models').Assistant;
|
||||
|
||||
/**
|
||||
* Update an assistant with new data without overwriting existing properties,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { balanceSchema } = require('@librechat/data-schemas');
|
||||
|
||||
module.exports = mongoose.model('Balance', balanceSchema);
|
||||
@@ -1,8 +1,7 @@
|
||||
const mongoose = require('mongoose');
|
||||
const logger = require('~/config/winston');
|
||||
const { bannerSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const Banner = mongoose.model('Banner', bannerSchema);
|
||||
const Banner = require('~/db/models').Banner;
|
||||
|
||||
/**
|
||||
* Retrieves the current active banner.
|
||||
@@ -28,4 +27,4 @@ const getBanner = async (user) => {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { Banner, getBanner };
|
||||
module.exports = { getBanner };
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const major = [0, 0];
|
||||
const minor = [0, 0];
|
||||
const patch = [0, 5];
|
||||
|
||||
const configSchema = mongoose.Schema(
|
||||
{
|
||||
tag: {
|
||||
type: String,
|
||||
required: true,
|
||||
validate: {
|
||||
validator: function (tag) {
|
||||
const [part1, part2, part3] = tag.replace('v', '').split('.').map(Number);
|
||||
|
||||
// Check if all parts are numbers
|
||||
if (isNaN(part1) || isNaN(part2) || isNaN(part3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if all parts are within their respective ranges
|
||||
if (part1 < major[0] || part1 > major[1]) {
|
||||
return false;
|
||||
}
|
||||
if (part2 < minor[0] || part2 > minor[1]) {
|
||||
return false;
|
||||
}
|
||||
if (part3 < patch[0] || part3 > patch[1]) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
message: 'Invalid tag value',
|
||||
},
|
||||
},
|
||||
searchEnabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
usersEnabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
startupCounts: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
{ timestamps: true },
|
||||
);
|
||||
|
||||
// Instance method
|
||||
configSchema.methods.incrementCount = function () {
|
||||
this.startupCounts += 1;
|
||||
};
|
||||
|
||||
// Static methods
|
||||
configSchema.statics.findByTag = async function (tag) {
|
||||
return await this.findOne({ tag }).lean();
|
||||
};
|
||||
|
||||
configSchema.statics.updateByTag = async function (tag, update) {
|
||||
return await this.findOneAndUpdate({ tag }, update, { new: true });
|
||||
};
|
||||
|
||||
const Config = mongoose.models.Config || mongoose.model('Config', configSchema);
|
||||
|
||||
module.exports = {
|
||||
getConfigs: async (filter) => {
|
||||
try {
|
||||
return await Config.find(filter).lean();
|
||||
} catch (error) {
|
||||
logger.error('Error getting configs', error);
|
||||
return { config: 'Error getting configs' };
|
||||
}
|
||||
},
|
||||
deleteConfigs: async (filter) => {
|
||||
try {
|
||||
return await Config.deleteMany(filter);
|
||||
} catch (error) {
|
||||
logger.error('Error deleting configs', error);
|
||||
return { config: 'Error deleting configs' };
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
const Conversation = require('./schema/convoSchema');
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getMessages, deleteMessages } = require('./Message');
|
||||
const logger = require('~/config/winston');
|
||||
|
||||
const Conversation = require('~/db/models').Conversation;
|
||||
|
||||
/**
|
||||
* Searches for a conversation by conversationId and returns a lean document with only conversationId and user.
|
||||
@@ -75,7 +77,6 @@ const getConvoFiles = async (conversationId) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Conversation,
|
||||
getConvoFiles,
|
||||
searchConversation,
|
||||
deleteNullOrEmptyConversations,
|
||||
@@ -155,7 +156,6 @@ module.exports = {
|
||||
{ cursor, limit = 25, isArchived = false, tags, search, order = 'desc' } = {},
|
||||
) => {
|
||||
const filters = [{ user }];
|
||||
|
||||
if (isArchived) {
|
||||
filters.push({ isArchived: true });
|
||||
} else {
|
||||
@@ -288,7 +288,6 @@ module.exports = {
|
||||
deleteConvos: async (user, filter) => {
|
||||
try {
|
||||
const userFilter = { ...filter, user };
|
||||
|
||||
const conversations = await Conversation.find(userFilter).select('conversationId');
|
||||
const conversationIds = conversations.map((c) => c.conversationId);
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Conversation = require('./schema/convoSchema');
|
||||
const logger = require('~/config/winston');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const { conversationTagSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const ConversationTag = mongoose.model('ConversationTag', conversationTagSchema);
|
||||
const ConversationTag = require('~/db/models').ConversationTag;
|
||||
const Conversation = require('~/db/models').Conversation;
|
||||
|
||||
/**
|
||||
* Retrieves all conversation tags for a user.
|
||||
@@ -140,13 +138,13 @@ const adjustPositions = async (user, oldPosition, newPosition) => {
|
||||
const position =
|
||||
oldPosition < newPosition
|
||||
? {
|
||||
$gt: Math.min(oldPosition, newPosition),
|
||||
$lte: Math.max(oldPosition, newPosition),
|
||||
}
|
||||
$gt: Math.min(oldPosition, newPosition),
|
||||
$lte: Math.max(oldPosition, newPosition),
|
||||
}
|
||||
: {
|
||||
$gte: Math.min(oldPosition, newPosition),
|
||||
$lt: Math.max(oldPosition, newPosition),
|
||||
};
|
||||
$gte: Math.min(oldPosition, newPosition),
|
||||
$lt: Math.max(oldPosition, newPosition),
|
||||
};
|
||||
|
||||
await ConversationTag.updateMany(
|
||||
{
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { EToolResources } = require('librechat-data-provider');
|
||||
const { fileSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const File = mongoose.model('File', fileSchema);
|
||||
const File = require('~/db/models').File;
|
||||
|
||||
/**
|
||||
* Finds a file by its file_id with additional query options.
|
||||
@@ -169,7 +168,6 @@ async function batchUpdateFiles(updates) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
File,
|
||||
findFileById,
|
||||
getFiles,
|
||||
getToolFilesByIds,
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { keySchema } = require('@librechat/data-schemas');
|
||||
|
||||
module.exports = mongoose.model('Key', keySchema);
|
||||
@@ -1,7 +1,7 @@
|
||||
const { z } = require('zod');
|
||||
const Message = require('./schema/messageSchema');
|
||||
const { logger } = require('~/config');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const Message = require('~/db/models').Message;
|
||||
const idSchema = z.string().uuid();
|
||||
|
||||
/**
|
||||
@@ -68,7 +68,6 @@ async function saveMessage(req, params, metadata) {
|
||||
logger.info(`---\`saveMessage\` context: ${metadata?.context}`);
|
||||
update.tokenCount = 0;
|
||||
}
|
||||
|
||||
const message = await Message.findOneAndUpdate(
|
||||
{ messageId: params.messageId, user: req.user.id },
|
||||
update,
|
||||
@@ -140,7 +139,6 @@ async function bulkSaveMessages(messages, overrideTimestamp = false) {
|
||||
upsert: true,
|
||||
},
|
||||
}));
|
||||
|
||||
const result = await Message.bulkWrite(bulkOps);
|
||||
return result;
|
||||
} catch (err) {
|
||||
@@ -355,7 +353,6 @@ async function deleteMessages(filter) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Message,
|
||||
saveMessage,
|
||||
bulkSaveMessages,
|
||||
recordMessage,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
jest.mock('mongoose');
|
||||
@@ -20,14 +19,20 @@ const mockSchema = {
|
||||
deleteMany: jest.fn(),
|
||||
};
|
||||
|
||||
mongoose.model.mockReturnValue(mockSchema);
|
||||
|
||||
jest.mock('~/models/schema/messageSchema', () => mockSchema);
|
||||
|
||||
jest.mock('~/config/winston', () => ({
|
||||
error: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockModels = {
|
||||
Message: {
|
||||
findOneAndUpdate: mockSchema.findOneAndUpdate,
|
||||
updateOne: mockSchema.updateOne,
|
||||
findOne: mockSchema.findOne,
|
||||
find: mockSchema.find,
|
||||
deleteMany: mockSchema.deleteMany,
|
||||
},
|
||||
};
|
||||
|
||||
const {
|
||||
saveMessage,
|
||||
getMessages,
|
||||
@@ -153,7 +158,7 @@ describe('Message Operations', () => {
|
||||
});
|
||||
|
||||
describe('Conversation Hijacking Prevention', () => {
|
||||
it('should not allow editing a message in another user\'s conversation', async () => {
|
||||
it("should not allow editing a message in another user's conversation", async () => {
|
||||
const attackerReq = { user: { id: 'attacker123' } };
|
||||
const victimConversationId = 'victim-convo-123';
|
||||
const victimMessageId = 'victim-msg-123';
|
||||
@@ -175,7 +180,7 @@ describe('Message Operations', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should not allow deleting messages from another user\'s conversation', async () => {
|
||||
it("should not allow deleting messages from another user's conversation", async () => {
|
||||
const attackerReq = { user: { id: 'attacker123' } };
|
||||
const victimConversationId = 'victim-convo-123';
|
||||
const victimMessageId = 'victim-msg-123';
|
||||
@@ -193,7 +198,7 @@ describe('Message Operations', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should not allow inserting a new message into another user\'s conversation', async () => {
|
||||
it("should not allow inserting a new message into another user's conversation", async () => {
|
||||
const attackerReq = { user: { id: 'attacker123' } };
|
||||
const victimConversationId = uuidv4(); // Use a valid UUID
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
const Preset = require('./schema/presetSchema');
|
||||
const { logger } = require('~/config');
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
|
||||
const Preset = require('~/db/models').Preset;
|
||||
|
||||
const getPreset = async (user, presetId) => {
|
||||
try {
|
||||
@@ -11,7 +13,6 @@ const getPreset = async (user, presetId) => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Preset,
|
||||
getPreset,
|
||||
getPresets: async (user, filter) => {
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
const { model } = require('mongoose');
|
||||
const mongoose = require('mongoose');
|
||||
const { GLOBAL_PROJECT_NAME } = require('librechat-data-provider').Constants;
|
||||
const { projectSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const Project = model('Project', projectSchema);
|
||||
const Project = require('~/db/models').Project;
|
||||
|
||||
/**
|
||||
* Retrieve a project by ID and convert the found project document to a plain object.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { ObjectId } = require('mongodb');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { SystemRoles, SystemCategories, Constants } = require('librechat-data-provider');
|
||||
const {
|
||||
getProjectByName,
|
||||
@@ -7,12 +8,10 @@ const {
|
||||
removeGroupIdsFromProject,
|
||||
removeGroupFromAllProjects,
|
||||
} = require('./Project');
|
||||
const { promptGroupSchema, promptSchema } = require('@librechat/data-schemas');
|
||||
const { escapeRegExp } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const PromptGroup = mongoose.model('PromptGroup', promptGroupSchema);
|
||||
const Prompt = mongoose.model('Prompt', promptSchema);
|
||||
const PromptGroup = require('~/db/models').PromptGroup;
|
||||
const Prompt = require('~/db/models').Prompt;
|
||||
|
||||
/**
|
||||
* Create a pipeline for the aggregation to get prompt groups
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
const mongoose = require('mongoose');
|
||||
const {
|
||||
CacheKeys,
|
||||
SystemRoles,
|
||||
@@ -7,11 +6,10 @@ const {
|
||||
permissionsSchema,
|
||||
removeNullishValues,
|
||||
} = require('librechat-data-provider');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const getLogStores = require('~/cache/getLogStores');
|
||||
const { roleSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Role = mongoose.model('Role', roleSchema);
|
||||
const Role = require('~/db/models').Role;
|
||||
|
||||
/**
|
||||
* Retrieve a role by name and convert the found role document to a plain object.
|
||||
@@ -282,7 +280,6 @@ const migrateRoleSchema = async function (roleName) {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
Role,
|
||||
getRoleByName,
|
||||
initializeRoles,
|
||||
updateRoleByName,
|
||||
|
||||
@@ -6,9 +6,11 @@ const {
|
||||
roleDefaults,
|
||||
PermissionTypes,
|
||||
} = require('librechat-data-provider');
|
||||
const { Role, getRoleByName, updateAccessPermissions, initializeRoles } = require('~/models/Role');
|
||||
const { getRoleByName, updateAccessPermissions, initializeRoles } = require('~/models/Role');
|
||||
const getLogStores = require('~/cache/getLogStores');
|
||||
|
||||
const Role = require('~/db/models').Role;
|
||||
|
||||
// Mock the cache
|
||||
jest.mock('~/cache/getLogStores', () =>
|
||||
jest.fn().mockReturnValue({
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const signPayload = require('~/server/services/signPayload');
|
||||
const { hashToken } = require('~/server/utils/crypto');
|
||||
const { sessionSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Session = mongoose.model('Session', sessionSchema);
|
||||
|
||||
const { REFRESH_TOKEN_EXPIRY } = process.env ?? {};
|
||||
const expires = eval(REFRESH_TOKEN_EXPIRY) ?? 1000 * 60 * 60 * 24 * 7; // 7 days default
|
||||
|
||||
/**
|
||||
* Error class for Session-related errors
|
||||
*/
|
||||
class SessionError extends Error {
|
||||
constructor(message, code = 'SESSION_ERROR') {
|
||||
super(message);
|
||||
this.name = 'SessionError';
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new session for a user
|
||||
* @param {string} userId - The ID of the user
|
||||
* @param {Object} options - Additional options for session creation
|
||||
* @param {Date} options.expiration - Custom expiration date
|
||||
* @returns {Promise<{session: Session, refreshToken: string}>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const createSession = async (userId, options = {}) => {
|
||||
if (!userId) {
|
||||
throw new SessionError('User ID is required', 'INVALID_USER_ID');
|
||||
}
|
||||
|
||||
try {
|
||||
const session = new Session({
|
||||
user: userId,
|
||||
expiration: options.expiration || new Date(Date.now() + expires),
|
||||
});
|
||||
const refreshToken = await generateRefreshToken(session);
|
||||
return { session, refreshToken };
|
||||
} catch (error) {
|
||||
logger.error('[createSession] Error creating session:', error);
|
||||
throw new SessionError('Failed to create session', 'CREATE_SESSION_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds a session by various parameters
|
||||
* @param {Object} params - Search parameters
|
||||
* @param {string} [params.refreshToken] - The refresh token to search by
|
||||
* @param {string} [params.userId] - The user ID to search by
|
||||
* @param {string} [params.sessionId] - The session ID to search by
|
||||
* @param {Object} [options] - Additional options
|
||||
* @param {boolean} [options.lean=true] - Whether to return plain objects instead of documents
|
||||
* @returns {Promise<Session|null>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const findSession = async (params, options = { lean: true }) => {
|
||||
try {
|
||||
const query = {};
|
||||
|
||||
if (!params.refreshToken && !params.userId && !params.sessionId) {
|
||||
throw new SessionError('At least one search parameter is required', 'INVALID_SEARCH_PARAMS');
|
||||
}
|
||||
|
||||
if (params.refreshToken) {
|
||||
const tokenHash = await hashToken(params.refreshToken);
|
||||
query.refreshTokenHash = tokenHash;
|
||||
}
|
||||
|
||||
if (params.userId) {
|
||||
query.user = params.userId;
|
||||
}
|
||||
|
||||
if (params.sessionId) {
|
||||
const sessionId = params.sessionId.sessionId || params.sessionId;
|
||||
if (!mongoose.Types.ObjectId.isValid(sessionId)) {
|
||||
throw new SessionError('Invalid session ID format', 'INVALID_SESSION_ID');
|
||||
}
|
||||
query._id = sessionId;
|
||||
}
|
||||
|
||||
// Add expiration check to only return valid sessions
|
||||
query.expiration = { $gt: new Date() };
|
||||
|
||||
const sessionQuery = Session.findOne(query);
|
||||
|
||||
if (options.lean) {
|
||||
return await sessionQuery.lean();
|
||||
}
|
||||
|
||||
return await sessionQuery.exec();
|
||||
} catch (error) {
|
||||
logger.error('[findSession] Error finding session:', error);
|
||||
throw new SessionError('Failed to find session', 'FIND_SESSION_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates session expiration
|
||||
* @param {Session|string} session - The session or session ID to update
|
||||
* @param {Date} [newExpiration] - Optional new expiration date
|
||||
* @returns {Promise<Session>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const updateExpiration = async (session, newExpiration) => {
|
||||
try {
|
||||
const sessionDoc = typeof session === 'string' ? await Session.findById(session) : session;
|
||||
|
||||
if (!sessionDoc) {
|
||||
throw new SessionError('Session not found', 'SESSION_NOT_FOUND');
|
||||
}
|
||||
|
||||
sessionDoc.expiration = newExpiration || new Date(Date.now() + expires);
|
||||
return await sessionDoc.save();
|
||||
} catch (error) {
|
||||
logger.error('[updateExpiration] Error updating session:', error);
|
||||
throw new SessionError('Failed to update session expiration', 'UPDATE_EXPIRATION_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a session by refresh token or session ID
|
||||
* @param {Object} params - Delete parameters
|
||||
* @param {string} [params.refreshToken] - The refresh token of the session to delete
|
||||
* @param {string} [params.sessionId] - The ID of the session to delete
|
||||
* @returns {Promise<Object>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const deleteSession = async (params) => {
|
||||
try {
|
||||
if (!params.refreshToken && !params.sessionId) {
|
||||
throw new SessionError(
|
||||
'Either refreshToken or sessionId is required',
|
||||
'INVALID_DELETE_PARAMS',
|
||||
);
|
||||
}
|
||||
|
||||
const query = {};
|
||||
|
||||
if (params.refreshToken) {
|
||||
query.refreshTokenHash = await hashToken(params.refreshToken);
|
||||
}
|
||||
|
||||
if (params.sessionId) {
|
||||
query._id = params.sessionId;
|
||||
}
|
||||
|
||||
const result = await Session.deleteOne(query);
|
||||
|
||||
if (result.deletedCount === 0) {
|
||||
logger.warn('[deleteSession] No session found to delete');
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error('[deleteSession] Error deleting session:', error);
|
||||
throw new SessionError('Failed to delete session', 'DELETE_SESSION_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes all sessions for a user
|
||||
* @param {string} userId - The ID of the user
|
||||
* @param {Object} [options] - Additional options
|
||||
* @param {boolean} [options.excludeCurrentSession] - Whether to exclude the current session
|
||||
* @param {string} [options.currentSessionId] - The ID of the current session to exclude
|
||||
* @returns {Promise<Object>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const deleteAllUserSessions = async (userId, options = {}) => {
|
||||
try {
|
||||
if (!userId) {
|
||||
throw new SessionError('User ID is required', 'INVALID_USER_ID');
|
||||
}
|
||||
|
||||
// Extract userId if it's passed as an object
|
||||
const userIdString = userId.userId || userId;
|
||||
|
||||
if (!mongoose.Types.ObjectId.isValid(userIdString)) {
|
||||
throw new SessionError('Invalid user ID format', 'INVALID_USER_ID_FORMAT');
|
||||
}
|
||||
|
||||
const query = { user: userIdString };
|
||||
|
||||
if (options.excludeCurrentSession && options.currentSessionId) {
|
||||
query._id = { $ne: options.currentSessionId };
|
||||
}
|
||||
|
||||
const result = await Session.deleteMany(query);
|
||||
|
||||
if (result.deletedCount > 0) {
|
||||
logger.debug(
|
||||
`[deleteAllUserSessions] Deleted ${result.deletedCount} sessions for user ${userIdString}.`,
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
logger.error('[deleteAllUserSessions] Error deleting user sessions:', error);
|
||||
throw new SessionError('Failed to delete user sessions', 'DELETE_ALL_SESSIONS_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a refresh token for a session
|
||||
* @param {Session} session - The session to generate a token for
|
||||
* @returns {Promise<string>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const generateRefreshToken = async (session) => {
|
||||
if (!session || !session.user) {
|
||||
throw new SessionError('Invalid session object', 'INVALID_SESSION');
|
||||
}
|
||||
|
||||
try {
|
||||
const expiresIn = session.expiration ? session.expiration.getTime() : Date.now() + expires;
|
||||
|
||||
if (!session.expiration) {
|
||||
session.expiration = new Date(expiresIn);
|
||||
}
|
||||
|
||||
const refreshToken = await signPayload({
|
||||
payload: {
|
||||
id: session.user,
|
||||
sessionId: session._id,
|
||||
},
|
||||
secret: process.env.JWT_REFRESH_SECRET,
|
||||
expirationTime: Math.floor((expiresIn - Date.now()) / 1000),
|
||||
});
|
||||
|
||||
session.refreshTokenHash = await hashToken(refreshToken);
|
||||
await session.save();
|
||||
|
||||
return refreshToken;
|
||||
} catch (error) {
|
||||
logger.error('[generateRefreshToken] Error generating refresh token:', error);
|
||||
throw new SessionError('Failed to generate refresh token', 'GENERATE_TOKEN_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Counts active sessions for a user
|
||||
* @param {string} userId - The ID of the user
|
||||
* @returns {Promise<number>}
|
||||
* @throws {SessionError}
|
||||
*/
|
||||
const countActiveSessions = async (userId) => {
|
||||
try {
|
||||
if (!userId) {
|
||||
throw new SessionError('User ID is required', 'INVALID_USER_ID');
|
||||
}
|
||||
|
||||
return await Session.countDocuments({
|
||||
user: userId,
|
||||
expiration: { $gt: new Date() },
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('[countActiveSessions] Error counting active sessions:', error);
|
||||
throw new SessionError('Failed to count active sessions', 'COUNT_SESSIONS_FAILED');
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
createSession,
|
||||
findSession,
|
||||
updateExpiration,
|
||||
deleteSession,
|
||||
deleteAllUserSessions,
|
||||
generateRefreshToken,
|
||||
countActiveSessions,
|
||||
SessionError,
|
||||
};
|
||||
@@ -1,11 +1,11 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { nanoid } = require('nanoid');
|
||||
const mongoose = require('mongoose');
|
||||
const { Constants } = require('librechat-data-provider');
|
||||
const { Conversation } = require('~/models/Conversation');
|
||||
const { shareSchema } = require('@librechat/data-schemas');
|
||||
const SharedLink = mongoose.model('SharedLink', shareSchema);
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getMessages } = require('./Message');
|
||||
const logger = require('~/config/winston');
|
||||
|
||||
const Conversation = require('~/db/models').Conversation;
|
||||
const SharedLink = require('~/db/models').SharedLink;
|
||||
|
||||
class ShareServiceError extends Error {
|
||||
constructor(message, code) {
|
||||
@@ -202,7 +202,6 @@ async function createSharedLink(user, conversationId) {
|
||||
if (!user || !conversationId) {
|
||||
throw new ShareServiceError('Missing required parameters', 'INVALID_PARAMS');
|
||||
}
|
||||
|
||||
try {
|
||||
const [existingShare, conversationMessages] = await Promise.all([
|
||||
SharedLink.findOne({ conversationId, isPublic: true }).select('-_id -__v -user').lean(),
|
||||
@@ -340,7 +339,6 @@ async function deleteSharedLink(user, shareId) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
SharedLink,
|
||||
getSharedLink,
|
||||
getSharedLinks,
|
||||
createSharedLink,
|
||||
|
||||
@@ -1,158 +1,5 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { findToken, updateToken, createToken } = require('~/models');
|
||||
const { encryptV2 } = require('~/server/utils/crypto');
|
||||
const { tokenSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
/**
|
||||
* Token model.
|
||||
* @type {mongoose.Model}
|
||||
*/
|
||||
const Token = mongoose.model('Token', tokenSchema);
|
||||
/**
|
||||
* Fixes the indexes for the Token collection from legacy TTL indexes to the new expiresAt index.
|
||||
*/
|
||||
async function fixIndexes() {
|
||||
try {
|
||||
if (
|
||||
process.env.NODE_ENV === 'CI' ||
|
||||
process.env.NODE_ENV === 'development' ||
|
||||
process.env.NODE_ENV === 'test'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const indexes = await Token.collection.indexes();
|
||||
logger.debug('Existing Token Indexes:', JSON.stringify(indexes, null, 2));
|
||||
const unwantedTTLIndexes = indexes.filter(
|
||||
(index) => index.key.createdAt === 1 && index.expireAfterSeconds !== undefined,
|
||||
);
|
||||
if (unwantedTTLIndexes.length === 0) {
|
||||
logger.debug('No unwanted Token indexes found.');
|
||||
return;
|
||||
}
|
||||
for (const index of unwantedTTLIndexes) {
|
||||
logger.debug(`Dropping unwanted Token index: ${index.name}`);
|
||||
await Token.collection.dropIndex(index.name);
|
||||
logger.debug(`Dropped Token index: ${index.name}`);
|
||||
}
|
||||
logger.debug('Token index cleanup completed successfully.');
|
||||
} catch (error) {
|
||||
logger.error('An error occurred while fixing Token indexes:', error);
|
||||
}
|
||||
}
|
||||
|
||||
fixIndexes();
|
||||
|
||||
/**
|
||||
* Creates a new Token instance.
|
||||
* @param {Object} tokenData - The data for the new Token.
|
||||
* @param {mongoose.Types.ObjectId} tokenData.userId - The user's ID. It is required.
|
||||
* @param {String} tokenData.email - The user's email.
|
||||
* @param {String} tokenData.token - The token. It is required.
|
||||
* @param {Number} tokenData.expiresIn - The number of seconds until the token expires.
|
||||
* @returns {Promise<mongoose.Document>} The new Token instance.
|
||||
* @throws Will throw an error if token creation fails.
|
||||
*/
|
||||
async function createToken(tokenData) {
|
||||
try {
|
||||
const currentTime = new Date();
|
||||
const expiresAt = new Date(currentTime.getTime() + tokenData.expiresIn * 1000);
|
||||
|
||||
const newTokenData = {
|
||||
...tokenData,
|
||||
createdAt: currentTime,
|
||||
expiresAt,
|
||||
};
|
||||
|
||||
return await Token.create(newTokenData);
|
||||
} catch (error) {
|
||||
logger.debug('An error occurred while creating token:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a Token document that matches the provided query.
|
||||
* @param {Object} query - The query to match against.
|
||||
* @param {mongoose.Types.ObjectId|String} query.userId - The ID of the user.
|
||||
* @param {String} query.token - The token value.
|
||||
* @param {String} [query.email] - The email of the user.
|
||||
* @param {String} [query.identifier] - Unique, alternative identifier for the token.
|
||||
* @returns {Promise<Object|null>} The matched Token document, or null if not found.
|
||||
* @throws Will throw an error if the find operation fails.
|
||||
*/
|
||||
async function findToken(query) {
|
||||
try {
|
||||
const conditions = [];
|
||||
|
||||
if (query.userId) {
|
||||
conditions.push({ userId: query.userId });
|
||||
}
|
||||
if (query.token) {
|
||||
conditions.push({ token: query.token });
|
||||
}
|
||||
if (query.email) {
|
||||
conditions.push({ email: query.email });
|
||||
}
|
||||
if (query.identifier) {
|
||||
conditions.push({ identifier: query.identifier });
|
||||
}
|
||||
|
||||
const token = await Token.findOne({
|
||||
$and: conditions,
|
||||
}).lean();
|
||||
|
||||
return token;
|
||||
} catch (error) {
|
||||
logger.debug('An error occurred while finding token:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a Token document that matches the provided query.
|
||||
* @param {Object} query - The query to match against.
|
||||
* @param {mongoose.Types.ObjectId|String} query.userId - The ID of the user.
|
||||
* @param {String} query.token - The token value.
|
||||
* @param {String} [query.email] - The email of the user.
|
||||
* @param {String} [query.identifier] - Unique, alternative identifier for the token.
|
||||
* @param {Object} updateData - The data to update the Token with.
|
||||
* @returns {Promise<mongoose.Document|null>} The updated Token document, or null if not found.
|
||||
* @throws Will throw an error if the update operation fails.
|
||||
*/
|
||||
async function updateToken(query, updateData) {
|
||||
try {
|
||||
return await Token.findOneAndUpdate(query, updateData, { new: true });
|
||||
} catch (error) {
|
||||
logger.debug('An error occurred while updating token:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all Token documents that match the provided token, user ID, or email.
|
||||
* @param {Object} query - The query to match against.
|
||||
* @param {mongoose.Types.ObjectId|String} query.userId - The ID of the user.
|
||||
* @param {String} query.token - The token value.
|
||||
* @param {String} [query.email] - The email of the user.
|
||||
* @param {String} [query.identifier] - Unique, alternative identifier for the token.
|
||||
* @returns {Promise<Object>} The result of the delete operation.
|
||||
* @throws Will throw an error if the delete operation fails.
|
||||
*/
|
||||
async function deleteTokens(query) {
|
||||
try {
|
||||
return await Token.deleteMany({
|
||||
$or: [
|
||||
{ userId: query.userId },
|
||||
{ token: query.token },
|
||||
{ email: query.email },
|
||||
{ identifier: query.identifier },
|
||||
],
|
||||
});
|
||||
} catch (error) {
|
||||
logger.debug('An error occurred while deleting tokens:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the OAuth token by creating or updating the token.
|
||||
@@ -191,9 +38,5 @@ async function handleOAuthToken({
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findToken,
|
||||
createToken,
|
||||
updateToken,
|
||||
deleteTokens,
|
||||
handleOAuthToken,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { toolCallSchema } = require('@librechat/data-schemas');
|
||||
const ToolCall = mongoose.model('ToolCall', toolCallSchema);
|
||||
|
||||
const ToolCall = require('~/db/models').ToolCall;
|
||||
|
||||
/**
|
||||
* Create a new tool call
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { transactionSchema } = require('@librechat/data-schemas');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const { getMultiplier, getCacheMultiplier } = require('./tx');
|
||||
const { logger } = require('~/config');
|
||||
const Balance = require('./Balance');
|
||||
|
||||
const Transaction = require('~/db/models').Transaction;
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
const cancelRate = 1.15;
|
||||
|
||||
@@ -140,19 +141,19 @@ const updateBalance = async ({ user, incrementValue, setValues }) => {
|
||||
};
|
||||
|
||||
/** Method to calculate and set the tokenValue for a transaction */
|
||||
transactionSchema.methods.calculateTokenValue = function () {
|
||||
if (!this.valueKey || !this.tokenType) {
|
||||
this.tokenValue = this.rawAmount;
|
||||
function calculateTokenValue(txn) {
|
||||
if (!txn.valueKey || !txn.tokenType) {
|
||||
txn.tokenValue = txn.rawAmount;
|
||||
}
|
||||
const { valueKey, tokenType, model, endpointTokenConfig } = this;
|
||||
const { valueKey, tokenType, model, endpointTokenConfig } = txn;
|
||||
const multiplier = Math.abs(getMultiplier({ valueKey, tokenType, model, endpointTokenConfig }));
|
||||
this.rate = multiplier;
|
||||
this.tokenValue = this.rawAmount * multiplier;
|
||||
if (this.context && this.tokenType === 'completion' && this.context === 'incomplete') {
|
||||
this.tokenValue = Math.ceil(this.tokenValue * cancelRate);
|
||||
this.rate *= cancelRate;
|
||||
txn.rate = multiplier;
|
||||
txn.tokenValue = txn.rawAmount * multiplier;
|
||||
if (txn.context && txn.tokenType === 'completion' && txn.context === 'incomplete') {
|
||||
txn.tokenValue = Math.ceil(txn.tokenValue * cancelRate);
|
||||
txn.rate *= cancelRate;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* New static method to create an auto-refill transaction that does NOT trigger a balance update.
|
||||
@@ -163,13 +164,13 @@ transactionSchema.methods.calculateTokenValue = function () {
|
||||
* @param {number} txData.rawAmount - The raw amount of tokens.
|
||||
* @returns {Promise<object>} - The created transaction.
|
||||
*/
|
||||
transactionSchema.statics.createAutoRefillTransaction = async function (txData) {
|
||||
async function createAutoRefillTransaction(txData) {
|
||||
if (txData.rawAmount != null && isNaN(txData.rawAmount)) {
|
||||
return;
|
||||
}
|
||||
const transaction = new this(txData);
|
||||
const transaction = new Transaction(txData);
|
||||
transaction.endpointTokenConfig = txData.endpointTokenConfig;
|
||||
transaction.calculateTokenValue();
|
||||
calculateTokenValue(transaction);
|
||||
await transaction.save();
|
||||
|
||||
const balanceResponse = await updateBalance({
|
||||
@@ -185,21 +186,20 @@ transactionSchema.statics.createAutoRefillTransaction = async function (txData)
|
||||
logger.debug('[Balance.check] Auto-refill performed', result);
|
||||
result.transaction = transaction;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to create a transaction and update the balance
|
||||
* @param {txData} txData - Transaction data.
|
||||
*/
|
||||
transactionSchema.statics.create = async function (txData) {
|
||||
const Transaction = this;
|
||||
async function createTransaction(txData) {
|
||||
if (txData.rawAmount != null && isNaN(txData.rawAmount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transaction = new Transaction(txData);
|
||||
transaction.endpointTokenConfig = txData.endpointTokenConfig;
|
||||
transaction.calculateTokenValue();
|
||||
calculateTokenValue(transaction);
|
||||
|
||||
await transaction.save();
|
||||
|
||||
@@ -209,7 +209,6 @@ transactionSchema.statics.create = async function (txData) {
|
||||
}
|
||||
|
||||
let incrementValue = transaction.tokenValue;
|
||||
|
||||
const balanceResponse = await updateBalance({
|
||||
user: transaction.user,
|
||||
incrementValue,
|
||||
@@ -221,21 +220,19 @@ transactionSchema.statics.create = async function (txData) {
|
||||
balance: balanceResponse.tokenCredits,
|
||||
[transaction.tokenType]: incrementValue,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to create a structured transaction and update the balance
|
||||
* @param {txData} txData - Transaction data.
|
||||
*/
|
||||
transactionSchema.statics.createStructured = async function (txData) {
|
||||
const Transaction = this;
|
||||
|
||||
async function createStructuredTransaction(txData) {
|
||||
const transaction = new Transaction({
|
||||
...txData,
|
||||
endpointTokenConfig: txData.endpointTokenConfig,
|
||||
});
|
||||
|
||||
transaction.calculateStructuredTokenValue();
|
||||
calculateStructuredTokenValue(transaction);
|
||||
|
||||
await transaction.save();
|
||||
|
||||
@@ -257,71 +254,69 @@ transactionSchema.statics.createStructured = async function (txData) {
|
||||
balance: balanceResponse.tokenCredits,
|
||||
[transaction.tokenType]: incrementValue,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** Method to calculate token value for structured tokens */
|
||||
transactionSchema.methods.calculateStructuredTokenValue = function () {
|
||||
if (!this.tokenType) {
|
||||
this.tokenValue = this.rawAmount;
|
||||
function calculateStructuredTokenValue(txn) {
|
||||
if (!txn.tokenType) {
|
||||
txn.tokenValue = txn.rawAmount;
|
||||
return;
|
||||
}
|
||||
|
||||
const { model, endpointTokenConfig } = this;
|
||||
const { model, endpointTokenConfig } = txn;
|
||||
|
||||
if (this.tokenType === 'prompt') {
|
||||
if (txn.tokenType === 'prompt') {
|
||||
const inputMultiplier = getMultiplier({ tokenType: 'prompt', model, endpointTokenConfig });
|
||||
const writeMultiplier =
|
||||
getCacheMultiplier({ cacheType: 'write', model, endpointTokenConfig }) ?? inputMultiplier;
|
||||
const readMultiplier =
|
||||
getCacheMultiplier({ cacheType: 'read', model, endpointTokenConfig }) ?? inputMultiplier;
|
||||
|
||||
this.rateDetail = {
|
||||
txn.rateDetail = {
|
||||
input: inputMultiplier,
|
||||
write: writeMultiplier,
|
||||
read: readMultiplier,
|
||||
};
|
||||
|
||||
const totalPromptTokens =
|
||||
Math.abs(this.inputTokens || 0) +
|
||||
Math.abs(this.writeTokens || 0) +
|
||||
Math.abs(this.readTokens || 0);
|
||||
Math.abs(txn.inputTokens || 0) +
|
||||
Math.abs(txn.writeTokens || 0) +
|
||||
Math.abs(txn.readTokens || 0);
|
||||
|
||||
if (totalPromptTokens > 0) {
|
||||
this.rate =
|
||||
(Math.abs(inputMultiplier * (this.inputTokens || 0)) +
|
||||
Math.abs(writeMultiplier * (this.writeTokens || 0)) +
|
||||
Math.abs(readMultiplier * (this.readTokens || 0))) /
|
||||
txn.rate =
|
||||
(Math.abs(inputMultiplier * (txn.inputTokens || 0)) +
|
||||
Math.abs(writeMultiplier * (txn.writeTokens || 0)) +
|
||||
Math.abs(readMultiplier * (txn.readTokens || 0))) /
|
||||
totalPromptTokens;
|
||||
} else {
|
||||
this.rate = Math.abs(inputMultiplier); // Default to input rate if no tokens
|
||||
txn.rate = Math.abs(inputMultiplier); // Default to input rate if no tokens
|
||||
}
|
||||
|
||||
this.tokenValue = -(
|
||||
Math.abs(this.inputTokens || 0) * inputMultiplier +
|
||||
Math.abs(this.writeTokens || 0) * writeMultiplier +
|
||||
Math.abs(this.readTokens || 0) * readMultiplier
|
||||
txn.tokenValue = -(
|
||||
Math.abs(txn.inputTokens || 0) * inputMultiplier +
|
||||
Math.abs(txn.writeTokens || 0) * writeMultiplier +
|
||||
Math.abs(txn.readTokens || 0) * readMultiplier
|
||||
);
|
||||
|
||||
this.rawAmount = -totalPromptTokens;
|
||||
} else if (this.tokenType === 'completion') {
|
||||
const multiplier = getMultiplier({ tokenType: this.tokenType, model, endpointTokenConfig });
|
||||
this.rate = Math.abs(multiplier);
|
||||
this.tokenValue = -Math.abs(this.rawAmount) * multiplier;
|
||||
this.rawAmount = -Math.abs(this.rawAmount);
|
||||
txn.rawAmount = -totalPromptTokens;
|
||||
} else if (txn.tokenType === 'completion') {
|
||||
const multiplier = getMultiplier({ tokenType: txn.tokenType, model, endpointTokenConfig });
|
||||
txn.rate = Math.abs(multiplier);
|
||||
txn.tokenValue = -Math.abs(txn.rawAmount) * multiplier;
|
||||
txn.rawAmount = -Math.abs(txn.rawAmount);
|
||||
}
|
||||
|
||||
if (this.context && this.tokenType === 'completion' && this.context === 'incomplete') {
|
||||
this.tokenValue = Math.ceil(this.tokenValue * cancelRate);
|
||||
this.rate *= cancelRate;
|
||||
if (this.rateDetail) {
|
||||
this.rateDetail = Object.fromEntries(
|
||||
Object.entries(this.rateDetail).map(([k, v]) => [k, v * cancelRate]),
|
||||
if (txn.context && txn.tokenType === 'completion' && txn.context === 'incomplete') {
|
||||
txn.tokenValue = Math.ceil(txn.tokenValue * cancelRate);
|
||||
txn.rate *= cancelRate;
|
||||
if (txn.rateDetail) {
|
||||
txn.rateDetail = Object.fromEntries(
|
||||
Object.entries(txn.rateDetail).map(([k, v]) => [k, v * cancelRate]),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Transaction = mongoose.model('Transaction', transactionSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries and retrieves transactions based on a given filter.
|
||||
@@ -340,4 +335,9 @@ async function getTransactions(filter) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Transaction, getTransactions };
|
||||
module.exports = {
|
||||
getTransactions,
|
||||
createTransaction,
|
||||
createAutoRefillTransaction,
|
||||
createStructuredTransaction,
|
||||
};
|
||||
|
||||
@@ -3,14 +3,13 @@ const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const { spendTokens, spendStructuredTokens } = require('./spendTokens');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const { getMultiplier, getCacheMultiplier } = require('./tx');
|
||||
const { Transaction } = require('./Transaction');
|
||||
const Balance = require('./Balance');
|
||||
const { createTransaction } = require('./Transaction');
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
// Mock the custom config module so we can control the balance flag.
|
||||
jest.mock('~/server/services/Config');
|
||||
|
||||
let mongoServer;
|
||||
|
||||
beforeAll(async () => {
|
||||
mongoServer = await MongoMemoryServer.create();
|
||||
const mongoUri = mongoServer.getUri();
|
||||
@@ -368,7 +367,7 @@ describe('NaN Handling Tests', () => {
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = await Transaction.create(txData);
|
||||
const result = await createTransaction(txData);
|
||||
|
||||
// Assert: No transaction should be created and balance remains unchanged.
|
||||
expect(result).toBeUndefined();
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { userSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const User = mongoose.model('User', userSchema);
|
||||
|
||||
module.exports = User;
|
||||
@@ -1,9 +1,11 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { ViolationTypes } = require('librechat-data-provider');
|
||||
const { Transaction } = require('./Transaction');
|
||||
const { createAutoRefillTransaction } = require('./Transaction');
|
||||
const { logViolation } = require('~/cache');
|
||||
const { getMultiplier } = require('./tx');
|
||||
const { logger } = require('~/config');
|
||||
const Balance = require('./Balance');
|
||||
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
function isInvalidDate(date) {
|
||||
return isNaN(date);
|
||||
@@ -60,7 +62,7 @@ const checkBalanceRecord = async function ({
|
||||
) {
|
||||
try {
|
||||
/** @type {{ rate: number, user: string, balance: number, transaction: import('@librechat/data-schemas').ITransaction}} */
|
||||
const result = await Transaction.createAutoRefillTransaction({
|
||||
const result = await createAutoRefillTransaction({
|
||||
user: user,
|
||||
tokenType: 'credits',
|
||||
context: 'autoRefill',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const { Message, getMessages, bulkSaveMessages } = require('./Message');
|
||||
const { getMessages, bulkSaveMessages } = require('./Message');
|
||||
|
||||
const Message = require('~/db/models').Message;
|
||||
|
||||
// Original version of buildTree function
|
||||
function buildTree({ messages, fileMap }) {
|
||||
@@ -42,7 +44,6 @@ function buildTree({ messages, fileMap }) {
|
||||
}
|
||||
|
||||
let mongod;
|
||||
|
||||
beforeAll(async () => {
|
||||
mongod = await MongoMemoryServer.create();
|
||||
const uri = mongod.getUri();
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
const {
|
||||
comparePassword,
|
||||
deleteUserById,
|
||||
generateToken,
|
||||
getUserById,
|
||||
updateUser,
|
||||
createUser,
|
||||
countUsers,
|
||||
findUser,
|
||||
} = require('./userMethods');
|
||||
const mongoose = require('mongoose');
|
||||
const { createMethods } = require('@librechat/data-schemas');
|
||||
const methods = createMethods(mongoose);
|
||||
const { comparePassword } = require('./userMethods');
|
||||
const {
|
||||
findFileById,
|
||||
createFile,
|
||||
@@ -26,32 +20,12 @@ const {
|
||||
deleteMessagesSince,
|
||||
deleteMessages,
|
||||
} = require('./Message');
|
||||
const {
|
||||
createSession,
|
||||
findSession,
|
||||
updateExpiration,
|
||||
deleteSession,
|
||||
deleteAllUserSessions,
|
||||
generateRefreshToken,
|
||||
countActiveSessions,
|
||||
} = require('./Session');
|
||||
const { getConvoTitle, getConvo, saveConvo, deleteConvos } = require('./Conversation');
|
||||
const { getPreset, getPresets, savePreset, deletePresets } = require('./Preset');
|
||||
const { createToken, findToken, updateToken, deleteTokens } = require('./Token');
|
||||
const Balance = require('./Balance');
|
||||
const User = require('./User');
|
||||
const Key = require('./Key');
|
||||
|
||||
module.exports = {
|
||||
...methods,
|
||||
comparePassword,
|
||||
deleteUserById,
|
||||
generateToken,
|
||||
getUserById,
|
||||
updateUser,
|
||||
createUser,
|
||||
countUsers,
|
||||
findUser,
|
||||
|
||||
findFileById,
|
||||
createFile,
|
||||
updateFile,
|
||||
@@ -77,21 +51,4 @@ module.exports = {
|
||||
getPresets,
|
||||
savePreset,
|
||||
deletePresets,
|
||||
|
||||
createToken,
|
||||
findToken,
|
||||
updateToken,
|
||||
deleteTokens,
|
||||
|
||||
createSession,
|
||||
findSession,
|
||||
updateExpiration,
|
||||
deleteSession,
|
||||
deleteAllUserSessions,
|
||||
generateRefreshToken,
|
||||
countActiveSessions,
|
||||
|
||||
User,
|
||||
Key,
|
||||
Balance,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { getRandomValues, hashToken } = require('~/server/utils/crypto');
|
||||
const { createToken, findToken } = require('./Token');
|
||||
const logger = require('~/config/winston');
|
||||
const { logger, hashToken } = require('@librechat/data-schemas');
|
||||
const { getRandomValues } = require('~/server/utils/crypto');
|
||||
const { createToken, findToken } = require('~/models');
|
||||
|
||||
/**
|
||||
* @module inviteUser
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongoMeili = require('../plugins/mongoMeili');
|
||||
|
||||
const { convoSchema } = require('@librechat/data-schemas');
|
||||
|
||||
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',
|
||||
});
|
||||
}
|
||||
|
||||
const Conversation = mongoose.models.Conversation || mongoose.model('Conversation', convoSchema);
|
||||
|
||||
module.exports = Conversation;
|
||||
@@ -1,16 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const mongoMeili = require('~/models/plugins/mongoMeili');
|
||||
const { messageSchema } = require('@librechat/data-schemas');
|
||||
|
||||
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',
|
||||
});
|
||||
}
|
||||
|
||||
const Message = mongoose.models.Message || mongoose.model('Message', messageSchema);
|
||||
|
||||
module.exports = Message;
|
||||
@@ -1,6 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { pluginAuthSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const PluginAuth = mongoose.models.Plugin || mongoose.model('PluginAuth', pluginAuthSchema);
|
||||
|
||||
module.exports = PluginAuth;
|
||||
@@ -1,6 +0,0 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { presetSchema } = require('@librechat/data-schemas');
|
||||
|
||||
const Preset = mongoose.models.Preset || mongoose.model('Preset', presetSchema);
|
||||
|
||||
module.exports = Preset;
|
||||
@@ -1,6 +1,5 @@
|
||||
const { Transaction } = require('./Transaction');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const { createTransaction, createStructuredTransaction } = require('./Transaction');
|
||||
/**
|
||||
* Creates up to two transactions to record the spending of tokens.
|
||||
*
|
||||
@@ -33,7 +32,7 @@ const spendTokens = async (txData, tokenUsage) => {
|
||||
let prompt, completion;
|
||||
try {
|
||||
if (promptTokens !== undefined) {
|
||||
prompt = await Transaction.create({
|
||||
prompt = await createTransaction({
|
||||
...txData,
|
||||
tokenType: 'prompt',
|
||||
rawAmount: promptTokens === 0 ? 0 : -Math.max(promptTokens, 0),
|
||||
@@ -41,7 +40,7 @@ const spendTokens = async (txData, tokenUsage) => {
|
||||
}
|
||||
|
||||
if (completionTokens !== undefined) {
|
||||
completion = await Transaction.create({
|
||||
completion = await createTransaction({
|
||||
...txData,
|
||||
tokenType: 'completion',
|
||||
rawAmount: completionTokens === 0 ? 0 : -Math.max(completionTokens, 0),
|
||||
@@ -101,7 +100,7 @@ const spendStructuredTokens = async (txData, tokenUsage) => {
|
||||
try {
|
||||
if (promptTokens) {
|
||||
const { input = 0, write = 0, read = 0 } = promptTokens;
|
||||
prompt = await Transaction.createStructured({
|
||||
prompt = await createStructuredTransaction({
|
||||
...txData,
|
||||
tokenType: 'prompt',
|
||||
inputTokens: -input,
|
||||
@@ -111,7 +110,7 @@ const spendStructuredTokens = async (txData, tokenUsage) => {
|
||||
}
|
||||
|
||||
if (completionTokens) {
|
||||
completion = await Transaction.create({
|
||||
completion = await createTransaction({
|
||||
...txData,
|
||||
tokenType: 'completion',
|
||||
rawAmount: -completionTokens,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const { Transaction } = require('./Transaction');
|
||||
const Balance = require('./Balance');
|
||||
const { spendTokens, spendStructuredTokens } = require('./spendTokens');
|
||||
const { createTransaction, createAutoRefillTransaction } = require('./Transaction');
|
||||
const Transaction = require('~/db/models').Transaction;
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
// Mock the logger to prevent console output during tests
|
||||
jest.mock('~/config', () => ({
|
||||
@@ -22,8 +23,7 @@ describe('spendTokens', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
mongoServer = await MongoMemoryServer.create();
|
||||
const mongoUri = mongoServer.getUri();
|
||||
await mongoose.connect(mongoUri);
|
||||
await mongoose.connect(mongoServer.getUri());
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
@@ -197,7 +197,7 @@ describe('spendTokens', () => {
|
||||
// Check that the transaction records show the adjusted values
|
||||
const transactionResults = await Promise.all(
|
||||
transactions.map((t) =>
|
||||
Transaction.create({
|
||||
createTransaction({
|
||||
...txData,
|
||||
tokenType: t.tokenType,
|
||||
rawAmount: t.rawAmount,
|
||||
@@ -280,7 +280,7 @@ describe('spendTokens', () => {
|
||||
|
||||
// Check the return values from Transaction.create directly
|
||||
// This is to verify that the incrementValue is not becoming positive
|
||||
const directResult = await Transaction.create({
|
||||
const directResult = await createTransaction({
|
||||
user: userId,
|
||||
conversationId: 'test-convo-3',
|
||||
model: 'gpt-4',
|
||||
@@ -607,7 +607,7 @@ describe('spendTokens', () => {
|
||||
const promises = [];
|
||||
for (let i = 0; i < numberOfRefills; i++) {
|
||||
promises.push(
|
||||
Transaction.createAutoRefillTransaction({
|
||||
createAutoRefillTransaction({
|
||||
user: userId,
|
||||
tokenType: 'credits',
|
||||
context: 'concurrent-refill-test',
|
||||
|
||||
@@ -1,159 +1,4 @@
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const signPayload = require('~/server/services/signPayload');
|
||||
const Balance = require('./Balance');
|
||||
const User = require('./User');
|
||||
|
||||
/**
|
||||
* Retrieve a user by ID and convert the found user document to a plain object.
|
||||
*
|
||||
* @param {string} userId - The ID of the user to find and return as a plain object.
|
||||
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
||||
* @returns {Promise<MongoUser>} A plain object representing the user document, or `null` if no user is found.
|
||||
*/
|
||||
const getUserById = async function (userId, fieldsToSelect = null) {
|
||||
const query = User.findById(userId);
|
||||
if (fieldsToSelect) {
|
||||
query.select(fieldsToSelect);
|
||||
}
|
||||
return await query.lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* Search for a single user based on partial data and return matching user document as plain object.
|
||||
* @param {Partial<MongoUser>} searchCriteria - The partial data to use for searching the user.
|
||||
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
||||
* @returns {Promise<MongoUser>} A plain object representing the user document, or `null` if no user is found.
|
||||
*/
|
||||
const findUser = async function (searchCriteria, fieldsToSelect = null) {
|
||||
const query = User.findOne(searchCriteria);
|
||||
if (fieldsToSelect) {
|
||||
query.select(fieldsToSelect);
|
||||
}
|
||||
return await query.lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* Update a user with new data without overwriting existing properties.
|
||||
*
|
||||
* @param {string} userId - The ID of the user to update.
|
||||
* @param {Object} updateData - An object containing the properties to update.
|
||||
* @returns {Promise<MongoUser>} The updated user document as a plain object, or `null` if no user is found.
|
||||
*/
|
||||
const updateUser = async function (userId, updateData) {
|
||||
const updateOperation = {
|
||||
$set: updateData,
|
||||
$unset: { expiresAt: '' }, // Remove the expiresAt field to prevent TTL
|
||||
};
|
||||
return await User.findByIdAndUpdate(userId, updateOperation, {
|
||||
new: true,
|
||||
runValidators: true,
|
||||
}).lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new user, optionally with a TTL of 1 week.
|
||||
* @param {MongoUser} data - The user data to be created, must contain user_id.
|
||||
* @param {boolean} [disableTTL=true] - Whether to disable the TTL. Defaults to `true`.
|
||||
* @param {boolean} [returnUser=false] - Whether to return the created user object.
|
||||
* @returns {Promise<ObjectId|MongoUser>} A promise that resolves to the created user document ID or user object.
|
||||
* @throws {Error} If a user with the same user_id already exists.
|
||||
*/
|
||||
const createUser = async (data, disableTTL = true, returnUser = false) => {
|
||||
const balance = await getBalanceConfig();
|
||||
const userData = {
|
||||
...data,
|
||||
expiresAt: disableTTL ? null : new Date(Date.now() + 604800 * 1000), // 1 week in milliseconds
|
||||
};
|
||||
|
||||
if (disableTTL) {
|
||||
delete userData.expiresAt;
|
||||
}
|
||||
|
||||
const user = await User.create(userData);
|
||||
|
||||
// If balance is enabled, create or update a balance record for the user using global.interfaceConfig.balance
|
||||
if (balance?.enabled && balance?.startBalance) {
|
||||
const update = {
|
||||
$inc: { tokenCredits: balance.startBalance },
|
||||
};
|
||||
|
||||
if (
|
||||
balance.autoRefillEnabled &&
|
||||
balance.refillIntervalValue != null &&
|
||||
balance.refillIntervalUnit != null &&
|
||||
balance.refillAmount != null
|
||||
) {
|
||||
update.$set = {
|
||||
autoRefillEnabled: true,
|
||||
refillIntervalValue: balance.refillIntervalValue,
|
||||
refillIntervalUnit: balance.refillIntervalUnit,
|
||||
refillAmount: balance.refillAmount,
|
||||
};
|
||||
}
|
||||
|
||||
await Balance.findOneAndUpdate({ user: user._id }, update, { upsert: true, new: true }).lean();
|
||||
}
|
||||
|
||||
if (returnUser) {
|
||||
return user.toObject();
|
||||
}
|
||||
return user._id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Count the number of user documents in the collection based on the provided filter.
|
||||
*
|
||||
* @param {Object} [filter={}] - The filter to apply when counting the documents.
|
||||
* @returns {Promise<number>} The count of documents that match the filter.
|
||||
*/
|
||||
const countUsers = async function (filter = {}) {
|
||||
return await User.countDocuments(filter);
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a user by their unique ID.
|
||||
*
|
||||
* @param {string} userId - The ID of the user to delete.
|
||||
* @returns {Promise<{ deletedCount: number }>} An object indicating the number of deleted documents.
|
||||
*/
|
||||
const deleteUserById = async function (userId) {
|
||||
try {
|
||||
const result = await User.deleteOne({ _id: userId });
|
||||
if (result.deletedCount === 0) {
|
||||
return { deletedCount: 0, message: 'No user found with that ID.' };
|
||||
}
|
||||
return { deletedCount: result.deletedCount, message: 'User was deleted successfully.' };
|
||||
} catch (error) {
|
||||
throw new Error('Error deleting user: ' + error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const { SESSION_EXPIRY } = process.env ?? {};
|
||||
const expires = eval(SESSION_EXPIRY) ?? 1000 * 60 * 15;
|
||||
|
||||
/**
|
||||
* Generates a JWT token for a given user.
|
||||
*
|
||||
* @param {MongoUser} user - The user for whom the token is being generated.
|
||||
* @returns {Promise<string>} A promise that resolves to a JWT token.
|
||||
*/
|
||||
const generateToken = async (user) => {
|
||||
if (!user) {
|
||||
throw new Error('No user provided');
|
||||
}
|
||||
|
||||
return await signPayload({
|
||||
payload: {
|
||||
id: user._id,
|
||||
username: user.username,
|
||||
provider: user.provider,
|
||||
email: user.email,
|
||||
},
|
||||
secret: process.env.JWT_SECRET,
|
||||
expirationTime: expires / 1000,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares the provided password with the user's password.
|
||||
@@ -179,11 +24,4 @@ const comparePassword = async (user, candidatePassword) => {
|
||||
|
||||
module.exports = {
|
||||
comparePassword,
|
||||
deleteUserById,
|
||||
generateToken,
|
||||
getUserById,
|
||||
countUsers,
|
||||
createUser,
|
||||
updateUser,
|
||||
findUser,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const openIdClient = require('openid-client');
|
||||
const cookies = require('cookie');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const openIdClient = require('openid-client');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
registerUser,
|
||||
resetPassword,
|
||||
@@ -8,9 +9,8 @@ const {
|
||||
requestPasswordReset,
|
||||
setOpenIDAuthTokens,
|
||||
} = require('~/server/services/AuthService');
|
||||
const { findSession, getUserById, deleteAllUserSessions, findUser } = require('~/models');
|
||||
const { findUser, getUserById, deleteAllUserSessions, findSession } = require('~/models');
|
||||
const { getOpenIdConfig } = require('~/strategies');
|
||||
const { logger } = require('~/config');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
|
||||
const registrationController = async (req, res) => {
|
||||
@@ -96,7 +96,10 @@ const refreshController = async (req, res) => {
|
||||
}
|
||||
|
||||
// Find the session with the hashed refresh token
|
||||
const session = await findSession({ userId: userId, refreshToken: refreshToken });
|
||||
const session = await findSession({
|
||||
userId: userId,
|
||||
refreshToken: refreshToken,
|
||||
});
|
||||
|
||||
if (session && session.expiration > new Date()) {
|
||||
const token = await setAuthTokens(userId, res, session._id);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const Balance = require('~/models/Balance');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
async function balanceController(req, res) {
|
||||
const balanceData = await Balance.findOne(
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
verifyTOTP,
|
||||
getTOTPSecret,
|
||||
verifyBackupCode,
|
||||
generateTOTPSecret,
|
||||
generateBackupCodes,
|
||||
verifyTOTP,
|
||||
verifyBackupCode,
|
||||
getTOTPSecret,
|
||||
} = require('~/server/services/twoFactorService');
|
||||
const { updateUser, getUserById } = require('~/models');
|
||||
const { logger } = require('~/config');
|
||||
const { getUserById, updateUser } = require('~/models');
|
||||
const { encryptV3 } = require('~/server/utils/crypto');
|
||||
|
||||
const safeAppTitle = (process.env.APP_TITLE || 'LibreChat').replace(/\s+/g, '');
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
const {
|
||||
Tools,
|
||||
Constants,
|
||||
FileSources,
|
||||
webSearchKeys,
|
||||
extractWebSearchEnvVars,
|
||||
} = require('librechat-data-provider');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
Balance,
|
||||
getFiles,
|
||||
updateUser,
|
||||
deleteFiles,
|
||||
@@ -16,7 +15,6 @@ const {
|
||||
deleteUserById,
|
||||
deleteAllUserSessions,
|
||||
} = require('~/models');
|
||||
const User = require('~/models/User');
|
||||
const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService');
|
||||
const { updateUserPluginsService, deleteUserKey } = require('~/server/services/UserService');
|
||||
const { verifyEmail, resendVerificationEmail } = require('~/server/services/AuthService');
|
||||
@@ -24,8 +22,10 @@ const { needsRefresh, getNewS3URL } = require('~/server/services/Files/S3/crud')
|
||||
const { processDeleteRequest } = require('~/server/services/Files/process');
|
||||
const { deleteAllSharedLinks } = require('~/models/Share');
|
||||
const { deleteToolCalls } = require('~/models/ToolCall');
|
||||
const { Transaction } = require('~/models/Transaction');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Transaction = require('~/db/models').Transaction;
|
||||
const Balance = require('~/db/models').Balance;
|
||||
const User = require('~/db/models').User;
|
||||
|
||||
const getUserController = async (req, res) => {
|
||||
/** @type {MongoUser} */
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
verifyTOTP,
|
||||
verifyBackupCode,
|
||||
getTOTPSecret,
|
||||
verifyBackupCode,
|
||||
} = require('~/server/services/twoFactorService');
|
||||
const { setAuthTokens } = require('~/server/services/AuthService');
|
||||
const { getUserById } = require('~/models/userMethods');
|
||||
const { logger } = require('~/config');
|
||||
const { getUserById } = require('~/models');
|
||||
|
||||
/**
|
||||
* Verifies the 2FA code during login using a temporary token.
|
||||
|
||||
@@ -9,8 +9,9 @@ const passport = require('passport');
|
||||
const mongoSanitize = require('express-mongo-sanitize');
|
||||
const fs = require('fs');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const { connectDb, indexSync } = require('~/db');
|
||||
|
||||
const { jwtLogin, passportLogin } = require('~/strategies');
|
||||
const { connectDb, indexSync } = require('~/lib/db');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { ldapLogin } = require('~/strategies');
|
||||
const { logger } = require('~/config');
|
||||
@@ -36,6 +37,7 @@ const startServer = async () => {
|
||||
axios.defaults.headers.common['Accept-Encoding'] = 'gzip';
|
||||
}
|
||||
await connectDb();
|
||||
|
||||
logger.info('Connected to MongoDB');
|
||||
await indexSync();
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
const { Keyv } = require('keyv');
|
||||
const uap = require('ua-parser-js');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { ViolationTypes } = require('librechat-data-provider');
|
||||
const { isEnabled, removePorts } = require('~/server/utils');
|
||||
const keyvMongo = require('~/cache/keyvMongo');
|
||||
const denyRequest = require('./denyRequest');
|
||||
const { getLogStores } = require('~/cache');
|
||||
const { findUser } = require('~/models');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const banCache = new Keyv({ store: keyvMongo, namespace: ViolationTypes.BAN, ttl: 0 });
|
||||
const message = 'Your account has been temporarily banned due to violations of our service.';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { getInvite } = require('~/models/inviteUser');
|
||||
const { deleteTokens } = require('~/models/Token');
|
||||
const { deleteTokens } = require('~/models');
|
||||
|
||||
async function checkInviteUser(req, res, next) {
|
||||
const token = req.body.token;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const Balance = require('~/models/Balance');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Balance = require('~/db/models').Balance;
|
||||
|
||||
/**
|
||||
* Middleware to synchronize user balance settings with current balance configuration.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const express = require('express');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { ContentTypes } = require('librechat-data-provider');
|
||||
const {
|
||||
saveConvo,
|
||||
@@ -13,8 +14,8 @@ const { requireJwtAuth, validateMessageReq } = require('~/server/middleware');
|
||||
const { cleanUpPrimaryKeyValue } = require('~/lib/utils/misc');
|
||||
const { getConvosQueried } = require('~/models/Conversation');
|
||||
const { countTokens } = require('~/server/utils');
|
||||
const { Message } = require('~/models/Message');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const Message = require('~/db/models').Message;
|
||||
|
||||
const router = express.Router();
|
||||
router.use(requireJwtAuth);
|
||||
@@ -40,7 +41,11 @@ router.get('/', async (req, res) => {
|
||||
const sortOrder = sortDirection === 'asc' ? 1 : -1;
|
||||
|
||||
if (conversationId && messageId) {
|
||||
const message = await Message.findOne({ conversationId, messageId, user: user }).lean();
|
||||
const message = await Message.findOne({
|
||||
conversationId,
|
||||
messageId,
|
||||
user: user,
|
||||
}).lean();
|
||||
response = { messages: message ? [message] : [], nextCursor: null };
|
||||
} else if (conversationId) {
|
||||
const filter = { conversationId, user: user };
|
||||
|
||||
@@ -17,9 +17,9 @@ const { logger, getFlowStateManager, sendEvent } = require('~/config');
|
||||
const { encryptV2, decryptV2 } = require('~/server/utils/crypto');
|
||||
const { getActions, deleteActions } = require('~/models/Action');
|
||||
const { deleteAssistant } = require('~/models/Assistant');
|
||||
const { findToken } = require('~/models/Token');
|
||||
const { logAxiosError } = require('~/utils');
|
||||
const { getLogStores } = require('~/cache');
|
||||
const { findToken } = require('~/models');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const toolNameRegex = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
@@ -3,24 +3,23 @@ const { webcrypto } = require('node:crypto');
|
||||
const { SystemRoles, errorsToString } = require('librechat-data-provider');
|
||||
const {
|
||||
findUser,
|
||||
countUsers,
|
||||
createUser,
|
||||
updateUser,
|
||||
getUserById,
|
||||
generateToken,
|
||||
deleteUserById,
|
||||
} = require('~/models/userMethods');
|
||||
const {
|
||||
createToken,
|
||||
findToken,
|
||||
deleteTokens,
|
||||
countUsers,
|
||||
getUserById,
|
||||
findSession,
|
||||
createToken,
|
||||
deleteTokens,
|
||||
deleteSession,
|
||||
createSession,
|
||||
generateToken,
|
||||
deleteUserById,
|
||||
generateRefreshToken,
|
||||
} = require('~/models');
|
||||
const { isEnabled, checkEmailConfig, sendEmail } = require('~/server/utils');
|
||||
const { isEmailDomainAllowed } = require('~/server/services/domains');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const { registerSchema } = require('~/strategies/validators');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
@@ -146,6 +145,7 @@ const verifyEmail = async (req) => {
|
||||
}
|
||||
|
||||
const updatedUser = await updateUser(emailVerificationData.userId, { emailVerified: true });
|
||||
|
||||
if (!updatedUser) {
|
||||
logger.warn(`[verifyEmail] [User update failed] [Email: ${decodedEmail}]`);
|
||||
return new Error('Failed to update user verification status');
|
||||
@@ -155,6 +155,7 @@ const verifyEmail = async (req) => {
|
||||
logger.info(`[verifyEmail] Email verification successful [Email: ${decodedEmail}]`);
|
||||
return { message: 'Email verification was successful', status: 'success' };
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a new user.
|
||||
* @param {MongoUser} user <email, password, name, username>
|
||||
@@ -216,7 +217,9 @@ const registerUser = async (user, additionalData = {}) => {
|
||||
|
||||
const emailEnabled = checkEmailConfig();
|
||||
const disableTTL = isEnabled(process.env.ALLOW_UNVERIFIED_EMAIL_LOGIN);
|
||||
const newUser = await createUser(newUserData, disableTTL, true);
|
||||
const balanceConfig = await getBalanceConfig();
|
||||
|
||||
const newUser = await createUser(newUserData, balanceConfig, disableTTL, true);
|
||||
newUserId = newUser._id;
|
||||
if (emailEnabled && !newUser.emailVerified) {
|
||||
await sendVerificationEmail({
|
||||
@@ -389,6 +392,7 @@ const setAuthTokens = async (userId, res, sessionId = null) => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function setOpenIDAuthTokens
|
||||
* Set OpenID Authentication Tokens
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { resizeImageBuffer } = require('../images/resize');
|
||||
const { updateUser } = require('~/models/userMethods');
|
||||
const { updateFile } = require('~/models/File');
|
||||
const { logger } = require('~/config');
|
||||
const { updateUser, updateFile } = require('~/models');
|
||||
const { saveBufferToAzure } = require('./crud');
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { resizeImageBuffer } = require('../images/resize');
|
||||
const { updateUser } = require('~/models/userMethods');
|
||||
const { updateUser, updateFile } = require('~/models');
|
||||
const { saveBufferToFirebase } = require('./crud');
|
||||
const { updateFile } = require('~/models/File');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
/**
|
||||
* Converts an image file to the target format. The function first resizes the image based on the specified
|
||||
|
||||
@@ -2,8 +2,7 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
const { resizeImageBuffer } = require('../images/resize');
|
||||
const { updateUser } = require('~/models/userMethods');
|
||||
const { updateFile } = require('~/models/File');
|
||||
const { updateUser, updateFile } = require('~/models');
|
||||
|
||||
/**
|
||||
* Converts an image file to the target format. The function first resizes the image based on the specified
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { resizeImageBuffer } = require('../images/resize');
|
||||
const { updateUser } = require('~/models/userMethods');
|
||||
const { updateUser, updateFile } = require('~/models');
|
||||
const { saveBufferToS3 } = require('./crud');
|
||||
const { updateFile } = require('~/models/File');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const defaultBasePath = 'images';
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const PluginAuth = require('~/models/schema/pluginAuthSchema');
|
||||
const { encrypt, decrypt } = require('~/server/utils/');
|
||||
const { encrypt, decrypt } = require('~/server/utils/crypto');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const PluginAuth = require('~/db/models').PluginAuth;
|
||||
|
||||
/**
|
||||
* Asynchronously retrieves and decrypts the authentication value for a user's plugin, based on a specified authentication field.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { ErrorTypes } = require('librechat-data-provider');
|
||||
const { encrypt, decrypt } = require('~/server/utils');
|
||||
const { updateUser, Key } = require('~/models');
|
||||
const { logger } = require('~/config');
|
||||
const { encrypt, decrypt } = require('~/server/utils/crypto');
|
||||
const { updateUser } = require('~/models');
|
||||
|
||||
const Key = require('~/db/models').Key;
|
||||
|
||||
/**
|
||||
* Updates the plugins for a user based on the action specified (install/uninstall).
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
/**
|
||||
* Signs a given payload using either the `jose` library (for Bun runtime) or `jsonwebtoken`.
|
||||
*
|
||||
* @async
|
||||
* @function
|
||||
* @param {Object} options - The options for signing the payload.
|
||||
* @param {Object} options.payload - The payload to be signed.
|
||||
* @param {string} options.secret - The secret key used for signing.
|
||||
* @param {number} options.expirationTime - The expiration time in seconds.
|
||||
* @returns {Promise<string>} Returns a promise that resolves to the signed JWT.
|
||||
* @throws {Error} Throws an error if there's an issue during signing.
|
||||
*
|
||||
* @example
|
||||
* const signedPayload = await signPayload({
|
||||
* payload: { userId: 123 },
|
||||
* secret: 'my-secret-key',
|
||||
* expirationTime: 3600
|
||||
* });
|
||||
*/
|
||||
async function signPayload({ payload, secret, expirationTime }) {
|
||||
return jwt.sign(payload, secret, { expiresIn: expirationTime });
|
||||
}
|
||||
|
||||
module.exports = signPayload;
|
||||
@@ -1,6 +1,6 @@
|
||||
const { webcrypto } = require('node:crypto');
|
||||
const { decryptV3, decryptV2 } = require('../utils/crypto');
|
||||
const { hashBackupCode } = require('~/server/utils/crypto');
|
||||
const { hashBackupCode, decryptV3, decryptV2 } = require('~/server/utils/crypto');
|
||||
const { updateUser } = require('~/models');
|
||||
|
||||
// Base32 alphabet for TOTP secret encoding.
|
||||
const BASE32_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
@@ -172,7 +172,6 @@ const verifyBackupCode = async ({ user, backupCode }) => {
|
||||
: codeObj,
|
||||
);
|
||||
// Update the user record with the marked backup code.
|
||||
const { updateUser } = require('~/models');
|
||||
await updateUser(user._id, { backupCodes: updatedBackupCodes });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,12 +106,6 @@ function decryptV3(encryptedValue) {
|
||||
return decrypted.toString('utf8');
|
||||
}
|
||||
|
||||
async function hashToken(str) {
|
||||
const data = new TextEncoder().encode(str);
|
||||
const hashBuffer = await webcrypto.subtle.digest('SHA-256', data);
|
||||
return Buffer.from(hashBuffer).toString('hex');
|
||||
}
|
||||
|
||||
async function getRandomValues(length) {
|
||||
if (!Number.isInteger(length) || length <= 0) {
|
||||
throw new Error('Length must be a positive integer');
|
||||
@@ -141,7 +135,6 @@ module.exports = {
|
||||
decryptV2,
|
||||
encryptV3,
|
||||
decryptV3,
|
||||
hashToken,
|
||||
hashBackupCode,
|
||||
getRandomValues,
|
||||
};
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
jest.mock('~/models/Message', () => ({
|
||||
Message: jest.fn(),
|
||||
}));
|
||||
jest.mock('~/models/Conversation', () => ({
|
||||
Conversation: jest.fn(),
|
||||
}));
|
||||
const { isEnabled, sanitizeFilename } = require('./handleText');
|
||||
|
||||
describe('isEnabled', () => {
|
||||
|
||||
@@ -18,17 +18,13 @@ const getProfileDetails = ({ idToken, profile }) => {
|
||||
|
||||
const decoded = jwt.decode(idToken);
|
||||
|
||||
logger.debug(
|
||||
`Decoded Apple JWT: ${JSON.stringify(decoded, null, 2)}`,
|
||||
);
|
||||
logger.debug(`Decoded Apple JWT: ${JSON.stringify(decoded, null, 2)}`);
|
||||
|
||||
return {
|
||||
email: decoded.email,
|
||||
id: decoded.sub,
|
||||
avatarUrl: null, // Apple does not provide an avatar URL
|
||||
username: decoded.email
|
||||
? decoded.email.split('@')[0].toLowerCase()
|
||||
: `user_${decoded.sub}`,
|
||||
username: decoded.email ? decoded.email.split('@')[0].toLowerCase() : `user_${decoded.sub}`,
|
||||
name: decoded.name
|
||||
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
||||
: profile.displayName || null,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
const mongoose = require('mongoose');
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Strategy: AppleStrategy } = require('passport-apple');
|
||||
const socialLogin = require('./socialLogin');
|
||||
const User = require('~/models/User');
|
||||
const { logger } = require('~/config');
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const { createSocialUser, handleExistingUser } = require('./process');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { findUser } = require('~/models');
|
||||
const socialLogin = require('./socialLogin');
|
||||
|
||||
const User = require('~/db/models').User;
|
||||
|
||||
// Mocking external dependencies
|
||||
jest.mock('jsonwebtoken');
|
||||
@@ -24,16 +24,12 @@ jest.mock('./process', () => ({
|
||||
jest.mock('~/server/utils', () => ({
|
||||
isEnabled: jest.fn(),
|
||||
}));
|
||||
jest.mock('~/models', () => ({
|
||||
findUser: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('Apple Login Strategy', () => {
|
||||
let mongoServer;
|
||||
let appleStrategyInstance;
|
||||
const OLD_ENV = process.env;
|
||||
let getProfileDetails;
|
||||
|
||||
// Start and stop in-memory MongoDB
|
||||
beforeAll(async () => {
|
||||
mongoServer = await MongoMemoryServer.create();
|
||||
@@ -64,7 +60,6 @@ describe('Apple Login Strategy', () => {
|
||||
|
||||
// Define getProfileDetails within the test scope
|
||||
getProfileDetails = ({ idToken, profile }) => {
|
||||
console.log('getProfileDetails called with idToken:', idToken);
|
||||
if (!idToken) {
|
||||
logger.error('idToken is missing');
|
||||
throw new Error('idToken is missing');
|
||||
@@ -84,9 +79,7 @@ describe('Apple Login Strategy', () => {
|
||||
email: decoded.email,
|
||||
id: decoded.sub,
|
||||
avatarUrl: null, // Apple does not provide an avatar URL
|
||||
username: decoded.email
|
||||
? decoded.email.split('@')[0].toLowerCase()
|
||||
: `user_${decoded.sub}`,
|
||||
username: decoded.email ? decoded.email.split('@')[0].toLowerCase() : `user_${decoded.sub}`,
|
||||
name: decoded.name
|
||||
? `${decoded.name.firstName} ${decoded.name.lastName}`
|
||||
: profile.displayName || null,
|
||||
@@ -96,8 +89,12 @@ describe('Apple Login Strategy', () => {
|
||||
|
||||
// Mock isEnabled based on environment variable
|
||||
isEnabled.mockImplementation((flag) => {
|
||||
if (flag === 'true') { return true; }
|
||||
if (flag === 'false') { return false; }
|
||||
if (flag === 'true') {
|
||||
return true;
|
||||
}
|
||||
if (flag === 'false') {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -154,9 +151,7 @@ describe('Apple Login Strategy', () => {
|
||||
});
|
||||
|
||||
expect(jwt.decode).toHaveBeenCalledWith('fake_id_token');
|
||||
expect(logger.debug).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Decoded Apple JWT'),
|
||||
);
|
||||
expect(logger.debug).toHaveBeenCalledWith(expect.stringContaining('Decoded Apple JWT'));
|
||||
expect(profileDetails).toEqual({
|
||||
email: 'john.doe@example.com',
|
||||
id: 'apple-sub-1234',
|
||||
@@ -209,12 +204,13 @@ describe('Apple Login Strategy', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jwt.decode.mockReturnValue(decodedToken);
|
||||
findUser.mockImplementation(({ email }) => User.findOne({ email }));
|
||||
User.findUser = jest.fn();
|
||||
User.findUser.mockImplementation(({ email }) => User.findOne({ email }));
|
||||
});
|
||||
|
||||
it('should create a new user if one does not exist and registration is allowed', async () => {
|
||||
// Mock findUser to return null (user does not exist)
|
||||
findUser.mockResolvedValue(null);
|
||||
User.findUser.mockResolvedValue(null);
|
||||
|
||||
// Mock createSocialUser to create a user
|
||||
createSocialUser.mockImplementation(async (userData) => {
|
||||
@@ -260,7 +256,7 @@ describe('Apple Login Strategy', () => {
|
||||
await existingUser.save();
|
||||
|
||||
// Mock findUser to return the existing user
|
||||
findUser.mockResolvedValue(existingUser);
|
||||
User.findUser.mockResolvedValue(existingUser);
|
||||
|
||||
// Mock handleExistingUser to update avatarUrl
|
||||
handleExistingUser.mockImplementation(async (user, avatarUrl) => {
|
||||
@@ -297,7 +293,7 @@ describe('Apple Login Strategy', () => {
|
||||
appleStrategyInstance._verify(
|
||||
fakeAccessToken,
|
||||
fakeRefreshToken,
|
||||
null, // idToken is missing
|
||||
null, // idToken is missing
|
||||
mockProfile,
|
||||
(err, user) => {
|
||||
mockVerifyCallback(err, user);
|
||||
@@ -344,7 +340,7 @@ describe('Apple Login Strategy', () => {
|
||||
|
||||
it('should handle errors during user creation', async () => {
|
||||
// Mock findUser to return null (user does not exist)
|
||||
findUser.mockResolvedValue(null);
|
||||
User.findUser.mockResolvedValue(null);
|
||||
|
||||
// Mock createSocialUser to throw an error
|
||||
createSocialUser.mockImplementation(() => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { SystemRoles } = require('librechat-data-provider');
|
||||
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
|
||||
const { getUserById, updateUser } = require('~/models');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
// JWT strategy
|
||||
const jwtLogin = () =>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const fs = require('fs');
|
||||
const LdapStrategy = require('passport-ldapauth');
|
||||
const { SystemRoles } = require('librechat-data-provider');
|
||||
const { findUser, createUser, updateUser } = require('~/models/userMethods');
|
||||
const { countUsers } = require('~/models/userMethods');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { createUser, findUser, updateUser, countUsers } = require('~/models');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const logger = require('~/utils/logger');
|
||||
|
||||
const {
|
||||
LDAP_URL,
|
||||
@@ -124,7 +124,8 @@ const ldapLogin = new LdapStrategy(ldapOptions, async (userinfo, done) => {
|
||||
name: fullName,
|
||||
role: isFirstRegisteredUser ? SystemRoles.ADMIN : SystemRoles.USER,
|
||||
};
|
||||
const userId = await createUser(user);
|
||||
const balanceConfig = await getBalanceConfig();
|
||||
const userId = await createUser(user, balanceConfig);
|
||||
user._id = userId;
|
||||
} else {
|
||||
// Users registered in LDAP are assumed to have their user information managed in LDAP,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { errorsToString } = require('librechat-data-provider');
|
||||
const { Strategy: PassportLocalStrategy } = require('passport-local');
|
||||
const { findUser, comparePassword, updateUser } = require('~/models');
|
||||
const { isEnabled, checkEmailConfig } = require('~/server/utils');
|
||||
const { findUser, comparePassword, updateUser } = require('~/models');
|
||||
const { loginSchema } = require('./validators');
|
||||
const logger = require('~/utils/logger');
|
||||
|
||||
// Unix timestamp for 2024-06-07 15:20:18 Eastern Time
|
||||
const verificationEnabledTimestamp = 1717788018;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
const { CacheKeys } = require('librechat-data-provider');
|
||||
const fetch = require('node-fetch');
|
||||
const passport = require('passport');
|
||||
const jwtDecode = require('jsonwebtoken/decode');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const client = require('openid-client');
|
||||
const jwtDecode = require('jsonwebtoken/decode');
|
||||
const { CacheKeys } = require('librechat-data-provider');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { hashToken, logger } = require('@librechat/data-schemas');
|
||||
const { Strategy: OpenIDStrategy } = require('openid-client/passport');
|
||||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
const { findUser, createUser, updateUser } = require('~/models/userMethods');
|
||||
const { hashToken } = require('~/server/utils/crypto');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { logger } = require('~/config');
|
||||
const { findUser, createUser, updateUser } = require('~/models');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const getLogStores = require('~/cache/getLogStores');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
|
||||
/**
|
||||
* @typedef {import('openid-client').ClientMetadata} ClientMetadata
|
||||
@@ -297,7 +297,10 @@ async function setupOpenId() {
|
||||
emailVerified: userinfo.email_verified || false,
|
||||
name: fullName,
|
||||
};
|
||||
user = await createUser(user, true, true);
|
||||
|
||||
const balanceConfig = await getBalanceConfig();
|
||||
|
||||
user = await createUser(user, balanceConfig, true, true);
|
||||
} else {
|
||||
user.provider = 'openid';
|
||||
user.openidId = userinfo.sub;
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
const fetch = require('node-fetch');
|
||||
const mongoose = require('mongoose');
|
||||
const jwtDecode = require('jsonwebtoken/decode');
|
||||
const { findUser, createUser, updateUser } = require('~/models/userMethods');
|
||||
const { setupOpenId } = require('./openidStrategy');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
|
||||
// --- Mocks ---
|
||||
const mockCreateUser = jest.fn();
|
||||
const mockFindUser = jest.fn();
|
||||
const mockUpdateUser = jest.fn();
|
||||
|
||||
const mockModels = {
|
||||
User: {
|
||||
createUser: mockCreateUser,
|
||||
findUser: mockFindUser,
|
||||
updateUser: mockUpdateUser,
|
||||
},
|
||||
};
|
||||
|
||||
jest.mock('~/server/services/Config', () => ({
|
||||
getBalanceConfig: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('node-fetch');
|
||||
jest.mock('jsonwebtoken/decode');
|
||||
jest.mock('~/server/services/Files/strategies', () => ({
|
||||
@@ -11,11 +28,7 @@ jest.mock('~/server/services/Files/strategies', () => ({
|
||||
saveBuffer: jest.fn().mockResolvedValue('/fake/path/to/avatar.png'),
|
||||
})),
|
||||
}));
|
||||
jest.mock('~/models/userMethods', () => ({
|
||||
findUser: jest.fn(),
|
||||
createUser: jest.fn(),
|
||||
updateUser: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('~/server/utils/crypto', () => ({
|
||||
hashToken: jest.fn().mockResolvedValue('hashed-token'),
|
||||
}));
|
||||
@@ -109,7 +122,7 @@ describe('setupOpenId', () => {
|
||||
picture: 'https://example.com/avatar.png',
|
||||
}),
|
||||
};
|
||||
|
||||
const User = require('~/db/models').User;
|
||||
beforeEach(async () => {
|
||||
// Clear previous mock calls and reset implementations
|
||||
jest.clearAllMocks();
|
||||
@@ -134,13 +147,16 @@ describe('setupOpenId', () => {
|
||||
roles: ['requiredRole'],
|
||||
});
|
||||
|
||||
User.findUser = jest.fn();
|
||||
// By default, assume that no user is found, so createUser will be called
|
||||
findUser.mockResolvedValue(null);
|
||||
createUser.mockImplementation(async (userData) => {
|
||||
|
||||
const balance = await getBalanceConfig.mockResolvedValue({ enabled: false });
|
||||
User.createUser.mockImplementation(async (userData, balance) => {
|
||||
// simulate created user with an _id property
|
||||
return { _id: 'newUserId', ...userData };
|
||||
});
|
||||
updateUser.mockImplementation(async (id, userData) => {
|
||||
// User.updateUser = jest.fn();
|
||||
User.updateUser.mockImplementation(async (id, userData) => {
|
||||
return { _id: id, ...userData };
|
||||
});
|
||||
|
||||
@@ -166,7 +182,7 @@ describe('setupOpenId', () => {
|
||||
|
||||
// Assert
|
||||
expect(user.username).toBe(userinfo.username);
|
||||
expect(createUser).toHaveBeenCalledWith(
|
||||
expect(User.createUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
provider: 'openid',
|
||||
openidId: userinfo.sub,
|
||||
@@ -174,6 +190,7 @@ describe('setupOpenId', () => {
|
||||
email: userinfo.email,
|
||||
name: `${userinfo.given_name} ${userinfo.family_name}`,
|
||||
}),
|
||||
{ enabled: false },
|
||||
true,
|
||||
true,
|
||||
);
|
||||
@@ -191,8 +208,9 @@ describe('setupOpenId', () => {
|
||||
|
||||
// Assert
|
||||
expect(user.username).toBe(expectUsername);
|
||||
expect(createUser).toHaveBeenCalledWith(
|
||||
expect(User.createUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ username: expectUsername }),
|
||||
{ enabled: false },
|
||||
true,
|
||||
true,
|
||||
);
|
||||
@@ -210,8 +228,9 @@ describe('setupOpenId', () => {
|
||||
|
||||
// Assert
|
||||
expect(user.username).toBe(expectUsername);
|
||||
expect(createUser).toHaveBeenCalledWith(
|
||||
expect(User.createUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ username: expectUsername }),
|
||||
{ enabled: false },
|
||||
true,
|
||||
true,
|
||||
);
|
||||
@@ -227,8 +246,9 @@ describe('setupOpenId', () => {
|
||||
|
||||
// Assert – username should equal the sub (converted as-is)
|
||||
expect(user.username).toBe(userinfo.sub);
|
||||
expect(createUser).toHaveBeenCalledWith(
|
||||
expect(User.createUser).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ username: userinfo.sub }),
|
||||
{ enabled: false },
|
||||
true,
|
||||
true,
|
||||
);
|
||||
@@ -268,11 +288,8 @@ describe('setupOpenId', () => {
|
||||
username: '',
|
||||
name: '',
|
||||
};
|
||||
findUser.mockImplementation(async (query) => {
|
||||
if (query.openidId === tokenset.claims().sub || query.email === tokenset.claims().email) {
|
||||
return existingUser;
|
||||
}
|
||||
return null;
|
||||
mockFindUser.mockImplementation(async (query) => {
|
||||
return existingUser;
|
||||
});
|
||||
|
||||
const userinfo = tokenset.claims();
|
||||
@@ -281,7 +298,7 @@ describe('setupOpenId', () => {
|
||||
await validate(tokenset);
|
||||
|
||||
// Assert – updateUser should be called and the user object updated
|
||||
expect(updateUser).toHaveBeenCalledWith(
|
||||
expect(User.updateUser).toHaveBeenCalledWith(
|
||||
existingUser._id,
|
||||
expect.objectContaining({
|
||||
provider: 'openid',
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const { FileSources } = require('librechat-data-provider');
|
||||
const { createUser, updateUser, getUserById } = require('~/models/userMethods');
|
||||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
const { resizeAvatar } = require('~/server/services/Files/images/avatar');
|
||||
const { updateUser, createUser, getUserById } = require('~/models');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
|
||||
/**
|
||||
* Updates the avatar URL of an existing user. If the user's avatar URL does not include the query parameter
|
||||
@@ -78,7 +79,8 @@ const createSocialUser = async ({
|
||||
emailVerified,
|
||||
};
|
||||
|
||||
const newUserId = await createUser(update);
|
||||
const balanceConfig = await getBalanceConfig();
|
||||
const newUserId = await createUser(update, balanceConfig);
|
||||
const fileStrategy = process.env.CDN_PROVIDER;
|
||||
const isLocal = fileStrategy === FileSources.local;
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const fetch = require('node-fetch');
|
||||
const passport = require('passport');
|
||||
const { hashToken, logger } = require('@librechat/data-schemas');
|
||||
const { Strategy: SamlStrategy } = require('@node-saml/passport-saml');
|
||||
const { findUser, createUser, updateUser } = require('~/models/userMethods');
|
||||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
const { hashToken } = require('~/server/utils/crypto');
|
||||
const { logger } = require('~/config');
|
||||
const { findUser, createUser, updateUser } = require('~/models');
|
||||
const { getBalanceConfig } = require('~/server/services/Config');
|
||||
const paths = require('~/config/paths');
|
||||
|
||||
let crypto;
|
||||
@@ -218,7 +218,8 @@ async function setupSaml() {
|
||||
emailVerified: true,
|
||||
name: fullName,
|
||||
};
|
||||
user = await createUser(user, true, true);
|
||||
const balanceConfig = await getBalanceConfig();
|
||||
user = await createUser(user, balanceConfig, true, true);
|
||||
} else {
|
||||
user.provider = 'saml';
|
||||
user.samlId = profile.nameID;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { createSocialUser, handleExistingUser } = require('./process');
|
||||
const { isEnabled } = require('~/server/utils');
|
||||
const { findUser } = require('~/models');
|
||||
const { logger } = require('~/config');
|
||||
|
||||
const socialLogin =
|
||||
(provider, getProfileDetails) => async (accessToken, refreshToken, idToken, profile, cb) => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const { isEnabled } = require('~/server/utils/handleText');
|
||||
const { Transaction } = require('~/models/Transaction');
|
||||
const User = require('~/models/User');
|
||||
const { createTransaction } = require('~/models/Transaction');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
@@ -78,7 +79,7 @@ const connect = require('./connect');
|
||||
*/
|
||||
let result;
|
||||
try {
|
||||
result = await Transaction.create({
|
||||
result = await createTransaction({
|
||||
user: user._id,
|
||||
tokenType: 'credits',
|
||||
context: 'admin',
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const banViolation = require('~/cache/banViolation');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -5,7 +5,7 @@ const moduleAlias = require('module-alias');
|
||||
const basePath = path.resolve(__dirname, '..', 'api');
|
||||
moduleAlias.addAlias('~', basePath);
|
||||
|
||||
const connectDb = require('~/lib/db/connectDb');
|
||||
const { connectDb } = require('~/db/connect');
|
||||
require('./helpers');
|
||||
|
||||
async function connect() {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { registerUser } = require('~/server/services/AuthService');
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { sendEmail, checkEmailConfig } = require('~/server/utils');
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const { createInvite } = require('~/models/inviteUser');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User, Balance } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { silentExit } = require('./helpers');
|
||||
const Balance = require('~/models/Balance');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const path = require('path');
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const User = require('../api/models/User');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
const connect = require('./connect');
|
||||
|
||||
const listUsers = async () => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
await connect();
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { User, Balance } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
const { isEnabled } = require('~/server/utils/handleText');
|
||||
const User = require('~/models/User');
|
||||
const connect = require('./connect');
|
||||
const Balance = require('~/models/Balance');
|
||||
|
||||
(async () => {
|
||||
await connect();
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
const { v5: uuidv5 } = require('uuid');
|
||||
const { Banner } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { askQuestion, askMultiLineQuestion, silentExit } = require('./helpers');
|
||||
const { Banner } = require('~/models/Banner');
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const path = require('path');
|
||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||
const { silentExit } = require('./helpers');
|
||||
const Conversation = require('~/models/schema/convoSchema');
|
||||
const Message = require('~/models/schema/messageSchema');
|
||||
const User = require('~/models/User');
|
||||
const { User, Conversation, Message } = require('@librechat/data-schemas').createModels(mongoose);
|
||||
const connect = require('./connect');
|
||||
|
||||
(async () => {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import connectDb from '@librechat/backend/lib/db/connectDb';
|
||||
import { connectDb } from '@librechat/backend/db/connect';
|
||||
import {
|
||||
deleteMessages,
|
||||
findUser,
|
||||
deleteConvos,
|
||||
User,
|
||||
deleteMessages,
|
||||
deleteAllUserSessions,
|
||||
Balance,
|
||||
} from '@librechat/backend/models';
|
||||
import { Transaction } from '@librechat/backend/models/Transaction';
|
||||
|
||||
type TUser = { email: string; password: string };
|
||||
|
||||
export default async function cleanupUser(user: TUser) {
|
||||
@@ -16,28 +15,38 @@ export default async function cleanupUser(user: TUser) {
|
||||
const db = await connectDb();
|
||||
console.log('🤖: ✅ Connected to Database');
|
||||
|
||||
const { _id: user } = await User.findOne({ email }).lean();
|
||||
const foundUser = await findUser({ email });
|
||||
if (!foundUser) {
|
||||
console.log('🤖: ⚠️ User not found in Database');
|
||||
return;
|
||||
}
|
||||
|
||||
const userId = foundUser._id;
|
||||
console.log('🤖: ✅ Found user in Database');
|
||||
|
||||
// Delete all conversations & associated messages
|
||||
const { deletedCount, messages } = await deleteConvos(user, {});
|
||||
const { deletedCount, messages } = await deleteConvos(userId, {});
|
||||
|
||||
if (messages.deletedCount > 0 || deletedCount > 0) {
|
||||
console.log(`🤖: ✅ Deleted ${deletedCount} convos & ${messages.deletedCount} messages`);
|
||||
}
|
||||
|
||||
// Ensure all user messages are deleted
|
||||
const { deletedCount: deletedMessages } = await deleteMessages({ user });
|
||||
const { deletedCount: deletedMessages } = await deleteMessages({ user: userId });
|
||||
if (deletedMessages > 0) {
|
||||
console.log(`🤖: ✅ Deleted ${deletedMessages} remaining message(s)`);
|
||||
}
|
||||
|
||||
// TODO: fix this to delete all user sessions with the user's email
|
||||
await deleteAllUserSessions(user);
|
||||
// Delete all user sessions
|
||||
await deleteAllUserSessions(userId.toString());
|
||||
|
||||
await User.deleteMany({ _id: user });
|
||||
await Balance.deleteMany({ user });
|
||||
await Transaction.deleteMany({ user });
|
||||
// Get models from the registered models
|
||||
const { User, Balance, Transaction } = getModels();
|
||||
|
||||
// Delete user, balance, and transactions using the registered models
|
||||
await User.deleteMany({ _id: userId });
|
||||
await Balance.deleteMany({ user: userId });
|
||||
await Transaction.deleteMany({ user: userId });
|
||||
|
||||
console.log('🤖: ✅ Deleted user from Database');
|
||||
|
||||
|
||||
362
package-lock.json
generated
362
package-lock.json
generated
@@ -2123,14 +2123,6 @@
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"api/node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"api/node_modules/agent-base": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
|
||||
@@ -2140,14 +2132,6 @@
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"api/node_modules/bson": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz",
|
||||
"integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"api/node_modules/cookie-parser": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
|
||||
@@ -25022,6 +25006,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA=="
|
||||
},
|
||||
"node_modules/@types/traverse": {
|
||||
"version": "0.6.37",
|
||||
"resolved": "https://registry.npmjs.org/@types/traverse/-/traverse-0.6.37.tgz",
|
||||
"integrity": "sha512-c90MVeDiUI1FhOZ6rLQ3kDWr50YE8+paDpM+5zbHjbmsqEp2DlMYkqnZnwbK9oI+NvDe8yRajup4jFwnVX6xsA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/triple-beam": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
@@ -25048,6 +25038,14 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
|
||||
"integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA=="
|
||||
},
|
||||
"node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/winston": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz",
|
||||
@@ -25774,7 +25772,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
|
||||
"integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -25922,7 +25919,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
|
||||
"integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.1",
|
||||
@@ -26008,7 +26004,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -26078,7 +26073,6 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"possible-typed-array-names": "^1.0.0"
|
||||
},
|
||||
@@ -26632,6 +26626,14 @@
|
||||
"node-int64": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bson": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz",
|
||||
"integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
@@ -26737,7 +26739,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
|
||||
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.0",
|
||||
@@ -27945,7 +27946,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
|
||||
"integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -27963,7 +27963,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
|
||||
"integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -27981,7 +27980,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
|
||||
"integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -28150,7 +28148,6 @@
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -28179,7 +28176,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
@@ -28703,7 +28699,6 @@
|
||||
"version": "1.23.9",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
|
||||
"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-buffer-byte-length": "^1.0.2",
|
||||
@@ -28858,7 +28853,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -28883,7 +28877,6 @@
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
|
||||
"integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-callable": "^1.2.7",
|
||||
@@ -30410,7 +30403,6 @@
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-callable": "^1.1.3"
|
||||
}
|
||||
@@ -30600,7 +30592,6 @@
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
|
||||
"integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -30621,7 +30612,6 @@
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
|
||||
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -30806,7 +30796,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
|
||||
"integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -30908,7 +30897,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -31131,7 +31119,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
|
||||
"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -31148,7 +31135,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
@@ -31160,7 +31146,6 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
|
||||
"integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.0"
|
||||
@@ -31188,7 +31173,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
@@ -31943,7 +31927,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -32061,7 +32044,6 @@
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
|
||||
"integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -32085,7 +32067,6 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
|
||||
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"async-function": "^1.0.0",
|
||||
@@ -32105,7 +32086,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
|
||||
"integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-bigints": "^1.0.2"
|
||||
@@ -32132,7 +32112,6 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
|
||||
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -32174,7 +32153,6 @@
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
|
||||
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -32201,7 +32179,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
|
||||
"integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -32219,7 +32196,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
|
||||
"integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -32268,7 +32244,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
|
||||
"integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3"
|
||||
@@ -32306,7 +32281,6 @@
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
@@ -32359,7 +32333,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
|
||||
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -32402,7 +32375,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
|
||||
"integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -32468,7 +32440,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
|
||||
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -32496,7 +32467,6 @@
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
|
||||
"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -32509,7 +32479,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
|
||||
"integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3"
|
||||
@@ -32536,7 +32505,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
|
||||
"integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -32553,7 +32521,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
|
||||
"integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -32571,7 +32538,6 @@
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
|
||||
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"which-typed-array": "^1.1.16"
|
||||
@@ -32587,7 +32553,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
|
||||
"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -32600,7 +32565,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
|
||||
"integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3"
|
||||
@@ -32616,7 +32580,6 @@
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
|
||||
"integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -35598,6 +35561,7 @@
|
||||
"version": "0.38.0",
|
||||
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.38.0.tgz",
|
||||
"integrity": "sha512-bHaq8nYxSKw9/Qslq1Zes5g9tHgFkxy/I9o8942wv2PqlNOT0CzptIkh/x98N52GikoSZOXSQkgt6oMjtf5uZw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-fetch": "^3.1.6"
|
||||
}
|
||||
@@ -36395,6 +36359,41 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
|
||||
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^14.1.0 || ^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url/node_modules/tr46": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
|
||||
"integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/mongodb-connection-string-url/node_modules/whatwg-url": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
|
||||
"integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tr46": "^5.1.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/moo-color": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/moo-color/-/moo-color-1.0.3.tgz",
|
||||
@@ -36915,7 +36914,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -36924,7 +36922,6 @@
|
||||
"version": "4.1.7",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
|
||||
"integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -37167,7 +37164,6 @@
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
|
||||
"integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.6",
|
||||
@@ -37807,7 +37803,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -40062,7 +40057,6 @@
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -40119,7 +40113,6 @@
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -41193,7 +41186,6 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
|
||||
"integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -41213,7 +41205,6 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
@@ -41239,7 +41230,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
|
||||
"integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -41256,14 +41246,12 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-regex-test": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
|
||||
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -41427,7 +41415,6 @@
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -41444,7 +41431,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
|
||||
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.4",
|
||||
@@ -41460,7 +41446,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
|
||||
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
@@ -42130,7 +42115,6 @@
|
||||
"version": "1.2.10",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
|
||||
"integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -42152,7 +42136,6 @@
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
|
||||
"integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -42171,7 +42154,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
|
||||
"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
@@ -43172,7 +43154,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
|
||||
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -43187,7 +43168,6 @@
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
|
||||
"integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
@@ -43207,7 +43187,6 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
|
||||
"integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
@@ -43229,7 +43208,6 @@
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
|
||||
"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
@@ -43251,6 +43229,28 @@
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
||||
},
|
||||
"node_modules/typedarray.prototype.slice": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.5.tgz",
|
||||
"integrity": "sha512-q7QNVDGTdl702bVFiI5eY4l/HkgCM6at9KhcFbgUAzezHFbOVy4+0O/lCjsABEQwbZPravVfBIiBVGo89yzHFg==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.9",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-proto": "^1.0.1",
|
||||
"math-intrinsics": "^1.1.0",
|
||||
"typed-array-buffer": "^1.0.3",
|
||||
"typed-array-byte-offset": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||
@@ -43341,7 +43341,6 @@
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||
"integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
@@ -44435,7 +44434,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
|
||||
"integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-bigint": "^1.1.0",
|
||||
@@ -44455,7 +44453,6 @@
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
|
||||
"integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
@@ -44483,14 +44480,12 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/which-collection": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
|
||||
"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-map": "^2.0.3",
|
||||
@@ -44509,7 +44504,6 @@
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz",
|
||||
"integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"available-typed-arrays": "^1.0.7",
|
||||
@@ -45431,6 +45425,46 @@
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"packages/auth": {
|
||||
"name": "@librechat/auth",
|
||||
"version": "0.0.1",
|
||||
"extraneous": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongoose": "^8.12.1",
|
||||
"openid-client": "^6.5.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-facebook": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@librechat/data-schemas": "^0.0.7",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^25.0.2",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^12.1.2",
|
||||
"@types/diff": "^6.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.0",
|
||||
"jest": "^29.5.0",
|
||||
"jest-junit": "^16.0.0",
|
||||
"rimraf": "^5.0.1",
|
||||
"rollup": "^4.22.4",
|
||||
"rollup-plugin-generate-package-json": "^3.2.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-typescript2": "^0.35.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"keyv": "^5.3.2"
|
||||
}
|
||||
},
|
||||
"packages/data-provider": {
|
||||
"name": "librechat-data-provider",
|
||||
"version": "0.7.86",
|
||||
@@ -45575,9 +45609,6 @@
|
||||
"name": "@librechat/data-schemas",
|
||||
"version": "0.0.7",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mongoose": "^8.12.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^25.0.2",
|
||||
@@ -45590,6 +45621,7 @@
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.0",
|
||||
"@types/traverse": "^0.6.37",
|
||||
"jest": "^29.5.0",
|
||||
"jest-junit": "^16.0.0",
|
||||
"rimraf": "^5.0.1",
|
||||
@@ -45601,15 +45633,16 @@
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"keyv": "^5.3.2"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/@types/whatwg-url": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
|
||||
"integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
|
||||
"dependencies": {
|
||||
"@types/webidl-conversions": "*"
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"keyv": "^5.3.2",
|
||||
"klona": "^2.0.6",
|
||||
"librechat-data-provider": "*",
|
||||
"lodash": "^4.17.21",
|
||||
"meilisearch": "^0.38.0",
|
||||
"mongoose": "^8.12.1",
|
||||
"traverse": "^0.6.11",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/brace-expansion": {
|
||||
@@ -45622,14 +45655,6 @@
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/bson": {
|
||||
"version": "6.10.3",
|
||||
"resolved": "https://registry.npmjs.org/bson/-/bson-6.10.3.tgz",
|
||||
"integrity": "sha512-MTxGsqgYTwfshYWTRdmZRC+M7FnG1b4y7RO7p2k3X24Wq0yv1m77Wsj0BzlPzd/IowgESfsruQCUToa7vbOpPQ==",
|
||||
"engines": {
|
||||
"node": ">=16.20.1"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
@@ -45667,6 +45692,23 @@
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/logform": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
|
||||
"integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@colors/colors": "1.6.0",
|
||||
"@types/triple-beam": "^1.3.2",
|
||||
"fecha": "^4.2.0",
|
||||
"ms": "^2.1.1",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"triple-beam": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
@@ -45687,6 +45729,7 @@
|
||||
"version": "6.14.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.14.2.tgz",
|
||||
"integrity": "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@mongodb-js/saslprep": "^1.1.9",
|
||||
"bson": "^6.10.3",
|
||||
@@ -45728,19 +45771,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/mongodb-connection-string-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
|
||||
"integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
|
||||
"dependencies": {
|
||||
"@types/whatwg-url": "^11.0.2",
|
||||
"whatwg-url": "^14.1.0 || ^13.0.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/mongoose": {
|
||||
"version": "8.12.1",
|
||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.12.1.tgz",
|
||||
"integrity": "sha512-UW22y8QFVYmrb36hm8cGncfn4ARc/XsYWQwRTaj0gxtQk1rDuhzDO1eBantS+hTTatfAIS96LlRCJrcNHvW5+Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"bson": "^6.10.3",
|
||||
"kareem": "2.6.3",
|
||||
@@ -45758,6 +45793,29 @@
|
||||
"url": "https://opencollective.com/mongoose"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/object-hash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/rimraf": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||
@@ -45774,27 +45832,75 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/tr46": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
|
||||
"integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
|
||||
"packages/data-schemas/node_modules/traverse": {
|
||||
"version": "0.6.11",
|
||||
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.11.tgz",
|
||||
"integrity": "sha512-vxXDZg8/+p3gblxB6BhhG5yWVn1kGRlaL8O78UDXc3wRnPizB5g83dcvWV1jpDMIPnjZjOFuxlMmE82XJ4407w==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"punycode": "^2.3.1"
|
||||
"gopd": "^1.2.0",
|
||||
"typedarray.prototype.slice": "^1.0.5",
|
||||
"which-typed-array": "^1.1.18"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/whatwg-url": {
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
|
||||
"integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
|
||||
"packages/data-schemas/node_modules/winston": {
|
||||
"version": "3.17.0",
|
||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
|
||||
"integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tr46": "^5.0.0",
|
||||
"webidl-conversions": "^7.0.0"
|
||||
"@colors/colors": "^1.6.0",
|
||||
"@dabh/diagnostics": "^2.0.2",
|
||||
"async": "^3.2.3",
|
||||
"is-stream": "^2.0.0",
|
||||
"logform": "^2.7.0",
|
||||
"one-time": "^1.0.0",
|
||||
"readable-stream": "^3.4.0",
|
||||
"safe-stable-stringify": "^2.3.1",
|
||||
"stack-trace": "0.0.x",
|
||||
"triple-beam": "^1.3.0",
|
||||
"winston-transport": "^4.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/winston-daily-rotate-file": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz",
|
||||
"integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"file-stream-rotator": "^0.6.1",
|
||||
"object-hash": "^3.0.0",
|
||||
"triple-beam": "^1.4.1",
|
||||
"winston-transport": "^4.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"winston": "^3"
|
||||
}
|
||||
},
|
||||
"packages/data-schemas/node_modules/winston-transport": {
|
||||
"version": "4.9.0",
|
||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
|
||||
"integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"logform": "^2.7.0",
|
||||
"readable-stream": "^3.6.2",
|
||||
"triple-beam": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
}
|
||||
},
|
||||
"packages/mcp": {
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.0",
|
||||
"@types/traverse": "^0.6.37",
|
||||
"jest": "^29.5.0",
|
||||
"jest-junit": "^16.0.0",
|
||||
"rimraf": "^5.0.1",
|
||||
@@ -58,11 +59,17 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"mongoose": "^8.12.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"keyv": "^5.3.2"
|
||||
"keyv": "^5.3.2",
|
||||
"mongoose": "^8.12.1",
|
||||
"librechat-data-provider": "*",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"klona": "^2.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"meilisearch": "^0.38.0",
|
||||
"traverse": "^0.6.11",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
|
||||
75
packages/data-schemas/src/config/meiliLogger.ts
Normal file
75
packages/data-schemas/src/config/meiliLogger.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import path from 'path';
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
|
||||
const logDir = path.join(__dirname, '..', 'logs');
|
||||
|
||||
const { NODE_ENV, DEBUG_LOGGING = 'false' } = process.env;
|
||||
|
||||
const useDebugLogging =
|
||||
(typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING.toLowerCase() === 'true') ||
|
||||
DEBUG_LOGGING === 'true';
|
||||
|
||||
const levels: winston.config.AbstractConfigSetLevels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
http: 3,
|
||||
verbose: 4,
|
||||
debug: 5,
|
||||
activity: 6,
|
||||
silly: 7,
|
||||
};
|
||||
|
||||
winston.addColors({
|
||||
info: 'green',
|
||||
warn: 'italic yellow',
|
||||
error: 'red',
|
||||
debug: 'blue',
|
||||
});
|
||||
|
||||
const level = (): string => {
|
||||
const env = NODE_ENV || 'development';
|
||||
const isDevelopment = env === 'development';
|
||||
return isDevelopment ? 'debug' : 'warn';
|
||||
};
|
||||
|
||||
const fileFormat = winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.splat(),
|
||||
);
|
||||
|
||||
const logLevel = useDebugLogging ? 'debug' : 'error';
|
||||
const transports: winston.transport[] = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: logLevel,
|
||||
filename: `${logDir}/meiliSync-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
];
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
winston.format.colorize({ all: true }),
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`),
|
||||
);
|
||||
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
level: 'info',
|
||||
format: consoleFormat,
|
||||
}),
|
||||
);
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: level(),
|
||||
levels,
|
||||
transports,
|
||||
});
|
||||
|
||||
export default logger;
|
||||
241
packages/data-schemas/src/config/parsers.ts
Normal file
241
packages/data-schemas/src/config/parsers.ts
Normal file
@@ -0,0 +1,241 @@
|
||||
import { klona } from 'klona';
|
||||
import winston from 'winston';
|
||||
import traverse from 'traverse';
|
||||
|
||||
const SPLAT_SYMBOL = Symbol.for('splat');
|
||||
const MESSAGE_SYMBOL = Symbol.for('message');
|
||||
const CONSOLE_JSON_STRING_LENGTH: number =
|
||||
parseInt(process.env.CONSOLE_JSON_STRING_LENGTH || '', 10) || 255;
|
||||
|
||||
const sensitiveKeys: RegExp[] = [
|
||||
/^(sk-)[^\s]+/, // OpenAI API key pattern
|
||||
/(Bearer )[^\s]+/, // Header: Bearer token pattern
|
||||
/(api-key:? )[^\s]+/, // Header: API key pattern
|
||||
/(key=)[^\s]+/, // URL query param: sensitive key pattern (Google)
|
||||
];
|
||||
|
||||
/**
|
||||
* Determines if a given value string is sensitive and returns matching regex patterns.
|
||||
*
|
||||
* @param valueStr - The value string to check.
|
||||
* @returns An array of regex patterns that match the value string.
|
||||
*/
|
||||
function getMatchingSensitivePatterns(valueStr: string): RegExp[] {
|
||||
if (valueStr) {
|
||||
// Filter and return all regex patterns that match the value string
|
||||
return sensitiveKeys.filter((regex) => regex.test(valueStr));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Redacts sensitive information from a console message and trims it to a specified length if provided.
|
||||
* @param str - The console message to be redacted.
|
||||
* @param trimLength - The optional length at which to trim the redacted message.
|
||||
* @returns The redacted and optionally trimmed console message.
|
||||
*/
|
||||
function redactMessage(str: string, trimLength?: number): string {
|
||||
if (!str) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const patterns = getMatchingSensitivePatterns(str);
|
||||
patterns.forEach((pattern) => {
|
||||
str = str.replace(pattern, '$1[REDACTED]');
|
||||
});
|
||||
|
||||
if (trimLength !== undefined && str.length > trimLength) {
|
||||
return `${str.substring(0, trimLength)}...`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redacts sensitive information from log messages if the log level is 'error'.
|
||||
* Note: Intentionally mutates the object.
|
||||
* @param info - The log information object.
|
||||
* @returns The modified log information object.
|
||||
*/
|
||||
const redactFormat = winston.format((info: winston.Logform.TransformableInfo) => {
|
||||
if (info.level === 'error') {
|
||||
// Type guard to ensure message is a string
|
||||
if (typeof info.message === 'string') {
|
||||
info.message = redactMessage(info.message);
|
||||
}
|
||||
|
||||
// Handle MESSAGE_SYMBOL with type safety
|
||||
const symbolValue = (info as Record<string | symbol, unknown>)[MESSAGE_SYMBOL];
|
||||
if (typeof symbolValue === 'string') {
|
||||
(info as Record<string | symbol, unknown>)[MESSAGE_SYMBOL] = redactMessage(symbolValue);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
});
|
||||
|
||||
/**
|
||||
* Truncates long strings, especially base64 image data, within log messages.
|
||||
*
|
||||
* @param value - The value to be inspected and potentially truncated.
|
||||
* @param length - The length at which to truncate the value. Default: 100.
|
||||
* @returns The truncated or original value.
|
||||
*/
|
||||
const truncateLongStrings = (value: unknown, length = 100): unknown => {
|
||||
if (typeof value === 'string') {
|
||||
return value.length > length ? value.substring(0, length) + '... [truncated]' : value;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* An array mapping function that truncates long strings (objects converted to JSON strings).
|
||||
* @param item - The item to be condensed.
|
||||
* @returns The condensed item.
|
||||
*/
|
||||
const condenseArray = (item: unknown): string | unknown => {
|
||||
if (typeof item === 'string') {
|
||||
return truncateLongStrings(JSON.stringify(item));
|
||||
} else if (typeof item === 'object') {
|
||||
return truncateLongStrings(JSON.stringify(item));
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats log messages for debugging purposes.
|
||||
* - Truncates long strings within log messages.
|
||||
* - Condenses arrays by truncating long strings and objects as strings within array items.
|
||||
* - Redacts sensitive information from log messages if the log level is 'error'.
|
||||
* - Converts log information object to a formatted string.
|
||||
*
|
||||
* @param options - The options for formatting log messages.
|
||||
* @returns The formatted log message.
|
||||
*/
|
||||
const debugTraverse = winston.format.printf(
|
||||
({ level, message, timestamp, ...metadata }: Record<string, unknown>) => {
|
||||
if (!message) {
|
||||
return `${timestamp} ${level}`;
|
||||
}
|
||||
|
||||
// Type-safe version of the CJS logic: !message?.trim || typeof message !== 'string'
|
||||
if (typeof message !== 'string' || !message.trim) {
|
||||
return `${timestamp} ${level}: ${JSON.stringify(message)}`;
|
||||
}
|
||||
|
||||
let msg = `${timestamp} ${level}: ${truncateLongStrings(message.trim(), 150)}`;
|
||||
|
||||
try {
|
||||
if (level !== 'debug') {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (!metadata) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Type-safe access to SPLAT_SYMBOL using bracket notation
|
||||
const metadataRecord = metadata as Record<string | symbol, unknown>;
|
||||
const splatArray = metadataRecord[SPLAT_SYMBOL];
|
||||
const debugValue = Array.isArray(splatArray) ? splatArray[0] : undefined;
|
||||
|
||||
if (!debugValue) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (debugValue && Array.isArray(debugValue)) {
|
||||
msg += `\n${JSON.stringify(debugValue.map(condenseArray))}`;
|
||||
return msg;
|
||||
}
|
||||
|
||||
if (typeof debugValue !== 'object') {
|
||||
return (msg += ` ${debugValue}`);
|
||||
}
|
||||
|
||||
msg += '\n{';
|
||||
|
||||
const copy = klona(metadata);
|
||||
|
||||
traverse(copy).forEach(function (this: traverse.TraverseContext, value: unknown) {
|
||||
if (typeof this?.key === 'symbol') {
|
||||
return;
|
||||
}
|
||||
|
||||
let _parentKey = '';
|
||||
const parent = this.parent;
|
||||
|
||||
if (typeof parent?.key !== 'symbol' && parent?.key) {
|
||||
_parentKey = parent.key;
|
||||
}
|
||||
|
||||
const parentKey = `${parent && parent.notRoot ? _parentKey + '.' : ''}`;
|
||||
const tabs = `${parent && parent.notRoot ? ' ' : ' '}`;
|
||||
const currentKey = this?.key ?? 'unknown';
|
||||
|
||||
if (this.isLeaf && typeof value === 'string') {
|
||||
const truncatedText = truncateLongStrings(value);
|
||||
msg += `\n${tabs}${parentKey}${currentKey}: ${JSON.stringify(truncatedText)},`;
|
||||
} else if (this.notLeaf && Array.isArray(value) && value.length > 0) {
|
||||
const currentMessage = `\n${tabs}// ${value.length} ${currentKey.replace(/s$/, '')}(s)`;
|
||||
this.update(currentMessage, true);
|
||||
msg += currentMessage;
|
||||
const stringifiedArray = value.map(condenseArray);
|
||||
msg += `\n${tabs}${parentKey}${currentKey}: [${stringifiedArray}],`;
|
||||
} else if (this.isLeaf && typeof value === 'function') {
|
||||
msg += `\n${tabs}${parentKey}${currentKey}: function,`;
|
||||
} else if (this.isLeaf) {
|
||||
msg += `\n${tabs}${parentKey}${currentKey}: ${value},`;
|
||||
}
|
||||
});
|
||||
|
||||
msg += '\n}';
|
||||
return msg;
|
||||
} catch (e: unknown) {
|
||||
const errorMessage = e instanceof Error ? e.message : 'Unknown error';
|
||||
return (msg += `\n[LOGGER PARSING ERROR] ${errorMessage}`);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Truncates long string values in JSON log objects.
|
||||
* Prevents outputting extremely long values (e.g., base64, blobs).
|
||||
*/
|
||||
const jsonTruncateFormat = winston.format((info: winston.Logform.TransformableInfo) => {
|
||||
const truncateLongStrings = (str: string, maxLength: number): string =>
|
||||
str.length > maxLength ? str.substring(0, maxLength) + '...' : str;
|
||||
|
||||
const seen = new WeakSet<object>();
|
||||
|
||||
const truncateObject = (obj: unknown): unknown => {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Handle circular references - now with proper object type
|
||||
if (seen.has(obj)) {
|
||||
return '[Circular]';
|
||||
}
|
||||
seen.add(obj);
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => truncateObject(item));
|
||||
}
|
||||
|
||||
// We know this is an object at this point
|
||||
const objectRecord = obj as Record<string, unknown>;
|
||||
const newObj: Record<string, unknown> = {};
|
||||
Object.entries(objectRecord).forEach(([key, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
newObj[key] = truncateLongStrings(value, CONSOLE_JSON_STRING_LENGTH);
|
||||
} else {
|
||||
newObj[key] = truncateObject(value);
|
||||
}
|
||||
});
|
||||
return newObj;
|
||||
};
|
||||
|
||||
return truncateObject(info) as winston.Logform.TransformableInfo;
|
||||
});
|
||||
|
||||
export { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat };
|
||||
123
packages/data-schemas/src/config/winston.ts
Normal file
123
packages/data-schemas/src/config/winston.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import path from 'path';
|
||||
import winston from 'winston';
|
||||
import 'winston-daily-rotate-file';
|
||||
import { redactFormat, redactMessage, debugTraverse, jsonTruncateFormat } from './parsers';
|
||||
|
||||
// Define log directory
|
||||
const logDir = path.join(__dirname, '..', 'logs');
|
||||
|
||||
// Type-safe environment variables
|
||||
const { NODE_ENV, DEBUG_LOGGING, CONSOLE_JSON, DEBUG_CONSOLE } = process.env;
|
||||
|
||||
const useConsoleJson = typeof CONSOLE_JSON === 'string' && CONSOLE_JSON.toLowerCase() === 'true';
|
||||
|
||||
const useDebugConsole = typeof DEBUG_CONSOLE === 'string' && DEBUG_CONSOLE.toLowerCase() === 'true';
|
||||
|
||||
const useDebugLogging = typeof DEBUG_LOGGING === 'string' && DEBUG_LOGGING.toLowerCase() === 'true';
|
||||
|
||||
// Define custom log levels
|
||||
const levels: winston.config.AbstractConfigSetLevels = {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
http: 3,
|
||||
verbose: 4,
|
||||
debug: 5,
|
||||
activity: 6,
|
||||
silly: 7,
|
||||
};
|
||||
|
||||
winston.addColors({
|
||||
info: 'green',
|
||||
warn: 'italic yellow',
|
||||
error: 'red',
|
||||
debug: 'blue',
|
||||
});
|
||||
|
||||
const level = (): string => {
|
||||
const env = NODE_ENV || 'development';
|
||||
return env === 'development' ? 'debug' : 'warn';
|
||||
};
|
||||
|
||||
const fileFormat = winston.format.combine(
|
||||
redactFormat(),
|
||||
winston.format.timestamp({ format: () => new Date().toISOString() }),
|
||||
winston.format.errors({ stack: true }),
|
||||
winston.format.splat(),
|
||||
);
|
||||
|
||||
const transports: winston.transport[] = [
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'error',
|
||||
filename: `${logDir}/error-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: fileFormat,
|
||||
}),
|
||||
];
|
||||
|
||||
if (useDebugLogging) {
|
||||
transports.push(
|
||||
new winston.transports.DailyRotateFile({
|
||||
level: 'debug',
|
||||
filename: `${logDir}/debug-%DATE%.log`,
|
||||
datePattern: 'YYYY-MM-DD',
|
||||
zippedArchive: true,
|
||||
maxSize: '20m',
|
||||
maxFiles: '14d',
|
||||
format: winston.format.combine(fileFormat, debugTraverse),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const consoleFormat = winston.format.combine(
|
||||
redactFormat(),
|
||||
winston.format.colorize({ all: true }),
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf((info) => {
|
||||
const message = `${info.timestamp} ${info.level}: ${info.message}`;
|
||||
return info.level.includes('error') ? redactMessage(message) : message;
|
||||
}),
|
||||
);
|
||||
|
||||
let consoleLogLevel: string = 'info';
|
||||
if (useDebugConsole) {
|
||||
consoleLogLevel = 'debug';
|
||||
}
|
||||
|
||||
// Add console transport
|
||||
if (useDebugConsole) {
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
level: consoleLogLevel,
|
||||
format: useConsoleJson
|
||||
? winston.format.combine(fileFormat, jsonTruncateFormat(), winston.format.json())
|
||||
: winston.format.combine(fileFormat, debugTraverse),
|
||||
}),
|
||||
);
|
||||
} else if (useConsoleJson) {
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
level: consoleLogLevel,
|
||||
format: winston.format.combine(fileFormat, jsonTruncateFormat(), winston.format.json()),
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
transports.push(
|
||||
new winston.transports.Console({
|
||||
level: consoleLogLevel,
|
||||
format: consoleFormat,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Create logger
|
||||
const logger = winston.createLogger({
|
||||
level: level(),
|
||||
levels,
|
||||
transports,
|
||||
});
|
||||
|
||||
export default logger;
|
||||
17
packages/data-schemas/src/crypto/index.ts
Normal file
17
packages/data-schemas/src/crypto/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { webcrypto } from 'node:crypto';
|
||||
import { SignPayloadParams } from '~/types';
|
||||
|
||||
export async function signPayload({
|
||||
payload,
|
||||
secret,
|
||||
expirationTime,
|
||||
}: SignPayloadParams): Promise<string> {
|
||||
return jwt.sign(payload, secret!, { expiresIn: expirationTime });
|
||||
}
|
||||
|
||||
export async function hashToken(str: string): Promise<string> {
|
||||
const data = new TextEncoder().encode(str);
|
||||
const hashBuffer = await webcrypto.subtle.digest('SHA-256', data);
|
||||
return Buffer.from(hashBuffer).toString('hex');
|
||||
}
|
||||
@@ -1,68 +1,6 @@
|
||||
export { default as actionSchema } from './schema/action';
|
||||
export type { IAction } from './schema/action';
|
||||
|
||||
export { default as agentSchema } from './schema/agent';
|
||||
export type { IAgent } from './schema/agent';
|
||||
|
||||
export { default as assistantSchema } from './schema/assistant';
|
||||
export type { IAssistant } from './schema/assistant';
|
||||
|
||||
export { default as balanceSchema } from './schema/balance';
|
||||
export type { IBalance } from './schema/balance';
|
||||
|
||||
export { default as bannerSchema } from './schema/banner';
|
||||
export type { IBanner } from './schema/banner';
|
||||
|
||||
export { default as categoriesSchema } from './schema/categories';
|
||||
export type { ICategory } from './schema/categories';
|
||||
|
||||
export { default as conversationTagSchema } from './schema/conversationTag';
|
||||
export type { IConversationTag } from './schema/conversationTag';
|
||||
|
||||
export { default as convoSchema } from './schema/convo';
|
||||
export type { IConversation } from './schema/convo';
|
||||
|
||||
export { default as fileSchema } from './schema/file';
|
||||
export type { IMongoFile } from './schema/file';
|
||||
|
||||
export { default as keySchema } from './schema/key';
|
||||
export type { IKey } from './schema/key';
|
||||
|
||||
export { default as messageSchema } from './schema/message';
|
||||
export type { IMessage } from './schema/message';
|
||||
|
||||
export { default as pluginAuthSchema } from './schema/pluginAuth';
|
||||
export type { IPluginAuth } from './schema/pluginAuth';
|
||||
|
||||
export { default as presetSchema } from './schema/preset';
|
||||
export type { IPreset } from './schema/preset';
|
||||
|
||||
export { default as projectSchema } from './schema/project';
|
||||
export type { IMongoProject } from './schema/project';
|
||||
|
||||
export { default as promptSchema } from './schema/prompt';
|
||||
export type { IPrompt } from './schema/prompt';
|
||||
|
||||
export { default as promptGroupSchema } from './schema/promptGroup';
|
||||
export type { IPromptGroup, IPromptGroupDocument } from './schema/promptGroup';
|
||||
|
||||
export { default as roleSchema } from './schema/role';
|
||||
export type { IRole } from './schema/role';
|
||||
|
||||
export { default as sessionSchema } from './schema/session';
|
||||
export type { ISession } from './schema/session';
|
||||
|
||||
export { default as shareSchema } from './schema/share';
|
||||
export type { ISharedLink } from './schema/share';
|
||||
|
||||
export { default as tokenSchema } from './schema/token';
|
||||
export type { IToken } from './schema/token';
|
||||
|
||||
export { default as toolCallSchema } from './schema/toolCall';
|
||||
export type { IToolCallData } from './schema/toolCall';
|
||||
|
||||
export { default as transactionSchema } from './schema/transaction';
|
||||
export type { ITransaction } from './schema/transaction';
|
||||
|
||||
export { default as userSchema } from './schema/user';
|
||||
export type { IUser } from './schema/user';
|
||||
export * from './crypto';
|
||||
export { createModels } from './models';
|
||||
export { createMethods } from './methods';
|
||||
export type * from './types';
|
||||
export { default as logger } from './config/winston';
|
||||
export { default as meiliLogger } from './config/meiliLogger';
|
||||
|
||||
18
packages/data-schemas/src/methods/index.ts
Normal file
18
packages/data-schemas/src/methods/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createUserMethods, type UserMethods } from './user';
|
||||
import { createSessionMethods, type SessionMethods } from './session';
|
||||
import { createTokenMethods, type TokenMethods } from './token';
|
||||
import { createRoleMethods, type RoleMethods } from './role';
|
||||
|
||||
/**
|
||||
* Creates all database methods for all collections
|
||||
*/
|
||||
export function createMethods(mongoose: typeof import('mongoose')) {
|
||||
return {
|
||||
...createUserMethods(mongoose),
|
||||
...createSessionMethods(mongoose),
|
||||
...createTokenMethods(mongoose),
|
||||
...createRoleMethods(mongoose),
|
||||
};
|
||||
}
|
||||
|
||||
export type AllMethods = UserMethods & SessionMethods & TokenMethods & RoleMethods;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user