import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { dedupeDiscoveryEntriesByPage, listWorkspacePublicHtmlIndexEntries, mergeDiscoveryEntries, renderLlmsTxt, renderRobotsTxt, renderSitemapXml, resolveWorkspacePublicationIndexSnapshot, } from './mindspace-seo-discovery-service.mjs'; test('renderSitemapXml emits only provided urls', () => { const xml = renderSitemapXml( [{ publicUrl: '/u/john/pages/demo', updatedAt: Date.parse('2026-08-01T00:00:00.000Z') }], { origin: 'https://m.tkmind.cn' }, ); assert.match(xml, /https:\/\/m\.tkmind\.cn\/u\/john\/pages\/demo<\/loc>/); }); test('renderRobotsTxt references sitemap when enabled', () => { const body = renderRobotsTxt({ origin: 'https://m.tkmind.cn', sitemapEnabled: true, llmsTxtEnabled: true, }); assert.match(body, /Sitemap: https:\/\/m\.tkmind\.cn\/sitemap\.xml/); assert.match(body, /llms\.txt/); }); test('dedupeDiscoveryEntriesByPage prefers /u/ urls for the same page', () => { const merged = dedupeDiscoveryEntriesByPage([ { pageId: 'page-1', publicUrl: '/MindSpace/user/public/demo.html', accessMode: 'public', status: 'online', }, { pageId: 'page-1', publicUrl: '/u/john/pages/demo', accessMode: 'public', status: 'online', }, ]); assert.equal(merged.length, 1); assert.equal(merged[0].publicUrl, '/u/john/pages/demo'); }); test('dedupeDiscoveryEntriesByPage drops archived duplicates', () => { const merged = dedupeDiscoveryEntriesByPage([ { pageId: 'page-2', publicUrl: '/MindSpace/user/public/_archived-demo.html', accessMode: 'public', status: 'online', }, { pageId: 'page-2', publicUrl: '/u/john/pages/demo', accessMode: 'public', status: 'online', }, ]); assert.equal(merged.length, 1); assert.equal(merged[0].publicUrl, '/u/john/pages/demo'); }); test('mergeDiscoveryEntries appends platform static pages', () => { const merged = mergeDiscoveryEntries([ { publicUrl: '/u/john/pages/demo', accessMode: 'public', status: 'online' }, ]); assert.ok(merged.some((entry) => String(entry.publicUrl ?? '').includes('/learn/'))); }); test('renderLlmsTxt lists markdown links', () => { const body = renderLlmsTxt( [{ publicUrl: '/u/john/pages/demo', summary: '仙居玩水' }], { origin: 'https://m.tkmind.cn' }, ); assert.match(body, /\[仙居玩水\]\(https:\/\/m\.tkmind\.cn\/u\/john\/pages\/demo\)/); }); test('listWorkspacePublicHtmlIndexEntries includes unpublished public html on disk', async () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mindspace-seo-disk-')); const userId = 'user-implicit-seo'; const publicDir = path.join(root, 'MindSpace', userId, 'public'); fs.mkdirSync(publicDir, { recursive: true }); fs.writeFileSync( path.join(publicDir, 'weather-broadcast-20260916.html'), 'Weather', 'utf8', ); const entries = await listWorkspacePublicHtmlIndexEntries(null, { h5Root: root }); assert.equal(entries.length, 1); assert.match(entries[0].publicUrl ?? '', /weather-broadcast-20260916\.html/); }); test('resolveWorkspacePublicationIndexSnapshot falls back to implicit public html', async () => { const snapshot = await resolveWorkspacePublicationIndexSnapshot(null, { userId: 'user-1', workspaceRelativePath: 'public/demo.html', publicUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/demo.html', }); assert.equal(snapshot?.accessMode, 'public'); assert.equal(snapshot?.status, 'online'); }); test('resolveWorkspacePublicationIndexSnapshot respects online non-public publication', async () => { const pool = { async query(sql, params) { if (/access_mode <> 'public'/i.test(sql)) { assert.equal(params[1], 'public/demo.html'); return [[{ id: 'pub-private', page_id: 'page-1', public_url: '/u/user/pages/demo', access_mode: 'password', status: 'online', user_confirmed_at: null, expires_at: null, updated_at: Date.now(), published_at: Date.now(), title: 'Demo', summary: '私有', }]]; } return [[], []]; }, }; const snapshot = await resolveWorkspacePublicationIndexSnapshot(pool, { userId: 'user-1', workspaceRelativePath: 'public/demo.html', publicUrl: 'https://m.tkmind.cn/MindSpace/user-1/public/demo.html', }); assert.equal(snapshot?.accessMode, 'password'); });