Something went wrong. Try again.
Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132import { randomUUID } from 'node:crypto'import { copyFileSync, existsSync, linkSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, unlinkSync } from 'node:fs'import path from 'node:path'
/** Publish completed immutable files before listening. A hard stop may leave a * hidden temporary file, never a partial file at a published URL. */export function retainAssets(root, archive) { mkdirSync(archive, { recursive: true, mode: 0o700 }) const archiveRoot = realpathSync(archive) function visit(relative) { const source = path.join(root, relative) const target = path.join(archiveRoot, relative) const info = lstatSync(source) if (info.isDirectory()) { mkdirSync(target, { recursive: true, mode: 0o700 }) if (!lstatSync(target).isDirectory() || lstatSync(target).isSymbolicLink() || realpathSync(target) !== target) throw new Error(`Invalid asset archive directory: ${relative}`) for (const name of readdirSync(source)) visit(path.join(relative, name)) return } if (!info.isFile()) throw new Error(`Only ordinary files may be retained: ${relative}`) const temporary = `${target}.${randomUUID()}.tmp` copyFileSync(source, temporary) try { try { linkSync(temporary, target) } catch (error) { if (error.code !== 'EEXIST') throw error } if (!lstatSync(target).isFile() || !readFileSync(target).equals(readFileSync(source))) throw new Error(`Retained asset collision: ${relative}`) } finally { unlinkSync(temporary) } } for (const directory of ['assets', 'fonts']) if (existsSync(path.join(root, directory))) visit(directory) return archiveRoot}