Files
behind_glass/scripts/check-sites-build.mjs
horoli e358e24436 Replace project with current server release and Windows setup
Import the 2026-10-09 source release, Fastify/SQLite backend, restored source
assets, and analytics-enabled server build. Replace files from the previous
release while retaining the existing repository history.

Make builds portable across Windows and Linux, configure local startup,
normalize Windows static asset paths, and fix test fixture cleanup and file
URL handling. Exclude local environment settings, databases, dependencies,
validation output, and TypeScript build cache from version control.

Validation: npm ci, static and server builds, 106 arrival tests, and actual
local HTTP checks passed. The full suite passed 467 of 470 tests; three tests
still require QA fixtures omitted from the supplied release, documented in
README-서버실행.md.
2026-10-09 16:43:35 +09:00

46 lines
2.9 KiB
JavaScript

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.`);