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 { createPageSyncService } from './mindspace-page-sync-service.mjs';
import { PUBLISH_ROOT_DIR } from './user-publish.mjs';
test('syncUserGeneratedPages registers html files from publish public dir', async () => {
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-page-sync-service-'));
const h5Root = tmp;
const userId = 'user-1';
const publishDir = path.join(h5Root, PUBLISH_ROOT_DIR, userId);
const html =
'
Sync DemoHi
';
await fs.mkdir(path.join(publishDir, 'public'), { recursive: true });
await fs.writeFile(path.join(publishDir, 'public/index.html'), html);
const calls = [];
const pageService = {
createFromChat: async (_userId, input, source) => {
calls.push({ input, source });
return { id: 'page-1' };
},
updatePage: async () => assert.fail('should create, not update'),
};
const pool = {
query: async (sql) => {
if (String(sql).includes('FROM h5_page_records')) return [[]];
return [[]];
},
};
const pageSyncService = createPageSyncService({
pool,
pageService,
assetService: null,
h5Root,
});
const result = await pageSyncService.syncUserGeneratedPages(userId);
assert.equal(result.created, 1);
assert.equal(calls.length, 1);
assert.equal(calls[0].input.title, 'Sync Demo');
assert.equal(calls[0].source.snapshot.relative_path, 'public/index.html');
});
test('syncUserGeneratedPages deduplicates concurrent sync for the same user', async () => {
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-page-sync-dedupe-'));
const h5Root = tmp;
const userId = 'user-1';
const publishDir = path.join(h5Root, PUBLISH_ROOT_DIR, userId);
await fs.mkdir(path.join(publishDir, 'public'), { recursive: true });
await fs.writeFile(
path.join(publishDir, 'public/index.html'),
'DedupeHi',
);
let active = 0;
let maxActive = 0;
const pageService = {
createFromChat: async () => {
active += 1;
maxActive = Math.max(maxActive, active);
await new Promise((resolve) => setTimeout(resolve, 20));
active -= 1;
return { id: 'page-1' };
},
};
const pool = {
query: async (sql) => {
if (String(sql).includes('FROM h5_page_records')) return [[]];
return [[]];
},
};
const pageSyncService = createPageSyncService({
pool,
pageService,
h5Root,
});
await Promise.all([
pageSyncService.syncUserGeneratedPages(userId),
pageSyncService.syncUserGeneratedPages(userId),
]);
assert.equal(maxActive, 1);
});