🧽 chore: Resolve TypeScript errors and test failures in agent/prompt deletion methods

Type AclEntry model as Model<IAclEntry> instead of Model<unknown> in
    deleteUserAgents and deleteUserPrompts, wire getSoleOwnedResourceIds
    into agent.spec.ts via createAclEntryMethods, replace permissionService
    calls with direct AclEntry.create, and add missing principalModel field.
This commit is contained in:
Danny Avila 2026-03-21 14:30:46 -04:00
parent 87a3b8221a
commit 150361273f
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
3 changed files with 60 additions and 33 deletions

View file

@ -17,6 +17,7 @@ import type {
} from 'mongoose';
import type { IAgent, IAclEntry, IUser, IAccessRole } from '..';
import { createAgentMethods, type AgentMethods } from './agent';
import { createAclEntryMethods } from './aclEntry';
import { createModels } from '~/models';
/** Version snapshot stored in `IAgent.versions[]`. Extends the base omit with runtime-only fields. */
@ -76,7 +77,14 @@ beforeAll(async () => {
await AclEntry.deleteMany({ resourceType, resourceId });
};
methods = createAgentMethods(mongoose, { removeAllPermissions, getActions });
const aclEntryMethods = createAclEntryMethods(mongoose);
const { getSoleOwnedResourceIds } = aclEntryMethods;
methods = createAgentMethods(mongoose, {
removeAllPermissions,
getActions,
getSoleOwnedResourceIds,
});
createAgent = methods.createAgent;
getAgent = methods.getAgent;
updateAgent = methods.updateAgent;
@ -932,21 +940,27 @@ describe('Agent Methods', () => {
author: otherAuthorId,
});
await permissionService.grantPermission({
const ownerBits =
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE;
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent1._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await permissionService.grantPermission({
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent2._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await User.create({
@ -1016,21 +1030,27 @@ describe('Agent Methods', () => {
author: authorId,
});
await permissionService.grantPermission({
const ownerBits =
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE;
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent1._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await permissionService.grantPermission({
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent2._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await User.create({
@ -1096,13 +1116,17 @@ describe('Agent Methods', () => {
author: otherAuthorId,
});
await permissionService.grantPermission({
const ownerBits =
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE;
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: otherAuthorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: existingAgent._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: otherAuthorId,
grantedAt: new Date(),
});
await User.create({
@ -1150,21 +1174,27 @@ describe('Agent Methods', () => {
author: authorId,
});
await permissionService.grantPermission({
const ownerBits =
PermissionBits.VIEW | PermissionBits.EDIT | PermissionBits.DELETE | PermissionBits.SHARE;
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent1._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await permissionService.grantPermission({
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: authorId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: agent2._id,
accessRoleId: AccessRoleIds.AGENT_OWNER,
permBits: ownerBits,
grantedBy: authorId,
grantedAt: new Date(),
});
await User.create({
@ -1216,24 +1246,27 @@ describe('Agent Methods', () => {
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: deletingUserId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: (soleAgent as unknown as { _id: mongoose.Types.ObjectId })._id,
permBits: PermissionBits.DELETE | PermissionBits.READ | PermissionBits.WRITE,
permBits: PermissionBits.DELETE | PermissionBits.VIEW | PermissionBits.EDIT,
});
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: deletingUserId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: (multiAgent as unknown as { _id: mongoose.Types.ObjectId })._id,
permBits: PermissionBits.DELETE | PermissionBits.READ | PermissionBits.WRITE,
permBits: PermissionBits.DELETE | PermissionBits.VIEW | PermissionBits.EDIT,
});
await AclEntry.create({
principalType: PrincipalType.USER,
principalId: otherOwnerId,
principalModel: PrincipalModel.USER,
resourceType: ResourceType.AGENT,
resourceId: (multiAgent as unknown as { _id: mongoose.Types.ObjectId })._id,
permBits: PermissionBits.DELETE | PermissionBits.READ | PermissionBits.WRITE,
permBits: PermissionBits.DELETE | PermissionBits.VIEW | PermissionBits.EDIT,
});
await deleteUserAgents(deletingUserId.toString());

View file

@ -1,8 +1,8 @@
import crypto from 'node:crypto';
import type { FilterQuery, Model, Types } from 'mongoose';
import { Constants, ResourceType, actionDelimiter } from 'librechat-data-provider';
import type { FilterQuery, Model, Types } from 'mongoose';
import type { IAgent, IAclEntry } from '~/types';
import logger from '~/config/winston';
import type { IAgent } from '~/types';
const { mcp_delimiter } = Constants;
@ -525,7 +525,7 @@ export function createAgentMethods(mongoose: typeof import('mongoose'), deps: Ag
*/
async function deleteUserAgents(userId: string): Promise<void> {
const Agent = mongoose.models.Agent as Model<IAgent>;
const AclEntry = mongoose.models.AclEntry as Model<unknown>;
const AclEntry = mongoose.models.AclEntry as Model<IAclEntry>;
const User = mongoose.models.User as Model<unknown>;
try {
@ -546,9 +546,7 @@ export function createAgentMethods(mongoose: typeof import('mongoose'), deps: Ag
.select('resourceId')
.lean()
: [];
const migratedIds = new Set(
(migratedEntries as Array<{ resourceId: Types.ObjectId }>).map((e) => e.resourceId.toString()),
);
const migratedIds = new Set(migratedEntries.map((e) => e.resourceId.toString()));
const legacyAgents = authoredAgents.filter((a) => !migratedIds.has(a._id.toString()));
const soleOwnedAgents =

View file

@ -1,6 +1,6 @@
import type { Model, Types } from 'mongoose';
import { ResourceType, SystemCategories } from 'librechat-data-provider';
import type { IPrompt, IPromptGroup, IPromptGroupDocument } from '~/types';
import type { Model, Types } from 'mongoose';
import type { IAclEntry, IPrompt, IPromptGroup, IPromptGroupDocument } from '~/types';
import { escapeRegExp } from '~/utils/string';
import logger from '~/config/winston';
@ -544,7 +544,7 @@ export function createPromptMethods(mongoose: typeof import('mongoose'), deps: P
try {
const PromptGroup = mongoose.models.PromptGroup as Model<IPromptGroupDocument>;
const Prompt = mongoose.models.Prompt as Model<IPrompt>;
const AclEntry = mongoose.models.AclEntry;
const AclEntry = mongoose.models.AclEntry as Model<IAclEntry>;
const userObjectId = new ObjectId(userId);
const soleOwnedIds = await getSoleOwnedResourceIds(userObjectId, ResourceType.PROMPTGROUP);
@ -561,12 +561,8 @@ export function createPromptMethods(mongoose: typeof import('mongoose'), deps: P
.select('resourceId')
.lean()
: [];
const migratedIds = new Set(
(migratedEntries as Array<{ resourceId: Types.ObjectId }>).map((e) => e.resourceId.toString()),
);
const legacyGroupIds = authoredGroupIds.filter(
(id) => !migratedIds.has(id.toString()),
);
const migratedIds = new Set(migratedEntries.map((e) => e.resourceId.toString()));
const legacyGroupIds = authoredGroupIds.filter((id) => !migratedIds.has(id.toString()));
const allGroupIdsToDelete = [...soleOwnedIds, ...legacyGroupIds];