feat: finalize mindspace service extraction phase a
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import crypto from 'node:crypto';
|
||||
import fsPromises from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
collectOwnPublicHtmlArtifactRefs,
|
||||
normalizePublicHtmlRelativePath,
|
||||
} from './mindspace-public-finish-sync.mjs';
|
||||
import {
|
||||
buildMindSpacePublicUrlForUser,
|
||||
resolveMindSpaceUserPublishDir,
|
||||
} from './mindspace-runtime-config.mjs';
|
||||
|
||||
export async function registerPublicHtmlArtifactsForConversationPackage({
|
||||
conversationPackageRegistry,
|
||||
h5Root,
|
||||
env = process.env,
|
||||
user,
|
||||
publishDir,
|
||||
sessionId,
|
||||
title = null,
|
||||
relativePaths = [],
|
||||
artifactRefs = [],
|
||||
} = {}) {
|
||||
if (
|
||||
!conversationPackageRegistry ||
|
||||
!user?.id ||
|
||||
!publishDir ||
|
||||
!sessionId ||
|
||||
((!Array.isArray(relativePaths) || relativePaths.length === 0) &&
|
||||
(!Array.isArray(artifactRefs) || artifactRefs.length === 0))
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
const publishRoot = path.resolve(publishDir);
|
||||
const packageTitle = String(title ?? '').trim() || null;
|
||||
const existingManifest = await conversationPackageRegistry
|
||||
.readManifestForSession({ userId: user.id, sessionId })
|
||||
.catch(() => null);
|
||||
const packageRecord =
|
||||
existingManifest?.packageId && existingManifest.title
|
||||
? { id: existingManifest.packageId }
|
||||
: await conversationPackageRegistry.ensurePackage({
|
||||
userId: user.id,
|
||||
sessionId,
|
||||
title: packageTitle ?? existingManifest?.title ?? null,
|
||||
});
|
||||
const recorded = [];
|
||||
const now = Date.now();
|
||||
const refs =
|
||||
Array.isArray(artifactRefs) && artifactRefs.length > 0
|
||||
? artifactRefs
|
||||
: relativePaths.map((relativePath) => ({ relativePath }));
|
||||
for (const ref of refs) {
|
||||
const relativePath = typeof ref === 'string' ? ref : ref?.relativePath;
|
||||
const normalized = normalizePublicHtmlRelativePath(relativePath);
|
||||
if (!normalized || !normalized.toLowerCase().endsWith('.html')) continue;
|
||||
const absolutePath = path.resolve(publishRoot, normalized);
|
||||
if (absolutePath !== publishRoot && !absolutePath.startsWith(`${publishRoot}${path.sep}`)) continue;
|
||||
let stat = null;
|
||||
try {
|
||||
stat = await fsPromises.stat(absolutePath);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (!stat.isFile()) continue;
|
||||
const hash = crypto
|
||||
.createHash('sha256')
|
||||
.update(`${user.id}:${sessionId}:${normalized}`)
|
||||
.digest('hex')
|
||||
.slice(0, 16);
|
||||
const artifactId = `ca_public_html_${hash}`;
|
||||
await conversationPackageRegistry.recordArtifact({
|
||||
id: artifactId,
|
||||
packageId: packageRecord.id,
|
||||
artifactKind: 'public_html',
|
||||
role: 'assistant',
|
||||
messageId:
|
||||
typeof ref?.messageId === 'string' && ref.messageId.trim() ? ref.messageId.trim() : null,
|
||||
displayName: path.posix.basename(normalized),
|
||||
mimeType: 'text/html',
|
||||
sizeBytes: stat.size,
|
||||
canonicalUrl: buildMindSpacePublicUrlForUser({
|
||||
h5Root,
|
||||
env,
|
||||
user,
|
||||
relativePath: normalized,
|
||||
}),
|
||||
sortOrder: Number.isFinite(stat.mtimeMs) ? Math.round(stat.mtimeMs) : now,
|
||||
now,
|
||||
});
|
||||
recorded.push({ artifactId, relativePath: normalized });
|
||||
}
|
||||
if (recorded.length > 0) {
|
||||
await conversationPackageRegistry.writeManifestForSession({
|
||||
userId: user.id,
|
||||
sessionId,
|
||||
});
|
||||
}
|
||||
return recorded;
|
||||
} catch (error) {
|
||||
console.warn('[MindSpace] failed to record public html artifacts:', error?.message ?? error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export function createConversationPackagePublicHtmlHydrator({
|
||||
h5Root,
|
||||
resolveSessionSnapshot,
|
||||
registerPublicHtmlArtifactsForConversation,
|
||||
} = {}) {
|
||||
return async function hydrateConversationPackagePublicHtmlArtifacts({ user, sessionId }) {
|
||||
if (!user?.id || !sessionId || typeof resolveSessionSnapshot !== 'function') return [];
|
||||
const snapshot = await resolveSessionSnapshot(sessionId).catch(() => null);
|
||||
const messages = Array.isArray(snapshot?.messages) ? snapshot.messages : [];
|
||||
const publishDir = resolveMindSpaceUserPublishDir(h5Root, { id: user.id });
|
||||
const artifactRefs = collectOwnPublicHtmlArtifactRefs({
|
||||
messages,
|
||||
currentUser: user,
|
||||
publishDir,
|
||||
});
|
||||
return (
|
||||
(await registerPublicHtmlArtifactsForConversation?.({
|
||||
user,
|
||||
publishDir,
|
||||
sessionId,
|
||||
title: snapshot?.session?.name,
|
||||
artifactRefs,
|
||||
})) ?? []
|
||||
);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user