zynor 0.0.44 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,758 +1,722 @@
1
1
  # zynor
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/zynor.svg)](https://badge.fury.io/js/zynor)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
4
  [![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)
6
5
  [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green.svg)](https://nodejs.org/)
7
6
 
8
- A comprehensive, promise-based DNS resolver library that aggregates multiple DNS-over-HTTPS (DoH) providers with advanced concurrency control, email validation, and flexible configuration. Built with TypeScript for maximum type safety and developer experience.
9
-
10
- ## 📋 Table of Contents
11
-
12
- - [Features](#-features)
13
- - [Installation](#-installation)
14
- - [Quick Start](#-quick-start)
15
- - [DNS Providers](#-dns-providers)
16
- - [Configuration](#-configuration)
17
- - [API Reference](#-api-reference)
18
- - [DNS Record Types](#-dns-record-types)
7
+ A DNS resolution and email intelligence library for Node.js. Zynor combines four DNS providers behind a single API with built-in concurrency control, caching, automatic failover, and a full-featured email validation engine.
8
+
9
+ ## Table of Contents
10
+
11
+ - [Installation](#installation)
12
+ - [Quick Start](#quick-start)
13
+ - [DNS Resolution](#dns-resolution)
14
+ - [Standalone Functions](#standalone-functions)
15
+ - [Zynor Class](#zynor-class)
16
+ - [Supported Record Types](#supported-record-types)
17
+ - [Provider Selection](#provider-selection)
18
+ - [AbortSignal and Timeout](#abortsignal-and-timeout)
19
+ - [DNS Caching](#dns-caching)
20
+ - [Request Deduplication](#request-deduplication)
21
+ - [LruCache](#lrucache)
22
+ - [Provider Configuration](#provider-configuration)
23
+ - [Concurrency and Rate Limiting](#concurrency-and-rate-limiting)
24
+ - [Runtime Configuration Updates](#runtime-configuration-updates)
19
25
  - [Email Validation](#email-validation)
20
- - [TypeScript Support](#-typescript-support)
21
- - [License](#-license)
22
-
23
- ## 🚀 Features
24
-
25
- Zynor is designed to be the most comprehensive and reliable DNS resolution library for modern JavaScript applications. It combines multiple DNS-over-HTTPS providers with intelligent load balancing, advanced error handling, and extensive email validation capabilities to deliver enterprise-grade DNS resolution with exceptional performance and reliability.
26
-
27
- - **🌐 Multiple DNS Providers**: Google DoH, Cloudflare DoH, Quad9 DoH, and Node.js native DNS
28
- - **⚡ High Performance**: Concurrent requests with intelligent load balancing
29
- - **🎯 Smart Provider Selection**: Automatic failover and random selection
30
- - **🔧 Flexible Configuration**: Per-provider concurrency and rate limiting
31
- - **📝 Full TypeScript Support**: Complete type definitions and IntelliSense
32
- - **🌍 Cross-Platform**: Works with Node.js 18+, Deno, and Bun
33
- - **📊 Complete DNS API**: All standard DNS record types supported
34
- - **📧 Email Validation**: Comprehensive email domain validation and webmail detection
35
- - **🛡️ Error Handling**: Robust error handling with detailed error information
36
- - **🔄 Automatic Retry**: Built-in retry logic with exponential backoff
37
- - **📈 Queue Management**: Advanced queue management with rate limiter
38
- - **🎛️ Runtime Configuration**: Dynamic configuration updates without restart
26
+ - [Basic Validation](#basic-validation)
27
+ - [Deep Validation](#deep-validation)
28
+ - [Bulk Validation](#bulk-validation)
29
+ - [Provider Detection](#provider-detection)
30
+ - [Disposable Email Detection](#disposable-email-detection)
31
+ - [Role-Based Email Detection](#role-based-email-detection)
32
+ - [Free Domain Detection](#free-domain-detection)
33
+ - [Webmail URL Lookup](#webmail-url-lookup)
34
+ - [Email Extraction](#email-extraction)
35
+ - [Persistent Caching](#persistent-caching)
36
+ - [Error Handling](#error-handling)
37
+ - [TypeScript Support](#typescript-support)
38
+ - [License](#license)
39
39
 
40
- ## 📦 Installation
40
+ ---
41
41
 
42
- Zynor is available as an npm package and can be installed using any modern JavaScript package manager. The library is built with zero dependencies for maximum compatibility and minimal bundle size, making it perfect for both server-side applications and edge computing environments.
42
+ ## Installation
43
43
 
44
- **Using npm:**
45
44
  ```bash
46
45
  npm install zynor
47
46
  ```
48
47
 
49
- **Using Yarn:**
50
48
  ```bash
51
49
  yarn add zynor
52
50
  ```
53
51
 
54
- **Using pnpm:**
55
52
  ```bash
56
53
  pnpm add zynor
57
54
  ```
58
55
 
59
- **Requirements:**
60
- - Node.js 18.0.0 or higher
61
- - TypeScript 4.5+ (for TypeScript projects)
62
- - Modern JavaScript environment with Promise support
63
-
64
- ## 🚀 Quick Start
65
-
66
- Get started with Zynor in seconds! The library offers two main approaches: standalone functions for simple DNS queries and the Zynor class for advanced configuration and control. Both approaches provide the same powerful DNS resolution capabilities with automatic provider selection and intelligent error handling.
56
+ **Requirements:** Node.js 18.0.0 or higher.
67
57
 
68
- ### Standalone Functions (Recommended for Simple Use Cases)
58
+ ---
69
59
 
70
- Standalone functions provide the quickest way to perform DNS lookups with sensible defaults and automatic provider selection:
60
+ ## Quick Start
71
61
 
72
62
  ```typescript
73
- // Using standalone functions (recommended for simple use cases)
74
- import { resolve4, resolveMx, resolveAny } from 'zynor';
75
-
76
- // Resolve A records
77
- const addresses = await resolve4('example.com');
78
- console.log(addresses); // ['93.184.216.34']
63
+ import { resolve4, resolveMx } from "zynor";
79
64
 
80
- // Resolve MX records
81
- const mxRecords = await resolveMx('example.com');
82
- console.log(mxRecords); // [{ priority: 10, exchange: 'mail.example.com' }]
65
+ // Resolve IPv4 addresses
66
+ const ips = await resolve4("example.com");
67
+ // => ['93.184.216.34']
83
68
 
84
- // Resolve with specific provider
85
- const googleResult = await resolve4('example.com', undefined, 'google');
69
+ // Resolve mail servers
70
+ const mx = await resolveMx("example.com");
71
+ // => [{ priority: 10, exchange: 'mail.example.com' }]
86
72
  ```
87
73
 
88
- ### Zynor Class (For Advanced Configuration)
74
+ Import a function, pass a hostname, get results. No configuration needed.
89
75
 
90
- The Zynor class provides fine-grained control over DNS providers, concurrency limits, timeouts, and retry behavior:
76
+ For more control:
91
77
 
92
78
  ```typescript
93
- // Using Zynor class (for advanced configuration)
94
- import { Zynor } from 'zynor';
79
+ import { Zynor } from "zynor";
95
80
 
96
81
  const dns = new Zynor({
97
82
  google: { enabled: true, limit: { concurrency: 10 } },
98
- cloudflare: { enabled: true, limit: { concurrency: 5 } }
83
+ cloudflare: { enabled: true, limit: { concurrency: 5 } },
84
+ quad9: { enabled: false },
85
+ native: { enabled: true },
99
86
  });
100
87
 
101
- const addresses = await dns.resolve4('example.com');
88
+ const ips = await dns.resolve4("example.com");
102
89
  ```
103
90
 
104
- ### CommonJS Support
105
-
106
- Zynor fully supports CommonJS environments for maximum compatibility:
91
+ CommonJS is also supported:
107
92
 
108
93
  ```javascript
109
- // CommonJS usage
110
- const { resolve4, Zynor } = require('zynor');
111
-
112
- const addresses = await resolve4('example.com');
94
+ const { resolve4, Zynor } = require("zynor");
113
95
  ```
114
96
 
115
- ## 🌐 DNS Providers
116
-
117
- Zynor integrates with multiple DNS providers to ensure maximum reliability, performance, and flexibility. Each provider offers unique advantages and can be configured independently with custom settings for concurrency, timeouts, and retry behavior. The library automatically selects the best available provider or allows manual provider specification for specific use cases.
118
-
119
- ### Native Provider
120
-
121
- The native provider leverages Node.js's built-in DNS resolution capabilities, providing seamless integration with system DNS settings and local network configurations.
122
-
123
- - **Endpoint**: Node.js built-in `dns/promises` module
124
- - **Features**: Supports all DNS methods including `lookup()`
125
- - **Use Case**: Local/internal DNS resolution, system DNS settings
126
- - **Advantages**: No external dependencies, respects system DNS configuration
127
- - **Best For**: Internal networks, development environments, system-integrated applications
128
-
129
- ### Google DoH (DNS-over-HTTPS)
130
-
131
- Google's public DNS service provides enterprise-grade DNS resolution with global infrastructure and comprehensive DNSSEC validation.
97
+ ---
132
98
 
133
- - **Endpoint**: `https://dns.google/resolve`
134
- - **Features**: DNSSEC validation, high reliability, global anycast network
135
- - **Use Case**: Public DNS resolution with Google's infrastructure
136
- - **Advantages**: Global CDN, excellent uptime, DNSSEC support, comprehensive logging
137
- - **Best For**: Production applications, global services, DNSSEC-required environments
99
+ ## DNS Resolution
138
100
 
139
- ### Cloudflare DoH (DNS-over-HTTPS)
101
+ ### Standalone Functions
140
102
 
141
- Cloudflare's privacy-focused DNS service emphasizes user privacy with minimal logging and fast global resolution.
103
+ You don't need to create an instance or configure anything to start resolving DNS records. Every DNS method is exported as a standalone function you can import and call directly. Each function handles provider selection, queuing, caching, and error translation behind the scenes — just pass a hostname and get back structured results:
142
104
 
143
- - **Endpoint**: `https://cloudflare-dns.com/dns-query`
144
- - **Features**: Privacy-focused, minimal logging, malware protection
145
- - **Use Case**: Privacy-conscious applications, consumer-facing services
146
- - **Advantages**: Fast global network, strong privacy policy, built-in security features
147
- - **Best For**: Privacy-sensitive applications, consumer products, GDPR-compliant services
105
+ ```typescript
106
+ import {
107
+ resolve4, // A records (IPv4)
108
+ resolve6, // AAAA records (IPv6)
109
+ resolveMx, // MX records (mail servers)
110
+ resolveTxt, // TXT records (SPF, DKIM, verification)
111
+ resolveCname, // CNAME records (aliases)
112
+ resolveNs, // NS records (name servers)
113
+ resolveSoa, // SOA records (zone authority)
114
+ resolveSrv, // SRV records (service discovery)
115
+ resolvePtr, // PTR records (reverse DNS)
116
+ resolveCaa, // CAA records (certificate authority)
117
+ resolveNaptr, // NAPTR records
118
+ resolveTlsa, // TLSA records (DANE)
119
+ resolveAny, // ALL available records
120
+ reverse, // Reverse DNS lookup
121
+ resolve, // Generic resolve by record type
122
+ } from "zynor";
123
+ ```
148
124
 
149
- ### Quad9 DoH (DNS-over-HTTPS)
125
+ Each function accepts an optional provider name as the last argument:
150
126
 
151
- Quad9's security-focused DNS service provides threat intelligence and malware blocking while maintaining user privacy.
127
+ ```typescript
128
+ const ips = await resolve4("example.com", "google");
129
+ const mx = await resolveMx("example.com", "cloudflare");
130
+ const ns = await resolve("example.com", "NS");
131
+ const nsViaGoogle = await resolve("example.com", "NS", "google");
132
+ ```
152
133
 
153
- - **Endpoint**: `https://dns.quad9.net/dns-query`
154
- - **Features**: Security-focused, threat blocking, privacy protection
155
- - **Use Case**: Security-sensitive applications, enterprise environments
156
- - **Advantages**: Malware blocking, threat intelligence, non-profit organization, no user tracking
157
- - **Best For**: Security-critical applications, enterprise networks, threat-aware environments
134
+ Request TTL information for A and AAAA records:
158
135
 
159
- ## ⚙️ Configuration
136
+ ```typescript
137
+ const withTtl = await resolve4("example.com", { ttl: true });
138
+ // => [{ address: '93.184.216.34', ttl: 300 }]
139
+ ```
160
140
 
161
- Zynor provides extensive configuration options to fine-tune DNS resolution behavior according to your application's specific requirements. Each DNS provider can be configured independently with custom concurrency limits, rate limiting, timeouts, and retry policies. The configuration system supports both static initialization and dynamic runtime updates.
141
+ ### Zynor Class
162
142
 
163
- ### Basic Configuration Example
143
+ The `Zynor` class gives full control over providers, concurrency, and caching:
164
144
 
165
145
  ```typescript
146
+ import { Zynor } from "zynor";
147
+
166
148
  const dns = new Zynor({
167
149
  google: {
168
150
  enabled: true,
169
- limit: { concurrency: 10, rps: 100 },
170
- timeout: 5000,
171
- retries: 3
151
+ limit: { concurrency: 10, interval: 1000, intervalCap: 500 },
172
152
  },
173
153
  cloudflare: {
174
154
  enabled: true,
175
- limit: { concurrency: 5, rps: 50 }
155
+ limit: { concurrency: 10 },
176
156
  },
177
157
  quad9: { enabled: false },
178
- native: { enabled: true }
158
+ native: { enabled: true },
159
+ cache: {
160
+ enabled: true,
161
+ maxSize: 100_000,
162
+ dnsTtl: 1_440_000,
163
+ },
179
164
  });
165
+
166
+ const ips = await dns.resolve4("example.com");
167
+ const mx = await dns.resolveMx("example.com", "google");
168
+ const txt = await dns.resolveTxt("example.com", { timeout: 5000 });
180
169
  ```
181
170
 
182
- ### Configuration Options
171
+ ### Supported Record Types
172
+
173
+ | Record Type | Method | Returns | Description |
174
+ | ----------- | ---------------- | --------------- | ------------------------------------------------------------------ |
175
+ | **A** | `resolve4()` | `string[]` | IPv4 addresses for a domain |
176
+ | **AAAA** | `resolve6()` | `string[]` | IPv6 addresses for a domain |
177
+ | **MX** | `resolveMx()` | `MxRecord[]` | Mail servers with priority, used to find where email is handled |
178
+ | **TXT** | `resolveTxt()` | `string[][]` | Text records holding SPF rules, DKIM keys, and verification tokens |
179
+ | **CNAME** | `resolveCname()` | `string[]` | Canonical name aliases showing what a hostname points to |
180
+ | **NS** | `resolveNs()` | `string[]` | Authoritative name servers for a domain |
181
+ | **SOA** | `resolveSoa()` | `SoaRecord` | Zone serial number, refresh intervals, and admin contact |
182
+ | **SRV** | `resolveSrv()` | `SrvRecord[]` | Service discovery records with priority, weight, and port |
183
+ | **PTR** | `resolvePtr()` | `string[]` | Maps an IP address back to a hostname |
184
+ | **CAA** | `resolveCaa()` | `CaaRecord[]` | Which certificate authorities can issue certificates for a domain |
185
+ | **NAPTR** | `resolveNaptr()` | `NaptrRecord[]` | Complex service resolution for ENUM and SIP routing |
186
+ | **TLSA** | `resolveTlsa()` | `TlsaRecord[]` | DANE TLS certificate pinning |
187
+ | **ANY** | `resolveAny()` | `AnyRecord[]` | All available record types in a single query |
183
188
 
184
- - **enabled**: Enable or disable the provider (boolean)
185
- - **limit.concurrency**: Maximum concurrent requests per provider (number)
186
- - **limit.rps**: Requests per second rate limit (number)
187
- - **timeout**: Request timeout in milliseconds (number)
188
- - **retries**: Number of retry attempts on failure (number)
189
- - **priority**: Provider selection priority (number, higher = preferred)
189
+ ```typescript
190
+ const mx = await resolveMx("gmail.com");
191
+ // => [
192
+ // { priority: 5, exchange: 'gmail-smtp-in.l.google.com' },
193
+ // { priority: 10, exchange: 'alt1.gmail-smtp-in.l.google.com' },
194
+ // ]
195
+
196
+ const soa = await resolveSoa("example.com");
197
+ // => {
198
+ // nsname: 'ns1.example.com',
199
+ // hostmaster: 'admin.example.com',
200
+ // serial: 2024010101,
201
+ // refresh: 3600,
202
+ // retry: 900,
203
+ // expire: 604800,
204
+ // minttl: 86400
205
+ // }
206
+
207
+ const srv = await resolveSrv("_sip._tcp.example.com");
208
+ // => [{ priority: 10, weight: 5, port: 5060, name: 'sip.example.com' }]
209
+
210
+ const hosts = await reverse("8.8.8.8");
211
+ // => ['dns.google']
212
+ ```
190
213
 
191
- ### Dynamic Configuration Updates
214
+ ### Provider Selection
215
+
216
+ When you don't specify which provider to use, zynor picks the best one for you automatically. It looks at how busy each provider's queue is and routes your request to the one with the most available capacity. This means that under heavy load, requests naturally spread across all your enabled providers rather than piling up on a single one — giving you faster response times and better reliability without any manual balancing on your part.
217
+
218
+ If you need a specific provider for a particular query (for example, Quad9 for its built-in malware filtering, or native for internal DNS resolution), you can always override the automatic selection:
192
219
 
193
220
  ```typescript
194
- // Update configuration at runtime
195
- dns.setConfig('google', { enabled: false });
196
- dns.setConfigs({ cloudflare: { limit: { concurrency: 15 } } });
221
+ const ips = await resolve4("example.com", "google");
222
+ const mx = await dns.resolveMx("example.com", "cloudflare");
197
223
  ```
198
224
 
199
- ## 📚 API Reference
225
+ Four providers are included:
200
226
 
201
- The Zynor API is designed for simplicity and flexibility, offering both class-based and functional approaches to DNS resolution. All methods return strongly-typed promises and support optional provider selection, custom timeouts, and advanced configuration options.
227
+ | Provider | Protocol | Best For |
228
+ | -------------- | ---------------------------- | ---------------------------------------------------- |
229
+ | **native** | Node.js `dns/promises` | Local/internal DNS, system DNS settings, development |
230
+ | **google** | DNS-over-HTTPS | Production, global services, DNSSEC validation |
231
+ | **cloudflare** | DNS-over-HTTPS | Privacy-sensitive apps, fast global resolution |
232
+ | **quad9** | DNS-over-HTTPS (wire format) | Security-focused apps, built-in malware blocking |
202
233
 
203
- ### Zynor Class
234
+ ### AbortSignal and Timeout
204
235
 
205
- The Zynor class provides a comprehensive DNS resolution interface with full configuration control and advanced features like provider management, concurrency control, and runtime configuration updates.
236
+ Every DNS method in zynor can be cancelled mid-flight or given a time limit. This is essential for production applications where you can't afford to wait forever on a DNS query that might be hanging due to network issues. The default timeout is 30 seconds, but you can set your own per-request timeout, pass in an `AbortSignal` for manual cancellation, or combine both — whichever fires first will cancel the operation and free up resources immediately.
206
237
 
207
238
  ```typescript
208
- const dns = new Zynor(config?: ZynorConfig);
239
+ // Timeout after 5 seconds
240
+ const ips = await resolve4("example.com", { timeout: 5000 });
241
+
242
+ // Manual cancellation
243
+ const controller = new AbortController();
244
+ setTimeout(() => controller.abort(), 3000);
245
+ const mx = await resolveMx("example.com", { signal: controller.signal });
246
+
247
+ // Both together -- whichever fires first cancels the operation
248
+ const txt = await resolveTxt("example.com", {
249
+ signal: controller.signal,
250
+ timeout: 10000,
251
+ });
252
+ ```
253
+
254
+ Cancellation works across the entire operation: queue wait, network request, and response parsing.
255
+
256
+ ---
257
+
258
+ ## DNS Caching
209
259
 
210
- // Basic DNS resolution methods
211
- dns.resolve4(hostname: string): Promise<string[]> // IPv4 addresses
212
- dns.resolve6(hostname: string): Promise<string[]> // IPv6 addresses
213
- dns.resolveMx(hostname: string): Promise<MxRecord[]> // Mail exchange records
214
- dns.resolveTxt(hostname: string): Promise<string[][]> // Text records
215
- dns.resolveCname(hostname: string): Promise<string[]> // Canonical name records
216
- dns.resolveNs(hostname: string): Promise<string[]> // Name server records
217
- dns.resolveSoa(hostname: string): Promise<SoaRecord> // Start of Authority
218
- dns.resolvePtr(ip: string): Promise<string[]> // Reverse DNS lookup
219
- dns.resolveSrv(hostname: string): Promise<SrvRecord[]> // Service records
220
- dns.resolveAny(hostname: string): Promise<AnyRecord[]> // All available records
260
+ ### Request Deduplication
221
261
 
222
- // Configuration methods
223
- dns.setConfig(provider: string, config: ProviderConfig): void
224
- dns.setConfigs(configs: Partial<ZynorConfig>): void
262
+ If your application fires off the same DNS query from multiple places at the same time — say, ten different parts of your code all resolve `example.com` within the same moment — zynor recognizes that these are duplicate requests and only sends a single query to the DNS provider. Every caller that asked for the same record receives the same result as soon as it comes back. This eliminates redundant network calls, reduces your DNS provider usage, and speeds up your application when multiple components depend on the same domain.
225
263
 
226
- // Email validation
227
- dns.emailValidator: EmailValidator
264
+ ```typescript
265
+ // Only ONE DNS query is made, all three get the same result
266
+ const [a, b, c] = await Promise.all([
267
+ resolve4("example.com"),
268
+ resolve4("example.com"),
269
+ resolve4("example.com"),
270
+ ]);
228
271
  ```
229
272
 
230
- ### Standalone Functions
273
+ Results are then stored in an LRU cache so subsequent requests are served instantly without any network call.
231
274
 
232
- Standalone functions provide a lightweight alternative for simple DNS queries without the need for class instantiation. These functions use sensible defaults and automatic provider selection.
275
+ ### LruCache
276
+
277
+ Zynor includes a general-purpose Least Recently Used (LRU) cache that you can use in your own application code — it's the same cache that powers zynor's internal DNS caching. An LRU cache automatically evicts the oldest unused entries when it reaches its maximum size, and each entry can have a time-to-live (TTL) so stale data expires on its own. This is useful for caching API responses, database queries, computed results, or anything else you want to keep in memory temporarily without worrying about unbounded growth:
233
278
 
234
279
  ```typescript
235
- import { resolve4, resolveMx, resolveAny } from 'zynor';
280
+ import { LruCache } from "zynor";
281
+
282
+ const cache = new LruCache<string>(500); // max 500 entries
283
+
284
+ cache.set("key", "value", 60_000); // expires in 60 seconds
285
+ cache.get("key"); // => "value"
286
+ cache.peek("key"); // => "value" (without affecting eviction order)
287
+ cache.has("key"); // => true
288
+ cache.ttl("key"); // => remaining ms until expiry
289
+ cache.delete("key"); // => true
290
+ cache.size; // => 0
291
+ cache.prune(); // remove all expired entries, returns count
292
+ cache.clear(); // remove everything
293
+
294
+ // Iterate non-expired entries
295
+ for (const key of cache.keys()) {
296
+ /* ... */
297
+ }
298
+ for (const value of cache.values()) {
299
+ /* ... */
300
+ }
301
+ for (const [key, value] of cache.entries()) {
302
+ /* ... */
303
+ }
304
+ ```
305
+
306
+ ---
236
307
 
237
- // Use directly without creating a class instance
238
- const addresses = await resolve4('example.com'); // Quick IPv4 resolution
239
- const mxRecords = await resolveMx('example.com'); // Mail server lookup
240
- const anyRecords = await resolveAny('example.com'); // Comprehensive DNS query
308
+ ## Provider Configuration
241
309
 
242
- // With optional provider specification
243
- const googleResult = await resolve4('example.com', undefined, 'google');
244
- const cloudflareResult = await resolveMx('example.com', undefined, 'cloudflare');
310
+ ### Concurrency and Rate Limiting
311
+
312
+ Each DNS provider runs its own independent request queue, which means you have fine-grained control over how aggressively your application talks to each provider. You can set how many requests are allowed to be in flight at the same time (`concurrency`), define a rate-limit window (`interval` in milliseconds), and cap how many requests can be sent within that window (`intervalCap`). This prevents you from being throttled or banned by DNS providers and lets you tune performance based on your use case — high throughput for batch processing, or conservative limits for shared environments:
313
+
314
+ ```typescript
315
+ const dns = new Zynor({
316
+ google: {
317
+ enabled: true,
318
+ limit: {
319
+ concurrency: 10, // max 10 requests in flight at once
320
+ interval: 1000, // rate limit window in ms
321
+ intervalCap: 500, // max requests per window
322
+ carryoverConcurrencyCount: true,
323
+ },
324
+ },
325
+ cloudflare: {
326
+ enabled: true,
327
+ limit: { concurrency: 5 },
328
+ },
329
+ quad9: { enabled: false },
330
+ native: {
331
+ enabled: true,
332
+ limit: { concurrency: 10, interval: 1000, intervalCap: 750 },
333
+ },
334
+ });
245
335
  ```
246
336
 
247
- ### Method Parameters
337
+ | Option | Type | Description |
338
+ | --------------------------------- | --------- | ----------------------------------------------- |
339
+ | `enabled` | `boolean` | Turn the provider on or off. Default: `true`. |
340
+ | `limit.concurrency` | `number` | Maximum requests running simultaneously. |
341
+ | `limit.interval` | `number` | Time window in ms for rate limiting. |
342
+ | `limit.intervalCap` | `number` | Maximum requests allowed per interval window. |
343
+ | `limit.carryoverConcurrencyCount` | `boolean` | Carry over concurrency count between intervals. |
248
344
 
249
- Most DNS resolution methods accept the following parameters:
345
+ ### Runtime Configuration Updates
250
346
 
251
- - **hostname/ip**: The domain name or IP address to resolve (string)
252
- - **options**: Optional configuration object (varies by method)
253
- - **provider**: Optional provider name for specific provider usage (string)
347
+ You can reconfigure providers on the fly without having to tear down and recreate your `Zynor` instance. This is useful when you need to react to changing conditions — for example, disabling a provider that's returning errors, increasing concurrency during off-peak hours, or enabling a provider that was previously turned off. All in-flight requests continue with their original settings; only new requests pick up the changes:
254
348
 
255
- ### Return Types
349
+ ```typescript
350
+ dns.setConfig("google", { enabled: false });
351
+ dns.setConfig("cloudflare", { limit: { concurrency: 20 } });
256
352
 
257
- All methods return strongly-typed promises with comprehensive type definitions for maximum TypeScript compatibility and IntelliSense support.
353
+ dns.setConfigs({
354
+ google: { enabled: true, limit: { concurrency: 15 } },
355
+ cloudflare: { enabled: false },
356
+ });
357
+ ```
258
358
 
359
+ ---
259
360
 
361
+ ## Email Validation
260
362
 
261
- ### Email Validation
363
+ A full email intelligence engine that validates addresses, identifies the hosting provider, detects disposable and role-based emails, and resolves webmail URLs.
262
364
 
263
- The Email Validation system provides comprehensive email address validation, domain analysis, and provider detection. It combines syntax validation, DNS lookups, and an extensive database of email providers to deliver accurate validation results with detailed metadata about the email address and its hosting provider.
365
+ ### Basic Validation
264
366
 
265
- #### `EmailValidator` Class
367
+ Validates an email address in a single call — checking syntax, screening for disposable domains, detecting role-based prefixes like `admin@` or `support@`, and identifying the email provider by domain or MX record lookup. Returns the provider name, free/paid status, role flag, and webmail URL when available.
266
368
 
267
- The EmailValidator class is the core component for email validation operations. It provides intelligent email analysis by checking syntax, validating domains through DNS resolution, detecting email providers, and identifying role-based addresses. The validator supports both basic and deep validation modes to accommodate different use cases and performance requirements.
369
+ ```typescript
370
+ import { Zynor } from "zynor";
268
371
 
269
- ##### `validate(email: string, deep?: boolean): Promise<EmailResponse>`
372
+ const validator = Zynor.emailValidator;
270
373
 
271
- Performs comprehensive email validation and analysis, returning detailed information about the email address including provider detection, webmail availability, and role-based email identification.
374
+ const result = await validator.validate("user@gmail.com");
375
+
376
+ if (result.success) {
377
+ console.log(result.data.provider); // "Gmail"
378
+ console.log(result.data.email); // "user@gmail.com"
379
+ console.log(result.data.isFree); // true
380
+ console.log(result.data.role); // false
381
+ console.log(result.data.webmail); // "https://mail.google.com"
382
+ } else {
383
+ console.log(result.type); // "Syntax" | "Invalid" | "Rejected" | "Disposable" | "Error"
384
+ console.log(result.email); // the email that failed
385
+ }
386
+ ```
272
387
 
273
- **Parameters:**
274
- - `email`: Email address to validate (string)
275
- - `deep` (optional): Enable deep validation with additional DNS lookups and extended checks (default: false)
388
+ Validation checks syntax, inappropriate terms, rejected patterns (noreply, marketing senders, platform notifications), disposable domains, and then identifies the email provider through domain matching and MX record analysis.
276
389
 
277
- **Returns:** EmailResponse object with one of the following structures:
390
+ **Success response:**
278
391
 
279
- **Success Response Structure:**
280
392
  ```typescript
281
393
  {
282
394
  success: true,
283
395
  data: {
284
- provider: string, // Email provider name (e.g., "Gmail", "Outlook")
285
- email: string, // Normalized email address
286
- isFree: boolean, // Whether it's a free email provider domain
287
- role: boolean, // Whether it's a role-based email (admin, support, etc.)
288
- webmail?: string // Webmail URL if available
396
+ provider: string, // "Gmail", "Office 365", "Zoho", etc.
397
+ email: string, // normalized (lowercased) email
398
+ isFree: boolean, // true for free providers (Gmail, Yahoo, etc.)
399
+ role: boolean, // true for admin@, support@, info@, etc.
400
+ webmail?: string, // webmail URL if known
289
401
  }
290
402
  }
291
403
  ```
292
404
 
293
- **Error Response Structure:**
405
+ **Error response:**
406
+
294
407
  ```typescript
295
408
  {
296
409
  success: false,
297
- type: 'Syntax' | 'Rejected' | 'Invalid' | 'Disposable' | 'Error',
410
+ type: "Syntax" | "Rejected" | "Invalid" | "Disposable" | "Error",
298
411
  email: string,
299
- role: boolean, // Whether it's a role-based email
300
- message?: string // Detailed error message (only present for 'Error' type)
412
+ role: boolean,
413
+ message?: string, // only for "Error" type
301
414
  }
302
415
  ```
303
416
 
304
- #### Basic Email Validation Examples
417
+ ### Deep Validation
305
418
 
306
- **Simple Validation:**
307
- ```typescript
308
- import { Zynor } from 'zynor';
419
+ When basic validation can't identify the provider, deep validation goes further — probing the domain's web presence and querying IP intelligence services to classify the hosting provider. The deep phase is time-capped (default 3 seconds) and results are cached, so repeated lookups are instant.
309
420
 
310
- const validator = Zynor.emailValidator;
421
+ ```typescript
422
+ const validator = Zynor.createEmailValidator({
423
+ options: {
424
+ enableDeepValidation: true,
425
+ deepValidationOptions: {
426
+ maxTimeout: 3000, // max 3 seconds for the deep validation phase
427
+ http: { timeout: 2500, maxRetry: 0 },
428
+ },
429
+ ipResolver: {
430
+ ipApi: true,
431
+ findip: { enabled: true, apiKey: ["your-api-key"] },
432
+ },
433
+ },
434
+ });
311
435
 
312
- // Basic email validation
313
- const result = await validator.validate('user@gmail.com');
314
- if (result.success) {
315
- console.log('✅ Valid email');
316
- console.log('Provider:', result.data.provider); // "Gmail"
317
- console.log('Webmail:', result.data.webmail); // "https://mail.google.com"
318
- console.log('Role email:', result.data.role); // false
319
- } else {
320
- console.log('❌ Invalid email:', result.type);
321
- }
436
+ const result = await validator.validate("employee@obscure-company.com", true);
322
437
  ```
323
438
 
324
- **Deep Validation Mode:**
439
+ Deep validation with abort support:
440
+
325
441
  ```typescript
326
- // Enable deep validation for thorough analysis
327
- const deepResult = await validator.validate('admin@company.com', true);
328
- if (deepResult.success) {
329
- console.log('Provider:', deepResult.data.provider);
330
- console.log('Is role-based:', deepResult.data.role); // likely true for "admin"
331
- }
442
+ const result = await validator.validate("user@company.com", {
443
+ deep: true,
444
+ timeout: 5000,
445
+ signal: controller.signal,
446
+ });
332
447
  ```
333
448
 
334
- #### Provider Detection Examples
449
+ The deep phase is always capped by `maxTimeout` (default 3s) so it never blocks indefinitely.
335
450
 
336
- **Major Email Providers:**
337
- ```typescript
338
- // Gmail detection
339
- const gmailResult = await validator.validate('john.doe@gmail.com');
340
- console.log(gmailResult.data?.provider); // "Gmail"
451
+ ### Bulk Validation
341
452
 
342
- // Outlook detection
343
- const outlookResult = await validator.validate('jane@outlook.com');
344
- console.log(outlookResult.data?.provider); // "Outlook"
453
+ Validate hundreds or thousands of email addresses concurrently with configurable parallelism. Results come back in the same order as the input array, making it easy to map results back to your original data:
345
454
 
346
- // Yahoo detection
347
- const yahooResult = await validator.validate('user@yahoo.com');
348
- console.log(yahooResult.data?.provider); // "Yahoo"
455
+ ```typescript
456
+ const results = await Zynor.validateBulk(
457
+ ["user@gmail.com", "admin@company.com", "test@mailinator.com"],
458
+ {
459
+ concurrency: 10,
460
+ deep: false,
461
+ timeout: 30000,
462
+ },
463
+ );
349
464
 
350
- // Corporate email detection
351
- const corpResult = await validator.validate('employee@microsoft.com');
352
- console.log(corpResult.data?.provider); // "Microsoft"
465
+ // results[0] => { success: true, data: { provider: "Gmail", ... } }
466
+ // results[2] => { success: false, type: "Disposable", ... }
353
467
  ```
354
468
 
355
- #### Role-Based Email Detection
469
+ Results are returned in the same order as the input array. Concurrency defaults to the sum of all enabled provider concurrency limits.
356
470
 
357
- **Identifying Role-Based Addresses:**
358
- ```typescript
359
- // Common role-based emails
360
- const roleEmails = [
361
- 'admin@company.com',
362
- 'support@service.com',
363
- 'info@business.org',
364
- 'sales@enterprise.net',
365
- 'noreply@platform.io'
366
- ];
367
-
368
- for (const email of roleEmails) {
369
- const result = await validator.validate(email);
370
- if (result.success && result.data.role) {
371
- console.log(`${email} is a role-based email`);
372
- }
373
- }
374
- ```
471
+ ### Provider Detection
375
472
 
376
- #### Webmail Detection and Access
473
+ Zynor identifies 60+ email providers by direct domain matching and 100+ by analyzing MX record patterns. Known domains like `gmail.com` or `outlook.com` are detected instantly without any DNS query. For custom domains (like `user@company.com`), zynor looks up the domain's MX records to figure out which provider handles their email:
377
474
 
378
- **Webmail URL Extraction:**
379
475
  ```typescript
380
- // Get webmail URLs for popular providers
381
- const webmailEmails = [
382
- 'user@gmail.com', // https://mail.google.com
383
- 'user@outlook.com', // https://outlook.live.com
384
- 'user@yahoo.com', // https://mail.yahoo.com
385
- 'user@icloud.com' // https://www.icloud.com/mail
386
- ];
387
-
388
- for (const email of webmailEmails) {
389
- const result = await validator.validate(email);
390
- if (result.success && result.data.webmail) {
391
- console.log(`${email} -> ${result.data.webmail}`);
392
- }
393
- }
476
+ const validator = Zynor.emailValidator;
477
+
478
+ // Instant detection by domain (no DNS needed)
479
+ await validator.validate("user@gmail.com"); // provider: "Gmail"
480
+ await validator.validate("user@outlook.com"); // provider: "Outlook"
481
+ await validator.validate("user@protonmail.com"); // provider: "ProtonMail"
482
+ await validator.validate("user@qq.com"); // provider: "QQ"
483
+ await validator.validate("user@mail.ru"); // provider: "Mail.ru"
484
+ await validator.validate("user@icloud.com"); // provider: "iCloud"
485
+ await validator.validate("user@zoho.com"); // provider: "Zoho"
486
+ await validator.validate("user@fastmail.com"); // provider: "Fastmail"
487
+
488
+ // Detection by MX record (requires one DNS lookup)
489
+ await validator.validate("user@company.com");
490
+ // MX points to Google => provider: "Gmail"
491
+
492
+ await validator.validate("user@enterprise.org");
493
+ // MX points to Outlook => provider: "Office 365"
494
+
495
+ await validator.validate("user@startup.io");
496
+ // MX points to Amazon SES => provider: "Amazon"
394
497
  ```
395
498
 
396
- #### Batch Email Validation
499
+ Detected providers include Gmail, Outlook, Office 365, Yahoo, Turbify, AOL, iCloud, ProtonMail, Zoho, Mail.ru, Yandex, GMX, Web.de, Mail.com, Fastmail, AT&T, Comcast, QQ, 163, Naver, Daum, Rackspace, Mimecast, Godaddy, Namecheap, SendGrid, Mailgun, Postmark, Amazon, Elastic Email, Zendesk, Intermedia, Mailjet, Front, and many more.
500
+
501
+ ### Disposable Email Detection
502
+
503
+ Detects disposable (temporary) email domains and automated/marketing sender patterns:
397
504
 
398
- **Validating Multiple Emails:**
399
505
  ```typescript
400
- async function validateEmailBatch(emails: string[]) {
401
- const results = await Promise.allSettled(
402
- emails.map(email => validator.validate(email))
403
- );
404
-
405
- return emails.map((email, index) => {
406
- const result = results[index];
407
- if (result.status === 'fulfilled' && result.value.success) {
408
- return {
409
- email,
410
- valid: true,
411
- provider: result.value.data.provider,
412
- role: result.value.data.role,
413
- webmail: result.value.data.webmail
414
- };
415
- } else {
416
- return {
417
- email,
418
- valid: false,
419
- error: result.status === 'fulfilled' ? result.value.type : 'validation_failed'
420
- };
421
- }
422
- });
423
- }
506
+ const validator = Zynor.emailValidator;
424
507
 
425
- // Usage example
426
- const emailList = [
427
- 'valid@gmail.com',
428
- 'invalid.email',
429
- 'admin@company.com',
430
- 'user@nonexistent-domain.xyz'
431
- ];
508
+ validator.isDisposable("test@mailinator.com"); // true
509
+ validator.isDisposable("user@guerrillamail.com"); // true
510
+ validator.isDisposable("user@gmail.com"); // false
432
511
 
433
- const batchResults = await validateEmailBatch(emailList);
434
- console.log('Batch validation results:', batchResults);
512
+ // Also caught during validation
513
+ const result = await validator.validate("test@tempmail.com");
514
+ // => { success: false, type: "Disposable", ... }
435
515
  ```
436
516
 
437
- #### Error Handling and Response Types
517
+ Additionally catches automated senders (noreply@, notifications@), marketing platforms (@mailchimp.com, @sendgrid.net, @hubspot.com), and platform notifications (GitHub, Amazon, Facebook, LinkedIn).
438
518
 
439
- **Comprehensive Error Handling:**
440
- ```typescript
441
- async function handleEmailValidation(email: string) {
442
- try {
443
- const result = await validator.validate(email);
444
-
445
- if (result.success) {
446
- return {
447
- status: 'valid',
448
- data: result.data
449
- };
450
- } else {
451
- // Handle different error types
452
- switch (result.type) {
453
- case 'Syntax':
454
- return { status: 'syntax_error', message: 'Invalid email format' };
455
- case 'Invalid':
456
- return { status: 'invalid_domain', message: 'Domain does not exist' };
457
- case 'Rejected':
458
- return { status: 'rejected', message: 'Email rejected by provider' };
459
- case 'Disposable':
460
- return { status: 'disposable', message: 'Disposable email address' };
461
- case 'Error':
462
- return { status: 'validation_error', message: result.message };
463
- default:
464
- return { status: 'unknown_error', message: 'Validation failed' };
465
- }
466
- }
467
- } catch (error) {
468
- return {
469
- status: 'exception',
470
- message: error instanceof Error ? error.message : 'Unexpected error'
471
- };
472
- }
473
- }
474
-
475
- // Usage
476
- const validationResult = await handleEmailValidation('test@example.com');
477
- console.log(validationResult);
478
- ```
519
+ ### Role-Based Email Detection
479
520
 
480
- #### Advanced Use Cases
521
+ Detects 250+ role-based prefixes -- addresses that represent a function rather than a person:
481
522
 
482
- **Email Domain Analysis:**
483
523
  ```typescript
484
- async function analyzeEmailDomain(email: string) {
485
- const result = await validator.validate(email, true); // Deep validation
486
-
487
- if (result.success) {
488
- const domain = email.split('@')[1];
489
- return {
490
- email: result.data.email,
491
- domain,
492
- provider: result.data.provider,
493
- hasWebmail: !!result.data.webmail,
494
- webmailUrl: result.data.webmail,
495
- isRoleBased: result.data.role,
496
- isPersonal: ['Gmail', 'Yahoo', 'Outlook', 'iCloud'].includes(result.data.provider),
497
- isCorporate: !['Gmail', 'Yahoo', 'Outlook', 'iCloud'].includes(result.data.provider)
498
- };
499
- } else {
500
- return {
501
- email,
502
- valid: false,
503
- errorType: result.type,
504
- errorMessage: result.message
505
- };
506
- }
507
- }
524
+ const result = await validator.validate("admin@company.com");
525
+ console.log(result.success && result.data.role); // true
508
526
 
509
- const analysis = await analyzeEmailDomain('ceo@apple.com');
510
- console.log('Email analysis:', analysis);
527
+ const result2 = await validator.validate("john.doe@company.com");
528
+ console.log(result2.success && result2.data.role); // false
511
529
  ```
512
530
 
513
- #### Additional EmailValidator Methods
531
+ Recognized prefixes include `admin`, `support`, `info`, `sales`, `billing`, `help`, `contact`, `hr`, `legal`, `marketing`, `security`, `postmaster`, `webmaster`, `noreply`, `abuse`, `careers`, `ceo`, `press`, `media`, `feedback`, `office`, `accounting`, `engineering`, `operations`, and many more.
514
532
 
515
- The EmailValidator class provides several utility methods for email validation and manipulation:
533
+ ### Free Domain Detection
516
534
 
517
- ##### `isEmail(email: string): boolean`
535
+ Check whether an email or domain belongs to a free email provider:
518
536
 
519
- Performs advanced email format validation with structural constraints.
520
-
521
- **Validation Rules:**
522
- - Maximum 35 characters for the local part
523
- - Maximum 3 hyphens in the local part
524
- - Maximum 3 dots in the local part
525
- - Maximum 3 dots in the domain part
526
- - Maximum 2 hyphens in the domain part
527
- - Maximum 55 total characters in the email address
528
- - Local part must be at least 2 characters
529
- - Domain part must be at least 5 characters
530
-
531
- **Example:**
532
537
  ```typescript
533
- const validator = EmailValidator.create();
538
+ validator.isFreeDomain("user@gmail.com"); // true
539
+ validator.isFreeDomain("yahoo.com"); // true
540
+ validator.isFreeDomain("user@company.com"); // false
534
541
 
535
- validator.isEmail("john.doe@example.com"); // true
536
- validator.isEmail("x@y.com"); // false (domain too short)
537
- validator.isEmail("toolong@d.c"); // false
542
+ // Also in validation results
543
+ const result = await validator.validate("user@gmail.com");
544
+ console.log(result.success && result.data.isFree); // true
538
545
  ```
539
546
 
540
- ##### `isFreeDomain(email_or_domain: string): boolean`
547
+ ### Webmail URL Lookup
541
548
 
542
- Checks if an email address or domain belongs to a free email provider (Gmail, Yahoo, Outlook, etc.).
549
+ Resolve webmail login URLs for 500+ domains including regional variants:
543
550
 
544
- **Example:**
545
551
  ```typescript
546
- validator.isFreeDomain('person@yahoo.com'); // true
547
- validator.isFreeDomain('gmail.com'); // true
548
- validator.isFreeDomain('user@company.org'); // false
549
- ```
552
+ const validator = Zynor.emailValidator;
550
553
 
551
- ##### `isDisposable(email: string): boolean`
554
+ validator.getProviderWebmailUrl("Gmail");
555
+ // => "https://mail.google.com"
552
556
 
553
- Checks if an email address is from a known disposable/temporary email provider.
557
+ validator.getProviderWebmailUrl("outlook.com");
558
+ // => "https://outlook.live.com/mail/"
554
559
 
555
- **Example:**
556
- ```typescript
557
- validator.isDisposable('test@mailinator.com'); // true
558
- validator.isDisposable('john.doe@gmail.com'); // false
559
- ```
560
+ validator.getProviderWebmailUrl("user@yahoo.fr");
561
+ // => "https://fr.mail.yahoo.com/"
560
562
 
561
- ##### `isJson(input: string): string[] | null`
563
+ validator.getProviderWebmailUrl("Gmail", "google.com");
564
+ // => "https://mail.google.com"
562
565
 
563
- Validates if a string is a JSON array of valid email addresses.
566
+ validator.getProviderWebmailUrl("unknown-provider.com");
567
+ // => null
568
+ ```
564
569
 
565
- **Returns:** Array of valid emails if successful, `null` otherwise.
570
+ Regional examples: `yahoo.fr` resolves to `https://fr.mail.yahoo.com/`, `hotmail.de` to `https://outlook.live.com/mail/`, `gmx.at` to `https://www.gmx.at/mail/`, `att.net` to `https://currently.att.yahoo.com/`.
566
571
 
567
- **Example:**
568
- ```typescript
569
- validator.isJson('["hello@site.com", "test@a.io"]');
570
- // Returns: ["hello@site.com", "test@a.io"]
572
+ Also included in validation results:
571
573
 
572
- validator.isJson('["foo", 1, null]'); // Returns: null
573
- validator.isJson('not json'); // Returns: null
574
+ ```typescript
575
+ const result = await validator.validate("user@gmail.com");
576
+ console.log(result.success && result.data.webmail);
577
+ // => "https://mail.google.com"
574
578
  ```
575
579
 
576
- ##### `extractEmails(input: string[]): string[]`
580
+ ### Email Extraction
577
581
 
578
- Extracts valid email addresses from various input formats including:
579
- - Plain email addresses
580
- - Comma-separated values
581
- - URL-encoded strings (automatically decoded)
582
- - JSON arrays
582
+ Extract valid emails from mixed input formats:
583
583
 
584
- **Example:**
585
584
  ```typescript
586
- // Single email
585
+ const validator = Zynor.emailValidator;
586
+
587
+ // Plain emails
587
588
  validator.extractEmails(["user@example.com"]);
588
- // Returns: ["user@example.com"]
589
+ // => ["user@example.com"]
589
590
 
590
- // Comma-separated emails
591
- validator.extractEmails(["user1@example.com,user2@example.com"]);
592
- // Returns: ["user1@example.com", "user2@example.com"]
591
+ // Comma-separated
592
+ validator.extractEmails(["a@test.com,b@test.com"]);
593
+ // => ["a@test.com", "b@test.com"]
593
594
 
594
595
  // URL-encoded
595
- validator.extractEmails(["user%40example.com,test%40domain.com"]);
596
- // Returns: ["user@example.com", "test@domain.com"]
596
+ validator.extractEmails(["user%40example.com"]);
597
+ // => ["user@example.com"]
597
598
 
598
- // JSON array
599
- validator.extractEmails(['["email1@test.com", "email2@test.com"]']);
600
- // Returns: ["email1@test.com", "email2@test.com"]
599
+ // JSON arrays
600
+ validator.extractEmails(['["a@test.com", "b@test.com"]']);
601
+ // => ["a@test.com", "b@test.com"]
601
602
 
602
603
  // Mixed formats
603
604
  validator.extractEmails([
604
- "user@example.com",
605
- "test@domain.com,admin@site.com",
606
- '["json@email.com"]'
605
+ "one@test.com",
606
+ "two@test.com,three@test.com",
607
+ '["four@test.com"]',
607
608
  ]);
608
- // Returns: ["user@example.com", "test@domain.com", "admin@site.com", "json@email.com"]
609
+ // => ["one@test.com", "two@test.com", "three@test.com", "four@test.com"]
609
610
  ```
610
611
 
611
- ##### `getProviderWebmailUrl(provider: ProviderName): string | null`
612
- ##### `getProviderWebmailUrl(provider: ProviderName, domainOrEmail: string): string | null`
613
- ##### `getProviderWebmailUrl(domainOrEmail: string): string | null`
614
-
615
- Retrieves the webmail URL for a given email provider. Supports multiple overloaded signatures for flexibility.
616
-
617
- **Parameters:**
618
- - `provider` - Provider name (e.g., "Gmail", "Outlook") or domain/email
619
- - `domainOrEmail` (optional) - Domain name or full email address
620
-
621
- **Returns:** Webmail URL string if found, `null` otherwise.
612
+ Utility methods:
622
613
 
623
- **Example:**
624
614
  ```typescript
625
- // Using provider name
626
- validator.getProviderWebmailUrl('Gmail');
627
- // Returns: "https://mail.google.com"
615
+ validator.isEmail("john.doe@example.com"); // true
616
+ validator.isEmail("x@y.co"); // false
628
617
 
629
- // Using domain
630
- validator.getProviderWebmailUrl('outlook.com');
631
- // Returns: "https://outlook.live.com"
618
+ validator.isJson('["a@test.com", "b@test.com"]');
619
+ // => ["a@test.com", "b@test.com"]
632
620
 
633
- // Using email address
634
- validator.getProviderWebmailUrl('user@yahoo.com');
635
- // Returns: "https://mail.yahoo.com"
636
-
637
- // Using provider name with domain
638
- validator.getProviderWebmailUrl('Gmail', 'google.com');
639
- // Returns: "https://mail.google.com"
640
-
641
- // Unknown provider
642
- validator.getProviderWebmailUrl('unknown-provider.com');
643
- // Returns: null
621
+ validator.isJson("not json");
622
+ // => null
644
623
  ```
645
624
 
646
- ## 🗂️ DNS Record Types
625
+ ### Persistent Caching
647
626
 
648
- Zynor supports all standard DNS record types with comprehensive parsing and type-safe return values. Each record type is optimized for specific use cases, from basic domain resolution to advanced service discovery and email routing. The library automatically handles record parsing and provides structured data objects for easy consumption.
627
+ Validation results are automatically cached to disk and survive process restarts:
649
628
 
650
- | Record Type | Description | Use Cases | Return Type |
651
- |-------------|-------------|-----------|-------------|
652
- | **A** | IPv4 address records | Web hosting, basic domain resolution | `string[]` |
653
- | **AAAA** | IPv6 address records | Modern networking, dual-stack configurations | `string[]` |
654
- | **MX** | Mail exchange records | Email routing, mail server discovery | `MxRecord[]` |
655
- | **TXT** | Text records | Domain verification, SPF, DKIM, configuration | `string[][]` |
656
- | **CNAME** | Canonical name records | Domain aliases, CDN configuration | `string[]` |
657
- | **NS** | Name server records | DNS delegation, authoritative servers | `string[]` |
658
- | **SOA** | Start of Authority | Zone information, DNS administration | `SoaRecord` |
659
- | **SRV** | Service records | Service discovery, load balancing | `SrvRecord[]` |
660
- | **PTR** | Pointer records (reverse DNS) | IP to domain mapping, security verification | `string[]` |
661
- | **CAA** | Certificate Authority Authorization | SSL certificate validation | `CaaRecord[]` |
662
- | **NAPTR** | Name Authority Pointer | Complex service resolution | `NaptrRecord[]` |
663
- | **TLSA** | Transport Layer Security Authentication | Certificate pinning, security | `TlsaRecord[]` |
664
- | **ANY** | All available records | Comprehensive domain analysis | `AnyRecord[]` |
629
+ - Results are cached at the domain level so different emails at the same domain share one entry.
630
+ - Entries expire after 48 hours.
631
+ - If a domain was cached as "Unknown" from basic validation, requesting deep validation bypasses the cache and performs a fresh lookup.
632
+ - Falls back to in-memory only if the disk cache directory is not writable.
665
633
 
666
- ### Record Type Examples
634
+ ---
667
635
 
668
- ```typescript
669
- // A records - IPv4 addresses
670
- const ipv4 = await resolve4('example.com');
671
- // Returns: ['93.184.216.34']
636
+ ## Error Handling
672
637
 
673
- // MX records - Mail servers with priority
674
- const mailServers = await resolveMx('example.com');
675
- // Returns: [{ priority: 10, exchange: 'mail.example.com' }]
638
+ Specific error classes for each failure mode:
676
639
 
677
- // TXT records - Text data (SPF, DKIM, etc.)
678
- const txtRecords = await resolveTxt('example.com');
679
- // Returns: [['v=spf1 include:_spf.example.com ~all']]
640
+ ```typescript
641
+ import {
642
+ InvalidHostnameError,
643
+ NoEnabledProvidersError,
644
+ ProviderNotEnabledError,
645
+ InvalidProviderError,
646
+ } from "zynor";
647
+
648
+ try {
649
+ await resolve4("");
650
+ } catch (err) {
651
+ if (err instanceof InvalidHostnameError) {
652
+ // empty or invalid hostname
653
+ }
654
+ }
680
655
 
681
- // SRV records - Service discovery
682
- const services = await resolveSrv('_sip._tcp.example.com');
683
- // Returns: [{ priority: 10, weight: 5, port: 5060, name: 'sip.example.com' }]
656
+ try {
657
+ await resolve4("example.com", "google");
658
+ } catch (err) {
659
+ if (err instanceof ProviderNotEnabledError) {
660
+ // provider is disabled
661
+ }
662
+ }
684
663
  ```
685
664
 
686
-
687
-
688
- ## 🔷 TypeScript Support
689
-
690
- Zynor is built with TypeScript from the ground up, providing comprehensive type definitions, full IntelliSense support, and compile-time type checking. The library exports all necessary types and interfaces, ensuring type safety across your entire DNS resolution workflow and eliminating runtime type errors.
691
-
692
- ### Complete Type Safety
665
+ DNS errors are returned as Node.js-compatible error objects with `code`, `errno`, `syscall`, and `hostname`:
693
666
 
694
667
  ```typescript
695
- import { Zynor, MxRecord, SrvRecord, ProviderName } from 'zynor';
668
+ try {
669
+ await resolve4("this-domain-does-not-exist.invalid");
670
+ } catch (err) {
671
+ err.code; // "ENOTFOUND"
672
+ err.syscall; // "queryA"
673
+ err.hostname; // "this-domain-does-not-exist.invalid"
674
+ }
675
+ ```
696
676
 
697
- // Strongly typed results with full IntelliSense
698
- const mxRecords: MxRecord[] = await resolveMx('example.com');
699
- const srvRecords: SrvRecord[] = await resolveSrv('_sip._tcp.example.com');
677
+ ---
700
678
 
701
- // Type-safe provider names prevent typos
702
- const provider: ProviderName = 'google';
703
- const addresses = await resolve4('example.com', undefined, provider);
704
- ```
679
+ ## TypeScript Support
705
680
 
706
- ### Available Type Exports
681
+ Written in TypeScript with every type exported:
707
682
 
708
683
  ```typescript
709
- // Core types
710
684
  import {
711
- Zynor, // Main DNS class
712
- ProviderName, // 'google' | 'cloudflare' | 'quad9' | 'native'
713
- ZynorConfig, // Configuration interface
714
- ProviderConfig, // Individual provider configuration
715
-
716
- // DNS record types
717
- MxRecord, // Mail exchange record
718
- SrvRecord, // Service record
719
- SoaRecord, // Start of Authority record
720
- CaaRecord, // Certificate Authority Authorization
721
- NaptrRecord, // Name Authority Pointer
722
- TlsaRecord, // Transport Layer Security Authentication
723
- AnyRecord, // Union of all record types
724
-
725
- // Email validation types
726
- EmailValidator, // Email validation class
727
- EmailResponse, // Validation response type
728
- EmailData, // Successful validation data
729
- EmailError // Validation error type
730
- } from 'zynor';
731
- ```
732
-
733
- ### Generic Type Support
734
-
735
- ```typescript
736
- // Generic functions with type inference
737
- const resolveWithType = async <T>(hostname: string, type: string): Promise<T> => {
738
- // Type-safe resolution with custom return types
739
- return await dns.resolveAny(hostname) as T;
740
- };
741
-
742
- // Usage with automatic type inference
743
- const mxRecords = await resolveWithType<MxRecord[]>('example.com', 'MX');
685
+ Zynor,
686
+ ZynorConfig,
687
+ ProviderConfig,
688
+ ProviderName,
689
+ RecordType,
690
+ AbortOptions,
691
+ MxRecord,
692
+ SoaRecord,
693
+ SrvRecord,
694
+ CaaRecord,
695
+ NaptrRecord,
696
+ TlsaRecord,
697
+ AnyRecord,
698
+ RecordWithTtl,
699
+ ResolveOptions,
700
+ ResolveWithTtlOptions,
701
+ LruCache,
702
+ CacheConfig,
703
+ EmailValidator,
704
+ EmailResponse,
705
+ ValidationConfig,
706
+ NoEnabledProvidersError,
707
+ InvalidHostnameError,
708
+ ProviderNotEnabledError,
709
+ InvalidProviderError,
710
+ } from "zynor";
744
711
  ```
745
712
 
713
+ Full overload signatures with correct return types:
746
714
 
747
-
748
-
749
-
750
- ## 📄 License
751
-
752
- MIT License - see the [LICENSE](LICENSE) file for details.
715
+ ```typescript
716
+ const strings: string[] = await resolve4("example.com");
717
+ const withTtl: RecordWithTtl[] = await resolve4("example.com", { ttl: true });
718
+ const mx: MxRecord[] = await resolveMx("example.com");
719
+ const soa: SoaRecord = await resolveSoa("example.com");
720
+ ```
753
721
 
754
722
  ---
755
-
756
- **Made with ❤️ by [Yuniq Solutions Tech](https://yuniq.solutions)**
757
-
758
- For more information, visit our [GitHub repository](https://github.com/yuniqsolutions/zynor) or check out our [documentation](https://github.com/yuniqsolutions/zynor#readme).