import { mkdir, readFile, writeFile, copyFile } from "node:fs/promises"; import { existsSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); const sourceDir = process.env.NODEDC_SOURCE_DIR || "/Users/dcconstructions/site-rescue/ssscript.app"; const targetDir = repoRoot; const pages = ["index.html", "beta-apply.html", "founders.html", "enterprise.html"]; const assetHosts = new Set([ "cdn.prod.website-files.com", "d3e54v103j8qbb.cloudfront.net", "ssscript-website.vercel.app", "ssscript.dev", "cloud.umami.is", ]); const assetExtensions = new Set([ ".avif", ".css", ".glb", ".gif", ".jpg", ".jpeg", ".js", ".mp4", ".otf", ".png", ".svg", ".ttf", ".webm", ".webp", ".woff", ".woff2", ]); const assetMap = new Map(); const queue = []; const failures = []; function cleanUrl(raw) { let value = raw.trim(); value = value.replace(/&/g, "&"); value = value.replace(/[),.;]+$/g, ""); if (value.startsWith("//")) value = `https:${value}`; return value; } function extensionFor(url) { return path.extname(decodeURIComponent(url.pathname)).toLowerCase(); } function isAssetUrl(url) { if (!assetHosts.has(url.hostname)) return false; if (url.href.includes("%7B") || url.href.includes("%7D") || url.href.includes("${")) return false; if (url.hostname === "cdn.prod.website-files.com" && url.pathname.includes("/vendor/webflow-badge-")) return false; if (url.hostname === "cloud.umami.is") return url.pathname === "/script.js"; return assetExtensions.has(extensionFor(url)); } function localAssetPath(url) { const decodedPath = decodeURIComponent(url.pathname); const basename = path.basename(decodedPath); const ext = path.extname(basename).toLowerCase(); if (url.hostname === "cdn.prod.website-files.com") { if (decodedPath.includes("/css/")) return path.join("assets", "webflow", "css", basename); if (decodedPath.includes("/js/")) return path.join("assets", "webflow", "js", basename); return path.join("assets", "webflow", "images", basename); } if (url.hostname === "d3e54v103j8qbb.cloudfront.net") { return path.join("assets", "vendor", basename); } if (url.hostname === "ssscript-website.vercel.app") { if (ext === ".css") return path.join("assets", "custom", "css", basename); if (ext === ".js") return path.join("assets", "custom", "js", basename); return path.join("assets", "custom", basename); } if (url.hostname === "ssscript.dev") { return path.join("assets", "media", basename); } if (url.hostname === "cloud.umami.is") { return path.join("assets", "vendor", "umami-script.js"); } return path.join("assets", url.hostname, basename); } function addAsset(rawUrl, baseUrl = undefined) { let url; try { url = new URL(cleanUrl(rawUrl), baseUrl); } catch { return null; } if (!isAssetUrl(url)) return null; const canonical = url.href; if (!assetMap.has(canonical)) { const localPath = localAssetPath(url); assetMap.set(canonical, localPath); queue.push({ url, localPath }); } return assetMap.get(canonical); } function extractUrls(text) { const urls = []; const absoluteUrlPattern = /(?:https?:)?\/\/[^\s"'<>\\]+/g; const cssUrlPattern = /url\((['"]?)([^'")]+)\1\)/g; const relativeAssetPattern = /(["'`])((?:\.{1,2}\/|\/)[^"'`?#)]+\.(?:avif|css|gif|glb|jpe?g|js|mp4|otf|png|svg|ttf|webm|webp|woff2?)(?:[?#][^"'`]*)?)\1/g; for (const match of text.matchAll(absoluteUrlPattern)) { urls.push(match[0]); } for (const match of text.matchAll(cssUrlPattern)) { urls.push(match[2]); } for (const match of text.matchAll(relativeAssetPattern)) { urls.push(match[2]); } return urls; } function rel(fromFile, toFile) { const relative = path.relative(path.dirname(fromFile), toFile).replaceAll(path.sep, "/"); const webPath = relative.split("/").map(encodeURIComponent).join("/"); return webPath.startsWith(".") ? webPath : `./${webPath}`; } function pageRel(localPath) { return `./${localPath.split(path.sep).join("/").split("/").map(encodeURIComponent).join("/")}`; } function rewriteUrls(text, fromLocalPath, baseUrl = undefined) { let output = text; const isJs = fromLocalPath.endsWith(".js"); const replacements = [...assetMap.entries()].map(([remote, local]) => { const remoteUrl = new URL(remote); return { remote, local, relative: isJs ? pageRel(local) : rel(path.join(targetDir, fromLocalPath), path.join(targetDir, local)), noQuery: `${remoteUrl.origin}${remoteUrl.pathname}`, }; }); for (const item of replacements) { output = output.split(item.remote).join(item.relative); output = output.split(item.remote.replaceAll("&", "&")).join(item.relative); output = output.split(item.noQuery).join(item.relative); output = output.split(item.noQuery.replaceAll("&", "&")).join(item.relative); } if (baseUrl) { output = output.replace(/url\((['"]?)([^'")]+)\1\)/g, (full, quote, value) => { const local = addAsset(value, baseUrl); if (!local) return full; const localRef = isJs ? pageRel(local) : rel(path.join(targetDir, fromLocalPath), path.join(targetDir, local)); return `url(${quote}${localRef}${quote})`; }); output = output.replace( /(["'`])((?:\.{1,2}\/|\/)[^"'`?#)]+\.(?:avif|css|gif|glb|jpe?g|js|mp4|otf|png|svg|ttf|webm|webp|woff2?)(?:[?#][^"'`]*)?)\1/g, (full, quote, value) => { const local = addAsset(value, baseUrl); if (!local) return full; const localRef = isJs ? pageRel(local) : rel(path.join(targetDir, fromLocalPath), path.join(targetDir, local)); return `${quote}${localRef}${quote}`; } ); } if (fromLocalPath.endsWith(".html")) { output = output .replace(/]*>/g, "") .replace(/]*>/g, "") .replaceAll("https://localhost:6545/app.js", "./assets/custom/js/app.js"); if (!output.includes("window.__API_ORIGIN__")) { output = output.replace( "