feat: Add cursor pagination utilities and refine user/group/role types in @librechat/data-schemas (#9218)

* feat: Add pagination interfaces and update user and group types for better data handling

* fix: Update data-schemas version to 0.0.19
This commit is contained in:
Marco Beretta 2025-08-23 06:18:31 +02:00 committed by GitHub
parent 0e00f357a6
commit ac608ded46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 108 additions and 20 deletions

2
package-lock.json generated
View file

@ -51876,7 +51876,7 @@
},
"packages/data-schemas": {
"name": "@librechat/data-schemas",
"version": "0.0.18",
"version": "0.0.19",
"license": "MIT",
"devDependencies": {
"@rollup/plugin-alias": "^5.1.0",

View file

@ -1,6 +1,6 @@
{
"name": "@librechat/data-schemas",
"version": "0.0.18",
"version": "0.0.19",
"description": "Mongoose schemas and models for LibreChat",
"type": "module",
"main": "dist/index.cjs",

View file

@ -1 +1,2 @@
export * from './enum';
export * from './pagination';

View file

@ -0,0 +1,17 @@
export interface CursorPaginationParams {
limit?: number;
cursor?: string;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
}
export interface CursorPaginationResponse<T> {
data: T[];
pagination: {
hasNextPage: boolean;
hasPreviousPage: boolean;
nextCursor?: string;
previousCursor?: string;
totalCount?: number;
};
}

View file

@ -1,5 +1,5 @@
import mongoose, { FilterQuery } from 'mongoose';
import type { IUser, BalanceConfig, UserCreateData, UserUpdateResult } from '~/types';
import type { IUser, BalanceConfig, CreateUserRequest, UserDeleteResult } from '~/types';
import { signPayload } from '~/crypto';
/** Factory function that takes mongoose instance and returns the methods */
@ -31,7 +31,7 @@ export function createUserMethods(mongoose: typeof import('mongoose')) {
* Creates a new user, optionally with a TTL of 1 week.
*/
async function createUser(
data: UserCreateData,
data: CreateUserRequest,
balanceConfig?: BalanceConfig,
disableTTL: boolean = true,
returnUser: boolean = false,
@ -123,7 +123,7 @@ export function createUserMethods(mongoose: typeof import('mongoose')) {
/**
* Delete a user by their unique ID.
*/
async function deleteUserById(userId: string): Promise<UserUpdateResult> {
async function deleteUserById(userId: string): Promise<UserDeleteResult> {
try {
const User = mongoose.models.User;
const result = await User.deleteOne({ _id: userId });

View file

@ -24,6 +24,7 @@ const groupSchema = new Schema<IGroup>(
memberIds: [
{
type: String,
required: false,
},
],
source: {

View file

@ -1,22 +1,44 @@
import type { Document, Types } from 'mongoose';
import { CursorPaginationParams } from '~/common';
export interface IGroup extends Document {
_id: Types.ObjectId;
/** The name of the group */
name: string;
/** Optional description of the group */
description?: string;
/** Optional email address for the group */
email?: string;
/** Optional avatar URL for the group */
avatar?: string;
/** Array of member IDs (stores idOnTheSource values, not ObjectIds) */
memberIds: string[];
/** The source of the group ('local' or 'entra') */
memberIds?: string[];
source: 'local' | 'entra';
/** External ID (e.g., Entra ID) - required for non-local sources */
idOnTheSource?: string;
/** Timestamps */
createdAt?: Date;
updatedAt?: Date;
}
export interface CreateGroupRequest {
name: string;
description?: string;
email?: string;
avatar?: string;
memberIds?: string[];
source: 'local' | 'entra';
idOnTheSource?: string;
}
export interface UpdateGroupRequest {
name?: string;
description?: string;
email?: string;
avatar?: string;
memberIds?: string[];
source?: 'local' | 'entra' | 'ldap';
idOnTheSource?: string;
}
export interface GroupFilterOptions extends CursorPaginationParams {
// Includes email, name and description
search?: string;
source?: 'local' | 'entra' | 'ldap';
hasMember?: string;
}

View file

@ -1,5 +1,6 @@
import { Document } from 'mongoose';
import { PermissionTypes, Permissions } from 'librechat-data-provider';
import type { Document } from 'mongoose';
import { CursorPaginationParams } from '~/common';
export interface IRole extends Document {
name: string;
@ -48,3 +49,25 @@ export interface IRole extends Document {
};
};
}
export type RolePermissions = IRole['permissions'];
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
export type RolePermissionsInput = DeepPartial<RolePermissions>;
export interface CreateRoleRequest {
name: string;
permissions: RolePermissionsInput;
}
export interface UpdateRoleRequest {
name?: string;
permissions?: RolePermissionsInput;
}
export interface RoleFilterOptions extends CursorPaginationParams {
// Includes role name
search?: string;
hasPermission?: string;
}

View file

@ -1,4 +1,5 @@
import { Document, Types } from 'mongoose';
import type { Document, Types } from 'mongoose';
import { CursorPaginationParams } from '~/common';
export interface IUser extends Document {
name?: string;
@ -48,18 +49,39 @@ export interface BalanceConfig {
refillAmount?: number;
}
export interface UserCreateData extends Partial<IUser> {
export interface CreateUserRequest extends Partial<IUser> {
email: string;
}
export interface UserUpdateResult {
export interface UpdateUserRequest {
name?: string;
username?: string;
email?: string;
role?: string;
emailVerified?: boolean;
avatar?: string;
plugins?: string[];
twoFactorEnabled?: boolean;
termsAccepted?: boolean;
personalization?: {
memories?: boolean;
};
}
export interface UserDeleteResult {
deletedCount: number;
message: string;
}
export interface UserSearchCriteria {
email?: string;
username?: string;
export interface UserFilterOptions extends CursorPaginationParams {
_id?: Types.ObjectId | string;
// Includes email, username and name
search?: string;
role?: string;
emailVerified?: boolean;
provider?: string;
twoFactorEnabled?: boolean;
// External IDs
googleId?: string;
facebookId?: string;
openidId?: string;
@ -68,7 +90,9 @@ export interface UserSearchCriteria {
githubId?: string;
discordId?: string;
appleId?: string;
_id?: Types.ObjectId | string;
// Date filters
createdAfter?: string;
createdBefore?: string;
}
export interface UserQueryOptions {