#!/usr/bin/env node import { existsSync, readdirSync, rmSync } from "node:fs"; import { join, resolve } from "node:path"; import { spawnSync } from "node:child_process"; const webDir = resolve("apps/web"); function listStaleNextArtifacts() { if (!existsSync(webDir)) { return []; } return readdirSync(webDir, { withFileTypes: true }) .filter((entry) => entry.isDirectory()) .map((entry) => entry.name) .filter((name) => name.startsWith(".next.")) .sort(); } function removeLocally(names) { for (const name of names) { rmSync(join(webDir, name), { recursive: true, force: true }); } } function removeWithDocker(names) { const dockerCheck = spawnSync("docker", ["--version"], { stdio: "ignore", }); if (dockerCheck.status !== 0) { return false; } const shellQuotedPaths = names .map((name) => `/work/${name}`) .map((path) => `'${path.replaceAll("'", "'\"'\"'")}'`) .join(" "); const result = spawnSync( "docker", [ "run", "--rm", "-v", `${webDir}:/work`, "alpine:3.20", "sh", "-lc", `rm -rf -- ${shellQuotedPaths}`, ], { stdio: "inherit", }, ); return result.status === 0; } const initialArtifacts = listStaleNextArtifacts(); if (initialArtifacts.length === 0) { console.log("No stale Next.js artifacts found."); process.exit(0); } removeLocally(initialArtifacts); const remainingArtifacts = listStaleNextArtifacts(); if (remainingArtifacts.length === 0) { console.log(`Removed stale Next.js artifacts: ${initialArtifacts.join(", ")}`); process.exit(0); } const dockerRemoved = removeWithDocker(remainingArtifacts); const finalArtifacts = listStaleNextArtifacts(); if (!dockerRemoved || finalArtifacts.length > 0) { console.error("Failed to remove stale Next.js artifacts:"); for (const artifact of finalArtifacts) { console.error(`- ${artifact}`); } console.error("Run the cleanup in an environment with Docker access or fix ownership before retrying."); process.exit(1); } console.log(`Removed stale Next.js artifacts: ${initialArtifacts.join(", ")}`);