import * as path from 'node:path';
import type { BasicAuthConfig, LoadBalancerConfig, PathRewrite, ProxyFrom, StaticRouteConfig } from './types';
/**
 * Default location for the registry directory. The daemon's PID file and log
 * sit alongside it under `~/.stacks/rpx/`.
 */
export declare function getRegistryDir(): string;
/**
 * Validate an entry id. Rejects anything that could escape the registry dir
 * (path traversal, slashes) or that would round-trip oddly through a filename.
 */
export declare function isValidId(id: string): boolean;
/**
 * Check whether a PID is alive. `kill(pid, 0)` returns without sending a
 * signal but throws ESRCH if the process is gone — exactly the probe we need.
 * EPERM means the process exists but we don't own it; treat as alive.
 */
export declare function isPidAlive(pid: number): boolean;
/**
 * Atomically write an entry to disk.
 *
 * Writes to a temp file in the same directory, then renames into place. POSIX
 * rename within the same filesystem is atomic, so a concurrent reader either
 * sees the old file or the new file — never a half-written one.
 */
export declare function writeEntry(entry: RegistryEntry, dir?: string, verbose?: boolean): Promise<void>;
/**
 * Remove an entry by id. No-op if the file is already gone.
 */
export declare function removeEntry(id: string, dir?: string, verbose?: boolean): Promise<void>;
/**
 * Read a single entry by id. Returns `null` if missing or malformed (malformed
 * files are deleted so they don't keep poisoning subsequent reads).
 */
export declare function readEntry(id: string, dir?: string, verbose?: boolean): Promise<RegistryEntry | null>;
/**
 * Read all entries from the registry directory. Malformed files are pruned.
 * This does NOT GC stale PIDs — call `gcStaleEntries` for that explicitly.
 */
export declare function readAll(dir?: string, verbose?: boolean): Promise<RegistryEntry[]>;
/**
 * Remove entries whose writer PID is no longer alive. Returns the count of
 * entries removed. Safe to call repeatedly; intended to run on daemon startup
 * and on a slow timer (e.g. every 5s) while the daemon is up.
 */
export declare function gcStaleEntries(dir?: string, verbose?: boolean): Promise<number>;
/**
 * Watch the registry directory and invoke `onChange` with the full current
 * entry list whenever something changes. Events are debounced so a flurry of
 * rapid writes (e.g. several `./buddy dev` invocations starting in parallel)
 * triggers at most one rebuild.
 *
 * The watcher tolerates a missing directory at startup — it creates the dir
 * before opening the watch, so the first `writeEntry` doesn't race the daemon.
 */
export declare function watchRegistry(onChange: (entries: RegistryEntry[]) => void | Promise<void>, opts?: WatchOptions & { dir?: string }): WatchHandle;
export declare interface RegistryEntry {
  id: string
  from?: ProxyFrom
  to: string
  path?: string
  pid?: number
  cwd?: string
  createdAt: string
  pathRewrites?: PathRewrite[]
  cleanUrls?: boolean
  changeOrigin?: boolean
  static?: string | StaticRouteConfig
  auth?: BasicAuthConfig
  loadBalancer?: LoadBalancerConfig
}
export declare interface WatchHandle {
  close: () => void
}
export declare interface WatchOptions {
  debounceMs?: number
  pollMs?: number
  verbose?: boolean
}
