function assertRouter(api) { if ( !api || typeof api.get !== 'function' || typeof api.post !== 'function' || typeof api.put !== 'function' || typeof api.delete !== 'function' ) { throw new Error( 'attachPortalMindSpacePageCoreRoutes requires an Express-compatible router', ); } } export function attachPortalMindSpacePageCoreRoutes( api, { getMindSpacePages = () => null, getMindSpacePublications = () => null, getMindSpace = () => null, getMindSpaceAudit = () => null, getMindSpacePageLiveEdit = () => null, getMindSpacePageEditSession = () => null, getUserAuth = () => null, syncUserGeneratedPages, ownsAgentSession, ensureMindSpaceEnabled, sendData, sendError, handleMindSpaceError, } = {}, ) { assertRouter(api); if ( typeof syncUserGeneratedPages !== 'function' || typeof ownsAgentSession !== 'function' || typeof ensureMindSpaceEnabled !== 'function' || typeof sendData !== 'function' || typeof sendError !== 'function' || typeof handleMindSpaceError !== 'function' ) { throw new Error( 'attachPortalMindSpacePageCoreRoutes requires page route dependencies', ); } api.post('/mindspace/v1/pages', async (req, res) => { const pages = getMindSpacePages(); if (!pages) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const page = await pages.createPage(req.currentUser.id, { title: req.body?.title, summary: req.body?.summary, content: req.body?.content, contentFormat: req.body?.content_format === 'html' ? 'html' : undefined, templateId: req.body?.template_id, pageType: req.body?.page_type, categoryCode: req.body?.category_code, }); return res.status(201).json({ data: page }); } catch (error) { return handleMindSpaceError(res, req, error); } }); api.get('/mindspace/v1/pages', async (req, res) => { const pages = getMindSpacePages(); if (!pages) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { await syncUserGeneratedPages(req.currentUser.id); const limit = Number.parseInt(String(req.query.limit ?? ''), 10); const offset = Number.parseInt(String(req.query.offset ?? ''), 10); const result = await pages.listPages(req.currentUser.id, { status: typeof req.query.status === 'string' ? req.query.status : undefined, categoryCode: typeof req.query.category_code === 'string' ? req.query.category_code : undefined, ...(Number.isFinite(limit) ? { limit } : {}), ...(Number.isFinite(offset) ? { offset } : {}), }); return res.json({ data: result.items, page: { total: result.total, limit: result.limit, offset: result.offset, has_more: result.hasMore, next_cursor: null, }, }); } catch (error) { return handleMindSpaceError(res, req, error); } }); api.get('/mindspace/v1/pages/:pageId', async (req, res) => { const pages = getMindSpacePages(); if (!pages) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const [page, versions, publication] = await Promise.all([ pages.getPage(req.currentUser.id, req.params.pageId), pages.listVersions(req.currentUser.id, req.params.pageId), getMindSpacePublications()?.getCurrent( req.currentUser.id, req.params.pageId, ) ?? null, ]); return res.json({ data: { ...page, versions, publication, }, }); } catch (error) { return handleMindSpaceError(res, req, error); } }); api.delete('/mindspace/v1/pages/:pageId', async (req, res) => { const pages = getMindSpacePages(); if (!pages || !ensureMindSpaceEnabled(res, req)) return; try { const removeFromPlaza = String( req.query?.remove_from_plaza ?? req.body?.remove_from_plaza ?? '', ).toLowerCase() === 'true' || req.query?.remove_from_plaza === '1' || req.body?.remove_from_plaza === true; const result = await pages.deletePage( req.currentUser.id, req.params.pageId, { removeFromPlaza }, ); const quota = await getMindSpace().getQuota(req.currentUser.id); await getMindSpaceAudit()?.write({ userId: req.currentUser.id, action: 'page.delete', objectType: 'page', objectId: req.params.pageId, ip: req.ip, detail: { offlinedPublicationCount: result.offlinedPublicationCount, hiddenPlazaPostCount: result.hiddenPlazaPostCount, deletedAssetCount: result.deletedAssetCount, freedBytes: result.freedBytes, }, }); return sendData(res, req, { ...result, quota }); } catch (error) { return handleMindSpaceError(res, req, error); } }); api.get( '/mindspace/v1/pages/:pageId/delete-preview', async (req, res) => { const pages = getMindSpacePages(); if (!pages || !ensureMindSpaceEnabled(res, req)) return; try { return sendData( res, req, await pages.getDeletePreview( req.currentUser.id, req.params.pageId, ), ); } catch (error) { return handleMindSpaceError(res, req, error); } }, ); api.put('/mindspace/v1/pages/:pageId', async (req, res) => { const pages = getMindSpacePages(); if (!pages) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const page = await pages.updatePage( req.currentUser.id, req.params.pageId, { expectedVersion: req.body?.expected_version, title: req.body?.title, summary: req.body?.summary, content: req.body?.content, templateId: req.body?.template_id, pageType: req.body?.page_type, changeNote: req.body?.change_note, }, ); return res.json({ data: page }); } catch (error) { return handleMindSpaceError(res, req, error); } }); api.post( '/mindspace/v1/pages/:pageId/live-edit/bind', async (req, res) => { const pageLiveEdit = getMindSpacePageLiveEdit(); const pages = getMindSpacePages(); if (!pageLiveEdit || !pages) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const sessionId = String(req.body?.session_id ?? '').trim(); if (!sessionId) { return sendError( res, req, 400, 'invalid_request', '缺少 session_id', ); } const owns = await ownsAgentSession( req.currentUser.id, sessionId, ); if (!owns) { return sendError( res, req, 403, 'forbidden', '无权绑定该 Agent 会话', ); } await pages.getPage( req.currentUser.id, req.params.pageId, ); const parentSessionId = String(req.body?.parent_session_id ?? '').trim() || null; return sendData( res, req, pageLiveEdit.bindSession({ userId: req.currentUser.id, sessionId, pageId: req.params.pageId, parentSessionId, }), ); } catch (error) { return handleMindSpaceError(res, req, error); } }, ); api.post( '/mindspace/v1/pages/:pageId/live-edit/fork-session', async (req, res) => { const pageEditSession = getMindSpacePageEditSession(); if (!pageEditSession || !getMindSpacePages()) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const parentSessionId = String( req.body?.parent_session_id ?? '', ).trim(); if (!parentSessionId) { return sendError( res, req, 400, 'invalid_request', '缺少 parent_session_id', ); } const gate = await getUserAuth().canUseChat( req.currentUser.id, ); if (!gate.ok) { return sendError( res, req, 402, gate.code ?? 'insufficient_balance', gate.message, ); } return sendData( res, req, await pageEditSession.forkSession({ userId: req.currentUser.id, pageId: req.params.pageId, parentSessionId, h5ApiBase: String( req.body?.h5_api_base ?? req.body?.h5ApiBase ?? '', ).trim() || null, }), ); } catch (error) { if (error?.code === 'forbidden') { return sendError( res, req, 403, error.code, error.message, ); } if (error?.code === 'invalid_request') { return sendError( res, req, 400, error.code, error.message, ); } return handleMindSpaceError(res, req, error); } }, ); api.post( '/mindspace/v1/pages/:pageId/live-edit/close-session', async (req, res) => { const pageEditSession = getMindSpacePageEditSession(); if (!pageEditSession || !getMindSpacePages()) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { const sessionId = String(req.body?.session_id ?? '').trim(); if (!sessionId) { return sendError( res, req, 400, 'invalid_request', '缺少 session_id', ); } return sendData( res, req, await pageEditSession.closeSession({ userId: req.currentUser.id, pageId: req.params.pageId, sessionId, parentSessionId: String(req.body?.parent_session_id ?? '').trim() || null, summary: String(req.body?.summary ?? ''), }), ); } catch (error) { if ( error?.code === 'forbidden' || error?.code === 'page_binding_mismatch' ) { return sendError( res, req, 403, error.code, error.message, ); } if (error?.code === 'invalid_request') { return sendError( res, req, 400, error.code, error.message, ); } return handleMindSpaceError(res, req, error); } }, ); api.get( '/mindspace/v1/pages/:pageId/live-edit/revision', async (req, res) => { const pageLiveEdit = getMindSpacePageLiveEdit(); if (!pageLiveEdit || !getMindSpacePages()) { return res.status(503).json({ message: 'MindSpace 未启用' }); } try { return sendData( res, req, await pageLiveEdit.getRevisionSnapshot( req.currentUser.id, req.params.pageId, ), ); } catch (error) { return handleMindSpaceError(res, req, error); } }, ); }