31 lines
1.6 KiB
JavaScript
31 lines
1.6 KiB
JavaScript
import { readFileSync, existsSync } from 'node:fs';
|
|
import { resolve, dirname, relative, extname } from 'node:path';
|
|
|
|
// Inspect only the graph reached from index.html; old chunks left in dist do not count.
|
|
export function verifyTokenBuild(directory) {
|
|
const root = resolve(directory);
|
|
const visited = new Set();
|
|
function visit(path) {
|
|
path = resolve(path);
|
|
const rel = relative(root, path);
|
|
if (rel.startsWith('..') || !existsSync(path) || visited.has(path)) return;
|
|
visited.add(path);
|
|
const text = readFileSync(path, 'utf8');
|
|
for (const match of text.matchAll(/["'`]((?:\.{0,2}\/)?[\w./-]+\.js)["'`]/g)) {
|
|
const ref = match[1];
|
|
visit(ref.startsWith('/') ? resolve(root, ref.slice(1)) : resolve(dirname(path), ref));
|
|
}
|
|
}
|
|
visit(resolve(root, 'index.html'));
|
|
const stats = [...visited].filter((path) => /[\\/]call-stats-[^\\/]+\.js$/.test(path));
|
|
if (stats.length !== 1 || !readFileSync(stats[0], 'utf8').includes('ModelUsageStats-')) {
|
|
throw new Error('The active call statistics page does not include Token usage. Refusing this build.');
|
|
}
|
|
const usage = [...visited].filter((path) => /[\\/]ModelUsageStats-[^\\/]+\.js$/.test(path));
|
|
const hasApi = [...visited].some((path) => extname(path) === '.js' && readFileSync(path, 'utf8').includes('/stats/model-usage/log'));
|
|
if (!usage.length || !hasApi) throw new Error('The active Token component or usage API is missing.');
|
|
return { page: relative(root, stats[0]), component: relative(root, usage[0]), assets: visited.size };
|
|
}
|
|
|
|
console.log(JSON.stringify(verifyTokenBuild(process.argv[2] || 'dist')));
|