import { OnDemandCertManager } from './on-demand';
import type { OnDemandSitesConfig, OnDemandTlsConfig, ProductionTlsConfig, TlsOption } from './types';
import type { ProxyRoute } from './proxy-handler';
import type { RegistryEntry } from './registry';
import type { SiteSnapshot } from './site-supervisor';
export declare function getDaemonRpxDir(): string;
export declare function getDaemonPidPath(rpxDir?: string): string;
/**
 * Read the PID stored in `daemon.pid`, or `null` if no file / unparseable.
 */
export declare function readDaemonPid(rpxDir?: string): Promise<number | null>;
/**
 * True if `daemon.pid` points at a process that is still alive.
 */
export declare function isDaemonRunning(rpxDir?: string): Promise<boolean>;
/**
 * Acquire the daemon's single-instance lock by atomically creating
 * `daemon.pid`. If the file exists but holds a stale PID we take it over;
 * otherwise we throw.
 *
 * `O_CREAT | O_EXCL` (`'wx'`) guarantees only one process wins the create
 * race, so we don't need an external lock library.
 */
export declare function acquireDaemonLock(rpxDir?: string): Promise<string>;
export declare function releaseDaemonLock(rpxDir?: string): Promise<void>;
/**
 * Translate a registry entry into the routing shape consumed by the proxy
 * fetch handler. The entry's `from` is normalized to `host:port`, or (for a
 * multi-upstream `from`) load-balanced via a per-entry-id cached pool.
 *
 * Exported for tests, which exercise the entry-id-keyed pool cache/reconcile
 * logic directly rather than through a full daemon + live HTTP round trip.
 */
export declare function entryToRoute(entry: RegistryEntry): ProxyRoute;
/**
 * The shared `:80` handler: serve ACME http-01 challenges, kick off on-demand
 * issuance for an approved-but-uncovered host, then 301 to HTTPS. The request
 * target is parsed defensively — scanners constantly send malformed/relative
 * targets, and a thrown `new URL` would reject the fetch handler and make Bun
 * drop the connection with no response. A bad target becomes a 400 instead.
 */
export declare function handleHttpRedirect(req: Request, onDemand: OnDemandCertManager | null, acmeChallengeWebroot?: string): Response;
// `opts` IS used throughout; pickier's no-unused-vars mis-fires on this fn after
// the on-demand serve refactor (its --fix would wrongly rename to `_opts`).
// eslint-disable-next-line pickier/no-unused-vars
export declare function runDaemon(opts?: DaemonOptions): Promise<DaemonHandle>;
/**
 * A cluster worker: binds :443 with `reusePort`, serves the proxy handler, keeps
 * its routing table in sync with the registry, and reloads its TLS certs from
 * the coordinator-published file on `SIGHUP`. It owns none of the singletons
 * (lock, DNS, hosts, :80, ACME issuance) — the coordinator does.
 */
export declare function runDaemonWorker(ctx: WorkerCtx): Promise<DaemonHandle>;
/**
 * Best-effort default for the spawn command used by lazy-spawn. Compiled
 * binaries (`bun build --compile`) self-invoke; source-mode executions invoke
 * the same Bun + script that's running now.
 *
 * Library consumers should not rely on this — pass `spawnCommand` explicitly.
 */
export declare function defaultDaemonSpawnCommand(): string[];
/**
 * Make sure a daemon is running, starting one as a detached child if needed.
 *
 * - If the pid file exists and points at a live process, returns immediately
 *   with `spawned: false`.
 * - Otherwise cleans any stale pid file, spawns the configured command with
 *   `detached: true` + `stdio: 'ignore'` + `unref()` so it survives the caller
 *   exiting, and polls the pid file until the new daemon registers itself.
 *
 * Throws if the daemon never appears within `startupTimeoutMs`.
 */
export declare function ensureDaemonRunning(opts?: EnsureDaemonOptions): Promise<EnsureDaemonResult>;
/**
 * Stop a running daemon by reading its pid and sending SIGTERM. Polls until
 * the process is gone (or escalates to SIGKILL if `forceAfterTimeout`). The
 * pid file is removed by the daemon's own SIGTERM handler — we clean up only
 * if we had to SIGKILL.
 */
export declare function stopDaemon(opts?: StopDaemonOptions): Promise<StopDaemonResult>;
/**
 * When the daemon is not running, ensure no stale macOS resolver overrides remain.
 */
export declare function reconcileDevelopmentDnsOnIdle(opts?: { rpxDir?: string, verbose?: boolean }): Promise<void>;
export declare interface DaemonOptions {
  verbose?: boolean
  rpxDir?: string
  registryDir?: string
  httpsPort?: number
  httpPort?: number
  hostname?: string
  https?: TlsOption
  productionCerts?: ProductionTlsConfig
  onDemandTls?: OnDemandTlsConfig
  onDemandSites?: OnDemandSitesConfig
  acmeChallengeWebroot?: string
  gcIntervalMs?: number
  workers?: number
}
export declare interface DaemonHandle {
  stop: () => Promise<void>
  done: Promise<void>
  httpsPort: number
  httpPort: number
  pidPath: string
  ensureCert: (host: string) => Promise<boolean>
  listSites: () => SiteSnapshot[]
}
// ───────────────────────── cluster: coordinator + workers ─────────────────────
declare interface WorkerCtx {
  rpxDir: string
  registryDir: string
  httpsPort: number
  hostname: string
  verbose: boolean
}
export declare interface EnsureDaemonOptions {
  rpxDir?: string
  spawnCommand?: string[]
  spawnCwd?: string
  spawnEnv?: Record<string, string>
  startupTimeoutMs?: number
  pollIntervalMs?: number
  verbose?: boolean
}
export declare interface EnsureDaemonResult {
  pid: number
  spawned: boolean
}
export declare interface StopDaemonOptions {
  rpxDir?: string
  timeoutMs?: number
  pollIntervalMs?: number
  forceAfterTimeout?: boolean
  verbose?: boolean
}
export declare interface StopDaemonResult {
  stopped: boolean
  pid: number | null
  forced: boolean
}
declare type SniEntry = { serverName: string, cert: string, key: string }
