Files
wehub-resource-sync e115934061
Publish `@librechat/data-schemas` to NPM / pack (push) Failing after 8s
Publish `@librechat/client` to NPM / pack (push) Failing after 0s
GitNexus Index / index (push) Failing after 1s
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Has been skipped
Sync Helm Chart Tags / Sync chart tags (push) Failing after 2s
Publish `librechat-data-provider` to NPM / pack (push) Failing after 1s
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Failing after 1s
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Failing after 0s
Sync Helm Chart Tags / Ignore non-main push (push) Has been skipped
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Failing after 1s
Publish `@librechat/client` to NPM / publish-npm (push) Has been cancelled
Publish `librechat-data-provider` to NPM / publish-npm (push) Has been cancelled
GitNexus Index / post-index (push) Has been cancelled
Publish `@librechat/data-schemas` to NPM / publish-npm (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:08:12 +08:00

101 lines
3.2 KiB
JavaScript

const mongoose = require('mongoose');
const { logger } = require('@librechat/data-schemas');
const {
MAX_SKILL_STATES,
toSkillStatesRecord,
validateSkillStatesPayload,
pruneOrphanSkillStates,
getDeploymentSkillIds,
mergeDeploymentSkillIds,
} = require('@librechat/api');
const { ResourceType, PermissionBits } = require('librechat-data-provider');
const { findAccessibleResources } = require('~/server/services/PermissionService');
const { updateUser, getUserById } = require('~/models');
/** Builds the injected deps for `pruneOrphanSkillStates` from live models. */
function buildPruneDeps(user) {
return {
findExistingSkillIds: async (validIds) => {
const Skill = mongoose.models.Skill;
if (!Skill) {
return validIds;
}
const existing = await Skill.find({ _id: { $in: validIds } })
.select('_id')
.lean();
const deploymentIds = getDeploymentSkillIds()
.map((id) => id.toString())
.filter((id) => validIds.includes(id));
return [...existing.map((doc) => doc._id.toString()), ...deploymentIds];
},
findAccessibleSkillIds: async () =>
mergeDeploymentSkillIds(
await findAccessibleResources({
userId: user.id,
role: user.role,
resourceType: ResourceType.SKILL,
requiredPermissions: PermissionBits.VIEW,
}),
),
};
}
const getSkillStatesController = async (req, res) => {
try {
const userId = req.user.id;
const user = await getUserById(userId, 'skillStates');
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
const states = toSkillStatesRecord(user.skillStates);
const pruned = await pruneOrphanSkillStates(states, buildPruneDeps(req.user));
return res.status(200).json(pruned);
} catch (error) {
logger.error('[SkillStatesController] Error fetching skill states:', error);
return res.status(500).json({ message: 'Internal server error' });
}
};
const updateSkillStatesController = async (req, res) => {
try {
const { skillStates } = req.body;
const validationError = validateSkillStatesPayload(skillStates);
if (validationError) {
const { message, code, limit } = validationError;
const payload = { message };
if (code) payload.code = code;
if (limit != null) payload.limit = limit;
return res.status(400).json(payload);
}
const pruned = await pruneOrphanSkillStates(skillStates, buildPruneDeps(req.user));
if (Object.keys(pruned).length > MAX_SKILL_STATES) {
return res.status(400).json({
code: 'MAX_SKILL_STATES_EXCEEDED',
message: `Maximum ${MAX_SKILL_STATES} skill state overrides allowed`,
limit: MAX_SKILL_STATES,
});
}
const user = await updateUser(req.user.id, { skillStates: pruned });
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
return res.status(200).json(toSkillStatesRecord(user.skillStates));
} catch (error) {
logger.error('[SkillStatesController] Error updating skill states:', error);
return res.status(500).json({ message: 'Internal server error' });
}
};
module.exports = {
getSkillStatesController,
updateSkillStatesController,
};