@darcas/smart-dns-promises 1.1.1 → 1.2.0

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
@@ -6,6 +6,8 @@
6
6
 
7
7
  ![NPM License](https://img.shields.io/npm/l/%40darcas%2Fsmart-dns-promises?style=for-the-badge)
8
8
 
9
+ [![Buy me a coffee](https://img.shields.io/badge/buy_me_a_coffee-%E2%9D%A4%EF%B8%8F-FEEBE7?style=for-the-badge&labelColor=FF0000)](https://www.paypal.com/donate/?hosted_button_id=YZQDE3TEYDBWA)
10
+
9
11
  A simple and efficient DNS resolver with caching and configurable DNS providers for Node.js 20 and 22 or above.
10
12
 
11
13
  The purpose of this library is to increase the speed and performance of DNS resolution in Node.js. In environments where requests are made using libraries like [fetch](https://github.com/node-fetch/node-fetch) or [axios](https://github.com/axios/axios), this can be very useful.
@@ -18,7 +20,7 @@ The purpose of this library is to increase the speed and performance of DNS reso
18
20
  - In-flight deduplication: concurrent lookups for the same hostname trigger a single DNS query.
19
21
  - Optional stale-while-revalidate: expired entries are served immediately and refreshed in background.
20
22
  - Lookup statistics: hits, misses, errors, revalidations and average resolve time.
21
- - Supports configurable DNS providers: CloudFlare, Google, and OpenDNS.
23
+ - Supports configurable DNS providers: AdGuard, CloudFlare, Comodo, DNS.WATCH, Google, OpenDNS, Quad9, Verisign, and Yandex.
22
24
  - Allows custom result order for DNS resolutions: IPv4 first, IPv6 first, or verbatim, plus `ipv4`/`ipv6` family selection.
23
25
  - Singleton pattern to ensure only one instance of the resolver is used.
24
26
  - Manual configuration of DNS server addresses.
@@ -57,12 +59,12 @@ const dnsWithConfig = SmartDns.factory('Google', 'ipv4first', 600000);
57
59
 
58
60
  // Advanced options (4th argument)
59
61
  const dnsAdvanced = SmartDns.factory('CloudFlare', 'ipv4first', undefined, {
60
- swr: true, // serve stale entries and refresh in background
61
- negativeTtl: 30000, // how long failed lookups are negatively cached (ms)
62
- minTtl: 1000, // clamp for record TTLs coming from DNS (ms)
63
- maxTtl: 3600000, // clamp for record TTLs coming from DNS (ms)
64
62
  family: 'ipv6', // resolve AAAA records instead of A records
63
+ maxTtl: 3600000, // clamp for record TTLs coming from DNS (ms)
64
+ minTtl: 1000, // clamp for record TTLs coming from DNS (ms)
65
+ negativeTtl: 30000, // how long failed lookups are negatively cached (ms)
65
66
  onStats: (stats) => console.log(stats),
67
+ swr: true, // serve stale entries and refresh in background
66
68
  });
67
69
  ```
68
70
 
@@ -88,12 +90,26 @@ const { hits, misses, errors, revalidations, avgResolveMs } = dns.stats
88
90
  ```
89
91
  ### Setting the DNS provider
90
92
 
91
- You can set the DNS provider to CloudFlare, Google, or OpenDNS using the `setProvider` method.
93
+ You can set the DNS provider using the `setProvider` method with any `DnsProvider` member.
92
94
 
93
95
  ```js
94
96
  dns.setProvider('CloudFlare');
95
97
  ```
96
98
 
99
+ Available providers:
100
+
101
+ | Provider | Servers |
102
+ |---|---|
103
+ | AdGuard | `94.140.14.14`, `94.140.15.15` |
104
+ | CloudFlare | `1.1.1.1`, `1.0.0.1` |
105
+ | Comodo | `8.26.56.26`, `8.20.247.20` |
106
+ | DNS.WATCH | `84.200.69.80`, `84.200.70.40` |
107
+ | Google | `8.8.8.8`, `8.8.4.4` |
108
+ | OpenDNS | `208.67.222.222`, `208.67.220.220` |
109
+ | Quad9 | `9.9.9.9`, `149.112.112.112` |
110
+ | Verisign | `64.6.64.6`, `64.6.65.6` |
111
+ | Yandex | `77.88.8.8`, `77.88.8.1` |
112
+
97
113
  ### Setting the result Order
98
114
 
99
115
  The result order for DNS resolutions can be configured as follows:
@@ -118,7 +134,10 @@ console.log(result.urlReplaced); // URL with IP address instead of hostname
118
134
  You can manually set DNS server IP addresses using the `setServers` method.
119
135
 
120
136
  ```js
121
- dns.setServers(['8.8.8.8', '8.8.4.4']);
137
+ dns.setServers([
138
+ '8.8.8.8',
139
+ '8.8.4.4',
140
+ ]);
122
141
  ```
123
142
 
124
143
  ## Error Handling
@@ -76,9 +76,15 @@ export interface SmartDnsStats {
76
76
  * @enum {number}
77
77
  */
78
78
  export declare enum DnsProvider {
79
- CloudFlare = 0,
80
- Google = 1,
81
- OpenDNS = 2
79
+ AdGuard = 0,
80
+ CloudFlare = 1,
81
+ Comodo = 2,
82
+ DnsWatch = 3,
83
+ Google = 4,
84
+ OpenDNS = 5,
85
+ Quad9 = 6,
86
+ Verisign = 7,
87
+ Yandex = 8
82
88
  }
83
89
  /**
84
90
  * Error class for DNS provider-related errors.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -14,9 +14,15 @@ const promises_1 = require("node:dns/promises");
14
14
  */
15
15
  var DnsProvider;
16
16
  (function (DnsProvider) {
17
- DnsProvider[DnsProvider["CloudFlare"] = 0] = "CloudFlare";
18
- DnsProvider[DnsProvider["Google"] = 1] = "Google";
19
- DnsProvider[DnsProvider["OpenDNS"] = 2] = "OpenDNS";
17
+ DnsProvider[DnsProvider["AdGuard"] = 0] = "AdGuard";
18
+ DnsProvider[DnsProvider["CloudFlare"] = 1] = "CloudFlare";
19
+ DnsProvider[DnsProvider["Comodo"] = 2] = "Comodo";
20
+ DnsProvider[DnsProvider["DnsWatch"] = 3] = "DnsWatch";
21
+ DnsProvider[DnsProvider["Google"] = 4] = "Google";
22
+ DnsProvider[DnsProvider["OpenDNS"] = 5] = "OpenDNS";
23
+ DnsProvider[DnsProvider["Quad9"] = 6] = "Quad9";
24
+ DnsProvider[DnsProvider["Verisign"] = 7] = "Verisign";
25
+ DnsProvider[DnsProvider["Yandex"] = 8] = "Yandex";
20
26
  })(DnsProvider || (exports.DnsProvider = DnsProvider = {}));
21
27
  /**
22
28
  * Error class for DNS provider-related errors.
@@ -156,12 +162,30 @@ class SmartDns {
156
162
  */
157
163
  setProvider(dnsProvider) {
158
164
  switch (dnsProvider) {
165
+ case DnsProvider.AdGuard:
166
+ (0, promises_1.setServers)([
167
+ '94.140.14.14',
168
+ '94.140.15.15',
169
+ ]);
170
+ break;
159
171
  case DnsProvider.CloudFlare:
160
172
  (0, promises_1.setServers)([
161
173
  '1.1.1.1',
162
174
  '1.0.0.1',
163
175
  ]);
164
176
  break;
177
+ case DnsProvider.Comodo:
178
+ (0, promises_1.setServers)([
179
+ '8.26.56.26',
180
+ '8.20.247.20',
181
+ ]);
182
+ break;
183
+ case DnsProvider.DnsWatch:
184
+ (0, promises_1.setServers)([
185
+ '84.200.69.80',
186
+ '84.200.70.40',
187
+ ]);
188
+ break;
165
189
  case DnsProvider.Google:
166
190
  (0, promises_1.setServers)([
167
191
  '8.8.8.8',
@@ -174,6 +198,24 @@ class SmartDns {
174
198
  '208.67.220.220',
175
199
  ]);
176
200
  break;
201
+ case DnsProvider.Quad9:
202
+ (0, promises_1.setServers)([
203
+ '9.9.9.9',
204
+ '149.112.112.112',
205
+ ]);
206
+ break;
207
+ case DnsProvider.Verisign:
208
+ (0, promises_1.setServers)([
209
+ '64.6.64.6',
210
+ '64.6.65.6',
211
+ ]);
212
+ break;
213
+ case DnsProvider.Yandex:
214
+ (0, promises_1.setServers)([
215
+ '77.88.8.8',
216
+ '77.88.8.1',
217
+ ]);
218
+ break;
177
219
  default:
178
220
  throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the "setServers" method to manually set the DNS server IP addresses.`);
179
221
  }
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports.SmartDns=exports.SmartDnsResolverError=exports.SmartDnsProviderError=exports.DnsProvider=void 0;var n=require("node:dns/promises"),o;(function(i){i[i.CloudFlare=0]="CloudFlare",i[i.Google=1]="Google",i[i.OpenDNS=2]="OpenDNS"})(o||(exports.DnsProvider=o={}));var h=class extends Error{};exports.SmartDnsProviderError=h;var a=class extends Error{};exports.SmartDnsResolverError=a;var d=class{maxEntries;entries=new Map;constructor(t){this.maxEntries=t}get(t){let e=this.entries.get(t);if(e)return this.entries.delete(t),this.entries.set(t,e),e}set(t,e){if(this.entries.delete(t),this.entries.set(t,e),this.entries.size>this.maxEntries){let s=this.entries.keys().next().value;s!==void 0&&this.entries.delete(s)}}},c,u=class i{ttl;cache;inflight=new Map;negative=new Map;swr;negativeTtl;minTtl;maxTtl;family;onStats;counters={errors:0,hits:0,misses:0,resolutions:0,revalidations:0,totalResolveMs:0};constructor(t,e="ipv4first",s=36e5,r={}){this.ttl=s,this.swr=r.swr??!1,this.negativeTtl=r.negativeTtl??3e4,this.minTtl=Math.max(r.minTtl??1e3,1),this.maxTtl=Math.max(r.maxTtl??36e5,this.minTtl),this.family=r.family??"ipv4",this.onStats=r.onStats,this.cache=new d(100),t&&this.setProvider(t),(0,n.setDefaultResultOrder)(e)}static factory(t,e,s,r){return c||(c=new i(t,e,s,r)),c}get stats(){return{avgResolveMs:this.counters.resolutions>0?this.counters.totalResolveMs/this.counters.resolutions:0,errors:this.counters.errors,hits:this.counters.hits,misses:this.counters.misses,revalidations:this.counters.revalidations}}setProvider(t){switch(t){case o.CloudFlare:(0,n.setServers)(["1.1.1.1","1.0.0.1"]);break;case o.Google:(0,n.setServers)(["8.8.8.8","8.8.4.4"]);break;case o.OpenDNS:(0,n.setServers)(["208.67.222.222","208.67.220.220"]);break;default:throw new h(`Unsupported DNS provider: ${t}. You can use the "setServers" method to manually set the DNS server IP addresses.`)}}async resolver(t){if(!/^https?:\/\//.test(t))throw new a("The URL must start with http/https.");let e;try{e=new URL(t)}catch{throw new a(`The URL "${t}" is not a valid URL.`)}let s=e.hostname,r=await this.resolveAddress(s);return{address:r,hostname:s,urlReplaced:t.replace(s,r)}}setServers(t){(0,n.setServers)(t)}async resolveAddress(t){let e=Date.now(),s=this.cache.get(t);if(s&&s.expiresAt>e)return this.counters.hits++,this.emit(),s.address;if(s&&this.swr)return this.counters.hits++,this.counters.revalidations++,this.revalidate(t),this.emit(),s.address;let r=this.negative.get(t);if(r!==void 0&&r>e)throw this.counters.errors++,this.emit(),new a(`A recent lookup for "${t}" failed; retrying is rate limited by the negative cache.`);return this.counters.misses++,this.fetchAddress(t).finally(()=>{this.emit()})}fetchAddress(t){let e=this.inflight.get(t);return e||(e=this.doResolve(t),this.inflight.set(t,e),e.then(()=>{},()=>{}).finally(()=>{this.inflight.delete(t)})),e}revalidate(t){this.fetchAddress(t)}async doResolve(t){let e=Date.now();try{let s=new n.Resolver,r=this.family==="ipv6"?await s.resolve6(t,{ttl:!0}):await s.resolve4(t,{ttl:!0}),[l]=r;if(!l)throw new Error(`No ${this.family} records found for "${t}".`);let v=l.ttl>0?l.ttl*1e3:this.ttl,f=Math.min(Math.max(v,this.minTtl),this.maxTtl);return this.cache.set(t,{address:l.address,expiresAt:Date.now()+f}),this.negative.delete(t),l.address}catch(s){throw this.counters.errors++,this.negative.set(t,Date.now()+this.negativeTtl),s}finally{this.counters.resolutions++,this.counters.totalResolveMs+=Date.now()-e}}emit(){this.onStats?.(this.stats)}};exports.SmartDns=u;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});exports.SmartDns=exports.SmartDnsResolverError=exports.SmartDnsProviderError=exports.DnsProvider=void 0;var a=require("node:dns/promises"),n;(function(t){t[t.AdGuard=0]="AdGuard",t[t.CloudFlare=1]="CloudFlare",t[t.Comodo=2]="Comodo",t[t.DnsWatch=3]="DnsWatch",t[t.Google=4]="Google",t[t.OpenDNS=5]="OpenDNS",t[t.Quad9=6]="Quad9",t[t.Verisign=7]="Verisign",t[t.Yandex=8]="Yandex"})(n||(exports.DnsProvider=n={}));var h=class extends Error{};exports.SmartDnsProviderError=h;var l=class extends Error{};exports.SmartDnsResolverError=l;var d=class{maxEntries;entries=new Map;constructor(e){this.maxEntries=e}get(e){let s=this.entries.get(e);if(s)return this.entries.delete(e),this.entries.set(e,s),s}set(e,s){if(this.entries.delete(e),this.entries.set(e,s),this.entries.size>this.maxEntries){let r=this.entries.keys().next().value;r!==void 0&&this.entries.delete(r)}}},c,u=class t{ttl;cache;inflight=new Map;negative=new Map;swr;negativeTtl;minTtl;maxTtl;family;onStats;counters={errors:0,hits:0,misses:0,resolutions:0,revalidations:0,totalResolveMs:0};constructor(e,s="ipv4first",r=36e5,i={}){this.ttl=r,this.swr=i.swr??!1,this.negativeTtl=i.negativeTtl??3e4,this.minTtl=Math.max(i.minTtl??1e3,1),this.maxTtl=Math.max(i.maxTtl??36e5,this.minTtl),this.family=i.family??"ipv4",this.onStats=i.onStats,this.cache=new d(100),e&&this.setProvider(e),(0,a.setDefaultResultOrder)(s)}static factory(e,s,r,i){return c||(c=new t(e,s,r,i)),c}get stats(){return{avgResolveMs:this.counters.resolutions>0?this.counters.totalResolveMs/this.counters.resolutions:0,errors:this.counters.errors,hits:this.counters.hits,misses:this.counters.misses,revalidations:this.counters.revalidations}}setProvider(e){switch(e){case n.AdGuard:(0,a.setServers)(["94.140.14.14","94.140.15.15"]);break;case n.CloudFlare:(0,a.setServers)(["1.1.1.1","1.0.0.1"]);break;case n.Comodo:(0,a.setServers)(["8.26.56.26","8.20.247.20"]);break;case n.DnsWatch:(0,a.setServers)(["84.200.69.80","84.200.70.40"]);break;case n.Google:(0,a.setServers)(["8.8.8.8","8.8.4.4"]);break;case n.OpenDNS:(0,a.setServers)(["208.67.222.222","208.67.220.220"]);break;case n.Quad9:(0,a.setServers)(["9.9.9.9","149.112.112.112"]);break;case n.Verisign:(0,a.setServers)(["64.6.64.6","64.6.65.6"]);break;case n.Yandex:(0,a.setServers)(["77.88.8.8","77.88.8.1"]);break;default:throw new h(`Unsupported DNS provider: ${e}. You can use the "setServers" method to manually set the DNS server IP addresses.`)}}async resolver(e){if(!/^https?:\/\//.test(e))throw new l("The URL must start with http/https.");let s;try{s=new URL(e)}catch{throw new l(`The URL "${e}" is not a valid URL.`)}let r=s.hostname,i=await this.resolveAddress(r);return{address:i,hostname:r,urlReplaced:e.replace(r,i)}}setServers(e){(0,a.setServers)(e)}async resolveAddress(e){let s=Date.now(),r=this.cache.get(e);if(r&&r.expiresAt>s)return this.counters.hits++,this.emit(),r.address;if(r&&this.swr)return this.counters.hits++,this.counters.revalidations++,this.revalidate(e),this.emit(),r.address;let i=this.negative.get(e);if(i!==void 0&&i>s)throw this.counters.errors++,this.emit(),new l(`A recent lookup for "${e}" failed; retrying is rate limited by the negative cache.`);return this.counters.misses++,this.fetchAddress(e).finally(()=>{this.emit()})}fetchAddress(e){let s=this.inflight.get(e);return s||(s=this.doResolve(e),this.inflight.set(e,s),s.then(()=>{},()=>{}).finally(()=>{this.inflight.delete(e)})),s}revalidate(e){this.fetchAddress(e)}async doResolve(e){let s=Date.now();try{let r=new a.Resolver,i=this.family==="ipv6"?await r.resolve6(e,{ttl:!0}):await r.resolve4(e,{ttl:!0}),[o]=i;if(!o)throw new Error(`No ${this.family} records found for "${e}".`);let f=o.ttl>0?o.ttl*1e3:this.ttl,v=Math.min(Math.max(f,this.minTtl),this.maxTtl);return this.cache.set(e,{address:o.address,expiresAt:Date.now()+v}),this.negative.delete(e),o.address}catch(r){throw this.counters.errors++,this.negative.set(e,Date.now()+this.negativeTtl),r}finally{this.counters.resolutions++,this.counters.totalResolveMs+=Date.now()-s}}emit(){this.onStats?.(this.stats)}};exports.SmartDns=u;
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["index.js"],
4
- "sourcesContent": ["\"use strict\";\n/*\n * Dario Casertano <dario@casertano.name>\n * Copyright (c) 2026 Casertano Dario \u2013 All rights reserved.\n * MIT\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.SmartDns = exports.SmartDnsResolverError = exports.SmartDnsProviderError = exports.DnsProvider = void 0;\nconst promises_1 = require(\"node:dns/promises\");\n/**\n * Enum for built-in DNS providers.\n * @readonly\n * @enum {number}\n */\nvar DnsProvider;\n(function (DnsProvider) {\n DnsProvider[DnsProvider[\"CloudFlare\"] = 0] = \"CloudFlare\";\n DnsProvider[DnsProvider[\"Google\"] = 1] = \"Google\";\n DnsProvider[DnsProvider[\"OpenDNS\"] = 2] = \"OpenDNS\";\n})(DnsProvider || (exports.DnsProvider = DnsProvider = {}));\n/**\n * Error class for DNS provider-related errors.\n * @extends {Error}\n */\nclass SmartDnsProviderError extends Error {\n}\nexports.SmartDnsProviderError = SmartDnsProviderError;\n/**\n * Error class for DNS resolution-related errors.\n * @extends {Error}\n */\nclass SmartDnsResolverError extends Error {\n}\nexports.SmartDnsResolverError = SmartDnsResolverError;\n/**\n * Minimal zero-dependency LRU cache with expiry support.\n */\nclass LruCache {\n maxEntries;\n entries = new Map();\n constructor(maxEntries) {\n this.maxEntries = maxEntries;\n }\n get(hostname) {\n const entry = this.entries.get(hostname);\n if (!entry) {\n return undefined;\n }\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n return entry;\n }\n set(hostname, entry) {\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n if (this.entries.size > this.maxEntries) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) {\n this.entries.delete(oldest);\n }\n }\n }\n}\nlet SmartDnsInstance;\n/**\n * SmartDns class for managing DNS resolution with caching and configurable DNS providers.\n *\n * Configuration is applied to Node's process-global DNS system (`node:dns`):\n * `setProvider` and `setServers` replace the resolver servers for the whole\n * process, and `resultOrder` calls `dns.setDefaultResultOrder`. Every HTTP\n * client in the application is affected by (and benefits from) this setup.\n * Instantiate and configure SmartDns as early as possible in the application\n * lifecycle, ideally once.\n */\nclass SmartDns {\n ttl;\n /**\n * Cache for hostname-IP mappings.\n */\n cache;\n inflight = new Map();\n negative = new Map();\n swr;\n negativeTtl;\n minTtl;\n maxTtl;\n family;\n onStats;\n counters = {\n errors: 0,\n hits: 0,\n misses: 0,\n resolutions: 0,\n revalidations: 0,\n totalResolveMs: 0,\n };\n /**\n * Creates an instance of SmartDns.\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder='ipv4first'] Order of DNS resolution results.\n * @param [ttl=3600000] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n */\n constructor(dnsProvider, resultOrder = 'ipv4first', ttl = 3_600_000, options = {}) {\n this.ttl = ttl;\n this.swr = options.swr ?? false;\n this.negativeTtl = options.negativeTtl ?? 30_000;\n this.minTtl = Math.max(options.minTtl ?? 1_000, 1);\n this.maxTtl = Math.max(options.maxTtl ?? 3_600_000, this.minTtl);\n this.family = options.family ?? 'ipv4';\n this.onStats = options.onStats;\n this.cache = new LruCache(100);\n if (dnsProvider) {\n this.setProvider(dnsProvider);\n }\n (0, promises_1.setDefaultResultOrder)(resultOrder);\n }\n /**\n * Creates or retrieves a singleton instance of SmartDns.\n *\n * As in v1, configuration passed after the first call is ignored because the\n * singleton has already been created.\n *\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder] Order of DNS resolution results.\n * @param [ttl] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n * @returns The singleton SmartDns instance.\n */\n static factory(dnsProvider, resultOrder, ttl, options) {\n if (!SmartDnsInstance) {\n SmartDnsInstance = new SmartDns(dnsProvider, resultOrder, ttl, options);\n }\n return SmartDnsInstance;\n }\n /**\n * Current lookup statistics for this instance.\n */\n get stats() {\n return {\n avgResolveMs: this.counters.resolutions > 0\n ? this.counters.totalResolveMs / this.counters.resolutions\n : 0,\n errors: this.counters.errors,\n hits: this.counters.hits,\n misses: this.counters.misses,\n revalidations: this.counters.revalidations,\n };\n }\n /**\n * Sets the DNS servers by the provider.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param dnsProvider The DNS provider to use.\n * @throws {SmartDnsProviderError} If the DNS provider is unsupported.\n */\n setProvider(dnsProvider) {\n switch (dnsProvider) {\n case DnsProvider.CloudFlare:\n (0, promises_1.setServers)([\n '1.1.1.1',\n '1.0.0.1',\n ]);\n break;\n case DnsProvider.Google:\n (0, promises_1.setServers)([\n '8.8.8.8',\n '8.8.4.4',\n ]);\n break;\n case DnsProvider.OpenDNS:\n (0, promises_1.setServers)([\n '208.67.222.222',\n '208.67.220.220',\n ]);\n break;\n default:\n throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the \"setServers\" method to manually set the DNS server IP addresses.`);\n }\n }\n /**\n * Resolves a URL and retrieves its IP address, hostname, and updated URL.\n * @async\n * @param url The URL to resolve (must start with http/https).\n * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.\n * @throws {SmartDnsResolverError} If the URL is invalid or the lookup was recently failing.\n * @throws {Error} If the resolution fails.\n */\n async resolver(url) {\n if (!/^https?:\\/\\//.test(url)) {\n throw new SmartDnsResolverError(`The URL must start with http/https.`);\n }\n let parsedUrl;\n try {\n parsedUrl = new URL(url);\n }\n catch {\n throw new SmartDnsResolverError(`The URL \"${url}\" is not a valid URL.`);\n }\n const hostname = parsedUrl.hostname;\n const address = await this.resolveAddress(hostname);\n return {\n address,\n hostname,\n urlReplaced: url.replace(hostname, address),\n };\n }\n /**\n * Manually sets DNS servers.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param servers Array of DNS server IP addresses.\n */\n setServers(servers) {\n (0, promises_1.setServers)(servers);\n }\n async resolveAddress(hostname) {\n const now = Date.now();\n const entry = this.cache.get(hostname);\n if (entry && entry.expiresAt > now) {\n this.counters.hits++;\n this.emit();\n return entry.address;\n }\n if (entry && this.swr) {\n this.counters.hits++;\n this.counters.revalidations++;\n this.revalidate(hostname);\n this.emit();\n return entry.address;\n }\n const negativeUntil = this.negative.get(hostname);\n if (negativeUntil !== undefined && negativeUntil > now) {\n this.counters.errors++;\n this.emit();\n throw new SmartDnsResolverError(`A recent lookup for \"${hostname}\" failed; retrying is rate limited by the negative cache.`);\n }\n this.counters.misses++;\n return this.fetchAddress(hostname).finally(() => {\n this.emit();\n });\n }\n fetchAddress(hostname) {\n let pending = this.inflight.get(hostname);\n if (!pending) {\n pending = this.doResolve(hostname);\n this.inflight.set(hostname, pending);\n pending.then(() => undefined, () => undefined).finally(() => {\n this.inflight.delete(hostname);\n });\n }\n return pending;\n }\n revalidate(hostname) {\n void this.fetchAddress(hostname);\n }\n async doResolve(hostname) {\n const startedAt = Date.now();\n try {\n const resolver = new promises_1.Resolver();\n const records = this.family === 'ipv6'\n ? await resolver.resolve6(hostname, { ttl: true })\n : await resolver.resolve4(hostname, { ttl: true });\n const [record] = records;\n if (!record) {\n throw new Error(`No ${this.family} records found for \"${hostname}\".`);\n }\n const rawTtl = record.ttl > 0 ? record.ttl * 1000 : this.ttl;\n const recordTtl = Math.min(Math.max(rawTtl, this.minTtl), this.maxTtl);\n this.cache.set(hostname, {\n address: record.address,\n expiresAt: Date.now() + recordTtl,\n });\n this.negative.delete(hostname);\n return record.address;\n }\n catch (e) {\n this.counters.errors++;\n this.negative.set(hostname, Date.now() + this.negativeTtl);\n throw e;\n }\n finally {\n this.counters.resolutions++;\n this.counters.totalResolveMs += Date.now() - startedAt;\n }\n }\n emit() {\n this.onStats?.(this.stats);\n }\n}\nexports.SmartDns = SmartDns;\n"],
5
- "mappings": "aAMA,OAAO,eAAe,QAAS,aAAc,CAAE,MAAO,EAAK,CAAC,EAC5D,QAAQ,SAAW,QAAQ,sBAAwB,QAAQ,sBAAwB,QAAQ,YAAc,OACzG,IAAMA,EAAa,QAAQ,mBAAmB,EAM1CC,GACH,SAAUA,EAAa,CACpBA,EAAYA,EAAY,WAAgB,CAAC,EAAI,aAC7CA,EAAYA,EAAY,OAAY,CAAC,EAAI,SACzCA,EAAYA,EAAY,QAAa,CAAC,EAAI,SAC9C,GAAGA,IAAgB,QAAQ,YAAcA,EAAc,CAAC,EAAE,EAK1D,IAAMC,EAAN,cAAoC,KAAM,CAC1C,EACA,QAAQ,sBAAwBA,EAKhC,IAAMC,EAAN,cAAoC,KAAM,CAC1C,EACA,QAAQ,sBAAwBA,EAIhC,IAAMC,EAAN,KAAe,CACX,WACA,QAAU,IAAI,IACd,YAAYC,EAAY,CACpB,KAAK,WAAaA,CACtB,CACA,IAAIC,EAAU,CACV,IAAMC,EAAQ,KAAK,QAAQ,IAAID,CAAQ,EACvC,GAAKC,EAGL,YAAK,QAAQ,OAAOD,CAAQ,EAC5B,KAAK,QAAQ,IAAIA,EAAUC,CAAK,EACzBA,CACX,CACA,IAAID,EAAUC,EAAO,CAGjB,GAFA,KAAK,QAAQ,OAAOD,CAAQ,EAC5B,KAAK,QAAQ,IAAIA,EAAUC,CAAK,EAC5B,KAAK,QAAQ,KAAO,KAAK,WAAY,CACrC,IAAMC,EAAS,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE,MACtCA,IAAW,QACX,KAAK,QAAQ,OAAOA,CAAM,CAElC,CACJ,CACJ,EACIC,EAWEC,EAAN,MAAMC,CAAS,CACX,IAIA,MACA,SAAW,IAAI,IACf,SAAW,IAAI,IACf,IACA,YACA,OACA,OACA,OACA,QACA,SAAW,CACP,OAAQ,EACR,KAAM,EACN,OAAQ,EACR,YAAa,EACb,cAAe,EACf,eAAgB,CACpB,EAQA,YAAYC,EAAaC,EAAc,YAAaC,EAAM,KAAWC,EAAU,CAAC,EAAG,CAC/E,KAAK,IAAMD,EACX,KAAK,IAAMC,EAAQ,KAAO,GAC1B,KAAK,YAAcA,EAAQ,aAAe,IAC1C,KAAK,OAAS,KAAK,IAAIA,EAAQ,QAAU,IAAO,CAAC,EACjD,KAAK,OAAS,KAAK,IAAIA,EAAQ,QAAU,KAAW,KAAK,MAAM,EAC/D,KAAK,OAASA,EAAQ,QAAU,OAChC,KAAK,QAAUA,EAAQ,QACvB,KAAK,MAAQ,IAAIX,EAAS,GAAG,EACzBQ,GACA,KAAK,YAAYA,CAAW,KAE5BZ,EAAW,uBAAuBa,CAAW,CACrD,CAaA,OAAO,QAAQD,EAAaC,EAAaC,EAAKC,EAAS,CACnD,OAAKN,IACDA,EAAmB,IAAIE,EAASC,EAAaC,EAAaC,EAAKC,CAAO,GAEnEN,CACX,CAIA,IAAI,OAAQ,CACR,MAAO,CACH,aAAc,KAAK,SAAS,YAAc,EACpC,KAAK,SAAS,eAAiB,KAAK,SAAS,YAC7C,EACN,OAAQ,KAAK,SAAS,OACtB,KAAM,KAAK,SAAS,KACpB,OAAQ,KAAK,SAAS,OACtB,cAAe,KAAK,SAAS,aACjC,CACJ,CAQA,YAAYG,EAAa,CACrB,OAAQA,EAAa,CACjB,KAAKX,EAAY,cACTD,EAAW,YAAY,CACvB,UACA,SACJ,CAAC,EACD,MACJ,KAAKC,EAAY,UACTD,EAAW,YAAY,CACvB,UACA,SACJ,CAAC,EACD,MACJ,KAAKC,EAAY,WACTD,EAAW,YAAY,CACvB,iBACA,gBACJ,CAAC,EACD,MACJ,QACI,MAAM,IAAIE,EAAsB,6BAA6BU,CAAW,oFAAoF,CACpK,CACJ,CASA,MAAM,SAASI,EAAK,CAChB,GAAI,CAAC,eAAe,KAAKA,CAAG,EACxB,MAAM,IAAIb,EAAsB,qCAAqC,EAEzE,IAAIc,EACJ,GAAI,CACAA,EAAY,IAAI,IAAID,CAAG,CAC3B,MACM,CACF,MAAM,IAAIb,EAAsB,YAAYa,CAAG,uBAAuB,CAC1E,CACA,IAAMV,EAAWW,EAAU,SACrBC,EAAU,MAAM,KAAK,eAAeZ,CAAQ,EAClD,MAAO,CACH,QAAAY,EACA,SAAAZ,EACA,YAAaU,EAAI,QAAQV,EAAUY,CAAO,CAC9C,CACJ,CAOA,WAAWC,EAAS,IACZnB,EAAW,YAAYmB,CAAO,CACtC,CACA,MAAM,eAAeb,EAAU,CAC3B,IAAMc,EAAM,KAAK,IAAI,EACfb,EAAQ,KAAK,MAAM,IAAID,CAAQ,EACrC,GAAIC,GAASA,EAAM,UAAYa,EAC3B,YAAK,SAAS,OACd,KAAK,KAAK,EACHb,EAAM,QAEjB,GAAIA,GAAS,KAAK,IACd,YAAK,SAAS,OACd,KAAK,SAAS,gBACd,KAAK,WAAWD,CAAQ,EACxB,KAAK,KAAK,EACHC,EAAM,QAEjB,IAAMc,EAAgB,KAAK,SAAS,IAAIf,CAAQ,EAChD,GAAIe,IAAkB,QAAaA,EAAgBD,EAC/C,WAAK,SAAS,SACd,KAAK,KAAK,EACJ,IAAIjB,EAAsB,wBAAwBG,CAAQ,2DAA2D,EAE/H,YAAK,SAAS,SACP,KAAK,aAAaA,CAAQ,EAAE,QAAQ,IAAM,CAC7C,KAAK,KAAK,CACd,CAAC,CACL,CACA,aAAaA,EAAU,CACnB,IAAIgB,EAAU,KAAK,SAAS,IAAIhB,CAAQ,EACxC,OAAKgB,IACDA,EAAU,KAAK,UAAUhB,CAAQ,EACjC,KAAK,SAAS,IAAIA,EAAUgB,CAAO,EACnCA,EAAQ,KAAK,IAAG,GAAc,IAAG,EAAY,EAAE,QAAQ,IAAM,CACzD,KAAK,SAAS,OAAOhB,CAAQ,CACjC,CAAC,GAEEgB,CACX,CACA,WAAWhB,EAAU,CACZ,KAAK,aAAaA,CAAQ,CACnC,CACA,MAAM,UAAUA,EAAU,CACtB,IAAMiB,EAAY,KAAK,IAAI,EAC3B,GAAI,CACA,IAAMC,EAAW,IAAIxB,EAAW,SAC1ByB,EAAU,KAAK,SAAW,OAC1B,MAAMD,EAAS,SAASlB,EAAU,CAAE,IAAK,EAAK,CAAC,EAC/C,MAAMkB,EAAS,SAASlB,EAAU,CAAE,IAAK,EAAK,CAAC,EAC/C,CAACoB,CAAM,EAAID,EACjB,GAAI,CAACC,EACD,MAAM,IAAI,MAAM,MAAM,KAAK,MAAM,uBAAuBpB,CAAQ,IAAI,EAExE,IAAMqB,EAASD,EAAO,IAAM,EAAIA,EAAO,IAAM,IAAO,KAAK,IACnDE,EAAY,KAAK,IAAI,KAAK,IAAID,EAAQ,KAAK,MAAM,EAAG,KAAK,MAAM,EACrE,YAAK,MAAM,IAAIrB,EAAU,CACrB,QAASoB,EAAO,QAChB,UAAW,KAAK,IAAI,EAAIE,CAC5B,CAAC,EACD,KAAK,SAAS,OAAOtB,CAAQ,EACtBoB,EAAO,OAClB,OACOG,EAAG,CACN,WAAK,SAAS,SACd,KAAK,SAAS,IAAIvB,EAAU,KAAK,IAAI,EAAI,KAAK,WAAW,EACnDuB,CACV,QACA,CACI,KAAK,SAAS,cACd,KAAK,SAAS,gBAAkB,KAAK,IAAI,EAAIN,CACjD,CACJ,CACA,MAAO,CACH,KAAK,UAAU,KAAK,KAAK,CAC7B,CACJ,EACA,QAAQ,SAAWb",
4
+ "sourcesContent": ["\"use strict\";\n/*\n * Dario Casertano <dario@casertano.name>\n * Copyright (c) 2026 Casertano Dario \u2013 All rights reserved.\n * MIT\n */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.SmartDns = exports.SmartDnsResolverError = exports.SmartDnsProviderError = exports.DnsProvider = void 0;\nconst promises_1 = require(\"node:dns/promises\");\n/**\n * Enum for built-in DNS providers.\n * @readonly\n * @enum {number}\n */\nvar DnsProvider;\n(function (DnsProvider) {\n DnsProvider[DnsProvider[\"AdGuard\"] = 0] = \"AdGuard\";\n DnsProvider[DnsProvider[\"CloudFlare\"] = 1] = \"CloudFlare\";\n DnsProvider[DnsProvider[\"Comodo\"] = 2] = \"Comodo\";\n DnsProvider[DnsProvider[\"DnsWatch\"] = 3] = \"DnsWatch\";\n DnsProvider[DnsProvider[\"Google\"] = 4] = \"Google\";\n DnsProvider[DnsProvider[\"OpenDNS\"] = 5] = \"OpenDNS\";\n DnsProvider[DnsProvider[\"Quad9\"] = 6] = \"Quad9\";\n DnsProvider[DnsProvider[\"Verisign\"] = 7] = \"Verisign\";\n DnsProvider[DnsProvider[\"Yandex\"] = 8] = \"Yandex\";\n})(DnsProvider || (exports.DnsProvider = DnsProvider = {}));\n/**\n * Error class for DNS provider-related errors.\n * @extends {Error}\n */\nclass SmartDnsProviderError extends Error {\n}\nexports.SmartDnsProviderError = SmartDnsProviderError;\n/**\n * Error class for DNS resolution-related errors.\n * @extends {Error}\n */\nclass SmartDnsResolverError extends Error {\n}\nexports.SmartDnsResolverError = SmartDnsResolverError;\n/**\n * Minimal zero-dependency LRU cache with expiry support.\n */\nclass LruCache {\n maxEntries;\n entries = new Map();\n constructor(maxEntries) {\n this.maxEntries = maxEntries;\n }\n get(hostname) {\n const entry = this.entries.get(hostname);\n if (!entry) {\n return undefined;\n }\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n return entry;\n }\n set(hostname, entry) {\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n if (this.entries.size > this.maxEntries) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) {\n this.entries.delete(oldest);\n }\n }\n }\n}\nlet SmartDnsInstance;\n/**\n * SmartDns class for managing DNS resolution with caching and configurable DNS providers.\n *\n * Configuration is applied to Node's process-global DNS system (`node:dns`):\n * `setProvider` and `setServers` replace the resolver servers for the whole\n * process, and `resultOrder` calls `dns.setDefaultResultOrder`. Every HTTP\n * client in the application is affected by (and benefits from) this setup.\n * Instantiate and configure SmartDns as early as possible in the application\n * lifecycle, ideally once.\n */\nclass SmartDns {\n ttl;\n /**\n * Cache for hostname-IP mappings.\n */\n cache;\n inflight = new Map();\n negative = new Map();\n swr;\n negativeTtl;\n minTtl;\n maxTtl;\n family;\n onStats;\n counters = {\n errors: 0,\n hits: 0,\n misses: 0,\n resolutions: 0,\n revalidations: 0,\n totalResolveMs: 0,\n };\n /**\n * Creates an instance of SmartDns.\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder='ipv4first'] Order of DNS resolution results.\n * @param [ttl=3600000] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n */\n constructor(dnsProvider, resultOrder = 'ipv4first', ttl = 3_600_000, options = {}) {\n this.ttl = ttl;\n this.swr = options.swr ?? false;\n this.negativeTtl = options.negativeTtl ?? 30_000;\n this.minTtl = Math.max(options.minTtl ?? 1_000, 1);\n this.maxTtl = Math.max(options.maxTtl ?? 3_600_000, this.minTtl);\n this.family = options.family ?? 'ipv4';\n this.onStats = options.onStats;\n this.cache = new LruCache(100);\n if (dnsProvider) {\n this.setProvider(dnsProvider);\n }\n (0, promises_1.setDefaultResultOrder)(resultOrder);\n }\n /**\n * Creates or retrieves a singleton instance of SmartDns.\n *\n * As in v1, configuration passed after the first call is ignored because the\n * singleton has already been created.\n *\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder] Order of DNS resolution results.\n * @param [ttl] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n * @returns The singleton SmartDns instance.\n */\n static factory(dnsProvider, resultOrder, ttl, options) {\n if (!SmartDnsInstance) {\n SmartDnsInstance = new SmartDns(dnsProvider, resultOrder, ttl, options);\n }\n return SmartDnsInstance;\n }\n /**\n * Current lookup statistics for this instance.\n */\n get stats() {\n return {\n avgResolveMs: this.counters.resolutions > 0\n ? this.counters.totalResolveMs / this.counters.resolutions\n : 0,\n errors: this.counters.errors,\n hits: this.counters.hits,\n misses: this.counters.misses,\n revalidations: this.counters.revalidations,\n };\n }\n /**\n * Sets the DNS servers by the provider.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param dnsProvider The DNS provider to use.\n * @throws {SmartDnsProviderError} If the DNS provider is unsupported.\n */\n setProvider(dnsProvider) {\n switch (dnsProvider) {\n case DnsProvider.AdGuard:\n (0, promises_1.setServers)([\n '94.140.14.14',\n '94.140.15.15',\n ]);\n break;\n case DnsProvider.CloudFlare:\n (0, promises_1.setServers)([\n '1.1.1.1',\n '1.0.0.1',\n ]);\n break;\n case DnsProvider.Comodo:\n (0, promises_1.setServers)([\n '8.26.56.26',\n '8.20.247.20',\n ]);\n break;\n case DnsProvider.DnsWatch:\n (0, promises_1.setServers)([\n '84.200.69.80',\n '84.200.70.40',\n ]);\n break;\n case DnsProvider.Google:\n (0, promises_1.setServers)([\n '8.8.8.8',\n '8.8.4.4',\n ]);\n break;\n case DnsProvider.OpenDNS:\n (0, promises_1.setServers)([\n '208.67.222.222',\n '208.67.220.220',\n ]);\n break;\n case DnsProvider.Quad9:\n (0, promises_1.setServers)([\n '9.9.9.9',\n '149.112.112.112',\n ]);\n break;\n case DnsProvider.Verisign:\n (0, promises_1.setServers)([\n '64.6.64.6',\n '64.6.65.6',\n ]);\n break;\n case DnsProvider.Yandex:\n (0, promises_1.setServers)([\n '77.88.8.8',\n '77.88.8.1',\n ]);\n break;\n default:\n throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the \"setServers\" method to manually set the DNS server IP addresses.`);\n }\n }\n /**\n * Resolves a URL and retrieves its IP address, hostname, and updated URL.\n * @async\n * @param url The URL to resolve (must start with http/https).\n * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.\n * @throws {SmartDnsResolverError} If the URL is invalid or the lookup was recently failing.\n * @throws {Error} If the resolution fails.\n */\n async resolver(url) {\n if (!/^https?:\\/\\//.test(url)) {\n throw new SmartDnsResolverError(`The URL must start with http/https.`);\n }\n let parsedUrl;\n try {\n parsedUrl = new URL(url);\n }\n catch {\n throw new SmartDnsResolverError(`The URL \"${url}\" is not a valid URL.`);\n }\n const hostname = parsedUrl.hostname;\n const address = await this.resolveAddress(hostname);\n return {\n address,\n hostname,\n urlReplaced: url.replace(hostname, address),\n };\n }\n /**\n * Manually sets DNS servers.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param servers Array of DNS server IP addresses.\n */\n setServers(servers) {\n (0, promises_1.setServers)(servers);\n }\n async resolveAddress(hostname) {\n const now = Date.now();\n const entry = this.cache.get(hostname);\n if (entry && entry.expiresAt > now) {\n this.counters.hits++;\n this.emit();\n return entry.address;\n }\n if (entry && this.swr) {\n this.counters.hits++;\n this.counters.revalidations++;\n this.revalidate(hostname);\n this.emit();\n return entry.address;\n }\n const negativeUntil = this.negative.get(hostname);\n if (negativeUntil !== undefined && negativeUntil > now) {\n this.counters.errors++;\n this.emit();\n throw new SmartDnsResolverError(`A recent lookup for \"${hostname}\" failed; retrying is rate limited by the negative cache.`);\n }\n this.counters.misses++;\n return this.fetchAddress(hostname).finally(() => {\n this.emit();\n });\n }\n fetchAddress(hostname) {\n let pending = this.inflight.get(hostname);\n if (!pending) {\n pending = this.doResolve(hostname);\n this.inflight.set(hostname, pending);\n pending.then(() => undefined, () => undefined).finally(() => {\n this.inflight.delete(hostname);\n });\n }\n return pending;\n }\n revalidate(hostname) {\n void this.fetchAddress(hostname);\n }\n async doResolve(hostname) {\n const startedAt = Date.now();\n try {\n const resolver = new promises_1.Resolver();\n const records = this.family === 'ipv6'\n ? await resolver.resolve6(hostname, { ttl: true })\n : await resolver.resolve4(hostname, { ttl: true });\n const [record] = records;\n if (!record) {\n throw new Error(`No ${this.family} records found for \"${hostname}\".`);\n }\n const rawTtl = record.ttl > 0 ? record.ttl * 1000 : this.ttl;\n const recordTtl = Math.min(Math.max(rawTtl, this.minTtl), this.maxTtl);\n this.cache.set(hostname, {\n address: record.address,\n expiresAt: Date.now() + recordTtl,\n });\n this.negative.delete(hostname);\n return record.address;\n }\n catch (e) {\n this.counters.errors++;\n this.negative.set(hostname, Date.now() + this.negativeTtl);\n throw e;\n }\n finally {\n this.counters.resolutions++;\n this.counters.totalResolveMs += Date.now() - startedAt;\n }\n }\n emit() {\n this.onStats?.(this.stats);\n }\n}\nexports.SmartDns = SmartDns;\n"],
5
+ "mappings": "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",
6
6
  "names": ["promises_1", "DnsProvider", "SmartDnsProviderError", "SmartDnsResolverError", "LruCache", "maxEntries", "hostname", "entry", "oldest", "SmartDnsInstance", "SmartDns", "_SmartDns", "dnsProvider", "resultOrder", "ttl", "options", "url", "parsedUrl", "address", "servers", "now", "negativeUntil", "pending", "startedAt", "resolver", "records", "record", "rawTtl", "recordTtl", "e"]
7
7
  }
@@ -76,9 +76,15 @@ export interface SmartDnsStats {
76
76
  * @enum {number}
77
77
  */
78
78
  export declare enum DnsProvider {
79
- CloudFlare = 0,
80
- Google = 1,
81
- OpenDNS = 2
79
+ AdGuard = 0,
80
+ CloudFlare = 1,
81
+ Comodo = 2,
82
+ DnsWatch = 3,
83
+ Google = 4,
84
+ OpenDNS = 5,
85
+ Quad9 = 6,
86
+ Verisign = 7,
87
+ Yandex = 8
82
88
  }
83
89
  /**
84
90
  * Error class for DNS provider-related errors.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/dist/esm/index.js CHANGED
@@ -11,9 +11,15 @@ import { Resolver, setDefaultResultOrder, setServers } from 'node:dns/promises';
11
11
  */
12
12
  export var DnsProvider;
13
13
  (function (DnsProvider) {
14
- DnsProvider[DnsProvider["CloudFlare"] = 0] = "CloudFlare";
15
- DnsProvider[DnsProvider["Google"] = 1] = "Google";
16
- DnsProvider[DnsProvider["OpenDNS"] = 2] = "OpenDNS";
14
+ DnsProvider[DnsProvider["AdGuard"] = 0] = "AdGuard";
15
+ DnsProvider[DnsProvider["CloudFlare"] = 1] = "CloudFlare";
16
+ DnsProvider[DnsProvider["Comodo"] = 2] = "Comodo";
17
+ DnsProvider[DnsProvider["DnsWatch"] = 3] = "DnsWatch";
18
+ DnsProvider[DnsProvider["Google"] = 4] = "Google";
19
+ DnsProvider[DnsProvider["OpenDNS"] = 5] = "OpenDNS";
20
+ DnsProvider[DnsProvider["Quad9"] = 6] = "Quad9";
21
+ DnsProvider[DnsProvider["Verisign"] = 7] = "Verisign";
22
+ DnsProvider[DnsProvider["Yandex"] = 8] = "Yandex";
17
23
  })(DnsProvider || (DnsProvider = {}));
18
24
  /**
19
25
  * Error class for DNS provider-related errors.
@@ -151,12 +157,30 @@ export class SmartDns {
151
157
  */
152
158
  setProvider(dnsProvider) {
153
159
  switch (dnsProvider) {
160
+ case DnsProvider.AdGuard:
161
+ setServers([
162
+ '94.140.14.14',
163
+ '94.140.15.15',
164
+ ]);
165
+ break;
154
166
  case DnsProvider.CloudFlare:
155
167
  setServers([
156
168
  '1.1.1.1',
157
169
  '1.0.0.1',
158
170
  ]);
159
171
  break;
172
+ case DnsProvider.Comodo:
173
+ setServers([
174
+ '8.26.56.26',
175
+ '8.20.247.20',
176
+ ]);
177
+ break;
178
+ case DnsProvider.DnsWatch:
179
+ setServers([
180
+ '84.200.69.80',
181
+ '84.200.70.40',
182
+ ]);
183
+ break;
160
184
  case DnsProvider.Google:
161
185
  setServers([
162
186
  '8.8.8.8',
@@ -169,6 +193,24 @@ export class SmartDns {
169
193
  '208.67.220.220',
170
194
  ]);
171
195
  break;
196
+ case DnsProvider.Quad9:
197
+ setServers([
198
+ '9.9.9.9',
199
+ '149.112.112.112',
200
+ ]);
201
+ break;
202
+ case DnsProvider.Verisign:
203
+ setServers([
204
+ '64.6.64.6',
205
+ '64.6.65.6',
206
+ ]);
207
+ break;
208
+ case DnsProvider.Yandex:
209
+ setServers([
210
+ '77.88.8.8',
211
+ '77.88.8.1',
212
+ ]);
213
+ break;
172
214
  default:
173
215
  throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the "setServers" method to manually set the DNS server IP addresses.`);
174
216
  }
@@ -1,2 +1,2 @@
1
- import{Resolver as w,setDefaultResultOrder as g,setServers as o}from"node:dns/promises";var a;(function(r){r[r.CloudFlare=0]="CloudFlare",r[r.Google=1]="Google",r[r.OpenDNS=2]="OpenDNS"})(a||(a={}));var c=class extends Error{},l=class extends Error{},d=class{maxEntries;entries=new Map;constructor(t){this.maxEntries=t}get(t){let e=this.entries.get(t);if(e)return this.entries.delete(t),this.entries.set(t,e),e}set(t,e){if(this.entries.delete(t),this.entries.set(t,e),this.entries.size>this.maxEntries){let s=this.entries.keys().next().value;s!==void 0&&this.entries.delete(s)}}},h,u=class r{ttl;cache;inflight=new Map;negative=new Map;swr;negativeTtl;minTtl;maxTtl;family;onStats;counters={errors:0,hits:0,misses:0,resolutions:0,revalidations:0,totalResolveMs:0};constructor(t,e="ipv4first",s=36e5,i={}){this.ttl=s,this.swr=i.swr??!1,this.negativeTtl=i.negativeTtl??3e4,this.minTtl=Math.max(i.minTtl??1e3,1),this.maxTtl=Math.max(i.maxTtl??36e5,this.minTtl),this.family=i.family??"ipv4",this.onStats=i.onStats,this.cache=new d(100),t&&this.setProvider(t),g(e)}static factory(t,e,s,i){return h||(h=new r(t,e,s,i)),h}get stats(){return{avgResolveMs:this.counters.resolutions>0?this.counters.totalResolveMs/this.counters.resolutions:0,errors:this.counters.errors,hits:this.counters.hits,misses:this.counters.misses,revalidations:this.counters.revalidations}}setProvider(t){switch(t){case a.CloudFlare:o(["1.1.1.1","1.0.0.1"]);break;case a.Google:o(["8.8.8.8","8.8.4.4"]);break;case a.OpenDNS:o(["208.67.222.222","208.67.220.220"]);break;default:throw new c(`Unsupported DNS provider: ${t}. You can use the "setServers" method to manually set the DNS server IP addresses.`)}}async resolver(t){if(!/^https?:\/\//.test(t))throw new l("The URL must start with http/https.");let e;try{e=new URL(t)}catch{throw new l(`The URL "${t}" is not a valid URL.`)}let s=e.hostname,i=await this.resolveAddress(s);return{address:i,hostname:s,urlReplaced:t.replace(s,i)}}setServers(t){o(t)}async resolveAddress(t){let e=Date.now(),s=this.cache.get(t);if(s&&s.expiresAt>e)return this.counters.hits++,this.emit(),s.address;if(s&&this.swr)return this.counters.hits++,this.counters.revalidations++,this.revalidate(t),this.emit(),s.address;let i=this.negative.get(t);if(i!==void 0&&i>e)throw this.counters.errors++,this.emit(),new l(`A recent lookup for "${t}" failed; retrying is rate limited by the negative cache.`);return this.counters.misses++,this.fetchAddress(t).finally(()=>{this.emit()})}fetchAddress(t){let e=this.inflight.get(t);return e||(e=this.doResolve(t),this.inflight.set(t,e),e.then(()=>{},()=>{}).finally(()=>{this.inflight.delete(t)})),e}revalidate(t){this.fetchAddress(t)}async doResolve(t){let e=Date.now();try{let s=new w,i=this.family==="ipv6"?await s.resolve6(t,{ttl:!0}):await s.resolve4(t,{ttl:!0}),[n]=i;if(!n)throw new Error(`No ${this.family} records found for "${t}".`);let f=n.ttl>0?n.ttl*1e3:this.ttl,v=Math.min(Math.max(f,this.minTtl),this.maxTtl);return this.cache.set(t,{address:n.address,expiresAt:Date.now()+v}),this.negative.delete(t),n.address}catch(s){throw this.counters.errors++,this.negative.set(t,Date.now()+this.negativeTtl),s}finally{this.counters.resolutions++,this.counters.totalResolveMs+=Date.now()-e}}emit(){this.onStats?.(this.stats)}};export{a as DnsProvider,u as SmartDns,c as SmartDnsProviderError,l as SmartDnsResolverError};
1
+ import{Resolver as g,setDefaultResultOrder as m,setServers as n}from"node:dns/promises";var a;(function(e){e[e.AdGuard=0]="AdGuard",e[e.CloudFlare=1]="CloudFlare",e[e.Comodo=2]="Comodo",e[e.DnsWatch=3]="DnsWatch",e[e.Google=4]="Google",e[e.OpenDNS=5]="OpenDNS",e[e.Quad9=6]="Quad9",e[e.Verisign=7]="Verisign",e[e.Yandex=8]="Yandex"})(a||(a={}));var c=class extends Error{},h=class extends Error{},d=class{maxEntries;entries=new Map;constructor(t){this.maxEntries=t}get(t){let s=this.entries.get(t);if(s)return this.entries.delete(t),this.entries.set(t,s),s}set(t,s){if(this.entries.delete(t),this.entries.set(t,s),this.entries.size>this.maxEntries){let i=this.entries.keys().next().value;i!==void 0&&this.entries.delete(i)}}},o,u=class e{ttl;cache;inflight=new Map;negative=new Map;swr;negativeTtl;minTtl;maxTtl;family;onStats;counters={errors:0,hits:0,misses:0,resolutions:0,revalidations:0,totalResolveMs:0};constructor(t,s="ipv4first",i=36e5,r={}){this.ttl=i,this.swr=r.swr??!1,this.negativeTtl=r.negativeTtl??3e4,this.minTtl=Math.max(r.minTtl??1e3,1),this.maxTtl=Math.max(r.maxTtl??36e5,this.minTtl),this.family=r.family??"ipv4",this.onStats=r.onStats,this.cache=new d(100),t&&this.setProvider(t),m(s)}static factory(t,s,i,r){return o||(o=new e(t,s,i,r)),o}get stats(){return{avgResolveMs:this.counters.resolutions>0?this.counters.totalResolveMs/this.counters.resolutions:0,errors:this.counters.errors,hits:this.counters.hits,misses:this.counters.misses,revalidations:this.counters.revalidations}}setProvider(t){switch(t){case a.AdGuard:n(["94.140.14.14","94.140.15.15"]);break;case a.CloudFlare:n(["1.1.1.1","1.0.0.1"]);break;case a.Comodo:n(["8.26.56.26","8.20.247.20"]);break;case a.DnsWatch:n(["84.200.69.80","84.200.70.40"]);break;case a.Google:n(["8.8.8.8","8.8.4.4"]);break;case a.OpenDNS:n(["208.67.222.222","208.67.220.220"]);break;case a.Quad9:n(["9.9.9.9","149.112.112.112"]);break;case a.Verisign:n(["64.6.64.6","64.6.65.6"]);break;case a.Yandex:n(["77.88.8.8","77.88.8.1"]);break;default:throw new c(`Unsupported DNS provider: ${t}. You can use the "setServers" method to manually set the DNS server IP addresses.`)}}async resolver(t){if(!/^https?:\/\//.test(t))throw new h("The URL must start with http/https.");let s;try{s=new URL(t)}catch{throw new h(`The URL "${t}" is not a valid URL.`)}let i=s.hostname,r=await this.resolveAddress(i);return{address:r,hostname:i,urlReplaced:t.replace(i,r)}}setServers(t){n(t)}async resolveAddress(t){let s=Date.now(),i=this.cache.get(t);if(i&&i.expiresAt>s)return this.counters.hits++,this.emit(),i.address;if(i&&this.swr)return this.counters.hits++,this.counters.revalidations++,this.revalidate(t),this.emit(),i.address;let r=this.negative.get(t);if(r!==void 0&&r>s)throw this.counters.errors++,this.emit(),new h(`A recent lookup for "${t}" failed; retrying is rate limited by the negative cache.`);return this.counters.misses++,this.fetchAddress(t).finally(()=>{this.emit()})}fetchAddress(t){let s=this.inflight.get(t);return s||(s=this.doResolve(t),this.inflight.set(t,s),s.then(()=>{},()=>{}).finally(()=>{this.inflight.delete(t)})),s}revalidate(t){this.fetchAddress(t)}async doResolve(t){let s=Date.now();try{let i=new g,r=this.family==="ipv6"?await i.resolve6(t,{ttl:!0}):await i.resolve4(t,{ttl:!0}),[l]=r;if(!l)throw new Error(`No ${this.family} records found for "${t}".`);let f=l.ttl>0?l.ttl*1e3:this.ttl,w=Math.min(Math.max(f,this.minTtl),this.maxTtl);return this.cache.set(t,{address:l.address,expiresAt:Date.now()+w}),this.negative.delete(t),l.address}catch(i){throw this.counters.errors++,this.negative.set(t,Date.now()+this.negativeTtl),i}finally{this.counters.resolutions++,this.counters.totalResolveMs+=Date.now()-s}}emit(){this.onStats?.(this.stats)}};export{a as DnsProvider,u as SmartDns,c as SmartDnsProviderError,h as SmartDnsResolverError};
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["index.js"],
4
- "sourcesContent": ["/*\n * Dario Casertano <dario@casertano.name>\n * Copyright (c) 2026 Casertano Dario \u2013 All rights reserved.\n * MIT\n */\nimport { Resolver, setDefaultResultOrder, setServers } from 'node:dns/promises';\n/**\n * Enum for built-in DNS providers.\n * @readonly\n * @enum {number}\n */\nexport var DnsProvider;\n(function (DnsProvider) {\n DnsProvider[DnsProvider[\"CloudFlare\"] = 0] = \"CloudFlare\";\n DnsProvider[DnsProvider[\"Google\"] = 1] = \"Google\";\n DnsProvider[DnsProvider[\"OpenDNS\"] = 2] = \"OpenDNS\";\n})(DnsProvider || (DnsProvider = {}));\n/**\n * Error class for DNS provider-related errors.\n * @extends {Error}\n */\nexport class SmartDnsProviderError extends Error {\n}\n/**\n * Error class for DNS resolution-related errors.\n * @extends {Error}\n */\nexport class SmartDnsResolverError extends Error {\n}\n/**\n * Minimal zero-dependency LRU cache with expiry support.\n */\nclass LruCache {\n maxEntries;\n entries = new Map();\n constructor(maxEntries) {\n this.maxEntries = maxEntries;\n }\n get(hostname) {\n const entry = this.entries.get(hostname);\n if (!entry) {\n return undefined;\n }\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n return entry;\n }\n set(hostname, entry) {\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n if (this.entries.size > this.maxEntries) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) {\n this.entries.delete(oldest);\n }\n }\n }\n}\nlet SmartDnsInstance;\n/**\n * SmartDns class for managing DNS resolution with caching and configurable DNS providers.\n *\n * Configuration is applied to Node's process-global DNS system (`node:dns`):\n * `setProvider` and `setServers` replace the resolver servers for the whole\n * process, and `resultOrder` calls `dns.setDefaultResultOrder`. Every HTTP\n * client in the application is affected by (and benefits from) this setup.\n * Instantiate and configure SmartDns as early as possible in the application\n * lifecycle, ideally once.\n */\nexport class SmartDns {\n ttl;\n /**\n * Cache for hostname-IP mappings.\n */\n cache;\n inflight = new Map();\n negative = new Map();\n swr;\n negativeTtl;\n minTtl;\n maxTtl;\n family;\n onStats;\n counters = {\n errors: 0,\n hits: 0,\n misses: 0,\n resolutions: 0,\n revalidations: 0,\n totalResolveMs: 0,\n };\n /**\n * Creates an instance of SmartDns.\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder='ipv4first'] Order of DNS resolution results.\n * @param [ttl=3600000] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n */\n constructor(dnsProvider, resultOrder = 'ipv4first', ttl = 3_600_000, options = {}) {\n this.ttl = ttl;\n this.swr = options.swr ?? false;\n this.negativeTtl = options.negativeTtl ?? 30_000;\n this.minTtl = Math.max(options.minTtl ?? 1_000, 1);\n this.maxTtl = Math.max(options.maxTtl ?? 3_600_000, this.minTtl);\n this.family = options.family ?? 'ipv4';\n this.onStats = options.onStats;\n this.cache = new LruCache(100);\n if (dnsProvider) {\n this.setProvider(dnsProvider);\n }\n setDefaultResultOrder(resultOrder);\n }\n /**\n * Creates or retrieves a singleton instance of SmartDns.\n *\n * As in v1, configuration passed after the first call is ignored because the\n * singleton has already been created.\n *\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder] Order of DNS resolution results.\n * @param [ttl] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n * @returns The singleton SmartDns instance.\n */\n static factory(dnsProvider, resultOrder, ttl, options) {\n if (!SmartDnsInstance) {\n SmartDnsInstance = new SmartDns(dnsProvider, resultOrder, ttl, options);\n }\n return SmartDnsInstance;\n }\n /**\n * Current lookup statistics for this instance.\n */\n get stats() {\n return {\n avgResolveMs: this.counters.resolutions > 0\n ? this.counters.totalResolveMs / this.counters.resolutions\n : 0,\n errors: this.counters.errors,\n hits: this.counters.hits,\n misses: this.counters.misses,\n revalidations: this.counters.revalidations,\n };\n }\n /**\n * Sets the DNS servers by the provider.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param dnsProvider The DNS provider to use.\n * @throws {SmartDnsProviderError} If the DNS provider is unsupported.\n */\n setProvider(dnsProvider) {\n switch (dnsProvider) {\n case DnsProvider.CloudFlare:\n setServers([\n '1.1.1.1',\n '1.0.0.1',\n ]);\n break;\n case DnsProvider.Google:\n setServers([\n '8.8.8.8',\n '8.8.4.4',\n ]);\n break;\n case DnsProvider.OpenDNS:\n setServers([\n '208.67.222.222',\n '208.67.220.220',\n ]);\n break;\n default:\n throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the \"setServers\" method to manually set the DNS server IP addresses.`);\n }\n }\n /**\n * Resolves a URL and retrieves its IP address, hostname, and updated URL.\n * @async\n * @param url The URL to resolve (must start with http/https).\n * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.\n * @throws {SmartDnsResolverError} If the URL is invalid or the lookup was recently failing.\n * @throws {Error} If the resolution fails.\n */\n async resolver(url) {\n if (!/^https?:\\/\\//.test(url)) {\n throw new SmartDnsResolverError(`The URL must start with http/https.`);\n }\n let parsedUrl;\n try {\n parsedUrl = new URL(url);\n }\n catch {\n throw new SmartDnsResolverError(`The URL \"${url}\" is not a valid URL.`);\n }\n const hostname = parsedUrl.hostname;\n const address = await this.resolveAddress(hostname);\n return {\n address,\n hostname,\n urlReplaced: url.replace(hostname, address),\n };\n }\n /**\n * Manually sets DNS servers.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param servers Array of DNS server IP addresses.\n */\n setServers(servers) {\n setServers(servers);\n }\n async resolveAddress(hostname) {\n const now = Date.now();\n const entry = this.cache.get(hostname);\n if (entry && entry.expiresAt > now) {\n this.counters.hits++;\n this.emit();\n return entry.address;\n }\n if (entry && this.swr) {\n this.counters.hits++;\n this.counters.revalidations++;\n this.revalidate(hostname);\n this.emit();\n return entry.address;\n }\n const negativeUntil = this.negative.get(hostname);\n if (negativeUntil !== undefined && negativeUntil > now) {\n this.counters.errors++;\n this.emit();\n throw new SmartDnsResolverError(`A recent lookup for \"${hostname}\" failed; retrying is rate limited by the negative cache.`);\n }\n this.counters.misses++;\n return this.fetchAddress(hostname).finally(() => {\n this.emit();\n });\n }\n fetchAddress(hostname) {\n let pending = this.inflight.get(hostname);\n if (!pending) {\n pending = this.doResolve(hostname);\n this.inflight.set(hostname, pending);\n pending.then(() => undefined, () => undefined).finally(() => {\n this.inflight.delete(hostname);\n });\n }\n return pending;\n }\n revalidate(hostname) {\n void this.fetchAddress(hostname);\n }\n async doResolve(hostname) {\n const startedAt = Date.now();\n try {\n const resolver = new Resolver();\n const records = this.family === 'ipv6'\n ? await resolver.resolve6(hostname, { ttl: true })\n : await resolver.resolve4(hostname, { ttl: true });\n const [record] = records;\n if (!record) {\n throw new Error(`No ${this.family} records found for \"${hostname}\".`);\n }\n const rawTtl = record.ttl > 0 ? record.ttl * 1000 : this.ttl;\n const recordTtl = Math.min(Math.max(rawTtl, this.minTtl), this.maxTtl);\n this.cache.set(hostname, {\n address: record.address,\n expiresAt: Date.now() + recordTtl,\n });\n this.negative.delete(hostname);\n return record.address;\n }\n catch (e) {\n this.counters.errors++;\n this.negative.set(hostname, Date.now() + this.negativeTtl);\n throw e;\n }\n finally {\n this.counters.resolutions++;\n this.counters.totalResolveMs += Date.now() - startedAt;\n }\n }\n emit() {\n this.onStats?.(this.stats);\n }\n}\n"],
5
- "mappings": "AAKA,OAAS,YAAAA,EAAU,yBAAAC,EAAuB,cAAAC,MAAkB,oBAMrD,IAAIC,GACV,SAAUA,EAAa,CACpBA,EAAYA,EAAY,WAAgB,CAAC,EAAI,aAC7CA,EAAYA,EAAY,OAAY,CAAC,EAAI,SACzCA,EAAYA,EAAY,QAAa,CAAC,EAAI,SAC9C,GAAGA,IAAgBA,EAAc,CAAC,EAAE,EAK7B,IAAMC,EAAN,cAAoC,KAAM,CACjD,EAKaC,EAAN,cAAoC,KAAM,CACjD,EAIMC,EAAN,KAAe,CACX,WACA,QAAU,IAAI,IACd,YAAYC,EAAY,CACpB,KAAK,WAAaA,CACtB,CACA,IAAIC,EAAU,CACV,IAAMC,EAAQ,KAAK,QAAQ,IAAID,CAAQ,EACvC,GAAKC,EAGL,YAAK,QAAQ,OAAOD,CAAQ,EAC5B,KAAK,QAAQ,IAAIA,EAAUC,CAAK,EACzBA,CACX,CACA,IAAID,EAAUC,EAAO,CAGjB,GAFA,KAAK,QAAQ,OAAOD,CAAQ,EAC5B,KAAK,QAAQ,IAAIA,EAAUC,CAAK,EAC5B,KAAK,QAAQ,KAAO,KAAK,WAAY,CACrC,IAAMC,EAAS,KAAK,QAAQ,KAAK,EAAE,KAAK,EAAE,MACtCA,IAAW,QACX,KAAK,QAAQ,OAAOA,CAAM,CAElC,CACJ,CACJ,EACIC,EAWSC,EAAN,MAAMC,CAAS,CAClB,IAIA,MACA,SAAW,IAAI,IACf,SAAW,IAAI,IACf,IACA,YACA,OACA,OACA,OACA,QACA,SAAW,CACP,OAAQ,EACR,KAAM,EACN,OAAQ,EACR,YAAa,EACb,cAAe,EACf,eAAgB,CACpB,EAQA,YAAYC,EAAaC,EAAc,YAAaC,EAAM,KAAWC,EAAU,CAAC,EAAG,CAC/E,KAAK,IAAMD,EACX,KAAK,IAAMC,EAAQ,KAAO,GAC1B,KAAK,YAAcA,EAAQ,aAAe,IAC1C,KAAK,OAAS,KAAK,IAAIA,EAAQ,QAAU,IAAO,CAAC,EACjD,KAAK,OAAS,KAAK,IAAIA,EAAQ,QAAU,KAAW,KAAK,MAAM,EAC/D,KAAK,OAASA,EAAQ,QAAU,OAChC,KAAK,QAAUA,EAAQ,QACvB,KAAK,MAAQ,IAAIX,EAAS,GAAG,EACzBQ,GACA,KAAK,YAAYA,CAAW,EAEhCb,EAAsBc,CAAW,CACrC,CAaA,OAAO,QAAQD,EAAaC,EAAaC,EAAKC,EAAS,CACnD,OAAKN,IACDA,EAAmB,IAAIE,EAASC,EAAaC,EAAaC,EAAKC,CAAO,GAEnEN,CACX,CAIA,IAAI,OAAQ,CACR,MAAO,CACH,aAAc,KAAK,SAAS,YAAc,EACpC,KAAK,SAAS,eAAiB,KAAK,SAAS,YAC7C,EACN,OAAQ,KAAK,SAAS,OACtB,KAAM,KAAK,SAAS,KACpB,OAAQ,KAAK,SAAS,OACtB,cAAe,KAAK,SAAS,aACjC,CACJ,CAQA,YAAYG,EAAa,CACrB,OAAQA,EAAa,CACjB,KAAKX,EAAY,WACbD,EAAW,CACP,UACA,SACJ,CAAC,EACD,MACJ,KAAKC,EAAY,OACbD,EAAW,CACP,UACA,SACJ,CAAC,EACD,MACJ,KAAKC,EAAY,QACbD,EAAW,CACP,iBACA,gBACJ,CAAC,EACD,MACJ,QACI,MAAM,IAAIE,EAAsB,6BAA6BU,CAAW,oFAAoF,CACpK,CACJ,CASA,MAAM,SAASI,EAAK,CAChB,GAAI,CAAC,eAAe,KAAKA,CAAG,EACxB,MAAM,IAAIb,EAAsB,qCAAqC,EAEzE,IAAIc,EACJ,GAAI,CACAA,EAAY,IAAI,IAAID,CAAG,CAC3B,MACM,CACF,MAAM,IAAIb,EAAsB,YAAYa,CAAG,uBAAuB,CAC1E,CACA,IAAMV,EAAWW,EAAU,SACrBC,EAAU,MAAM,KAAK,eAAeZ,CAAQ,EAClD,MAAO,CACH,QAAAY,EACA,SAAAZ,EACA,YAAaU,EAAI,QAAQV,EAAUY,CAAO,CAC9C,CACJ,CAOA,WAAWC,EAAS,CAChBnB,EAAWmB,CAAO,CACtB,CACA,MAAM,eAAeb,EAAU,CAC3B,IAAMc,EAAM,KAAK,IAAI,EACfb,EAAQ,KAAK,MAAM,IAAID,CAAQ,EACrC,GAAIC,GAASA,EAAM,UAAYa,EAC3B,YAAK,SAAS,OACd,KAAK,KAAK,EACHb,EAAM,QAEjB,GAAIA,GAAS,KAAK,IACd,YAAK,SAAS,OACd,KAAK,SAAS,gBACd,KAAK,WAAWD,CAAQ,EACxB,KAAK,KAAK,EACHC,EAAM,QAEjB,IAAMc,EAAgB,KAAK,SAAS,IAAIf,CAAQ,EAChD,GAAIe,IAAkB,QAAaA,EAAgBD,EAC/C,WAAK,SAAS,SACd,KAAK,KAAK,EACJ,IAAIjB,EAAsB,wBAAwBG,CAAQ,2DAA2D,EAE/H,YAAK,SAAS,SACP,KAAK,aAAaA,CAAQ,EAAE,QAAQ,IAAM,CAC7C,KAAK,KAAK,CACd,CAAC,CACL,CACA,aAAaA,EAAU,CACnB,IAAIgB,EAAU,KAAK,SAAS,IAAIhB,CAAQ,EACxC,OAAKgB,IACDA,EAAU,KAAK,UAAUhB,CAAQ,EACjC,KAAK,SAAS,IAAIA,EAAUgB,CAAO,EACnCA,EAAQ,KAAK,IAAG,GAAc,IAAG,EAAY,EAAE,QAAQ,IAAM,CACzD,KAAK,SAAS,OAAOhB,CAAQ,CACjC,CAAC,GAEEgB,CACX,CACA,WAAWhB,EAAU,CACZ,KAAK,aAAaA,CAAQ,CACnC,CACA,MAAM,UAAUA,EAAU,CACtB,IAAMiB,EAAY,KAAK,IAAI,EAC3B,GAAI,CACA,IAAMC,EAAW,IAAI1B,EACf2B,EAAU,KAAK,SAAW,OAC1B,MAAMD,EAAS,SAASlB,EAAU,CAAE,IAAK,EAAK,CAAC,EAC/C,MAAMkB,EAAS,SAASlB,EAAU,CAAE,IAAK,EAAK,CAAC,EAC/C,CAACoB,CAAM,EAAID,EACjB,GAAI,CAACC,EACD,MAAM,IAAI,MAAM,MAAM,KAAK,MAAM,uBAAuBpB,CAAQ,IAAI,EAExE,IAAMqB,EAASD,EAAO,IAAM,EAAIA,EAAO,IAAM,IAAO,KAAK,IACnDE,EAAY,KAAK,IAAI,KAAK,IAAID,EAAQ,KAAK,MAAM,EAAG,KAAK,MAAM,EACrE,YAAK,MAAM,IAAIrB,EAAU,CACrB,QAASoB,EAAO,QAChB,UAAW,KAAK,IAAI,EAAIE,CAC5B,CAAC,EACD,KAAK,SAAS,OAAOtB,CAAQ,EACtBoB,EAAO,OAClB,OACOG,EAAG,CACN,WAAK,SAAS,SACd,KAAK,SAAS,IAAIvB,EAAU,KAAK,IAAI,EAAI,KAAK,WAAW,EACnDuB,CACV,QACA,CACI,KAAK,SAAS,cACd,KAAK,SAAS,gBAAkB,KAAK,IAAI,EAAIN,CACjD,CACJ,CACA,MAAO,CACH,KAAK,UAAU,KAAK,KAAK,CAC7B,CACJ",
4
+ "sourcesContent": ["/*\n * Dario Casertano <dario@casertano.name>\n * Copyright (c) 2026 Casertano Dario \u2013 All rights reserved.\n * MIT\n */\nimport { Resolver, setDefaultResultOrder, setServers } from 'node:dns/promises';\n/**\n * Enum for built-in DNS providers.\n * @readonly\n * @enum {number}\n */\nexport var DnsProvider;\n(function (DnsProvider) {\n DnsProvider[DnsProvider[\"AdGuard\"] = 0] = \"AdGuard\";\n DnsProvider[DnsProvider[\"CloudFlare\"] = 1] = \"CloudFlare\";\n DnsProvider[DnsProvider[\"Comodo\"] = 2] = \"Comodo\";\n DnsProvider[DnsProvider[\"DnsWatch\"] = 3] = \"DnsWatch\";\n DnsProvider[DnsProvider[\"Google\"] = 4] = \"Google\";\n DnsProvider[DnsProvider[\"OpenDNS\"] = 5] = \"OpenDNS\";\n DnsProvider[DnsProvider[\"Quad9\"] = 6] = \"Quad9\";\n DnsProvider[DnsProvider[\"Verisign\"] = 7] = \"Verisign\";\n DnsProvider[DnsProvider[\"Yandex\"] = 8] = \"Yandex\";\n})(DnsProvider || (DnsProvider = {}));\n/**\n * Error class for DNS provider-related errors.\n * @extends {Error}\n */\nexport class SmartDnsProviderError extends Error {\n}\n/**\n * Error class for DNS resolution-related errors.\n * @extends {Error}\n */\nexport class SmartDnsResolverError extends Error {\n}\n/**\n * Minimal zero-dependency LRU cache with expiry support.\n */\nclass LruCache {\n maxEntries;\n entries = new Map();\n constructor(maxEntries) {\n this.maxEntries = maxEntries;\n }\n get(hostname) {\n const entry = this.entries.get(hostname);\n if (!entry) {\n return undefined;\n }\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n return entry;\n }\n set(hostname, entry) {\n this.entries.delete(hostname);\n this.entries.set(hostname, entry);\n if (this.entries.size > this.maxEntries) {\n const oldest = this.entries.keys().next().value;\n if (oldest !== undefined) {\n this.entries.delete(oldest);\n }\n }\n }\n}\nlet SmartDnsInstance;\n/**\n * SmartDns class for managing DNS resolution with caching and configurable DNS providers.\n *\n * Configuration is applied to Node's process-global DNS system (`node:dns`):\n * `setProvider` and `setServers` replace the resolver servers for the whole\n * process, and `resultOrder` calls `dns.setDefaultResultOrder`. Every HTTP\n * client in the application is affected by (and benefits from) this setup.\n * Instantiate and configure SmartDns as early as possible in the application\n * lifecycle, ideally once.\n */\nexport class SmartDns {\n ttl;\n /**\n * Cache for hostname-IP mappings.\n */\n cache;\n inflight = new Map();\n negative = new Map();\n swr;\n negativeTtl;\n minTtl;\n maxTtl;\n family;\n onStats;\n counters = {\n errors: 0,\n hits: 0,\n misses: 0,\n resolutions: 0,\n revalidations: 0,\n totalResolveMs: 0,\n };\n /**\n * Creates an instance of SmartDns.\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder='ipv4first'] Order of DNS resolution results.\n * @param [ttl=3600000] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n */\n constructor(dnsProvider, resultOrder = 'ipv4first', ttl = 3_600_000, options = {}) {\n this.ttl = ttl;\n this.swr = options.swr ?? false;\n this.negativeTtl = options.negativeTtl ?? 30_000;\n this.minTtl = Math.max(options.minTtl ?? 1_000, 1);\n this.maxTtl = Math.max(options.maxTtl ?? 3_600_000, this.minTtl);\n this.family = options.family ?? 'ipv4';\n this.onStats = options.onStats;\n this.cache = new LruCache(100);\n if (dnsProvider) {\n this.setProvider(dnsProvider);\n }\n setDefaultResultOrder(resultOrder);\n }\n /**\n * Creates or retrieves a singleton instance of SmartDns.\n *\n * As in v1, configuration passed after the first call is ignored because the\n * singleton has already been created.\n *\n * @param [dnsProvider] Optional DNS provider to use.\n * @param [resultOrder] Order of DNS resolution results.\n * @param [ttl] Fallback time-to-live for cached entries in milliseconds.\n * @param [options] Advanced cache and resolver options.\n * @returns The singleton SmartDns instance.\n */\n static factory(dnsProvider, resultOrder, ttl, options) {\n if (!SmartDnsInstance) {\n SmartDnsInstance = new SmartDns(dnsProvider, resultOrder, ttl, options);\n }\n return SmartDnsInstance;\n }\n /**\n * Current lookup statistics for this instance.\n */\n get stats() {\n return {\n avgResolveMs: this.counters.resolutions > 0\n ? this.counters.totalResolveMs / this.counters.resolutions\n : 0,\n errors: this.counters.errors,\n hits: this.counters.hits,\n misses: this.counters.misses,\n revalidations: this.counters.revalidations,\n };\n }\n /**\n * Sets the DNS servers by the provider.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param dnsProvider The DNS provider to use.\n * @throws {SmartDnsProviderError} If the DNS provider is unsupported.\n */\n setProvider(dnsProvider) {\n switch (dnsProvider) {\n case DnsProvider.AdGuard:\n setServers([\n '94.140.14.14',\n '94.140.15.15',\n ]);\n break;\n case DnsProvider.CloudFlare:\n setServers([\n '1.1.1.1',\n '1.0.0.1',\n ]);\n break;\n case DnsProvider.Comodo:\n setServers([\n '8.26.56.26',\n '8.20.247.20',\n ]);\n break;\n case DnsProvider.DnsWatch:\n setServers([\n '84.200.69.80',\n '84.200.70.40',\n ]);\n break;\n case DnsProvider.Google:\n setServers([\n '8.8.8.8',\n '8.8.4.4',\n ]);\n break;\n case DnsProvider.OpenDNS:\n setServers([\n '208.67.222.222',\n '208.67.220.220',\n ]);\n break;\n case DnsProvider.Quad9:\n setServers([\n '9.9.9.9',\n '149.112.112.112',\n ]);\n break;\n case DnsProvider.Verisign:\n setServers([\n '64.6.64.6',\n '64.6.65.6',\n ]);\n break;\n case DnsProvider.Yandex:\n setServers([\n '77.88.8.8',\n '77.88.8.1',\n ]);\n break;\n default:\n throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the \"setServers\" method to manually set the DNS server IP addresses.`);\n }\n }\n /**\n * Resolves a URL and retrieves its IP address, hostname, and updated URL.\n * @async\n * @param url The URL to resolve (must start with http/https).\n * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.\n * @throws {SmartDnsResolverError} If the URL is invalid or the lookup was recently failing.\n * @throws {Error} If the resolution fails.\n */\n async resolver(url) {\n if (!/^https?:\\/\\//.test(url)) {\n throw new SmartDnsResolverError(`The URL must start with http/https.`);\n }\n let parsedUrl;\n try {\n parsedUrl = new URL(url);\n }\n catch {\n throw new SmartDnsResolverError(`The URL \"${url}\" is not a valid URL.`);\n }\n const hostname = parsedUrl.hostname;\n const address = await this.resolveAddress(hostname);\n return {\n address,\n hostname,\n urlReplaced: url.replace(hostname, address),\n };\n }\n /**\n * Manually sets DNS servers.\n *\n * Note: this mutates the process-global DNS configuration via `node:dns`.\n * @param servers Array of DNS server IP addresses.\n */\n setServers(servers) {\n setServers(servers);\n }\n async resolveAddress(hostname) {\n const now = Date.now();\n const entry = this.cache.get(hostname);\n if (entry && entry.expiresAt > now) {\n this.counters.hits++;\n this.emit();\n return entry.address;\n }\n if (entry && this.swr) {\n this.counters.hits++;\n this.counters.revalidations++;\n this.revalidate(hostname);\n this.emit();\n return entry.address;\n }\n const negativeUntil = this.negative.get(hostname);\n if (negativeUntil !== undefined && negativeUntil > now) {\n this.counters.errors++;\n this.emit();\n throw new SmartDnsResolverError(`A recent lookup for \"${hostname}\" failed; retrying is rate limited by the negative cache.`);\n }\n this.counters.misses++;\n return this.fetchAddress(hostname).finally(() => {\n this.emit();\n });\n }\n fetchAddress(hostname) {\n let pending = this.inflight.get(hostname);\n if (!pending) {\n pending = this.doResolve(hostname);\n this.inflight.set(hostname, pending);\n pending.then(() => undefined, () => undefined).finally(() => {\n this.inflight.delete(hostname);\n });\n }\n return pending;\n }\n revalidate(hostname) {\n void this.fetchAddress(hostname);\n }\n async doResolve(hostname) {\n const startedAt = Date.now();\n try {\n const resolver = new Resolver();\n const records = this.family === 'ipv6'\n ? await resolver.resolve6(hostname, { ttl: true })\n : await resolver.resolve4(hostname, { ttl: true });\n const [record] = records;\n if (!record) {\n throw new Error(`No ${this.family} records found for \"${hostname}\".`);\n }\n const rawTtl = record.ttl > 0 ? record.ttl * 1000 : this.ttl;\n const recordTtl = Math.min(Math.max(rawTtl, this.minTtl), this.maxTtl);\n this.cache.set(hostname, {\n address: record.address,\n expiresAt: Date.now() + recordTtl,\n });\n this.negative.delete(hostname);\n return record.address;\n }\n catch (e) {\n this.counters.errors++;\n this.negative.set(hostname, Date.now() + this.negativeTtl);\n throw e;\n }\n finally {\n this.counters.resolutions++;\n this.counters.totalResolveMs += Date.now() - startedAt;\n }\n }\n emit() {\n this.onStats?.(this.stats);\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["Resolver", "setDefaultResultOrder", "setServers", "DnsProvider", "SmartDnsProviderError", "SmartDnsResolverError", "LruCache", "maxEntries", "hostname", "entry", "oldest", "SmartDnsInstance", "SmartDns", "_SmartDns", "dnsProvider", "resultOrder", "ttl", "options", "url", "parsedUrl", "address", "servers", "now", "negativeUntil", "pending", "startedAt", "resolver", "records", "record", "rawTtl", "recordTtl", "e"]
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "author": {
3
3
  "email": "dario@casertano.name",
4
- "name": "Dario Casertano (DarCas)"
4
+ "name": "Dario Casertano (DarCas)",
5
+ "url": "https://dariocasertano.com"
5
6
  },
6
7
  "bugs": {
7
8
  "url": "https://github.com/DarCas/smart-dns-promises/issues"
@@ -40,18 +41,23 @@
40
41
  "files": [
41
42
  "dist"
42
43
  ],
43
- "homepage": "https://github.com/DarCas/smart-dns-promises",
44
+ "homepage": "https://smartdns.os.darcas.app",
45
+ "description": "Zero-dependency DNS resolver for Node.js with TTL-aware caching, request deduplication and stale-while-revalidate — 9 configurable providers, built for fetch and axios.",
44
46
  "keywords": [
45
47
  "dns",
48
+ "dns-resolver",
46
49
  "dns-cache",
47
- "dns-provider",
48
- "node",
49
- "node-20",
50
- "node-22",
51
- "resolver",
52
- "smart-dns",
53
- "performance",
54
- "speed"
50
+ "dns-lookup",
51
+ "nodejs",
52
+ "typescript",
53
+ "axios",
54
+ "fetch",
55
+ "caching",
56
+ "ttl",
57
+ "stale-while-revalidate",
58
+ "zero-dependency",
59
+ "deduplication",
60
+ "performance"
55
61
  ],
56
62
  "license": "MIT",
57
63
  "main": "./dist/commonjs/index.js",
@@ -73,5 +79,5 @@
73
79
  },
74
80
  "type": "module",
75
81
  "types": "./dist/commonjs/index.d.ts",
76
- "version": "1.1.1"
82
+ "version": "1.2.0"
77
83
  }