import assert from 'node:assert/strict'; import test from 'node:test'; import { assertConversationArtifactKind, buildConversationDisplayFolderName, buildConversationPackageManifest, buildConversationPackageUri, buildConversationStoragePrefix, createConversationArtifact, createConversationPackageRecord, } from './mindspace-conversation-package.mjs'; test('buildConversationStoragePrefix produces backend-neutral object prefixes', () => { assert.equal( buildConversationStoragePrefix({ userId: 'user-1', sessionId: 'session-1' }), 'users/user-1/conversations/session-1', ); assert.equal( buildConversationPackageUri({ userId: 'user 1', sessionId: 'session:1' }), 'mindspace://users/user%201/conversations/session%3A1', ); }); test('buildConversationStoragePrefix rejects path separators', () => { assert.throws( () => buildConversationStoragePrefix({ userId: '../user', sessionId: 'session-1' }), (error) => error.code === 'invalid_storage_segment', ); assert.throws( () => buildConversationStoragePrefix({ userId: 'user-1', sessionId: 'a/b' }), (error) => error.code === 'invalid_storage_segment', ); }); test('createConversationPackageRecord defaults storage prefix and timestamps', () => { assert.deepEqual( createConversationPackageRecord({ id: 'cp_custom', userId: 'user-1', sessionId: 'session-1', title: '旅行页面', now: 1000, }), { id: 'cp_custom', userId: 'user-1', sessionId: 'session-1', title: '旅行页面', status: 'active', storagePrefix: 'users/user-1/conversations/session-1', manifestAssetId: null, createdAt: 1000, updatedAt: 1000, }, ); }); test('buildConversationDisplayFolderName prefers title and hides internal ids', () => { assert.equal(buildConversationDisplayFolderName('旅行计划'), '旅行计划'); assert.equal(buildConversationDisplayFolderName(' '), '本次对话文件夹'); }); test('createConversationArtifact validates artifact kind and preserves provenance', () => { assert.equal(assertConversationArtifactKind('public_html'), 'public_html'); assert.throws( () => assertConversationArtifactKind('random_blob'), (error) => error.code === 'unsupported_conversation_artifact_kind', ); const artifact = createConversationArtifact({ id: 'ca_1', packageId: 'cp_1', artifactKind: 'public_html', assetId: 'asset-1', pageId: 'page-1', publicationId: 'pub-1', agentRunId: 'run-1', messageId: 'msg-1', displayName: 'report.html', mimeType: 'text/html', sizeBytes: 120, storageKey: 'users/user-1/conversations/session-1/public/report.html', canonicalUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', sortOrder: 2, now: 2000, }); assert.equal(artifact.packageId, 'cp_1'); assert.equal(artifact.artifactKind, 'public_html'); assert.equal(artifact.assetId, 'asset-1'); assert.equal(artifact.pageId, 'page-1'); assert.equal(artifact.publicationId, 'pub-1'); assert.equal(artifact.messageId, 'msg-1'); }); test('createConversationArtifact preserves unknown size as null', () => { const artifact = createConversationArtifact({ packageId: 'cp_1', artifactKind: 'generated_file', sizeBytes: null, now: 1000, }); assert.equal(artifact.sizeBytes, null); }); test('createConversationArtifact keeps sort order inside MySQL INT range', () => { const artifact = createConversationArtifact({ packageId: 'cp_1', artifactKind: 'public_html', sortOrder: 1783003000123, now: 1000, }); assert.equal(artifact.sortOrder, 1783003000); const clamped = createConversationArtifact({ packageId: 'cp_1', artifactKind: 'public_html', sortOrder: Number.MAX_SAFE_INTEGER, now: 1000, }); assert.equal(clamped.sortOrder, 2147483647); }); test('buildConversationPackageManifest sorts artifacts and emits stable public shape', () => { const manifest = buildConversationPackageManifest({ packageRecord: { id: 'cp_1', userId: 'user-1', sessionId: 'session-1', title: '项目周报', now: 1000, }, artifacts: [ { id: 'ca_late', artifactKind: 'page', displayName: '项目周报', pageId: 'page-1', messageId: 'msg-2', agentRunId: 'run-1', sortOrder: 2, createdAt: 3000, }, { id: 'ca_first', artifactKind: 'input_image', displayName: 'cover.png', messageId: 'msg-1', sortOrder: 1, createdAt: 2000, }, { id: 'ca_public', artifactKind: 'public_html', displayName: 'report.html', pageId: 'page-1', publicationId: 'pub-1', messageId: 'msg-2', agentRunId: 'run-1', canonicalUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', sortOrder: 3, createdAt: 4000, }, ], }); assert.equal(manifest.schemaVersion, 1); assert.equal(manifest.uri, 'mindspace://users/user-1/conversations/session-1'); assert.equal(manifest.displayFolderName, '项目周报'); assert.equal(manifest.storagePrefix, 'users/user-1/conversations/session-1'); assert.deepEqual( manifest.artifacts.map((artifact) => artifact.artifactId), ['ca_first', 'ca_late', 'ca_public'], ); assert.deepEqual(manifest.artifacts[0], { artifactId: 'ca_first', kind: 'input_image', messageId: 'msg-1', displayName: 'cover.png', sortOrder: 1, createdAt: 2000, }); assert.deepEqual(manifest.pages, [ { pageId: 'page-1', artifactIds: ['ca_late', 'ca_public'], displayName: '项目周报', canonicalUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', createdAt: 3000, updatedAt: 4000, }, ]); assert.deepEqual(manifest.publications, [ { publicationId: 'pub-1', artifactIds: ['ca_public'], displayName: 'report.html', canonicalUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/report.html', createdAt: 4000, updatedAt: 4000, }, ]); assert.deepEqual(manifest.messages, [ { messageId: 'msg-1', artifactIds: ['ca_first'], kinds: ['input_image'], createdAt: 2000, updatedAt: 2000, }, { messageId: 'msg-2', artifactIds: ['ca_late', 'ca_public'], kinds: ['page', 'public_html'], createdAt: 3000, updatedAt: 4000, }, ]); assert.deepEqual(manifest.agentRuns, [ { agentRunId: 'run-1', artifactIds: ['ca_late', 'ca_public'], kinds: ['page', 'public_html'], createdAt: 3000, updatedAt: 4000, }, ]); });