163 lines
5.6 KiB
JavaScript
163 lines
5.6 KiB
JavaScript
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: '<h1>Report</h1>',
|
|
});
|
|
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'), '<h1>Report</h1>');
|
|
|
|
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:');
|
|
});
|