92 lines
2.9 KiB
JavaScript
92 lines
2.9 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { access, readFile, stat } from "node:fs/promises";
|
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
|
|
const manifestPath = resolve(process.argv[2] || "");
|
|
if (!process.argv[2]) {
|
|
console.error("Usage: npm run audit:engine-cache -- /absolute/path/to/cesium/manifest.json");
|
|
process.exitCode = 1;
|
|
} else {
|
|
await audit(manifestPath);
|
|
}
|
|
|
|
async function audit(path) {
|
|
let manifest;
|
|
try {
|
|
manifest = JSON.parse(await readFile(path, "utf8"));
|
|
} catch (error) {
|
|
throw new Error(`Cannot read legacy cache manifest: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
}
|
|
|
|
const root = dirname(path);
|
|
const entries = Object.entries(manifest?.entries || {});
|
|
const providers = new Map();
|
|
let bytesFromManifest = 0;
|
|
let presentFiles = 0;
|
|
let missingFiles = 0;
|
|
let bytesOnDisk = 0;
|
|
|
|
for (const [rawUrl, entry] of entries) {
|
|
let hostname = "invalid-url";
|
|
try { hostname = new URL(rawUrl).hostname.toLowerCase() || "invalid-url"; } catch {}
|
|
const provider = providers.get(hostname) || { entries: 0, bytes: 0, presentFiles: 0, missingFiles: 0 };
|
|
const entryBytes = Math.max(0, Number(entry?.size || 0));
|
|
provider.entries += 1;
|
|
provider.bytes += entryBytes;
|
|
bytesFromManifest += entryBytes;
|
|
|
|
const relativeFile = String(entry?.path || "");
|
|
const candidate = resolve(root, relativeFile);
|
|
if (!relativeFile || !candidate.startsWith(`${root}/`) || isAbsolute(relativeFile) || !(await fileExists(candidate))) {
|
|
provider.missingFiles += 1;
|
|
missingFiles += 1;
|
|
providers.set(hostname, provider);
|
|
continue;
|
|
}
|
|
|
|
const fileInfo = await stat(candidate);
|
|
presentFiles += 1;
|
|
provider.presentFiles += 1;
|
|
bytesOnDisk += fileInfo.size;
|
|
providers.set(hostname, provider);
|
|
}
|
|
|
|
const report = {
|
|
kind: "nodedc-legacy-cesium-cache-audit",
|
|
generatedAt: new Date().toISOString(),
|
|
manifestPath: path,
|
|
manifestVersion: manifest?.version ?? null,
|
|
entries: entries.length,
|
|
declaredBytes: bytesFromManifest,
|
|
declaredMegabytes: toMegabytes(bytesFromManifest),
|
|
presentFiles,
|
|
missingFiles,
|
|
bytesOnDisk,
|
|
megabytesOnDisk: toMegabytes(bytesOnDisk),
|
|
providers: [...providers.entries()]
|
|
.map(([hostname, value]) => ({ hostname, ...value, megabytes: toMegabytes(value.bytes) }))
|
|
.sort((left, right) => right.bytes - left.bytes),
|
|
migrationPolicy: {
|
|
automaticImport: false,
|
|
reason: "Audit only. Import requires an explicit licence/provider decision for every source host and must preserve required attribution.",
|
|
target: "Map Gateway persistent volume or approved object storage; never Git history or a Docker image layer."
|
|
}
|
|
};
|
|
|
|
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
}
|
|
|
|
async function fileExists(path) {
|
|
try {
|
|
await access(path);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function toMegabytes(bytes) {
|
|
return Number((bytes / 1024 / 1024).toFixed(2));
|
|
}
|