/**
 * directory/ldapDirectory — the {@link Directory} port over LDAPS, through
 * `ldapts` (an optional peer, loaded lazily — the `jose` precedent).
 *
 * LDAPS only: `ldap://` would send the password in the clear on the bind, and
 * StartTLS needs the same DC certificate LDAPS does, so refusing it loses
 * nothing real. The certificate chain is checked against EITHER the CA the
 * operator supplies (`caPem`) OR — said in so many words, `systemCa: true` —
 * Node's default CA store, and the host name against the URL. There is no
 * switch to skip either check, and no default between the two trusts.
 *
 * ── What to trust: the ROOT ─────────────────────────────────────────────────
 * Trust the CA at the top of the DC certificate's chain, never the DC's own
 * certificate (refused at construction: it is not a CA) or an intermediate.
 * A DC certificate is renewed every few months, and an intermediate is
 * replaced on its own schedule; a root lives for years. Trusting the root
 * means a renewal — a new leaf, even a new intermediate the DC sends in its
 * chain — needs no change here. A DC certificate issued by a PUBLIC CA chains
 * to a root Node already ships (`systemCa: true`); a company CA does not, so
 * give its root as `caPem`.
 */
import type { Directory } from './port.js';
/** The slice of `ldapts` this adapter uses, declared structurally. */
export interface LdaptsBackend {
    Client: new (options: Record<string, unknown>) => {
        bind(name: string, password?: string): Promise<void>;
        exop(oid: string): Promise<{
            oid?: string;
            value?: string;
        }>;
        search(base: string, options: Record<string, unknown>): Promise<{
            searchEntries: Record<string, unknown>[];
        }>;
        unbind(): Promise<void>;
    };
}
export interface LdapDirectoryOptions {
    /** `ldaps://dc1.corp.example:636`. `ldap://` is refused. */
    readonly url: string;
    /**
     * The CA certificate(s), PEM, the DC's certificate must chain to — the
     * company's ROOT CA. Exactly one of this and `systemCa`.
     */
    readonly caPem?: string;
    /**
     * `true`: trust Node's default CA store instead of a file — the public
     * roots Node ships (Mozilla's list), plus `NODE_EXTRA_CA_CERTS`, plus the
     * operating system's store when Node runs with `--use-system-ca`. For a DC
     * whose certificate a PUBLIC CA issued. Exactly one of this and `caPem`;
     * the host-name check stays on either way.
     */
    readonly systemCa?: true;
    /** Connect and operation timeout, ms. Default 5000. */
    readonly timeoutMs?: number;
    /** An already-imported `ldapts`. */
    readonly backend?: LdaptsBackend;
    /**
     * Told why the directory could not answer — never reached (with the
     * connection or TLS error's CODE, e.g. `UNABLE_TO_VERIFY_LEAF_SIGNATURE`
     * for a CA that does not issue the DC's certificate,
     * `ERR_TLS_CERT_ALTNAME_INVALID` for a name it does not carry), or failed
     * after the bind was sent. For the operator; never the password, the name
     * or an error's text. A REFUSED bind is not logged here: its AD sub-code
     * travels in the bind's answer to the sign-in door's audit record.
     */
    readonly log?: (line: string) => void;
}
/** Raised when `directory-password` is configured and `ldapts` is not installed. */
export declare class MissingLdaptsError extends Error {
    readonly code: "ERR_MISSING_LDAPTS";
    constructor();
}
export declare function ldapDirectory(options: LdapDirectoryOptions): Directory;
/**
 * Every certificate block in a PEM bundle, in order — what
 * `pem.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g)`
 * finds, in one pass. The regex re-reads the rest of the bundle from every
 * BEGIN line that has no END after it, which is quadratic on a file of
 * repeated BEGIN lines; once a BEGIN has no END after it, no later one has
 * either, so the scan stops there.
 */
export declare function pemCertificateBlocks(pem: string): string[];
/**
 * Why a CA file is not one, or `undefined`: every PEM block must parse as an
 * X.509 certificate with the CA flag set (review idI57 N-10 — a leaf
 * certificate booted, then failed every sign-in).
 */
export declare function caPemProblem(caPem: unknown): string | undefined;
/**
 * The subjects of the CA certificates in a PEM bundle that are NOT
 * self-signed roots — intermediates. Trusting one alone breaks at the next
 * renewal that changes it, so boot says so (`directory-password`'s banner).
 */
export declare function intermediateCaSubjects(caPem: string): string[];
