Files

105 lines
3.5 KiB
JavaScript
Raw Permalink Normal View History

import { mergeMindSpacePagePatch, normalizeMindSpacePagePatchInput } from './mindspace-page-patch.mjs';
export function createPageLiveEditService({ pageService, resolveUserIdForAgentSession }) {
/** @type {Map<string, { userId: string, pageId: string, boundAt: number }>} */
const sessionBindings = new Map();
/** @type {Map<string, number>} */
const liveRevisions = new Map();
const bumpRevision = (pageId) => {
liveRevisions.set(pageId, (liveRevisions.get(pageId) ?? 0) + 1);
};
return {
bindSession({ userId, sessionId, pageId, parentSessionId = null }) {
if (!userId || !sessionId || !pageId) {
throw Object.assign(new Error('缺少绑定参数'), { code: 'invalid_request' });
}
sessionBindings.set(String(sessionId), {
userId: String(userId),
pageId: String(pageId),
parentSessionId: parentSessionId ? String(parentSessionId) : null,
boundAt: Date.now(),
});
return {
sessionId: String(sessionId),
pageId: String(pageId),
...(parentSessionId ? { parentSessionId: String(parentSessionId) } : {}),
};
},
unbindSession(sessionId) {
sessionBindings.delete(String(sessionId));
},
getBinding(sessionId) {
return sessionBindings.get(String(sessionId)) ?? null;
},
getLiveRevision(pageId) {
return liveRevisions.get(String(pageId)) ?? 0;
},
async applyAgentPatch(input) {
const sessionId = String(input?.sessionId ?? input?.session_id ?? '').trim();
const pageId = String(input?.pageId ?? input?.page_id ?? '').trim();
if (!sessionId || !pageId) {
throw Object.assign(new Error('缺少 session_id 或 page_id'), { code: 'invalid_request' });
}
const userId = await resolveUserIdForAgentSession(sessionId);
if (!userId) {
throw Object.assign(new Error('无效的 Agent 会话'), { code: 'forbidden' });
}
const binding = sessionBindings.get(sessionId);
if (binding && binding.pageId !== pageId) {
throw Object.assign(new Error('当前会话未绑定该页面'), { code: 'page_binding_mismatch' });
}
if (binding && binding.userId !== userId) {
throw Object.assign(new Error('会话与用户不匹配'), { code: 'forbidden' });
}
const patch = normalizeMindSpacePagePatchInput(input);
if (!patch) {
throw Object.assign(new Error('缺少 title / summary / content 变更'), { code: 'invalid_request' });
}
const page = await pageService.getPage(userId, pageId);
const merged = mergeMindSpacePagePatch(
{
title: page.title,
summary: page.summary ?? '',
content: page.content ?? '',
},
patch,
);
const updated = await pageService.updatePage(userId, pageId, {
expectedVersion: input?.expectedVersion ?? input?.expected_version ?? page.versionNo,
title: merged.title,
summary: merged.summary,
content: merged.content,
templateId: page.templateId,
changeNote: String(input?.changeNote ?? input?.change_note ?? 'Agent 对话修改').slice(0, 255),
});
bumpRevision(pageId);
return {
page: updated,
liveRevision: liveRevisions.get(pageId) ?? 0,
};
},
async getRevisionSnapshot(userId, pageId) {
const page = await pageService.getPage(userId, pageId);
return {
pageId: page.id,
versionNo: page.versionNo,
updatedAt: page.updatedAt,
liveRevision: liveRevisions.get(pageId) ?? 0,
};
},
};
}