export interface FileLockOptions { staleMs?: number; retries?: number; retryDelayMs?: number; signal?: AbortSignal; onAcquired?: () => void; /** Stable host identity required to safely reclaim locks on a shared volume. */ ownerHostId?: string; /** Previous local host identities accepted only when deciding stale-owner reclamation. */ previousOwnerHostIds?: readonly string[]; } export declare const FileLockTestHooks: { afterParentMkdir?: (lockPath: string) => void | Promise; }; /** * Returns the OS-provided process start timestamp for PID-reuse detection. * `ps` is available on the supported Unix hosts (macOS and Linux), unlike * Linux's `/proc//stat` pseudo-file. */ export declare function processStartTime(pid: number): string | null; /** @internal */ export declare function readFileLockInfoForGc(lockDir: string): Promise; /** Owner identity stamped into a `.lock/info` record. */ export interface FileLockOwnerToken { pid: number; start_time?: string; owner_host_id?: string; timestamp: number; } /** Outcome of a guarded lock-dir removal attempt (`removeFileLockDirForGc`). */ export type FileLockGcRemoval = "removed" | "owner_changed" | "missing"; /** * @internal * Fail-closed removal of a lock dir whose owner is expected to be dead or * finished. Re-reads the on-disk owner token as close to the unlink as possible * and only deletes the dir when it STILL holds the exact `{pid, timestamp}` * identity the caller observed. * * Closes stale-cleanup TOCTOU windows (#606): between a dead/stale re-read and * the unlink, a live process can reclaim a stale lock at the same path * (`acquireLock` rms the stale dir, then re-`mkdir`s and rewrites `info` with a * fresh pid+timestamp). Deleting by path alone would reap that LIVE lock. Any * mismatch (`owner_changed`) or absent/unreadable info (`missing` — e.g. a * fresh acquirer between `mkdir` and `writeLockInfo`) refuses the delete and * leaves the dir intact. POSIX has no atomic compare-and-delete for a * directory, so the residual read->unlink window cannot be fully eliminated, * but the reclaim-after-stale scenario the issue describes is now guarded. */ export declare function removeFileLockDirForGc(lockDir: string, expected: FileLockOwnerToken): Promise; /** * @internal * READ-ONLY verdict on an EXISTING generic `.lock/` directory that another lock * protocol has collided with: is its owner gone, by this protocol's own rules? * * Exposed so a foreign holder of the same path never has to reimplement this protocol's * owner parsing or liveness rules. Reusing them is what makes the two implementations * agree: `processStartTime` here is the portable `ps` value that `info.start_time` was * written from, so a live owner is proved live rather than compared against a value from a * different clock source and then reaped. A live owner is never reported stale by elapsed * time alone. * * Deletion is deliberately NOT offered. This protocol can only re-read an owner token and * then unlink a pathname, which a successor can take over in between; a caller that must * remove the directory has to do it under an identity-bound primitive that refuses when * the object is no longer the one that was judged. */ export declare function genericFileLockDirIsStale(lockDir: string, staleMs: number, ownerHostId?: string): Promise; /** * Serializes all contenders, including callers in the same process. Because this * API exposes no ownership token, recursive acquisition is indistinguishable * from independent async contention; code that already holds the lock must pass * that fact through its own `lockHeld` path instead of acquiring it again. */ export declare function withFileLock(filePath: string, fn: () => Promise, options?: FileLockOptions): Promise;