import assert from 'node:assert/strict'; import { readFileSync, readdirSync, statSync } from 'node:fs'; import { join } from 'node:path'; const maxAssetBytes = 25 * 1024 * 1024; function files(root, relative = '') { return readdirSync(join(root, relative), { withFileTypes: true }).flatMap(entry => { const path = join(relative, entry.name); return entry.isDirectory() ? files(root, path) : [path]; }); } const built = files('dist'); for (const file of built) { const bytes = statSync(join('dist', file)).size; assert(bytes <= maxAssetBytes, `${file}: ${bytes} bytes exceeds Sites' ${maxAssetBytes}-byte asset limit`); } for (const file of files('public')) { assert(readFileSync(join('public', file)).equals(readFileSync(join('dist', file))), `${file}: public asset changed or missing in build`); } const html = readFileSync('dist/index.html', 'utf8'); assert(html.includes('id="sample"'), 'Sample button is missing'); assert(html.includes('value="dog1"'), 'Recommended sample option is missing'); for (const match of html.matchAll(/(?:src|href)="(\/assets\/[^"?#]+)"/g)) { assert(built.includes(match[1].slice(1)), `Missing HTML asset ${match[1]}`); } const js = built.filter(file => file.endsWith('.js')).map(file => readFileSync(join('dist', file), 'utf8')).join('\n'); for (const id of ['dog1', 'dog2', 'dog3', 'dog4']) { const path = `assets/samples/${id}.jpg`; assert(built.includes(path), `Missing sample ${path}`); assert(statSync(join('dist', path)).size < 1_000_000, `${path} must be under 1 MB`); assert(html.includes('/' + path), `Missing sample thumbnail ${path}`); } assert(js.includes('/assets/samples/'), 'Sample loader path missing'); assert(!/(?:sample-pet|assets\/qa\/dog)/.test(html + js), 'Retired sample reference in shipped bundle'); assert(!built.some(file => /(?:sample-pet|assets\/qa\/dog)/.test(file)), 'Retired sample asset shipped'); assert(js.includes('https://cdn.jsdelivr.net/npm/onnxruntime-web@'), 'Transformers runtime CDN configuration is missing'); assert(!built.some(file => /(?:assets\/countryside\/|CountrysideExperience)/i.test(file)), 'Retired photo-composite scene must not ship'); assert(built.includes('models/u2netp/model.onnx'),'Explicit opt-in small model is missing'); assert(built.filter(file=>file.endsWith('.onnx')).length===1,'Unexpected additional model'); assert(!/(?:cutout-review|countryside-start|scene-mode)/.test(html), 'Retired scene entry is still present'); assert(!/(?:CountrysideExperience|\/assets\/countryside\/)/.test(js), 'Retired scene runtime can still be requested'); assert(js.includes('이 누끼로 배치'),'Experiment must retain explicit review acceptance'); console.log(`Sites build checks passed: ${built.length} assets within 25 MiB, public assets byte-matched, sample UI/paths and runtime CDN configuration preserved, opt-in small cutout model present, retired photo-composite scene absent. Browser rendering and AI inference are separate checks.`);