import assert from 'node:assert/strict'; import test from 'node:test'; import { createConversationPackageStore } from './mindspace-conversation-package-store.mjs'; function createFakePool() { const packages = new Map(); const artifacts = new Map(); const queries = []; return { queries, async query(sql, params = []) { queries.push({ sql, params }); if (/INSERT INTO h5_conversation_packages/i.test(sql)) { const [ id, user_id, session_id, title, status, storage_prefix, manifest_asset_id, created_at, updated_at, ] = params; packages.set(`${user_id}:${session_id}`, { id, user_id, session_id, title, status, storage_prefix, manifest_asset_id, created_at, updated_at, }); return [{ affectedRows: 1 }]; } if (/FROM h5_conversation_packages/i.test(sql)) { return [[packages.get(`${params[0]}:${params[1]}`)].filter(Boolean)]; } if (/INSERT INTO h5_conversation_artifacts/i.test(sql)) { const [ id, package_id, artifact_kind, role, asset_id, page_id, publication_id, agent_run_id, message_id, display_name, mime_type, size_bytes, storage_key, canonical_url, sort_order, created_at, ] = params; artifacts.set(id, { id, package_id, artifact_kind, role, asset_id, page_id, publication_id, agent_run_id, message_id, display_name, mime_type, size_bytes, storage_key, canonical_url, sort_order, created_at, }); return [{ affectedRows: 1 }]; } if (/FROM h5_conversation_artifacts/i.test(sql)) { const packageId = params[0]; const rows = [...artifacts.values()] .filter((row) => row.package_id === packageId) .sort( (a, b) => Number(a.sort_order) - Number(b.sort_order) || Number(a.created_at) - Number(b.created_at) || String(a.id).localeCompare(String(b.id)), ); return [rows]; } throw new Error(`unexpected query: ${sql}`); }, }; } test('createConversationPackageStore requires a queryable pool', () => { assert.throws( () => createConversationPackageStore({}), (error) => error.code === 'missing_query_pool', ); }); test('conversation package store upserts package metadata and builds manifest', async () => { const pool = createFakePool(); const store = createConversationPackageStore(pool); const packageRecord = await store.upsertPackage({ userId: 'user-1', sessionId: 'session-1', title: '旅行计划', now: 1000, }); assert.equal(packageRecord.id, 'cp_session-1'); assert.equal(packageRecord.storagePrefix, 'users/user-1/conversations/session-1'); assert.match(pool.queries[0].sql, /ON DUPLICATE KEY UPDATE/); await store.upsertArtifact({ id: 'ca_late', packageId: packageRecord.id, artifactKind: 'public_html', displayName: 'plan.html', storageKey: 'users/user-1/conversations/session-1/public/plan.html', canonicalUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/plan.html', sortOrder: 2, now: 3000, }); await store.upsertArtifact({ id: 'ca_first', packageId: packageRecord.id, artifactKind: 'input_image', displayName: 'cover.png', sortOrder: 1, now: 2000, }); const manifest = await store.buildManifestForSession({ userId: 'user-1', sessionId: 'session-1', }); assert.equal(manifest.packageId, 'cp_session-1'); assert.equal(manifest.uri, 'mindspace://users/user-1/conversations/session-1'); assert.deepEqual( manifest.artifacts.map((artifact) => artifact.artifactId), ['ca_first', 'ca_late'], ); assert.equal( manifest.artifacts[1].canonicalUrl, 'https://m.tkmind.cn/MindSpace/user-1/public/plan.html', ); }); test('conversation package store returns null manifest for missing session', async () => { const store = createConversationPackageStore(createFakePool()); assert.equal(await store.buildManifestForSession({ userId: 'user-1', sessionId: 'missing' }), null); });