187 lines
5.5 KiB
JavaScript
187 lines
5.5 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createMindSpaceConversationArtifactService } from './mindspace-conversation-package-artifact-service.mjs';
|
|
|
|
function createRegistry() {
|
|
const calls = [];
|
|
return {
|
|
calls,
|
|
async putObjectForSession(input) {
|
|
calls.push({ kind: 'put', input });
|
|
return {
|
|
packageRecord: { id: 'package-1' },
|
|
writeResult: { key: 'packages/object' },
|
|
};
|
|
},
|
|
async recordArtifact(input) {
|
|
calls.push({ kind: 'record', input });
|
|
return input;
|
|
},
|
|
async writeManifestForSession(input) {
|
|
calls.push({ kind: 'manifest', input });
|
|
return { ok: true };
|
|
},
|
|
};
|
|
}
|
|
|
|
test('public HTML artifact registration resolves the physical publish directory inside MindSpace', async () => {
|
|
const registry = createRegistry();
|
|
const calls = [];
|
|
const service = createMindSpaceConversationArtifactService({
|
|
conversationPackageRegistry: registry,
|
|
h5Root: '/srv/h5',
|
|
env: { H5_PUBLIC_BASE_URL: 'https://example.com' },
|
|
resolveMindSpaceUserPublishDirFn(h5Root, user) {
|
|
calls.push({ kind: 'resolve', h5Root, user });
|
|
return '/srv/h5/MindSpace/user-1';
|
|
},
|
|
async registerPublicHtmlArtifactsFn(input) {
|
|
calls.push({ kind: 'register', input });
|
|
return [{ artifactId: 'artifact-1' }];
|
|
},
|
|
});
|
|
|
|
const result = await service.registerPublicHtmlArtifacts({
|
|
userId: 'user-1',
|
|
sessionId: 'session-1',
|
|
artifactRefs: [
|
|
{
|
|
relativePath: 'public/page.html',
|
|
messageId: 'message-1',
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.deepEqual(result, [{ artifactId: 'artifact-1' }]);
|
|
assert.equal(calls[0].kind, 'resolve');
|
|
assert.equal(calls[0].h5Root, '/srv/h5');
|
|
assert.equal(calls[1].kind, 'register');
|
|
assert.equal(
|
|
calls[1].input.publishDir,
|
|
'/srv/h5/MindSpace/user-1',
|
|
);
|
|
assert.equal(
|
|
calls[1].input.artifactRefs[0].relativePath,
|
|
'public/page.html',
|
|
);
|
|
});
|
|
|
|
test('DOCX artifact registration accepts RPC-revived binary data and delegates to the package helper', async () => {
|
|
const registry = createRegistry();
|
|
const calls = [];
|
|
const service = createMindSpaceConversationArtifactService({
|
|
conversationPackageRegistry: registry,
|
|
h5Root: '/srv/h5',
|
|
async registerChatDocxArtifactFn(input) {
|
|
calls.push(input);
|
|
return { id: 'docx-1' };
|
|
},
|
|
});
|
|
|
|
const body = new Uint8Array([1, 2, 3]);
|
|
const result = await service.registerChatDocxArtifact({
|
|
userId: 'user-1',
|
|
sessionId: 'session-1',
|
|
messageId: 'message-1',
|
|
selectedLinkIndex: 2,
|
|
title: 'Chat title',
|
|
filename: 'chat.docx',
|
|
body,
|
|
});
|
|
|
|
assert.deepEqual(result, { id: 'docx-1' });
|
|
assert.ok(Buffer.isBuffer(calls[0].buffer));
|
|
assert.equal(calls[0].buffer.length, 3);
|
|
assert.equal(
|
|
calls[0].requestBody.selected_link_index,
|
|
2,
|
|
);
|
|
assert.equal(
|
|
calls[0].bundle.source.session.name,
|
|
'Chat title',
|
|
);
|
|
});
|
|
|
|
test('published long image registration stores the object, artifact, and refreshed manifest idempotently', async () => {
|
|
const registry = createRegistry();
|
|
const service = createMindSpaceConversationArtifactService({
|
|
conversationPackageRegistry: registry,
|
|
h5Root: '/srv/h5',
|
|
});
|
|
|
|
const input = {
|
|
ownerId: 'user-1',
|
|
sessionId: 'session-1',
|
|
messageId: 'message-1',
|
|
publicationId: 'publication-1',
|
|
pageId: 'page-1',
|
|
title: 'Page title',
|
|
body: Buffer.from('png'),
|
|
canonicalUrl: 'https://example.com/page.long.png',
|
|
};
|
|
const result =
|
|
await service.registerPublishedLongImageArtifact(input);
|
|
const repeated =
|
|
await service.registerPublishedLongImageArtifact(input);
|
|
|
|
assert.equal(result.artifactKind, 'long_image');
|
|
assert.equal(repeated.id, result.id);
|
|
assert.equal(result.publicationId, 'publication-1');
|
|
assert.equal(result.pageId, 'page-1');
|
|
assert.equal(result.messageId, 'message-1');
|
|
assert.equal(registry.calls[0].kind, 'put');
|
|
assert.equal(registry.calls[1].kind, 'record');
|
|
assert.equal(registry.calls[2].kind, 'manifest');
|
|
assert.equal(
|
|
registry.calls[0].input.body.toString('utf8'),
|
|
'png',
|
|
);
|
|
assert.match(
|
|
registry.calls[1].input.id,
|
|
/^ca_long_image_[a-f0-9]{16}$/,
|
|
);
|
|
assert.equal(registry.calls[4].input.id, result.id);
|
|
});
|
|
|
|
test('workspace file registration stores every logical write in the conversation package', async () => {
|
|
const registry = createRegistry();
|
|
const service = createMindSpaceConversationArtifactService({
|
|
conversationPackageRegistry: registry,
|
|
h5Root: '/srv/h5',
|
|
});
|
|
const input = {
|
|
userId: 'user-1',
|
|
sessionId: 'session-1',
|
|
messageId: 'message-1',
|
|
title: 'Workspace output',
|
|
relativePath: 'oa/notes.txt',
|
|
body: 'generated notes',
|
|
};
|
|
|
|
const result =
|
|
await service.registerWorkspaceFileArtifact(input);
|
|
const repeated =
|
|
await service.registerWorkspaceFileArtifact(input);
|
|
|
|
assert.equal(result.artifactKind, 'generated_file');
|
|
assert.equal(result.mimeType, 'text/plain');
|
|
assert.equal(result.messageId, 'message-1');
|
|
assert.equal(repeated.id, result.id);
|
|
assert.match(
|
|
result.id,
|
|
/^ca_workspace_write_[a-f0-9]{20}$/,
|
|
);
|
|
assert.equal(registry.calls[0].kind, 'put');
|
|
assert.equal(
|
|
registry.calls[0].input.body.toString('utf8'),
|
|
'generated notes',
|
|
);
|
|
assert.match(
|
|
registry.calls[0].input.relativePath,
|
|
/^artifacts\/ca_workspace_write_[a-f0-9]{20}\/notes\.txt$/,
|
|
);
|
|
assert.equal(registry.calls[1].kind, 'record');
|
|
assert.equal(registry.calls[2].kind, 'manifest');
|
|
assert.equal(registry.calls[4].input.id, result.id);
|
|
});
|