/**
 * Cross-peer propagation of generic-webhook-source registration changes.
 *
 * Sister to the GitHub-app `SourceManager`
 * (`packages/orchestrator/src/sources/source-manager.ts`), which owns the
 * `sources_change` channel. This listener owns `generic_sources_change`
 * — the channel the migration-019 trigger emits on every INSERT, UPDATE,
 * or DELETE of a `generic_webhook_sources` row.
 *
 * On NOTIFY:
 *   1. Queue the affected `routing_key` (the channel payload).
 *   2. Debounce 200 ms so rapid edits coalesce into one drain pass.
 *   3. For each queued routing_key:
 *        - Re-query `GenericSourceManager.getByRoutingKey()`. The query
 *          already filters out soft-deleted (`deleted_at IS NOT NULL`)
 *          and disabled (`enabled = false`) rows.
 *        - If the row is gone (DELETE, soft-delete, or disable):
 *          `providerRegistry.unregister(routingKey)`.
 *        - Otherwise: `registerProviderBundleForSource(row, deps)`
 *          (idempotent — a second call replaces the prior bundle).
 *
 * The listener does NOT own the `ProviderRegistry` — it mutates the
 * shared instance the rest of the orchestrator dispatches against. This
 * differs from `SourceManager`, which rebuilds a fresh registry on
 * every reload and asks the caller to swap the reference. The reason is
 * shared ownership: the GitHub-app and generic-webhook sources both
 * populate the same `ProviderRegistry` instance, so a wholesale rebuild
 * by one of them would clobber the other's bundles.
 *
 * The admin POST/PATCH/DELETE handlers in `routes/admin-events.ts` ALSO
 * mutate the registry inline so the API response is self-consistent on
 * the issuing peer (a webhook fired immediately after a 200 OK sees the
 * change without waiting for the NOTIFY round-trip). The local NOTIFY
 * fires too — `registerByRoutingKey` is idempotent, so the redundant
 * apply is harmless.
 */
import type pg from 'pg';
import type { GenericSourceManager } from './generic-sources.js';
import type { ProviderRegistry } from '../provider-registry.js';
import type { AppConfig } from '../config.js';
import type { SecretResolver } from '../secrets/secret-resolver.js';
export interface GenericSourcesChangeListenerOptions {
    /** Raw pg pool — a dedicated PoolClient is checked out for LISTEN. */
    pool: pg.Pool;
    /** Used to re-query the affected row by routing_key on each NOTIFY. */
    sourceManager: GenericSourceManager;
    /** Mutated in place — registerByRoutingKey / unregister. */
    providerRegistry: ProviderRegistry;
    /** Gates internal-provider bundle registration in the helper. */
    config: AppConfig;
    /** Required for universal-git source rows; null is acceptable on
     *  peers that cannot serve them. */
    secretResolver: SecretResolver | null;
    /** Coalesce window for rapid NOTIFYs against the same row. Default 200 ms. */
    debounceMs?: number;
    /**
     * Invoked once per drain pass that applied at least one change. The
     * platform-mode boot wires this to re-push the full source list to the
     * Platform (`platformClient.updateSources()`) so a generic source added /
     * removed at runtime reaches the Platform's `webhook_sources` immediately,
     * not just the local registry.
     */
    onChange?: () => void;
}
export declare class GenericSourcesChangeListener {
    private readonly opts;
    private client;
    private readonly pending;
    private debounceTimer;
    private readonly debounceMs;
    /**
     * Drain-applied-change callback. Mutable so the platform-mode boot can wire
     * it after the Platform client exists (this listener is constructed before).
     */
    private onChange?;
    constructor(opts: GenericSourcesChangeListenerOptions);
    /** Replace the drain-applied-change callback after construction. */
    setOnChange(cb: () => void): void;
    /** Open the dedicated client and subscribe. Cold-boot bundle
     *  registration is handled by the orchestrator-core startup loop
     *  via the same helper; this listener only services warm-path
     *  NOTIFYs. */
    start(): Promise<void>;
    stop(): Promise<void>;
    private scheduleDrain;
    /** Visible for tests — drain the queued routing_keys synchronously. */
    drain(): Promise<void>;
}
//# sourceMappingURL=generic-sources-listener.d.ts.map