import { randomBytes } from 'node:crypto'; import { closeSync, fsyncSync, openSync } from 'node:fs'; import * as nodeFs from 'node:fs'; import { open, rename, unlink } from 'node:fs/promises'; export async function syncDir(dirPath: string): Promise { if (process.platform === 'win32') return; const dirFh = await open(dirPath, 'r'); try { await dirFh.sync(); } finally { await dirFh.close(); } } export function syncDirSync(dirPath: string): void { if (process.platform === 'win32') return; const fd = openSync(dirPath, 'r'); try { fsyncSync(fd); } finally { closeSync(fd); } } function syncFd(fd: number): Promise { return new Promise((resolve, reject) => { nodeFs.fsync(fd, (err) => { if (err) { reject(err); return; } resolve(); }); }); } export async function atomicWrite( filePath: string, content: string | Uint8Array, _syncOverride?: (fd: number) => Promise, ): Promise { const hex = randomBytes(4).toString('hex'); const tmpPath = `${filePath}.tmp.${process.pid}.${hex}`; let renamed = false; try { const fh = await open(tmpPath, 'w'); try { await fh.writeFile(content); await (_syncOverride ?? syncFd)(fh.fd); } finally { await fh.close(); } if (process.platform === 'win32') { try { await unlink(filePath); } catch (error) { const code = (error as NodeJS.ErrnoException).code; if (code !== 'ENOENT') throw error; } } await rename(tmpPath, filePath); renamed = true; } finally { if (!renamed) { try { await unlink(tmpPath); } catch { } } } }