import type { ZynorConfig, ProviderConfig } from './types.cjs'; import { IResolver } from './interfaces/overloading.cjs'; import { EmailValidator } from './email/index.cjs'; import type { EmailBulkValidationOptions, EmailEachOptions, EmailResponse, EmailResponseWithMx, ValidationConfig } from './email/index.cjs'; /** * Main DNS resolver class that aggregates multiple DNS providers. */ export declare class Zynor { private providers; private static __emailValidator; private dnsCache; private dnsTtl; private inflight; private rrIndex; private dnsInFlight; /** Epoch-ms until which a DoH provider is considered failing and excluded * from {@link pickFreestProvider}. Native is never paused because it is a * local resolver backend rather than a separately health-checked DoH * service. */ private dohPausedUntil; /** Consecutive-failure counters per provider; reset on any success. We only * pause once a provider's streak exceeds {@link DOH_PAUSE_AFTER}, so single * transient errors don't cascade-pause healthy providers under high load. */ private dohFailureStreak; private static readonly DOH_PAUSE_MS; private static readonly DOH_PAUSE_AFTER; /** * Creates a new Zynor resolver instance. * @param config - Configuration for all providers * @example * ```typescript * const dns = new Zynor({ * google: { enabled: true, limit: { concurrency: 10 } }, * cloudflare: { enabled: false } * }); * ``` */ constructor(config?: ZynorConfig); /** * Enforce the caller boundary even if a provider is slow to observe its * signal. Bounded requests are isolated from singleflight and receive the * same controls upstream; unbounded requests are the only shared work. */ private waitForCaller; private validateCallerOptions; private callerSignalError; private callerWaitError; private isCallerWaitError; private hasCallerControls; /** * Give one bounded caller an isolated upstream signal. The controller is * aborted when that caller settles, so a provider cannot keep consuming a * queue slot after waitForCaller has stopped waiting. A single timer covers * the full failover chain rather than restarting the deadline per provider. */ private createUpstreamAbortContext; private isCallerCancellation; private cachedResolve; /** Keep provider-owned, cached, and caller-owned DNS result graphs isolated. */ private cloneDnsResult; /** * Creates or returns a singleton instance of EmailValidator. * If an instance already exists, returns the existing instance. * If no instance exists, creates a new one with the provided configuration. * * @param config - Configuration object for the EmailValidator * @param config.options - Optional validation configuration settings * @param config.options.allowIPv6 - Whether to allow IPv6 addresses in email domains * @param config.options.allowInternational - Whether to allow international email addresses * @param config.options.checkDNS - Whether to perform DNS lookups during validation * @param config.dns - Optional DNS configuration for the validator's DNS resolver * @returns An EmailValidator instance * * @example * ```typescript * // Create with default configuration * const validator = Zynor.createEmailValidator(); * * // Create with custom configuration * const validator = Zynor.createEmailValidator({ * options: { * allowIPv6: true, * checkDNS: true * }, * dns: { * google: { enabled: true } * } * }); * ``` */ static createEmailValidator(config?: { options?: ValidationConfig; dns?: ZynorConfig; }): EmailValidator; static get emailValidator(): EmailValidator; /** * Initializes all DNS providers with their configurations. */ private initializeProviders; /** * Sets configuration for a specific provider. * @param provider - The provider name * @param config - The provider configuration * @throws {InvalidProviderError} If the provider name is invalid * @example * ```typescript * dns.setConfig('google', { enabled: true, limit: { concurrency: 15 } }); * ``` */ setConfig(provider: string, config: ProviderConfig): void; /** * Sets configurations for all providers. * @param config - Configuration object for all providers * @example * ```typescript * dns.setConfigs({ * native: { enabled: true }, * google: { enabled: true, limit: { concurrency: 10 } }, * cloudflare: { enabled: false }, * quad9: { enabled: true } * }); * ``` */ setConfigs(config: ZynorConfig): void; /** * Validates if a provider name is valid. */ private isValidProvider; /** Admit only the exact primitive record types exposed by the public API. */ private normalizeRecordType; /** * Snapshot caller-owned option accessors exactly once. Only own documented * fields cross the boundary, so prototype pollution and later getter changes * cannot alter cache identity or provider behavior. */ private normalizeCallOptions; /** Keep the options and positional provider forms strictly exclusive. */ private mergeCallProvider; /** Normalize one DNS owner before it can affect cache or provider state. */ private normalizeHostname; /** Keep address-based reverse lookup distinct from PTR owner queries. */ private normalizeReverseAddress; /** * Gets all enabled providers. */ private getEnabledProviders; /** * Selects a random enabled provider, preferring non-full queues. */ private selectProvider; private rnd; /** * Parses the second argument which can be either AbortOptions or a provider string. */ private parseArgs; /** * Gets a provider instance by name. */ private getProvider; private publicCacheKey; private directCacheKey; /** * Resolve through one explicitly selected provider, or retry each enabled * provider once when selection is automatic. Cache and singleflight state * are provider-scoped so an explicit override can never inherit another * provider's answer or in-flight request. Calls with caller controls bypass * singleflight and own an abortable provider operation. */ private resolvePublic; /** * Resolves A records for a hostname. * @param hostname - The hostname to resolve * @param options - Optional resolution options * @param provider - Optional specific provider to use (e.g., 'google', 'cloudflare') * @returns A promise resolving to an array of IPv4 addresses or records with TTL * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const addresses = await dns.resolve4('example.com'); * console.log(addresses); // ['93.184.216.34'] * * const withTtl = await dns.resolve4('example.com', { ttl: true }); * console.log(withTtl); // [{ address: '93.184.216.34', ttl: 300 }] * ``` */ resolve4: IResolver['resolve4']; /** * Resolves AAAA records for a hostname. * @param hostname - The hostname to resolve * @param options - Optional resolution options * @param provider - Optional specific provider to use * @returns A promise resolving to an array of IPv6 addresses or records with TTL * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const addresses = await dns.resolve6('example.com'); * console.log(addresses); // ['2606:2800:220:1:248:1893:25c8:1946'] * ``` */ resolve6: IResolver['resolve6']; /** * Resolves ANY records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of any DNS records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const records = await dns.resolveAny('example.com'); * console.log(records); // [{ type: 'A', address: '93.184.216.34' }, ...] * ``` */ resolveAny: IResolver['resolveAny']; /** * Resolves CAA records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of CAA records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveCaa: IResolver['resolveCaa']; /** * Resolves CNAME records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of CNAME records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveCname: IResolver['resolveCname']; /** * Resolves MX records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of MX records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const mxRecords = await dns.resolveMx('example.com'); * console.log(mxRecords); // [{ priority: 10, exchange: 'mail.example.com' }] * ``` */ resolveMx: IResolver['resolveMx']; /** * Resolves NAPTR records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of NAPTR records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveNaptr: IResolver['resolveNaptr']; /** * Resolves NS records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of NS records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveNs: IResolver['resolveNs']; /** * Resolves PTR records for an IP address. * @param ip - The IP address to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of PTR records * @throws {InvalidHostnameError} If the IP address is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolvePtr: IResolver['resolvePtr']; /** * Resolves SOA record for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to the SOA record * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveSoa: IResolver['resolveSoa']; /** * Resolves SRV records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of SRV records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveSrv: IResolver['resolveSrv']; /** * Resolves TLSA records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of TLSA records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled */ resolveTlsa: IResolver['resolveTlsa']; /** * Resolves TXT records for a hostname. * @param hostname - The hostname to resolve * @param provider - Optional specific provider to use * @returns A promise resolving to an array of TXT records * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const txtRecords = await dns.resolveTxt('example.com'); * console.log(txtRecords); // [['v=spf1 include:_spf.example.com ~all']] * ``` */ resolveTxt: IResolver['resolveTxt']; /** * Performs reverse DNS lookup for an IP address. * @param ip - The IP address to reverse lookup * @param provider - Optional specific provider to use * @returns A promise resolving to an array of hostnames * @throws {InvalidHostnameError} If the IP address is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const hostnames = await dns.reverse('8.8.8.8'); * console.log(hostnames); // ['dns.google.'] * ``` */ reverse: IResolver['reverse']; /** * Generic resolve method that delegates to specific resolve methods. * @param hostname - The hostname to resolve * @param rrtype - The DNS record type * @param provider - Optional specific provider to use * @returns A promise resolving to DNS records of the specified type * @throws {InvalidHostnameError} If the hostname is invalid * @throws {NoEnabledProvidersError} If no providers are enabled * @example * ```typescript * const aRecords = await dns.resolve('example.com', 'A'); * const mxRecords = await dns.resolve('example.com', 'MX'); * ``` */ resolve: IResolver['resolve']; private errorCode; private isAuthoritativeNegative; private isHttpClientError; private isQueryLocalError; /** * Transport, timeout, malformed-response, and server-side failures are * provider health failures. Authoritative negatives and query-local/client * errors are valid responses to this query, so they neither fail over nor * poison the provider's failure streak. */ private isProviderFailure; private recordProviderSuccess; private recordProviderFailure; /** * Returns the sum of concurrency limits across all enabled DNS providers. * Used by `validateBulk` to determine default parallelism. * @example * ```typescript * const dns = new Zynor({ google: { enabled: true }, cloudflare: { enabled: true } }); * console.log(dns.totalConcurrency); // 20 (10 + 10) * ``` */ get totalConcurrency(): number; /** * Validates multiple email addresses in parallel using the email validator. * Concurrency is derived from enabled DNS provider limits unless explicitly provided. * @param emails - Array of email addresses to validate * @param options - Optional bulk validation options * @param options.includeMx - Include normalized MX records in successful results * @returns A promise resolving to an array of EmailResponse in the same order as input * @example * ```typescript * const results = await Zynor.validateBulk(['user@gmail.com', 'test@example.com']); * console.log(results); // [{ success: true, data: { provider: 'Google', ... } }, ...] * ``` */ static validateBulk(emails: string[], options: EmailBulkValidationOptions & { includeMx: true; }): Promise; static validateBulk(emails: string[], options?: EmailBulkValidationOptions): Promise; /** * Streams validation results as they complete. Forwards to * {@link EmailValidator.each} on the singleton validator. See `each` for * full semantics — defaults are `concurrency: 500` and `perPage: 10`. * Every validator-routed DNS lookup also passes through the selected * provider's configured concurrency/rate queue. * * @param emails - The list of email addresses to validate * @param options - Streaming options (concurrency, perPage, deep, etc.) * @param options.includeMx - Include normalized MX records in successful results * @param onBatch - Callback invoked with each completed batch * @returns Resolves once every input has been processed and flushed * * @example * ```typescript * await Zynor.each(emails, { perPage: 50 }, async (batch) => { * await db.insertMany(batch); * }); * ``` */ static each(emails: string[], options: EmailEachOptions & { includeMx: true; }, onBatch: (batch: EmailResponseWithMx[]) => void | Promise): Promise; static each(emails: string[], options: EmailEachOptions | undefined, onBatch: (batch: EmailResponse[]) => void | Promise): Promise; }