import { createHash } from 'node:crypto' import { readdir, readFile } from 'node:fs/promises' const dist = new URL('../dist/', import.meta.url) async function filesBelow(directory, prefix = '') { const entries = await readdir(directory, { withFileTypes: true }) const files = [] for (const entry of entries) { const relative = `${prefix}${entry.name}` if (entry.isDirectory()) { files.push(...(await filesBelow(new URL(`${entry.name}/`, directory), `${relative}/`))) } else { files.push(relative) } } return files } const files = await filesBelow(dist) const expectedFonts = ['noto-serif-sc', 'zcool-xiaowei', 'lxgw-wenkai'] const liyuFont = 'fonts/liyu-shoushu-v0.107.woff2' for (const font of expectedFonts) { if (!files.some(file => file.startsWith(`assets/${font}-`) && file.endsWith('.woff2'))) { throw new Error(`Missing bundled WOFF2 assets for ${font}`) } if (!files.includes(`fonts/licenses/${font}-OFL.txt`)) { throw new Error(`Missing bundled license for ${font}`) } } if (!files.includes(liyuFont)) throw new Error('Missing bundled WOFF2 asset for liyu-shoushu') if (!files.includes('fonts/licenses/liyu-shoushu-OFL.txt')) { throw new Error('Missing bundled license for liyu-shoushu') } const liyuDigest = createHash('sha256') .update(await readFile(new URL(liyuFont, dist))) .digest('hex') if (liyuDigest !== 'b17f8c4fc6612a539d7a46e0eb5f57fdc732cff1d17804563b00a3f0a7eb9ab3') { throw new Error(`Unexpected liyu-shoushu WOFF2 digest: ${liyuDigest}`) } const legacyWoff = files.find(file => file.endsWith('.woff')) if (legacyWoff) throw new Error(`Unexpected legacy WOFF asset: ${legacyWoff}`) const css = ( await Promise.all( files.filter(file => file.endsWith('.css')).map(file => readFile(new URL(file, dist), 'utf8')), ) ).join('\n') for (const family of ['Noto Serif SC', 'ZCOOL XiaoWei', 'LXGW WenKai', 'Liyu Shoushu']) { const declarations = [ `font-family:${family}`, `font-family:${JSON.stringify(family)}`, `font-family:'${family}'`, ] if (!declarations.some(declaration => css.includes(declaration))) { throw new Error(`Missing @font-face declaration for ${family}`) } } if (!css.includes('font-display:block') || css.includes('font-display:swap')) { throw new Error('Bundled fonts must block local fallback while loading') } console.log('Verified same-origin WOFF2 component fonts and licenses.')