Files
memind/server/portal-account-feedback-routes.mjs
T
john 212ff3ff80 Add User Model Service and Temporal Recall for MeMind V0.1.
Introduce UMS ingest/snapshot pipeline, Context Planner with multi-source recall, runtime context injection, canonical user mapping, and session snapshot loading on auth/me.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 23:25:18 +08:00

317 lines
7.9 KiB
JavaScript

import { loadSessionUserModelSnapshot } from '../user-model-service/session-snapshot.mjs';
export function attachPortalAccountFeedbackRoutes({
app,
jsonBody,
userAuthReady = Promise.resolve(),
getUserAuth = () => null,
getLegacyAuth = () => null,
getSubscriptionService = () => null,
getFeedbackService = () => null,
getUmsPool = () => null,
userToken,
legacySessionToken,
clearUserLoginCookies,
resolveSkillRuntimeForClient = async () => null,
resolveAgentCodeRunForClient = async () => null,
logger = console,
} = {}) {
if (
!app ||
typeof jsonBody !== 'function' ||
typeof userToken !== 'function' ||
typeof legacySessionToken !== 'function' ||
typeof clearUserLoginCookies !== 'function'
) {
throw new Error(
'attachPortalAccountFeedbackRoutes requires route dependencies',
);
}
app.get('/auth/me', async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
if (!userAuth) {
return res.status(503).json({
message: '未启用用户系统',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
const subscriptionService =
getSubscriptionService();
const [
paths,
capabilityState,
subscription,
skillRuntime,
agentCodeRun,
userModelSnapshot,
] = await Promise.all([
userAuth.listPathGrants(me.id),
userAuth.resolveUserCapabilities(
await userAuth.getUserById(me.id),
),
subscriptionService
? subscriptionService.getActiveSubscription(
me.id,
)
: null,
resolveSkillRuntimeForClient(),
resolveAgentCodeRunForClient(me.id),
loadSessionUserModelSnapshot(getUmsPool?.(), me.id).catch((err) => {
logger?.warn?.(
'[auth/me] user model snapshot skipped:',
err instanceof Error ? err.message : err,
);
return null;
}),
]);
return res.json({
user: {
...me,
subscription,
},
paths,
capabilities: capabilityState.capabilities,
grantedSkills:
capabilityState.grantedSkills ?? [],
unrestricted: capabilityState.unrestricted,
skillRuntime,
agentCodeRun,
userModelSnapshot,
});
});
app.post('/auth/logout', async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
const legacyAuth = getLegacyAuth();
if (userAuth) {
await userAuth.revoke(userToken(req));
}
if (legacyAuth) {
legacyAuth.revoke(legacySessionToken(req));
}
if (userAuth || legacyAuth) {
clearUserLoginCookies(res, req);
}
res.status(204).end();
});
app.get('/auth/usage', async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
if (!userAuth) {
return res.status(503).json({
message: '未启用用户系统',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
const records = await userAuth.listUsageRecords({
userId: me.id,
limit: 30,
});
res.json({ records });
});
app.post(
'/auth/feedback',
jsonBody,
async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
const feedbackService = getFeedbackService();
if (!userAuth || !feedbackService) {
return res.status(503).json({
message: '反馈服务未启用',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
try {
const result = await feedbackService.submit(
me.id,
{
type: req.body?.type,
title: req.body?.title,
description: req.body?.description,
contact: req.body?.contact,
images: req.body?.images,
context: req.body?.context,
},
);
res.status(201).json({
feedback: result,
});
} catch (error) {
const code =
error &&
typeof error === 'object' &&
'code' in error
? String(error.code)
: '';
if (code === 'invalid_input') {
return res.status(400).json({
message:
error instanceof Error
? error.message
: '提交内容无效',
});
}
logger.warn(
'Submit feedback failed:',
error instanceof Error
? error.message
: error,
);
return res.status(500).json({
message: '反馈提交失败,请稍后重试',
});
}
},
);
app.get('/auth/feedback', async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
const feedbackService = getFeedbackService();
if (!userAuth || !feedbackService) {
return res.status(503).json({
message: '反馈服务未启用',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
const limit = Math.min(
Math.max(Number(req.query?.limit) || 20, 1),
50,
);
const items = await feedbackService.listForUser(
me.id,
{ limit },
);
res.json({ items });
});
app.get(
'/auth/feedback/board',
async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
const feedbackService = getFeedbackService();
if (!userAuth || !feedbackService) {
return res.status(503).json({
message: '反馈服务未启用',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
const page = Math.max(
Number(req.query?.page) || 1,
1,
);
const limit = Math.min(
Math.max(
Number(req.query?.limit) || 10,
1,
),
10,
);
try {
const result =
await feedbackService.listAll({
page,
limit,
});
res.json(result);
} catch (error) {
logger.warn(
'List feedback board failed:',
error instanceof Error
? error.message
: error,
);
return res.status(500).json({
message: '反馈列表加载失败',
});
}
},
);
app.get(
'/auth/feedback/:feedbackId',
async (req, res) => {
await userAuthReady;
const userAuth = getUserAuth();
const feedbackService = getFeedbackService();
if (!userAuth || !feedbackService) {
return res.status(503).json({
message: '反馈服务未启用',
});
}
const me = await userAuth.getMe(userToken(req));
if (!me) {
return res.status(401).json({
message: '未登录',
});
}
try {
const item = await feedbackService.getById(
req.params.feedbackId,
me.id,
);
res.json({
item,
isMine: item.userId === me.id,
});
} catch (error) {
const code =
error &&
typeof error === 'object' &&
'code' in error
? String(error.code)
: '';
if (code === 'feedback_not_found') {
return res.status(404).json({
message:
error instanceof Error
? error.message
: '反馈不存在',
});
}
logger.warn(
'Get feedback detail failed:',
error instanceof Error
? error.message
: error,
);
return res.status(500).json({
message: '反馈详情加载失败',
});
}
},
);
}