const crypto = require("crypto"); const fs = require("fs"); const path = require("path"); const { threadId } = require("worker_threads"); const TRANSIENT_CODES = new Set(["EACCES", "EBUSY", "EEXIST", "ENOTEMPTY", "EPERM"]); const activeWrites = new Set(); const diagnostics = []; const sleepArray = new Int32Array(new SharedArrayBuffer(4)); function writeJsonAtomicSync(target, value, options = {}) { return writeTextAtomicSync(target, `${JSON.stringify(value, null, options.indent ?? 2)}\n`, options); } function writeTextAtomicSync(target, content, options = {}) { if (!String(target || "").trim()) throw new Error("A target file is required."); const file = path.resolve(String(target)); if (activeWrites.has(file)) { const error = new Error(`A write to ${file} is already in progress.`); error.code = "EWRITELOCKED"; recordDiagnostic(file, "write_locked", error, 0, "error", options); throw error; } activeWrites.add(file); fs.mkdirSync(path.dirname(file), { recursive: true }); cleanupStaleTempFilesSync(file, options); const temporary = temporaryPath(file); let descriptor = null; try { descriptor = fs.openSync(temporary, "wx", options.mode ?? 0o600); fs.writeFileSync(descriptor, content, options.encoding || "utf8"); try { fs.fsyncSync(descriptor); } catch (error) { recordDiagnostic(file, "fsync_unavailable", error, 0, "warning", options); } fs.closeSync(descriptor); descriptor = null; replaceFileSync(temporary, file, options); if (options.mode != null) { try { fs.chmodSync(file, options.mode); } catch {} } syncParentDirectory(file, options); return file; } catch (error) { recordDiagnostic(file, "write_failed", error, 0, "error", options); throw error; } finally { if (descriptor != null) { try { fs.closeSync(descriptor); } catch {} } try { fs.rmSync(temporary, { force: true }); } catch {} activeWrites.delete(file); } } function replaceFileSync(temporary, target, options = {}) { try { retrySync(() => fs.renameSync(temporary, target), target, "rename", options); return; } catch (renameError) { if (!fs.existsSync(target) || !TRANSIENT_CODES.has(renameError.code)) throw renameError; } const backup = `${target}.${process.pid}.${threadId}.${crypto.randomBytes(5).toString("hex")}.bak`; let movedOriginal = false; try { retrySync(() => fs.renameSync(target, backup), target, "backup_existing", options); movedOriginal = true; retrySync(() => fs.renameSync(temporary, target), target, "install_replacement", options); fs.rmSync(backup, { force: true }); recordDiagnostic(target, "backup_replace_succeeded", null, 0, "warning", options); } catch (error) { if (movedOriginal && fs.existsSync(backup) && !fs.existsSync(target)) { try { retrySync(() => fs.renameSync(backup, target), target, "restore_original", options); } catch (restoreError) { recordDiagnostic(target, "restore_failed", restoreError, 0, "error", options); error.message = `${error.message} The original file remains at ${backup}.`; } } throw error; } finally { if (fs.existsSync(backup) && fs.existsSync(target)) { try { fs.rmSync(backup, { force: true }); } catch {} } } } function retrySync(operation, target, operationName, options = {}) { const attempts = Math.max(1, Number(options.attempts) || 8); const delayMs = Math.max(1, Number(options.delayMs) || 15); let lastError = null; for (let attempt = 1; attempt <= attempts; attempt += 1) { try { return operation(); } catch (error) { lastError = error; if (!TRANSIENT_CODES.has(error.code) || attempt === attempts) throw error; recordDiagnostic(target, operationName, error, attempt, "warning", options); Atomics.wait(sleepArray, 0, 0, Math.min(250, delayMs * attempt)); } } throw lastError; } function runFileOperationWithRetries(operation, options = {}) { if (typeof operation !== "function") throw new Error("A file operation function is required."); return retrySync( operation, options.target || "file operation", options.operation || "file_operation", options ); } function cleanupStaleTempFilesSync(target, options = {}) { const directory = path.dirname(target); const basename = path.basename(target); const maxAgeMs = Math.max(1000, Number(options.staleTempAgeMs) || 60 * 60 * 1000); const now = Date.now(); let names = []; try { names = fs.readdirSync(directory); } catch { return; } for (const name of names) { if (name !== `${basename}.tmp` && !(name.startsWith(`${basename}.`) && name.endsWith(".tmp"))) continue; const candidate = path.join(directory, name); try { if (now - fs.statSync(candidate).mtimeMs < maxAgeMs) continue; fs.rmSync(candidate, { force: true }); recordDiagnostic(target, "stale_temp_removed", null, 0, "warning", options); } catch {} } } function temporaryPath(target) { return `${target}.${process.pid}.${threadId}.${crypto.randomBytes(7).toString("hex")}.tmp`; } function syncParentDirectory(target, options) { let descriptor = null; try { descriptor = fs.openSync(path.dirname(target), "r"); fs.fsyncSync(descriptor); } catch (error) { if (process.platform !== "win32") { recordDiagnostic(target, "directory_fsync_unavailable", error, 0, "warning", options); } } finally { if (descriptor != null) try { fs.closeSync(descriptor); } catch {} } } function recordDiagnostic(target, operation, error, attempt, level, options = {}) { const entry = { timestamp: new Date().toISOString(), level, operation, target, attempt, code: error?.code || null, message: error?.message || null }; diagnostics.push(entry); if (diagnostics.length > 100) diagnostics.splice(0, diagnostics.length - 100); if (typeof options.onDiagnostic === "function") options.onDiagnostic(entry); } function getSafeFileDiagnostics() { return diagnostics.map((entry) => ({ ...entry })); } function clearSafeFileDiagnostics() { diagnostics.length = 0; } module.exports = { TRANSIENT_CODES, writeJsonAtomicSync, writeTextAtomicSync, cleanupStaleTempFilesSync, runFileOperationWithRetries, getSafeFileDiagnostics, clearSafeFileDiagnostics };