mindspace: close authority boundaries
This commit is contained in:
+67
-118
@@ -1,7 +1,5 @@
|
||||
import express from 'express';
|
||||
import crypto from 'node:crypto';
|
||||
import fs from 'node:fs';
|
||||
import fsPromises from 'node:fs/promises';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
@@ -73,13 +71,10 @@ import { attachPortalSessionRoutes } from './server/portal-session-routes.mjs';
|
||||
import { attachPortalUserMemoryRoutes } from './server/portal-user-memory-routes.mjs';
|
||||
import { assertMindSpaceRoute, mindspaceFlags } from './mindspace-flags.mjs';
|
||||
import { normalizeWorkspaceRelativePath } from './mindspace-pages.mjs';
|
||||
import { registerPublicHtmlArtifactsForConversationPackage } from './mindspace-conversation-package-public-html.mjs';
|
||||
import {
|
||||
buildMindSpacePublicUrlForUser,
|
||||
resolveMindSpaceRuntimeConfig,
|
||||
resolveMindSpacePublishRoot,
|
||||
resolveMindSpaceServerRuntimeOptions,
|
||||
resolveMindSpaceUserPublishDir,
|
||||
resolvePortalH5Root,
|
||||
} from './mindspace-runtime-config.mjs';
|
||||
import {
|
||||
@@ -92,15 +87,12 @@ import {
|
||||
buildChatSaveThumbnailUrl,
|
||||
buildWorkspaceAssetUrl,
|
||||
buildWorkspaceThumbnailUrl,
|
||||
materializePrivateAssetsInWorkspaceHtml,
|
||||
repairMissingHtmlAssetReferences,
|
||||
resolveChatSaveAnalysis,
|
||||
} from './mindspace-chat-save.mjs';
|
||||
import {
|
||||
normalizePublicHtmlRelativePath,
|
||||
} from './mindspace-public-finish-sync.mjs';
|
||||
import { resolvePlazaPostPath, resolvePlazaPublicBase } from './src/utils/public-site-bases.mjs';
|
||||
import { listRecentlyModifiedPublicHtmlRelativePaths } from './mindspace-run-public-html-scope.mjs';
|
||||
import { DEFAULT_IMAGE_UPLOAD_MAX_BYTES } from './user-image-normalize.mjs';
|
||||
import { loadWechatMpConfig } from './wechat-mp-config.mjs';
|
||||
import {
|
||||
@@ -290,6 +282,11 @@ let mindSpace = null;
|
||||
let mindSpaceAssets = null;
|
||||
let mindSpaceAudit = null;
|
||||
let mindSpaceServiceFacade = null;
|
||||
let mindSpaceChatSave = null;
|
||||
let mindSpaceConversationArtifacts = null;
|
||||
let mindSpacePublicFinish = null;
|
||||
let mindSpaceWorkspacePublicationDelivery =
|
||||
null;
|
||||
let mindSpaceConversationPackageRegistry = null;
|
||||
let mindSpacePages = null;
|
||||
let mindSpacePageSync = null;
|
||||
@@ -342,7 +339,6 @@ async function bootstrapUserAuth() {
|
||||
onMindSearchSchemaReady: () => {
|
||||
authPool = pool;
|
||||
},
|
||||
registerPublicHtmlArtifactsForConversation,
|
||||
workspaceMaintenanceEnabled:
|
||||
WORKSPACE_MAINTENANCE_ENABLED,
|
||||
logger: console,
|
||||
@@ -362,6 +358,15 @@ async function bootstrapUserAuth() {
|
||||
mindSpace = domainServices.mindSpace;
|
||||
mindSpaceServiceFacade =
|
||||
domainServices.mindSpaceServiceFacade;
|
||||
mindSpaceChatSave =
|
||||
domainServices.mindSpaceChatSave;
|
||||
mindSpaceConversationArtifacts =
|
||||
domainServices.mindSpaceConversationArtifacts;
|
||||
mindSpacePublicFinish =
|
||||
domainServices.mindSpacePublicFinish;
|
||||
mindSpaceWorkspacePublicationDelivery =
|
||||
domainServices
|
||||
.mindSpaceWorkspacePublicationDelivery;
|
||||
mindSpaceConversationPackageRegistry =
|
||||
domainServices.mindSpaceConversationPackageRegistry;
|
||||
mindSpaceAssets = domainServices.mindSpaceAssets;
|
||||
@@ -485,6 +490,8 @@ async function bootstrapUserAuth() {
|
||||
memoryV2,
|
||||
systemDisclosurePolicyService,
|
||||
mindSpaceAssets,
|
||||
getWorkspacePublicationDelivery: () =>
|
||||
mindSpaceWorkspacePublicationDelivery,
|
||||
directChatService,
|
||||
chatIntentRouter,
|
||||
syncUserGeneratedPages,
|
||||
@@ -501,7 +508,7 @@ async function bootstrapUserAuth() {
|
||||
env: process.env,
|
||||
usersRoot: USERS_ROOT,
|
||||
wechatMpConfig: WECHAT_MP_CONFIG,
|
||||
authPool,
|
||||
mindSpacePublicFinish,
|
||||
userAuth,
|
||||
sessionAccess,
|
||||
tkmindProxy,
|
||||
@@ -1115,12 +1122,18 @@ async function syncUserGeneratedPages(userId, { sessionId = null, sinceMs = null
|
||||
// no conversation artifact. Discover only files written around this run;
|
||||
// `null` would rescan every historical page and let stale Page Data pages
|
||||
// block an unrelated delivery.
|
||||
const recentWorkspaceRelativePaths = sessionId && !discoveredRelativePaths?.length
|
||||
? listRecentlyModifiedPublicHtmlRelativePaths(
|
||||
resolveMindSpaceUserPublishDir(H5_ROOT, { id: userId }),
|
||||
{ sinceMs },
|
||||
)
|
||||
: [];
|
||||
const recentWorkspaceRelativePaths =
|
||||
sessionId &&
|
||||
!discoveredRelativePaths?.length &&
|
||||
mindSpaceWorkspacePublicationDelivery
|
||||
? (
|
||||
await mindSpaceWorkspacePublicationDelivery
|
||||
.listRecentlyModifiedPublicHtml({
|
||||
userId,
|
||||
sinceMs,
|
||||
})
|
||||
)?.relativePaths ?? []
|
||||
: [];
|
||||
const pageDataRelativePaths = sessionId
|
||||
? (discoveredRelativePaths?.length ? discoveredRelativePaths : recentWorkspaceRelativePaths)
|
||||
: null;
|
||||
@@ -1147,42 +1160,23 @@ async function resolveChatSaveBundle(user, h5Root, input = {}) {
|
||||
selectedLinkIndex,
|
||||
});
|
||||
|
||||
if (resolvedHtml?.content && resolvedHtml.relativePath && authPool) {
|
||||
const { storageRoot } = resolveMindSpaceRuntimeConfig(h5Root, process.env);
|
||||
let htmlContent = resolvedHtml.content;
|
||||
|
||||
const repaired = await repairMissingHtmlAssetReferences({
|
||||
pool: authPool,
|
||||
userId: user.id,
|
||||
sourceContent: source.content,
|
||||
html: htmlContent,
|
||||
}).catch(() => ({ html: htmlContent, changed: false }));
|
||||
if (repaired.changed) {
|
||||
htmlContent = repaired.html;
|
||||
}
|
||||
|
||||
const materialized = await materializePrivateAssetsInWorkspaceHtml({
|
||||
pool: authPool,
|
||||
storageRoot,
|
||||
h5Root,
|
||||
userId: user.id,
|
||||
html: htmlContent,
|
||||
htmlRelativePath: resolvedHtml.relativePath,
|
||||
writeBack: false,
|
||||
}).catch(() => ({ html: htmlContent, count: 0, changed: false }));
|
||||
if (materialized.changed) {
|
||||
htmlContent = materialized.html;
|
||||
}
|
||||
|
||||
if (htmlContent !== resolvedHtml.content) {
|
||||
const publishDir = resolveMindSpaceUserPublishDir(h5Root, { id: user.id });
|
||||
await fsPromises.writeFile(
|
||||
path.join(publishDir, resolvedHtml.relativePath),
|
||||
htmlContent,
|
||||
'utf8',
|
||||
);
|
||||
resolvedHtml = { ...resolvedHtml, content: htmlContent };
|
||||
}
|
||||
if (
|
||||
resolvedHtml?.content &&
|
||||
resolvedHtml.relativePath &&
|
||||
mindSpaceChatSave
|
||||
) {
|
||||
const materialized =
|
||||
await mindSpaceChatSave.materializeWorkspaceHtml({
|
||||
userId: user.id,
|
||||
sourceContent: source.content,
|
||||
html: resolvedHtml.content,
|
||||
relativePath: resolvedHtml.relativePath,
|
||||
});
|
||||
resolvedHtml = {
|
||||
...resolvedHtml,
|
||||
relativePath: materialized.relativePath,
|
||||
content: materialized.html,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -1228,7 +1222,7 @@ async function registerPublishedLongImageArtifactForConversation({
|
||||
const messageId = String(pageSource.sourceMessageId ?? '').trim();
|
||||
const publicationId = String(result?.publication?.id ?? '').trim();
|
||||
if (
|
||||
!mindSpaceConversationPackageRegistry ||
|
||||
!mindSpaceConversationArtifacts ||
|
||||
!ownerId ||
|
||||
!sessionId ||
|
||||
!publicationId ||
|
||||
@@ -1237,77 +1231,34 @@ async function registerPublishedLongImageArtifactForConversation({
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const hash = crypto
|
||||
.createHash('sha256')
|
||||
.update(`${ownerId}:${sessionId}:${publicationId}:long-image`)
|
||||
.digest('hex')
|
||||
.slice(0, 16);
|
||||
const artifactId = `ca_long_image_${hash}`;
|
||||
const filename = `${publicationId || 'published-page'}.long.png`;
|
||||
const relativePath = `artifacts/${artifactId}/${filename}`;
|
||||
const now = Date.now();
|
||||
const { packageRecord, writeResult } =
|
||||
await mindSpaceConversationPackageRegistry.putObjectForSession({
|
||||
userId: ownerId,
|
||||
await mindSpaceConversationArtifacts
|
||||
.registerPublishedLongImageArtifact({
|
||||
ownerId,
|
||||
sessionId,
|
||||
messageId: messageId || null,
|
||||
publicationId,
|
||||
pageId:
|
||||
pageSource.pageId ??
|
||||
result?.publication?.pageId ??
|
||||
null,
|
||||
title: pageSource.title ?? null,
|
||||
relativePath,
|
||||
body: image,
|
||||
canonicalUrl,
|
||||
});
|
||||
await mindSpaceConversationPackageRegistry.recordArtifact({
|
||||
id: artifactId,
|
||||
packageId: packageRecord.id,
|
||||
artifactKind: 'long_image',
|
||||
role: 'assistant',
|
||||
pageId: pageSource.pageId ?? result?.publication?.pageId ?? null,
|
||||
publicationId,
|
||||
messageId: messageId || null,
|
||||
displayName: filename,
|
||||
mimeType: 'image/png',
|
||||
sizeBytes: image.length,
|
||||
storageKey: writeResult.key,
|
||||
canonicalUrl,
|
||||
sortOrder: now,
|
||||
now,
|
||||
});
|
||||
await mindSpaceConversationPackageRegistry.writeManifestForSession({
|
||||
userId: ownerId,
|
||||
sessionId,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('[MindSpace] failed to record published long image artifact:', error?.message ?? error);
|
||||
}
|
||||
}
|
||||
|
||||
async function registerPublicHtmlArtifactsForConversation({
|
||||
user,
|
||||
publishDir,
|
||||
sessionId,
|
||||
title = null,
|
||||
relativePaths = [],
|
||||
artifactRefs = [],
|
||||
}) {
|
||||
return registerPublicHtmlArtifactsForConversationPackage({
|
||||
conversationPackageRegistry: mindSpaceConversationPackageRegistry,
|
||||
h5Root: H5_ROOT,
|
||||
env: process.env,
|
||||
user,
|
||||
publishDir,
|
||||
sessionId,
|
||||
title,
|
||||
relativePaths,
|
||||
artifactRefs,
|
||||
});
|
||||
}
|
||||
|
||||
attachPortalMindSpaceChatSaveRoutes(api, {
|
||||
h5Root: H5_ROOT,
|
||||
env: process.env,
|
||||
getMindSpacePages: () => mindSpacePages,
|
||||
getMindSpaceAssets: () => mindSpaceAssets,
|
||||
getMindSpaceChatSave: () => mindSpaceChatSave,
|
||||
getConversationArtifactService: () =>
|
||||
mindSpaceConversationArtifacts,
|
||||
getAuthPool: () => authPool,
|
||||
getConversationPackageRegistry: () =>
|
||||
mindSpaceConversationPackageRegistry,
|
||||
resolveChatSaveBundle,
|
||||
resolveExistingSavedPage,
|
||||
resolveOwnedAssistantMessage,
|
||||
@@ -1317,11 +1268,10 @@ attachPortalMindSpaceChatSaveRoutes(api, {
|
||||
|
||||
attachPortalMindSpaceChatShareRoutes(api, {
|
||||
h5Root: H5_ROOT,
|
||||
env: process.env,
|
||||
getMindSpacePages: () => mindSpacePages,
|
||||
getMindSpaceChatSave: () => mindSpaceChatSave,
|
||||
getMindSpacePublications: () => mindSpacePublications,
|
||||
getPlazaPosts: () => plazaPosts,
|
||||
getAuthPool: () => authPool,
|
||||
resolveChatSaveBundle,
|
||||
resolvePlazaPostUrl: resolvePlazaPostUrlForRequest,
|
||||
mapPlazaError,
|
||||
@@ -1406,25 +1356,21 @@ attachPortalAgentRuntimeRoutes(api, {
|
||||
});
|
||||
|
||||
attachPortalSessionRoutes(api, {
|
||||
h5Root: H5_ROOT,
|
||||
env: process.env,
|
||||
waitForUserAuthReady: () => userAuthReady,
|
||||
getUserAuth: () => userAuth,
|
||||
getTkmindProxy: () => tkmindProxy,
|
||||
getSessionSnapshotService: () => sessionSnapshotService,
|
||||
getAuthPool: () => authPool,
|
||||
getMindSpaceAssets: () => mindSpaceAssets,
|
||||
getMindSpacePublicFinish: () =>
|
||||
mindSpacePublicFinish,
|
||||
getMemoryV2: () => memoryV2,
|
||||
getMindSpaceAnalyticsConfig: () => mindSpaceAnalyticsConfig,
|
||||
getMindSpaceRybbitConfig: () => mindSpaceRybbitConfig,
|
||||
isWorkspaceMaintenanceEnabled: () =>
|
||||
WORKSPACE_MAINTENANCE_ENABLED,
|
||||
ownsAgentSession,
|
||||
unregisterAgentSessionForUser,
|
||||
beginSessionPageDelivery,
|
||||
endSessionPageDelivery,
|
||||
syncUserGeneratedPages,
|
||||
registerPublicHtmlArtifactsForConversation,
|
||||
logger: console,
|
||||
});
|
||||
|
||||
@@ -1517,7 +1463,6 @@ app.use('/rybbit', createProxyMiddleware({
|
||||
}));
|
||||
const { serveUserPublishFile } =
|
||||
createPortalWorkspacePublicationDelivery({
|
||||
h5Root: H5_ROOT,
|
||||
internalAgentSecret:
|
||||
INTERNAL_AGENT_SECRET,
|
||||
analyticsConfig:
|
||||
@@ -1527,6 +1472,8 @@ const { serveUserPublishFile } =
|
||||
getAuthPool: () => authPool,
|
||||
getUserAuth: () => userAuth,
|
||||
getMindSpacePages: () => mindSpacePages,
|
||||
getWorkspacePublicationDelivery: () =>
|
||||
mindSpaceWorkspacePublicationDelivery,
|
||||
resolveRequestOrigin,
|
||||
removeQueryParam,
|
||||
logger: console,
|
||||
@@ -1557,6 +1504,8 @@ attachPortalPublicationRoutes({
|
||||
getMindSpacePages: () => mindSpacePages,
|
||||
getMindSpacePublications: () =>
|
||||
mindSpacePublications,
|
||||
getWorkspacePublicationDelivery: () =>
|
||||
mindSpaceWorkspacePublicationDelivery,
|
||||
getUserAuth: () => userAuth,
|
||||
sendPublishedPage,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user