import "./fs-safe-defaults-A4awSMom.js";
import { C as FsSafeError } from "./path-CDlvTIfD.js";
import { t as stringifyJsonDocument } from "./json-stringify-D1335--5.js";
import { i as openRootFileSync } from "./root-file-Brkbm2Vn.js";
import { i as readRegularFileSync, o as statRegularFile, r as readRegularFile } from "./regular-file-B6htoRh4.js";
import { a as replaceFileAtomic, r as replaceFileAtomic$1 } from "./replace-file-DlzIPzco.js";
import fs from "node:fs";
import path from "node:path";
import { randomUUID } from "node:crypto";
//#region packages/fs-safe/dist/async-lock.js
function createAsyncLock$1() {
	let lock = Promise.resolve();
	return async function withLock(fn) {
		const prev = lock;
		let release;
		lock = new Promise((resolve) => {
			release = resolve;
		});
		await prev;
		try {
			return await fn();
		} finally {
			release?.();
		}
	};
}
//#endregion
//#region packages/fs-safe/dist/text-atomic.js
async function writeTextAtomic$1(filePath, content, options) {
	const payload = options?.trailingNewline && !content.endsWith("\n") ? `${content}\n` : content;
	const durable = options?.durable ?? true;
	await replaceFileAtomic({
		filePath,
		content: payload,
		mode: options?.mode ?? 384,
		dirMode: options?.dirMode ?? 511 & ~process.umask(),
		copyFallbackOnPermissionError: true,
		syncTempFile: durable,
		syncParentDir: durable
	});
}
//#endregion
//#region packages/fs-safe/dist/json.js
const READ_RETRY_MAX_ATTEMPTS = 5;
const READ_RETRY_BASE_DELAY_MS = 50;
function isRetryableReadError(err, options) {
	if (err instanceof FsSafeError && err.code === "path-mismatch") return true;
	if (options.retryOpenRaceErrors !== true) return false;
	const code = getErrorCode(err);
	return code === "ENOENT" || code === "EPERM";
}
function sleep(ms) {
	return new Promise((resolve) => setTimeout(resolve, ms));
}
async function readRegularFileWithRetry(filePath, options = {}) {
	let lastErr;
	for (let attempt = 0; attempt < READ_RETRY_MAX_ATTEMPTS; attempt++) try {
		return (await readRegularFile({ filePath })).buffer;
	} catch (err) {
		lastErr = err;
		if (!isRetryableReadError(err, options) || attempt === READ_RETRY_MAX_ATTEMPTS - 1) throw err;
		await sleep(READ_RETRY_BASE_DELAY_MS * Math.pow(2, attempt));
	}
	throw lastErr;
}
async function readRegularFileIfExistsWithRetry(filePath) {
	if ((await statRegularFile(filePath)).missing) return null;
	return await readRegularFileWithRetry(filePath, { retryOpenRaceErrors: true });
}
const JSON_FILE_MODE = 384;
const JSON_DIR_MODE = 448;
const SUPPORTS_SYNC_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in fs.constants;
function getErrorCode(err) {
	return err instanceof Error ? err.code : void 0;
}
function trySetSecureMode(pathname) {
	let fd;
	try {
		fd = fs.openSync(pathname, fs.constants.O_RDONLY | (SUPPORTS_SYNC_NOFOLLOW ? fs.constants.O_NOFOLLOW : 0));
		fs.fchmodSync(fd, JSON_FILE_MODE);
	} catch {} finally {
		if (fd !== void 0) try {
			fs.closeSync(fd);
		} catch {}
	}
}
function trySyncDirectory(pathname) {
	let fd;
	try {
		fd = fs.openSync(path.dirname(pathname), "r");
		fs.fsyncSync(fd);
	} catch {} finally {
		if (fd !== void 0) try {
			fs.closeSync(fd);
		} catch {}
	}
}
function renameJsonFileWithFallback(tmpPath, pathname) {
	try {
		fs.renameSync(tmpPath, pathname);
		return;
	} catch (error) {
		const code = error.code;
		if (code === "EPERM" || code === "EEXIST") {
			if ((() => {
				try {
					return fs.lstatSync(pathname);
				} catch (lstatError) {
					if (lstatError.code === "ENOENT") return null;
					throw lstatError;
				}
			})()?.isSymbolicLink()) {
				fs.rmSync(pathname, { force: true });
				fs.renameSync(tmpPath, pathname);
				return;
			}
			fs.rmSync(pathname, { force: true });
			fs.renameSync(tmpPath, pathname);
			return;
		}
		throw error;
	}
}
function writeTempJsonFile(pathname, payload) {
	const fd = fs.openSync(pathname, "wx", JSON_FILE_MODE);
	try {
		fs.writeFileSync(fd, payload, "utf8");
		fs.fsyncSync(fd);
	} finally {
		fs.closeSync(fd);
	}
}
function tryReadJsonSync$1(pathname) {
	try {
		const raw = readRegularFileSync({ filePath: pathname }).buffer.toString("utf8");
		return JSON.parse(raw);
	} catch {
		return null;
	}
}
function writeJsonSync$1(pathname, data) {
	const targetPath = pathname;
	const tmpPath = `${targetPath}.${randomUUID()}.tmp`;
	const payload = `${stringifyJsonDocument(data, null, 2)}\n`;
	fs.mkdirSync(path.dirname(targetPath), {
		recursive: true,
		mode: JSON_DIR_MODE
	});
	try {
		writeTempJsonFile(tmpPath, payload);
		trySetSecureMode(tmpPath);
		renameJsonFileWithFallback(tmpPath, targetPath);
		trySetSecureMode(targetPath);
		trySyncDirectory(targetPath);
	} finally {
		try {
			fs.rmSync(tmpPath, { force: true });
		} catch {}
	}
}
var JsonFileReadError$1 = class extends Error {
	filePath;
	reason;
	constructor(filePath, reason, cause) {
		super(`Failed to ${reason} JSON file: ${filePath}`, { cause });
		this.name = "JsonFileReadError";
		this.filePath = filePath;
		this.reason = reason;
	}
};
function isRecord(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}
function resolveInvalidMessage(invalidMessage, relativePath) {
	if (typeof invalidMessage === "function") return invalidMessage(relativePath);
	return invalidMessage ?? `${relativePath} has an unexpected shape`;
}
function readRootStructuredFileSync$1(options) {
	const opened = openRootFileSync({
		absolutePath: path.resolve(options.rootDir, options.relativePath),
		rootPath: options.rootDir,
		...options.rootRealPath !== void 0 ? { rootRealPath: options.rootRealPath } : {},
		boundaryLabel: options.boundaryLabel,
		rejectHardlinks: options.rejectHardlinks,
		maxBytes: options.maxBytes,
		allowedType: "file"
	});
	if (!opened.ok) return {
		ok: false,
		reason: "open",
		failure: opened
	};
	try {
		const parsed = options.parse(fs.readFileSync(opened.fd, "utf8"));
		if (options.validate && !options.validate(parsed)) return {
			ok: false,
			reason: "invalid",
			error: resolveInvalidMessage(options.invalidMessage, options.relativePath)
		};
		return {
			ok: true,
			value: parsed,
			stat: opened.stat,
			path: opened.path,
			rootRealPath: opened.rootRealPath
		};
	} catch (error) {
		return {
			ok: false,
			reason: "parse",
			error: `failed to parse ${options.relativePath}: ${String(error)}`
		};
	} finally {
		fs.closeSync(opened.fd);
	}
}
function readRootJsonSync$1(options) {
	return readRootStructuredFileSync$1({
		...options,
		parse: (raw) => JSON.parse(raw)
	});
}
function readRootJsonObjectSync$1(options) {
	return readRootStructuredFileSync$1({
		...options,
		parse: (raw) => JSON.parse(raw),
		validate: isRecord,
		invalidMessage: (relativePath) => `${relativePath} must contain a JSON object`
	});
}
async function readJson$1(filePath) {
	let raw;
	try {
		raw = (await readRegularFileWithRetry(filePath, { retryOpenRaceErrors: true })).toString("utf8");
	} catch (err) {
		throw new JsonFileReadError$1(filePath, "read", err);
	}
	try {
		return JSON.parse(raw);
	} catch (err) {
		throw new JsonFileReadError$1(filePath, "parse", err);
	}
}
async function readJsonIfExists$1(filePath) {
	let raw;
	try {
		const buffer = await readRegularFileIfExistsWithRetry(filePath);
		if (buffer === null) return null;
		raw = buffer.toString("utf8");
	} catch (err) {
		if (getErrorCode(err) === "ENOENT") return null;
		throw new JsonFileReadError$1(filePath, "read", err);
	}
	try {
		return JSON.parse(raw);
	} catch (err) {
		throw new JsonFileReadError$1(filePath, "parse", err);
	}
}
function readJsonSync$1(filePath) {
	let raw;
	try {
		raw = readRegularFileSync({ filePath }).buffer.toString("utf8");
	} catch (err) {
		throw new JsonFileReadError$1(filePath, "read", err);
	}
	try {
		return JSON.parse(raw);
	} catch (err) {
		throw new JsonFileReadError$1(filePath, "parse", err);
	}
}
async function writeJson$1(filePath, value, options) {
	await writeTextAtomic$1(filePath, stringifyJsonDocument(value, null, 2), {
		mode: options?.mode,
		dirMode: options?.dirMode,
		trailingNewline: options?.trailingNewline,
		durable: options?.durable
	});
}
//#endregion
//#region src/infra/json-files.ts
const JsonFileReadError = JsonFileReadError$1;
function readJsonSync(...args) {
	return readJsonSync$1(...args);
}
function readRootJsonObjectSync(...args) {
	return readRootJsonObjectSync$1(...args);
}
function readRootJsonSync(...args) {
	return readRootJsonSync$1(...args);
}
function readRootStructuredFileSync(...args) {
	return readRootStructuredFileSync$1(...args);
}
function tryReadJsonSync(pathname) {
	return tryReadJsonSync$1(pathname);
}
function writeJson(...args) {
	return writeJson$1(...args);
}
function writeJsonSync(...args) {
	return writeJsonSync$1(...args);
}
function writeJsonAtomic(...args) {
	return writeJson$1(...args);
}
async function readJson(filePath) {
	try {
		return await readJson$1(filePath);
	} catch (err) {
		throw err instanceof JsonFileReadError ? err : new JsonFileReadError(filePath, "read", err);
	}
}
async function readJsonFileStrict(filePath) {
	return readJson(filePath);
}
async function readJsonIfExists(filePath) {
	try {
		return await readJsonIfExists$1(filePath);
	} catch (err) {
		if (err instanceof JsonFileReadError) throw err;
		throw new JsonFileReadError(filePath, "read", err);
	}
}
async function readDurableJsonFile(filePath) {
	return readJsonIfExists(filePath);
}
/**
* tryReadJson delegates to readJsonIfExists instead of the internal
* tryReadJsonImpl from @nodmix/fs-safe. The fs-safe implementation retries
* race conditions before propagating errors; this wrapper keeps the historical
* null-on-error contract for callers that intentionally treat reads as optional.
*/
async function tryReadJson(filePath) {
	try {
		return await readJsonIfExists(filePath);
	} catch {
		return null;
	}
}
async function readJsonFile(filePath) {
	return tryReadJson(filePath);
}
function createAsyncLock(...args) {
	return createAsyncLock$1(...args);
}
async function writeTextAtomic(filePath, content, options) {
	await replaceFileAtomic$1({
		filePath,
		content: options?.trailingNewline && !content.endsWith("\n") ? `${content}\n` : content,
		mode: options?.mode ?? 384,
		dirMode: options?.dirMode ?? 511 & ~process.umask(),
		copyFallbackOnPermissionError: true,
		syncTempFile: options?.durable !== false,
		syncParentDir: options?.durable !== false,
		...options?.beforeRename ? { beforeRename: options.beforeRename } : {},
		...options?.tempPrefix ? { tempPrefix: options.tempPrefix } : {}
	});
}
//#endregion
export { writeTextAtomic as _, readJsonFile as a, writeJsonSync$1 as b, readJsonSync as c, readRootStructuredFileSync as d, tryReadJson as f, writeJsonSync as g, writeJsonAtomic as h, readJson as i, readRootJsonObjectSync as l, writeJson as m, createAsyncLock as n, readJsonFileStrict as o, tryReadJsonSync as p, readDurableJsonFile as r, readJsonIfExists as s, JsonFileReadError as t, readRootJsonSync as u, readRootJsonObjectSync$1 as v, tryReadJsonSync$1 as y };
