import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { createMindSpaceServiceFacade } from './mindspace-service.mjs'; import { createLocalMindSpaceStorageAdapter } from './mindspace-storage-adapter.mjs'; test('createMindSpaceServiceFacade requires a storage adapter', () => { assert.throws( () => createMindSpaceServiceFacade({ publicBaseUrl: 'https://m.tkmind.cn' }), (error) => error.code === 'missing_mindspace_storage_adapter', ); }); test('MindSpace service facade coordinates package storage and public URLs without raw paths', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-service-')); const service = createMindSpaceServiceFacade({ storageAdapter: createLocalMindSpaceStorageAdapter(root), publicBaseUrl: 'https://m.tkmind.cn', }); const packageRecord = service.createConversationPackage({ id: 'cp_session-1', userId: 'user-1', sessionId: 'session-1', title: '项目周报', now: 1000, }); assert.equal(packageRecord.storagePrefix, 'users/user-1/conversations/session-1'); assert.equal( service.resolvePackageStorageKey({ packageRecord, relativePath: 'public/report.html' }), 'users/user-1/conversations/session-1/public/report.html', ); const writeResult = await service.putPackageObject({ packageRecord, relativePath: 'public/report.html', body: '

Report

', }); assert.equal(writeResult.key, 'users/user-1/conversations/session-1/public/report.html'); const body = await service.getPackageObject({ packageRecord, relativePath: 'public/report.html' }); assert.equal(body.toString('utf8'), '

Report

'); assert.deepEqual( (await service.listPackageObjects({ packageRecord })).map((item) => item.key), ['users/user-1/conversations/session-1/public/report.html'], ); assert.equal( service.createPublicPageUrl({ ownerKey: 'user-1', filename: 'report.html' }), 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', ); }); test('MindSpace service facade builds manifests from package artifacts', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-service-')); const service = createMindSpaceServiceFacade({ storageAdapter: createLocalMindSpaceStorageAdapter(root), publicBaseUrl: 'https://m.tkmind.cn', }); const packageRecord = service.createConversationPackage({ id: 'cp_session-1', userId: 'user-1', sessionId: 'session-1', now: 1000, }); const artifact = service.createConversationArtifact({ id: 'ca_1', packageId: packageRecord.id, artifactKind: 'public_html', displayName: 'report.html', storageKey: 'users/user-1/conversations/session-1/public/report.html', canonicalUrl: service.createPublicPageUrl({ ownerKey: 'user-1', filename: 'report.html' }), now: 2000, }); const manifest = service.buildConversationManifest({ packageRecord, artifacts: [artifact], }); assert.equal(manifest.packageId, 'cp_session-1'); assert.equal(manifest.artifacts[0].kind, 'public_html'); assert.equal( manifest.artifacts[0].canonicalUrl, 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', ); }); test('MindSpace service facade writes manifest.json inside the conversation package', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-service-')); const service = createMindSpaceServiceFacade({ storageAdapter: createLocalMindSpaceStorageAdapter(root), publicBaseUrl: 'https://m.tkmind.cn', }); const packageRecord = service.createConversationPackage({ id: 'cp_session-1', userId: 'user-1', sessionId: 'session-1', now: 1000, }); const artifact = service.createConversationArtifact({ id: 'ca_report', packageId: packageRecord.id, artifactKind: 'public_html', displayName: 'report.html', sortOrder: 1, now: 2000, }); const result = await service.putConversationManifest({ packageRecord, artifacts: [artifact], }); assert.equal(result.storageKey, 'users/user-1/conversations/session-1/manifest.json'); const manifestJson = await service.getPackageObject({ packageRecord, relativePath: 'manifest.json' }); const manifest = JSON.parse(manifestJson.toString('utf8')); assert.equal(manifest.packageId, 'cp_session-1'); assert.deepEqual( manifest.artifacts.map((item) => item.artifactId), ['ca_report'], ); }); test('MindSpace service facade prepares conversation package reads through injected hooks', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-service-')); const calls = []; const warnings = []; const service = createMindSpaceServiceFacade({ storageAdapter: createLocalMindSpaceStorageAdapter(root), publicBaseUrl: 'https://m.tkmind.cn', conversationPackageBackfill: async (input) => { calls.push(['backfill', input]); throw new Error('transient db issue'); }, conversationPackagePublicHtmlHydrator: async (input) => { calls.push(['hydrate', input]); return ['artifact-1']; }, logger: { warn: (...args) => warnings.push(args), }, }); const result = await service.prepareConversationPackageRead({ user: { id: 'user-1' }, sessionId: 'session-1', }); assert.deepEqual(result, ['artifact-1']); assert.deepEqual( calls.map(([name]) => name), ['backfill', 'hydrate'], ); assert.equal(calls[0][1].sessionId, 'session-1'); assert.equal(warnings.length, 1); assert.equal(warnings[0][0], '[MindSpace] conversation package DB backfill failed:'); });