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 Demo

Hi

'; 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); });