import { buildConversationPackageManifest, buildConversationStoragePrefix, createConversationArtifact, createConversationPackageRecord, } from './mindspace-conversation-package.mjs'; import { createMindSpacePublicPageUrl, createMindSpacePublicUrl, normalizeMindSpacePublicRelativePath, } from './mindspace-canonical-url.mjs'; import { normalizeMindSpaceStorageKey } from './mindspace-storage-adapter.mjs'; function serviceError(message, code, details = {}) { return Object.assign(new Error(message), { code, ...details }); } function requireStorageAdapter(storageAdapter) { if (!storageAdapter || typeof storageAdapter.putObject !== 'function') { throw serviceError('MindSpace storage adapter is required', 'missing_mindspace_storage_adapter'); } return storageAdapter; } function packageStorageKey(packageRecord, relativePath) { const record = createConversationPackageRecord(packageRecord); const relative = normalizeMindSpaceStorageKey(relativePath); return `${record.storagePrefix}/${relative}`; } export function createMindSpaceServiceFacade({ storageAdapter, publicBaseUrl, conversationPackageBackfill, conversationPackagePublicHtmlHydrator, logger = console, } = {}) { const storage = requireStorageAdapter(storageAdapter); return { createConversationPackage(input) { return createConversationPackageRecord(input); }, createConversationArtifact(input) { return createConversationArtifact(input); }, buildConversationManifest(input) { return buildConversationPackageManifest(input); }, async putConversationManifest({ packageRecord, artifacts = [] }) { const manifest = buildConversationPackageManifest({ packageRecord, artifacts }); const body = `${JSON.stringify(manifest, null, 2)}\n`; const writeResult = await this.putPackageObject({ packageRecord: manifest, relativePath: 'manifest.json', body, }); return { manifest, storageKey: writeResult.key, writeResult, }; }, buildConversationStoragePrefix(input) { return buildConversationStoragePrefix(input); }, createPublicPageUrl({ ownerKey, filename }) { return createMindSpacePublicPageUrl({ publicBaseUrl, ownerKey, filename }); }, createPublicObjectUrl({ ownerKey, relativePath }) { return createMindSpacePublicUrl({ publicBaseUrl, ownerKey, relativePath }); }, resolvePackageStorageKey({ packageRecord, relativePath }) { return packageStorageKey(packageRecord, relativePath); }, async putPackageObject({ packageRecord, relativePath, body }) { return storage.putObject(packageStorageKey(packageRecord, relativePath), body); }, async getPackageObject({ packageRecord, relativePath }) { return storage.getObject(packageStorageKey(packageRecord, relativePath)); }, async statPackageObject({ packageRecord, relativePath }) { return storage.statObject(packageStorageKey(packageRecord, relativePath)); }, async listPackageObjects({ packageRecord, prefix = '' }) { const record = createConversationPackageRecord(packageRecord); const cleanPrefix = prefix ? normalizeMindSpacePublicRelativePath(prefix) : ''; const storagePrefix = cleanPrefix ? `${record.storagePrefix}/${cleanPrefix}` : record.storagePrefix; return storage.listObjects(storagePrefix); }, async prepareConversationPackageRead({ user, sessionId } = {}) { if (typeof conversationPackageBackfill === 'function') { await conversationPackageBackfill({ user, sessionId }).catch((error) => { logger?.warn?.('[MindSpace] conversation package DB backfill failed:', error?.message ?? error); }); } if (typeof conversationPackagePublicHtmlHydrator === 'function') { return conversationPackagePublicHtmlHydrator({ user, sessionId }); } return []; }, }; } export const mindspaceServiceInternals = { serviceError, packageStorageKey, };