import { cp, lstat, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; const workspace = fileURLToPath(new URL('../', import.meta.url)); const output = resolve(workspace, 'dist'); // Only replace this script's generated output, never a symlink or another folder. if (dirname(output) !== resolve(workspace) || output !== resolve(workspace, 'dist')) throw Error('Unexpected output directory.'); const existing = await lstat(output).catch(error => { if (error.code !== 'ENOENT') throw error; }); if (existing?.isSymbolicLink()) throw Error('Refusing to replace a linked output directory.'); await rm(output, { recursive: true, force: true }); await mkdir(output, { recursive: true }); const source = resolve(workspace, 'public'); // The editorial draft desk and source/release files remain local. for (const name of ['assets', 'brand', 'build', 'fonts', 'media', 'themes', 'docs', 'theme.css', 'landing.css', 'app.html', 'vesting.html', 'demo-video.html']) { await cp(join(source, name), join(output, name), { recursive: true }); } for (const name of ['index.html', 'app.css', 'brand/veylock-mark.svg', 'brand/veylock-wordmark.svg']) { await cp(join(source, 'themes/digital-blue', name), join(output, name)); } // Bake in the transformations normally applied by the local Node server. for (const name of ['index.html', 'themes/digital-blue/index.html', 'app.html']) { const path = join(output, name); let html = await readFile(path, 'utf8'); if (name === 'app.html') html = html.replace('href="/app.css"', 'href="/themes/digital-blue/app.css"').replaceAll('/brand/veylock-mark.svg', '/themes/digital-blue/brand/veylock-mark.svg'); html = html.replace('', ''); await writeFile(path, html); } await writeFile(join(output, '_redirects'), '/rono / 301\n/app/ /app 301\n'); await writeFile(join(output, '_headers'), '/*\n X-Content-Type-Options: nosniff\n X-Frame-Options: DENY\n Referrer-Policy: strict-origin-when-cross-origin\n'); await writeFile(join(output, '404.html'), 'Page not found · VEYLOCK

Page not found.

This address does not exist.

Return to VEYLOCK ↗
'); const files = await readdir(output, { recursive: true, withFileTypes: true }); for (const file of files.filter(file => file.isFile())) { const path = join(file.parentPath, file.name); if ((await lstat(path)).size > 25 * 1024 * 1024) throw Error(`Asset exceeds Cloudflare Pages' 25 MiB limit: ${path}`); if (/\.(html|css|js|svg)$/.test(file.name) && /(?:https?:)?\/\/[^\s"'<>]*ronolaunch\.com/i.test(await readFile(path,'utf8'))) throw Error(`External Ronolaunch dependency in production asset: ${path}`); } console.log(`Prepared ${files.filter(file => file.isFile()).length} production assets in dist/.`);