import { mkdir, readFile, rename, writeFile } from "node:fs/promises"; import { homedir } from "node:os"; import path from "node:path"; /** * Where routing measurements persist across restarts. Same convention as the * web extension: XDG_STATE_HOME wins, else the platform's user state dir. */ export function routingStatePath( platform: NodeJS.Platform = process.platform, env: NodeJS.ProcessEnv = process.env, home = homedir(), ): string { const paths = platform === "win32" ? path.win32 : path.posix; const root = env.XDG_STATE_HOME ? paths.join(env.XDG_STATE_HOME, "pi") : platform === "win32" ? paths.join( env.LOCALAPPDATA ?? paths.join(home, "AppData", "Local"), "pi", ) : platform === "darwin" ? paths.join(home, "Library", "Application Support", "pi") : paths.join(home, ".local", "state", "pi"); return paths.join(root, "gratis", "routing.json"); } /** Missing, unreadable, or corrupt state is simply absent. */ export async function loadRoutingState(file: string): Promise { try { return JSON.parse(await readFile(file, "utf8")); } catch { return undefined; } } /** Owner-only, atomic: write a sibling temp file, then rename over the target. */ export async function saveRoutingState( file: string, state: unknown, ): Promise { await mkdir(path.dirname(file), { recursive: true, mode: 0o700 }); const temporary = `${file}.${process.pid}.tmp`; await writeFile(temporary, JSON.stringify(state), { mode: 0o600 }); await rename(temporary, file); }