@darcas/smart-dns-promises 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Dario Casertano <dario@casertano.name>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # SmartDns
2
+
3
+ ![NPM Last Update](https://img.shields.io/npm/last-update/%40darcas%2Fsmart-dns-promises)
4
+ ![NPM Version](https://img.shields.io/npm/v/%40darcas%2Fsmart-dns-promises)
5
+ ![NPM Downloads](https://img.shields.io/npm/dw/%40darcas%2Fsmart-dns-promises)
6
+ ![NPM License](https://img.shields.io/npm/l/%40darcas%2Fsmart-dns-promises)
7
+
8
+ A simple and efficient DNS resolver with caching and configurable DNS providers for Node.js 20 and 22 or above.
9
+
10
+ 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.
11
+
12
+ ## Features
13
+
14
+ - DNS resolution with caching for faster lookups.
15
+ - Supports configurable DNS providers: CloudFlare, Google, and OpenDNS.
16
+ - Allows custom result order for DNS resolutions: IPv4 first, IPv6 first, or verbatim.
17
+ - Singleton pattern to ensure only one instance of the resolver is used.
18
+ - Manual configuration of DNS server addresses.
19
+
20
+ ## Installation
21
+
22
+ To install the `SmartDns` in your project, run the following npm command:
23
+
24
+ ```bash
25
+ npm install @darcas/smart-dns-promises
26
+ ```
27
+
28
+ Or, if you're using yarn:
29
+
30
+ ```bash
31
+ yarn add @darcas/smart-dns-promises
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ > In environments such as APIs, it is recommended to call `factory` as early as possible in the application lifecycle to benefit from Node.js's DNS system configuration.
37
+
38
+ ### Creating an instance
39
+
40
+ You can create or retrieve a singleton instance of the `SmartDns` class using the `factory` method. This method also allows you to configure the DNS provider, result order, and cache time-to-live (TTL).
41
+
42
+ ```js
43
+ import { SmartDns } from '@darcas/smart-dns-promises'
44
+
45
+ // Create or get the singleton instance
46
+ const dns = SmartDns.factory();
47
+
48
+ // Optionally, configure DNS provider and result order
49
+ const dnsWithConfig = SmartDns.factory('Google', 'ipv4first', 600000);
50
+ ```
51
+ ### Setting the DNS provider
52
+
53
+ You can set the DNS provider to CloudFlare, Google, or OpenDNS using the `setProvider` method.
54
+
55
+ ```js
56
+ dns.setProvider('CloudFlare');
57
+ ```
58
+
59
+ ### Setting the result Order
60
+
61
+ The result order for DNS resolutions can be configured as follows:
62
+
63
+ - **`ipv4first`**: IPv4 addresses are preferred and returned before IPv6 addresses.
64
+ - **`ipv6first`**: IPv6 addresses are preferred and returned before IPv4 addresses.
65
+ - **`verbatim`**: The DNS resolution returns results in the exact order as returned by the DNS provider without preference for IPv4 or IPv6.
66
+
67
+ ### Resolving URLs
68
+
69
+ Use the `resolver` method to resolve a URL and get its IP address, hostname, and updated URL with the hostname replaced by the IP address.
70
+
71
+ ```js
72
+ const result = await dns.resolver('https://example.com');
73
+ console.log(result.address); // Resolved IP address
74
+ console.log(result.hostname); // Original hostname
75
+ console.log(result.urlReplaced); // URL with IP address instead of hostname
76
+ ```
77
+
78
+ ### Manually setting DNS servers
79
+
80
+ You can manually set DNS server IP addresses using the `setServers` method.
81
+
82
+ ```js
83
+ dns.setServers(['8.8.8.8', '8.8.4.4']);
84
+ ```
85
+
86
+ ## Error Handling
87
+
88
+ The library throws two types of errors:
89
+
90
+ 1. **SmartDnsProviderError**: Thrown when an unsupported DNS provider is used.
91
+ 2. **SmartDnsResolverError**: Thrown when there is an issue with resolving a URL (e.g., invalid URL format).
92
+
93
+ ## Example with Axios
94
+
95
+ This example shows how to use the package along with Axios to automatically resolve the hostname in requests to the corresponding IP address and adjust the request headers.
96
+
97
+ ```ts
98
+ import { DnsProvider, SmartDns } from '@darcas/smart-dns-promises'
99
+ import { default as _axios, InternalAxiosRequestConfig } from 'axios';
100
+
101
+ const axios = _axios.create()
102
+ const dns = SmartDns.factory(DnsProvider.OpenDNS)
103
+
104
+ axios.interceptors.request.use(async (config: InternalAxiosRequestConfig): Promise<InternalAxiosRequestConfig> => {
105
+ const {
106
+ address,
107
+ hostname,
108
+ urlReplaced,
109
+ } = await dns.resolver(config.url)
110
+
111
+ config.headers = {
112
+ ...config.headers ?? {},
113
+ Host: hostname,
114
+ }
115
+ config.url = urlReplaced
116
+
117
+ return config
118
+ })
119
+ ```
120
+
121
+ ## Contributing
122
+
123
+ If you'd like to contribute to the project, feel free to fork it and create a pull request. Please ensure that your changes are well-tested and properly documented.
124
+
125
+ ## License
126
+
127
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
128
+
129
+ ---
130
+
131
+ Made with ❤️ by [Dario Casertano (DarCas)](https://github.com/DarCas).
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @author Dario Casertano <dario@casertano.name>
3
+ * @copyright Copyright (c) 2024 Casertano Dario – All rights reserved.
4
+ * @license MIT
5
+ */
6
+ import { LRUCache } from "lru-cache";
7
+ /**
8
+ * Represents a hostname of a server.
9
+ */
10
+ type Hostname = string;
11
+ /**
12
+ * Represents an IP address.
13
+ */
14
+ type IPAddress = string;
15
+ /**
16
+ * Specifies the order of DNS resolution results.
17
+ */
18
+ type ResultOrder = 'ipv4first' | 'ipv6first' | 'verbatim';
19
+ /**
20
+ * Enum for built-in DNS providers.
21
+ * @readonly
22
+ * @enum {number}
23
+ */
24
+ export declare enum DnsProvider {
25
+ CloudFlare = 0,
26
+ Google = 1,
27
+ OpenDNS = 2
28
+ }
29
+ /**
30
+ * Error class for DNS provider-related errors.
31
+ * @extends {Error}
32
+ */
33
+ export declare class SmartDnsProviderError extends Error {
34
+ }
35
+ /**
36
+ * Error class for DNS resolution-related errors.
37
+ * @extends {Error}
38
+ */
39
+ export declare class SmartDnsResolverError extends Error {
40
+ }
41
+ /**
42
+ * SmartDns class for managing DNS resolution with caching and configurable DNS providers.
43
+ */
44
+ export declare class SmartDns {
45
+ /**
46
+ * Cache for hostname-IP mappings.
47
+ */
48
+ protected readonly cache: LRUCache<Hostname, IPAddress>;
49
+ /**
50
+ * Creates an instance of SmartDns.
51
+ * @param [dnsProvider] Optional DNS provider to use.
52
+ * @param [resultOrder='ipv4first'] Order of DNS resolution results.
53
+ * @param [ttl=3600000] Time-to-live for cached entries in milliseconds.
54
+ */
55
+ protected constructor(dnsProvider?: DnsProvider, resultOrder?: ResultOrder, ttl?: number);
56
+ /**
57
+ * Creates or retrieves a singleton instance of SmartDns.
58
+ * @param [dnsProvider] Optional DNS provider to use.
59
+ * @param [resultOrder] Order of DNS resolution results.
60
+ * @param [ttl] Time-to-live for cached entries in milliseconds.
61
+ * @returns The singleton SmartDns instance.
62
+ */
63
+ static factory(dnsProvider?: DnsProvider, resultOrder?: ResultOrder, ttl?: number): SmartDns;
64
+ /**
65
+ * Sets the DNS servers by the provider.
66
+ * @param dnsProvider The DNS provider to use.
67
+ * @throws {SmartDnsProviderError} If the DNS provider is unsupported.
68
+ */
69
+ setProvider(dnsProvider: DnsProvider): void;
70
+ /**
71
+ * Resolves a URL and retrieves its IP address, hostname, and updated URL.
72
+ * @async
73
+ * @param url The URL to resolve.
74
+ * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.
75
+ * @throws {SmartDnsResolverError} If the URL is invalid.
76
+ * @throws {Error} If the resolution fails.
77
+ */
78
+ resolver(url: string): Promise<{
79
+ address: IPAddress;
80
+ hostname: Hostname;
81
+ urlReplaced: string;
82
+ } | undefined>;
83
+ /**
84
+ * Manually sets DNS servers.
85
+ * @param servers Array of DNS server IP addresses.
86
+ */
87
+ setServers(servers: IPAddress[]): void;
88
+ }
89
+ export {};
90
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGrC;;GAEG;AACH,KAAK,QAAQ,GAAG,MAAM,CAAA;AAEtB;;GAEG;AACH,KAAK,SAAS,GAAG,MAAM,CAAA;AAEvB;;GAEG;AACH,KAAK,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAA;AAEzD;;;;GAIG;AACH,oBAAY,WAAW;IACnB,UAAU,IAAA;IACV,MAAM,IAAA;IACN,OAAO,IAAA;CACV;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;CAC/C;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;CAC/C;AAID;;GAEG;AACH,qBAAa,QAAQ;IACjB;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IAEvD;;;;;OAKG;IACH,SAAS,aACL,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,GAAE,WAAyB,EACtC,GAAG,SAAY;IAcnB;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ;IAQ5F;;;;OAIG;IACH,WAAW,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IA4B3C;;;;;;;OAOG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACjC,OAAO,EAAE,SAAS,CAAA;QAClB,QAAQ,EAAE,QAAQ,CAAA;QAClB,WAAW,EAAE,MAAM,CAAA;KACtB,GAAG,SAAS,CAAC;IA8Bd;;;OAGG;IACH,UAAU,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI;CAGzC"}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ // noinspection JSUnusedGlobalSymbols
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.SmartDns = exports.SmartDnsResolverError = exports.SmartDnsProviderError = exports.DnsProvider = void 0;
5
+ /**
6
+ * @author Dario Casertano <dario@casertano.name>
7
+ * @copyright Copyright (c) 2024 Casertano Dario – All rights reserved.
8
+ * @license MIT
9
+ */
10
+ const lru_cache_1 = require("lru-cache");
11
+ const promises_1 = require("node:dns/promises");
12
+ /**
13
+ * Enum for built-in DNS providers.
14
+ * @readonly
15
+ * @enum {number}
16
+ */
17
+ var DnsProvider;
18
+ (function (DnsProvider) {
19
+ DnsProvider[DnsProvider["CloudFlare"] = 0] = "CloudFlare";
20
+ DnsProvider[DnsProvider["Google"] = 1] = "Google";
21
+ DnsProvider[DnsProvider["OpenDNS"] = 2] = "OpenDNS";
22
+ })(DnsProvider || (exports.DnsProvider = DnsProvider = {}));
23
+ /**
24
+ * Error class for DNS provider-related errors.
25
+ * @extends {Error}
26
+ */
27
+ class SmartDnsProviderError extends Error {
28
+ }
29
+ exports.SmartDnsProviderError = SmartDnsProviderError;
30
+ /**
31
+ * Error class for DNS resolution-related errors.
32
+ * @extends {Error}
33
+ */
34
+ class SmartDnsResolverError extends Error {
35
+ }
36
+ exports.SmartDnsResolverError = SmartDnsResolverError;
37
+ let SmartDnsInstance;
38
+ /**
39
+ * SmartDns class for managing DNS resolution with caching and configurable DNS providers.
40
+ */
41
+ class SmartDns {
42
+ /**
43
+ * Cache for hostname-IP mappings.
44
+ */
45
+ cache;
46
+ /**
47
+ * Creates an instance of SmartDns.
48
+ * @param [dnsProvider] Optional DNS provider to use.
49
+ * @param [resultOrder='ipv4first'] Order of DNS resolution results.
50
+ * @param [ttl=3600000] Time-to-live for cached entries in milliseconds.
51
+ */
52
+ constructor(dnsProvider, resultOrder = 'ipv4first', ttl = 3_600_000) {
53
+ this.cache = new lru_cache_1.LRUCache({
54
+ max: 100,
55
+ ttl,
56
+ });
57
+ if (dnsProvider) {
58
+ this.setProvider(dnsProvider);
59
+ }
60
+ (0, promises_1.setDefaultResultOrder)(resultOrder);
61
+ }
62
+ /**
63
+ * Creates or retrieves a singleton instance of SmartDns.
64
+ * @param [dnsProvider] Optional DNS provider to use.
65
+ * @param [resultOrder] Order of DNS resolution results.
66
+ * @param [ttl] Time-to-live for cached entries in milliseconds.
67
+ * @returns The singleton SmartDns instance.
68
+ */
69
+ static factory(dnsProvider, resultOrder, ttl) {
70
+ if (!SmartDnsInstance) {
71
+ SmartDnsInstance = new SmartDns(dnsProvider, resultOrder, ttl);
72
+ }
73
+ return SmartDnsInstance;
74
+ }
75
+ /**
76
+ * Sets the DNS servers by the provider.
77
+ * @param dnsProvider The DNS provider to use.
78
+ * @throws {SmartDnsProviderError} If the DNS provider is unsupported.
79
+ */
80
+ setProvider(dnsProvider) {
81
+ switch (dnsProvider) {
82
+ case DnsProvider.CloudFlare:
83
+ (0, promises_1.setServers)([
84
+ '1.1.1.1',
85
+ '1.0.0.1',
86
+ ]);
87
+ break;
88
+ case DnsProvider.Google:
89
+ (0, promises_1.setServers)([
90
+ '8.8.8.8',
91
+ '8.8.4.4',
92
+ ]);
93
+ break;
94
+ case DnsProvider.OpenDNS:
95
+ (0, promises_1.setServers)([
96
+ '208.67.222.222',
97
+ '208.67.220.220',
98
+ ]);
99
+ break;
100
+ default:
101
+ throw new SmartDnsProviderError(`Unsupported DNS provider: ${dnsProvider}. You can use the "setServers" method to manually set the DNS server IP addresses.`);
102
+ }
103
+ }
104
+ /**
105
+ * Resolves a URL and retrieves its IP address, hostname, and updated URL.
106
+ * @async
107
+ * @param url The URL to resolve.
108
+ * @returns An object containing the resolved IP address, hostname, and the URL with the hostname replaced by the IP address.
109
+ * @throws {SmartDnsResolverError} If the URL is invalid.
110
+ * @throws {Error} If the resolution fails.
111
+ */
112
+ async resolver(url) {
113
+ if (!/^https?:\/\//.test(url)) {
114
+ throw new SmartDnsResolverError(`The URL must start with http/https.`);
115
+ }
116
+ try {
117
+ const hostname = new URL(url).hostname;
118
+ if (!this.cache.has(hostname)) {
119
+ const resolver = new promises_1.Resolver();
120
+ const [address] = await resolver.resolve4(hostname);
121
+ this.cache.set(hostname, address);
122
+ }
123
+ if (this.cache.has(hostname)) {
124
+ const address = this.cache.get(hostname);
125
+ return {
126
+ address,
127
+ hostname,
128
+ urlReplaced: url.replace(hostname, address),
129
+ };
130
+ }
131
+ return undefined;
132
+ }
133
+ catch (e) {
134
+ throw e;
135
+ }
136
+ }
137
+ /**
138
+ * Manually sets DNS servers.
139
+ * @param servers Array of DNS server IP addresses.
140
+ */
141
+ setServers(servers) {
142
+ (0, promises_1.setServers)(servers);
143
+ }
144
+ }
145
+ exports.SmartDns = SmartDns;
@@ -0,0 +1,7 @@
1
+ "use strict";var B=(o,t)=>()=>(t||o((t={exports:{}}).exports,t),t.exports);var q=B(D=>{"use strict";Object.defineProperty(D,"__esModule",{value:!0});D.LRUCache=void 0;var F=typeof performance=="object"&&performance&&typeof performance.now=="function"?performance:Date,k=new Set,U=typeof process=="object"&&process?process:{},H=(o,t,e,i)=>{typeof U.emitWarning=="function"?U.emitWarning(o,t,e,i):console.error(`[${e}] ${t}: ${o}`)},R=globalThis.AbortController,P=globalThis.AbortSignal;if(typeof R>"u"){P=class{onabort;_onabort=[];reason;aborted=!1;addEventListener(i,s){this._onabort.push(s)}},R=class{constructor(){t()}signal=new P;abort(i){if(!this.signal.aborted){this.signal.reason=i,this.signal.aborted=!0;for(let s of this.signal._onabort)s(i);this.signal.onabort?.(i)}}};let o=U.env?.LRU_CACHE_IGNORE_AC_WARNING!=="1",t=()=>{o&&(o=!1,H("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.","NO_ABORT_CONTROLLER","ENOTSUP",t))}}var $=o=>!k.has(o),Q=Symbol("type"),A=o=>o&&o===Math.floor(o)&&o>0&&isFinite(o),V=o=>A(o)?o<=Math.pow(2,8)?Uint8Array:o<=Math.pow(2,16)?Uint16Array:o<=Math.pow(2,32)?Uint32Array:o<=Number.MAX_SAFE_INTEGER?O:null:null,O=class extends Array{constructor(t){super(t),this.fill(0)}},G=class o{heap;length;static#l=!1;static create(t){let e=V(t);if(!e)return[];o.#l=!0;let i=new o(t,e);return o.#l=!1,i}constructor(t,e){if(!o.#l)throw new TypeError("instantiate Stack using Stack.create(n)");this.heap=new e(t),this.length=0}push(t){this.heap[this.length++]=t}pop(){return this.heap[--this.length]}},M=class o{#l;#c;#p;#w;#R;#D;ttl;ttlResolution;ttlAutopurge;updateAgeOnGet;updateAgeOnHas;allowStale;noDisposeOnSet;noUpdateTTL;maxEntrySize;sizeCalculation;noDeleteOnFetchRejection;noDeleteOnStaleGet;allowStaleOnFetchAbort;allowStaleOnFetchRejection;ignoreFetchAbort;#n;#S;#s;#i;#t;#a;#u;#o;#h;#m;#r;#_;#b;#d;#y;#E;#f;static unsafeExposeInternals(t){return{starts:t.#b,ttls:t.#d,sizes:t.#_,keyMap:t.#s,keyList:t.#i,valList:t.#t,next:t.#a,prev:t.#u,get head(){return t.#o},get tail(){return t.#h},free:t.#m,isBackgroundFetch:e=>t.#e(e),backgroundFetch:(e,i,s,n)=>t.#x(e,i,s,n),moveToTail:e=>t.#C(e),indexes:e=>t.#A(e),rindexes:e=>t.#v(e),isStale:e=>t.#g(e)}}get max(){return this.#l}get maxSize(){return this.#c}get calculatedSize(){return this.#S}get size(){return this.#n}get fetchMethod(){return this.#R}get memoMethod(){return this.#D}get dispose(){return this.#p}get disposeAfter(){return this.#w}constructor(t){let{max:e=0,ttl:i,ttlResolution:s=1,ttlAutopurge:n,updateAgeOnGet:h,updateAgeOnHas:l,allowStale:r,dispose:g,disposeAfter:_,noDisposeOnSet:f,noUpdateTTL:u,maxSize:c=0,maxEntrySize:v=0,sizeCalculation:d,fetchMethod:S,memoMethod:a,noDeleteOnFetchRejection:w,noDeleteOnStaleGet:b,allowStaleOnFetchRejection:p,allowStaleOnFetchAbort:m,ignoreFetchAbort:T}=t;if(e!==0&&!A(e))throw new TypeError("max option must be a nonnegative integer");let y=e?V(e):Array;if(!y)throw new Error("invalid max value: "+e);if(this.#l=e,this.#c=c,this.maxEntrySize=v||this.#c,this.sizeCalculation=d,this.sizeCalculation){if(!this.#c&&!this.maxEntrySize)throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");if(typeof this.sizeCalculation!="function")throw new TypeError("sizeCalculation set to non-function")}if(a!==void 0&&typeof a!="function")throw new TypeError("memoMethod must be a function if defined");if(this.#D=a,S!==void 0&&typeof S!="function")throw new TypeError("fetchMethod must be a function if specified");if(this.#R=S,this.#E=!!S,this.#s=new Map,this.#i=new Array(e).fill(void 0),this.#t=new Array(e).fill(void 0),this.#a=new y(e),this.#u=new y(e),this.#o=0,this.#h=0,this.#m=G.create(e),this.#n=0,this.#S=0,typeof g=="function"&&(this.#p=g),typeof _=="function"?(this.#w=_,this.#r=[]):(this.#w=void 0,this.#r=void 0),this.#y=!!this.#p,this.#f=!!this.#w,this.noDisposeOnSet=!!f,this.noUpdateTTL=!!u,this.noDeleteOnFetchRejection=!!w,this.allowStaleOnFetchRejection=!!p,this.allowStaleOnFetchAbort=!!m,this.ignoreFetchAbort=!!T,this.maxEntrySize!==0){if(this.#c!==0&&!A(this.#c))throw new TypeError("maxSize must be a positive integer if specified");if(!A(this.maxEntrySize))throw new TypeError("maxEntrySize must be a positive integer if specified");this.#P()}if(this.allowStale=!!r,this.noDeleteOnStaleGet=!!b,this.updateAgeOnGet=!!h,this.updateAgeOnHas=!!l,this.ttlResolution=A(s)||s===0?s:1,this.ttlAutopurge=!!n,this.ttl=i||0,this.ttl){if(!A(this.ttl))throw new TypeError("ttl must be a positive integer if specified");this.#U()}if(this.#l===0&&this.ttl===0&&this.#c===0)throw new TypeError("At least one of max, maxSize, or ttl is required");if(!this.ttlAutopurge&&!this.#l&&!this.#c){let C="LRU_CACHE_UNBOUNDED";$(C)&&(k.add(C),H("TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.","UnboundedCacheWarning",C,o))}}getRemainingTTL(t){return this.#s.has(t)?1/0:0}#U(){let t=new O(this.#l),e=new O(this.#l);this.#d=t,this.#b=e,this.#G=(n,h,l=F.now())=>{if(e[n]=h!==0?l:0,t[n]=h,h!==0&&this.ttlAutopurge){let r=setTimeout(()=>{this.#g(n)&&this.#F(this.#i[n],"expire")},h+1);r.unref&&r.unref()}},this.#T=n=>{e[n]=t[n]!==0?F.now():0},this.#O=(n,h)=>{if(t[h]){let l=t[h],r=e[h];if(!l||!r)return;n.ttl=l,n.start=r,n.now=i||s();let g=n.now-r;n.remainingTTL=l-g}};let i=0,s=()=>{let n=F.now();if(this.ttlResolution>0){i=n;let h=setTimeout(()=>i=0,this.ttlResolution);h.unref&&h.unref()}return n};this.getRemainingTTL=n=>{let h=this.#s.get(n);if(h===void 0)return 0;let l=t[h],r=e[h];if(!l||!r)return 1/0;let g=(i||s())-r;return l-g},this.#g=n=>{let h=e[n],l=t[n];return!!l&&!!h&&(i||s())-h>l}}#T=()=>{};#O=()=>{};#G=()=>{};#g=()=>!1;#P(){let t=new O(this.#l);this.#S=0,this.#_=t,this.#z=e=>{this.#S-=t[e],t[e]=0},this.#M=(e,i,s,n)=>{if(this.#e(i))return 0;if(!A(s))if(n){if(typeof n!="function")throw new TypeError("sizeCalculation must be a function");if(s=n(i,e),!A(s))throw new TypeError("sizeCalculation return invalid (expect positive integer)")}else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");return s},this.#W=(e,i,s)=>{if(t[e]=i,this.#c){let n=this.#c-t[e];for(;this.#S>n;)this.#L(!0)}this.#S+=t[e],s&&(s.entrySize=i,s.totalCalculatedSize=this.#S)}}#z=t=>{};#W=(t,e,i)=>{};#M=(t,e,i,s)=>{if(i||s)throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");return 0};*#A({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#h;!(!this.#N(e)||((t||!this.#g(e))&&(yield e),e===this.#o));)e=this.#u[e]}*#v({allowStale:t=this.allowStale}={}){if(this.#n)for(let e=this.#o;!(!this.#N(e)||((t||!this.#g(e))&&(yield e),e===this.#h));)e=this.#a[e]}#N(t){return t!==void 0&&this.#s.get(this.#i[t])===t}*entries(){for(let t of this.#A())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*rentries(){for(let t of this.#v())this.#t[t]!==void 0&&this.#i[t]!==void 0&&!this.#e(this.#t[t])&&(yield[this.#i[t],this.#t[t]])}*keys(){for(let t of this.#A()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*rkeys(){for(let t of this.#v()){let e=this.#i[t];e!==void 0&&!this.#e(this.#t[t])&&(yield e)}}*values(){for(let t of this.#A())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}*rvalues(){for(let t of this.#v())this.#t[t]!==void 0&&!this.#e(this.#t[t])&&(yield this.#t[t])}[Symbol.iterator](){return this.entries()}[Symbol.toStringTag]="LRUCache";find(t,e={}){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;if(n!==void 0&&t(n,this.#i[i],this))return this.get(this.#i[i],e)}}forEach(t,e=this){for(let i of this.#A()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}rforEach(t,e=this){for(let i of this.#v()){let s=this.#t[i],n=this.#e(s)?s.__staleWhileFetching:s;n!==void 0&&t.call(e,n,this.#i[i],this)}}purgeStale(){let t=!1;for(let e of this.#v({allowStale:!0}))this.#g(e)&&(this.#F(this.#i[e],"expire"),t=!0);return t}info(t){let e=this.#s.get(t);if(e===void 0)return;let i=this.#t[e],s=this.#e(i)?i.__staleWhileFetching:i;if(s===void 0)return;let n={value:s};if(this.#d&&this.#b){let h=this.#d[e],l=this.#b[e];if(h&&l){let r=h-(F.now()-l);n.ttl=r,n.start=Date.now()}}return this.#_&&(n.size=this.#_[e]),n}dump(){let t=[];for(let e of this.#A({allowStale:!0})){let i=this.#i[e],s=this.#t[e],n=this.#e(s)?s.__staleWhileFetching:s;if(n===void 0||i===void 0)continue;let h={value:n};if(this.#d&&this.#b){h.ttl=this.#d[e];let l=F.now()-this.#b[e];h.start=Math.floor(Date.now()-l)}this.#_&&(h.size=this.#_[e]),t.unshift([i,h])}return t}load(t){this.clear();for(let[e,i]of t){if(i.start){let s=Date.now()-i.start;i.start=F.now()-s}this.set(e,i.value,i)}}set(t,e,i={}){if(e===void 0)return this.delete(t),this;let{ttl:s=this.ttl,start:n,noDisposeOnSet:h=this.noDisposeOnSet,sizeCalculation:l=this.sizeCalculation,status:r}=i,{noUpdateTTL:g=this.noUpdateTTL}=i,_=this.#M(t,e,i.size||0,l);if(this.maxEntrySize&&_>this.maxEntrySize)return r&&(r.set="miss",r.maxEntrySizeExceeded=!0),this.#F(t,"set"),this;let f=this.#n===0?void 0:this.#s.get(t);if(f===void 0)f=this.#n===0?this.#h:this.#m.length!==0?this.#m.pop():this.#n===this.#l?this.#L(!1):this.#n,this.#i[f]=t,this.#t[f]=e,this.#s.set(t,f),this.#a[this.#h]=f,this.#u[f]=this.#h,this.#h=f,this.#n++,this.#W(f,_,r),r&&(r.set="add"),g=!1;else{this.#C(f);let u=this.#t[f];if(e!==u){if(this.#E&&this.#e(u)){u.__abortController.abort(new Error("replaced"));let{__staleWhileFetching:c}=u;c!==void 0&&!h&&(this.#y&&this.#p?.(c,t,"set"),this.#f&&this.#r?.push([c,t,"set"]))}else h||(this.#y&&this.#p?.(u,t,"set"),this.#f&&this.#r?.push([u,t,"set"]));if(this.#z(f),this.#W(f,_,r),this.#t[f]=e,r){r.set="replace";let c=u&&this.#e(u)?u.__staleWhileFetching:u;c!==void 0&&(r.oldValue=c)}}else r&&(r.set="update")}if(s!==0&&!this.#d&&this.#U(),this.#d&&(g||this.#G(f,s,n),r&&this.#O(r,f)),!h&&this.#f&&this.#r){let u=this.#r,c;for(;c=u?.shift();)this.#w?.(...c)}return this}pop(){try{for(;this.#n;){let t=this.#t[this.#o];if(this.#L(!0),this.#e(t)){if(t.__staleWhileFetching)return t.__staleWhileFetching}else if(t!==void 0)return t}}finally{if(this.#f&&this.#r){let t=this.#r,e;for(;e=t?.shift();)this.#w?.(...e)}}}#L(t){let e=this.#o,i=this.#i[e],s=this.#t[e];return this.#E&&this.#e(s)?s.__abortController.abort(new Error("evicted")):(this.#y||this.#f)&&(this.#y&&this.#p?.(s,i,"evict"),this.#f&&this.#r?.push([s,i,"evict"])),this.#z(e),t&&(this.#i[e]=void 0,this.#t[e]=void 0,this.#m.push(e)),this.#n===1?(this.#o=this.#h=0,this.#m.length=0):this.#o=this.#a[e],this.#s.delete(i),this.#n--,e}has(t,e={}){let{updateAgeOnHas:i=this.updateAgeOnHas,status:s}=e,n=this.#s.get(t);if(n!==void 0){let h=this.#t[n];if(this.#e(h)&&h.__staleWhileFetching===void 0)return!1;if(this.#g(n))s&&(s.has="stale",this.#O(s,n));else return i&&this.#T(n),s&&(s.has="hit",this.#O(s,n)),!0}else s&&(s.has="miss");return!1}peek(t,e={}){let{allowStale:i=this.allowStale}=e,s=this.#s.get(t);if(s===void 0||!i&&this.#g(s))return;let n=this.#t[s];return this.#e(n)?n.__staleWhileFetching:n}#x(t,e,i,s){let n=e===void 0?void 0:this.#t[e];if(this.#e(n))return n;let h=new R,{signal:l}=i;l?.addEventListener("abort",()=>h.abort(l.reason),{signal:h.signal});let r={signal:h.signal,options:i,context:s},g=(d,S=!1)=>{let{aborted:a}=h.signal,w=i.ignoreFetchAbort&&d!==void 0;if(i.status&&(a&&!S?(i.status.fetchAborted=!0,i.status.fetchError=h.signal.reason,w&&(i.status.fetchAbortIgnored=!0)):i.status.fetchResolved=!0),a&&!w&&!S)return f(h.signal.reason);let b=c;return this.#t[e]===c&&(d===void 0?b.__staleWhileFetching?this.#t[e]=b.__staleWhileFetching:this.#F(t,"fetch"):(i.status&&(i.status.fetchUpdated=!0),this.set(t,d,r.options))),d},_=d=>(i.status&&(i.status.fetchRejected=!0,i.status.fetchError=d),f(d)),f=d=>{let{aborted:S}=h.signal,a=S&&i.allowStaleOnFetchAbort,w=a||i.allowStaleOnFetchRejection,b=w||i.noDeleteOnFetchRejection,p=c;if(this.#t[e]===c&&(!b||p.__staleWhileFetching===void 0?this.#F(t,"fetch"):a||(this.#t[e]=p.__staleWhileFetching)),w)return i.status&&p.__staleWhileFetching!==void 0&&(i.status.returnedStale=!0),p.__staleWhileFetching;if(p.__returned===p)throw d},u=(d,S)=>{let a=this.#R?.(t,n,r);a&&a instanceof Promise&&a.then(w=>d(w===void 0?void 0:w),S),h.signal.addEventListener("abort",()=>{(!i.ignoreFetchAbort||i.allowStaleOnFetchAbort)&&(d(void 0),i.allowStaleOnFetchAbort&&(d=w=>g(w,!0)))})};i.status&&(i.status.fetchDispatched=!0);let c=new Promise(u).then(g,_),v=Object.assign(c,{__abortController:h,__staleWhileFetching:n,__returned:void 0});return e===void 0?(this.set(t,v,{...r.options,status:void 0}),e=this.#s.get(t)):this.#t[e]=v,v}#e(t){if(!this.#E)return!1;let e=t;return!!e&&e instanceof Promise&&e.hasOwnProperty("__staleWhileFetching")&&e.__abortController instanceof R}async fetch(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,ttl:h=this.ttl,noDisposeOnSet:l=this.noDisposeOnSet,size:r=0,sizeCalculation:g=this.sizeCalculation,noUpdateTTL:_=this.noUpdateTTL,noDeleteOnFetchRejection:f=this.noDeleteOnFetchRejection,allowStaleOnFetchRejection:u=this.allowStaleOnFetchRejection,ignoreFetchAbort:c=this.ignoreFetchAbort,allowStaleOnFetchAbort:v=this.allowStaleOnFetchAbort,context:d,forceRefresh:S=!1,status:a,signal:w}=e;if(!this.#E)return a&&(a.fetch="get"),this.get(t,{allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,status:a});let b={allowStale:i,updateAgeOnGet:s,noDeleteOnStaleGet:n,ttl:h,noDisposeOnSet:l,size:r,sizeCalculation:g,noUpdateTTL:_,noDeleteOnFetchRejection:f,allowStaleOnFetchRejection:u,allowStaleOnFetchAbort:v,ignoreFetchAbort:c,status:a,signal:w},p=this.#s.get(t);if(p===void 0){a&&(a.fetch="miss");let m=this.#x(t,p,b,d);return m.__returned=m}else{let m=this.#t[p];if(this.#e(m)){let j=i&&m.__staleWhileFetching!==void 0;return a&&(a.fetch="inflight",j&&(a.returnedStale=!0)),j?m.__staleWhileFetching:m.__returned=m}let T=this.#g(p);if(!S&&!T)return a&&(a.fetch="hit"),this.#C(p),s&&this.#T(p),a&&this.#O(a,p),m;let y=this.#x(t,p,b,d),x=y.__staleWhileFetching!==void 0&&i;return a&&(a.fetch=T?"stale":"refresh",x&&T&&(a.returnedStale=!0)),x?y.__staleWhileFetching:y.__returned=y}}async forceFetch(t,e={}){let i=await this.fetch(t,e);if(i===void 0)throw new Error("fetch() returned undefined");return i}memo(t,e={}){let i=this.#D;if(!i)throw new Error("no memoMethod provided to constructor");let{context:s,forceRefresh:n,...h}=e,l=this.get(t,h);if(!n&&l!==void 0)return l;let r=i(t,l,{options:h,context:s});return this.set(t,r,h),r}get(t,e={}){let{allowStale:i=this.allowStale,updateAgeOnGet:s=this.updateAgeOnGet,noDeleteOnStaleGet:n=this.noDeleteOnStaleGet,status:h}=e,l=this.#s.get(t);if(l!==void 0){let r=this.#t[l],g=this.#e(r);return h&&this.#O(h,l),this.#g(l)?(h&&(h.get="stale"),g?(h&&i&&r.__staleWhileFetching!==void 0&&(h.returnedStale=!0),i?r.__staleWhileFetching:void 0):(n||this.#F(t,"expire"),h&&i&&(h.returnedStale=!0),i?r:void 0)):(h&&(h.get="hit"),g?r.__staleWhileFetching:(this.#C(l),s&&this.#T(l),r))}else h&&(h.get="miss")}#I(t,e){this.#u[e]=t,this.#a[t]=e}#C(t){t!==this.#h&&(t===this.#o?this.#o=this.#a[t]:this.#I(this.#u[t],this.#a[t]),this.#I(this.#h,t),this.#h=t)}delete(t){return this.#F(t,"delete")}#F(t,e){let i=!1;if(this.#n!==0){let s=this.#s.get(t);if(s!==void 0)if(i=!0,this.#n===1)this.#j(e);else{this.#z(s);let n=this.#t[s];if(this.#e(n)?n.__abortController.abort(new Error("deleted")):(this.#y||this.#f)&&(this.#y&&this.#p?.(n,t,e),this.#f&&this.#r?.push([n,t,e])),this.#s.delete(t),this.#i[s]=void 0,this.#t[s]=void 0,s===this.#h)this.#h=this.#u[s];else if(s===this.#o)this.#o=this.#a[s];else{let h=this.#u[s];this.#a[h]=this.#a[s];let l=this.#a[s];this.#u[l]=this.#u[s]}this.#n--,this.#m.push(s)}}if(this.#f&&this.#r?.length){let s=this.#r,n;for(;n=s?.shift();)this.#w?.(...n)}return i}clear(){return this.#j("delete")}#j(t){for(let e of this.#v({allowStale:!0})){let i=this.#t[e];if(this.#e(i))i.__abortController.abort(new Error("deleted"));else{let s=this.#i[e];this.#y&&this.#p?.(i,s,t),this.#f&&this.#r?.push([i,s,t])}}if(this.#s.clear(),this.#t.fill(void 0),this.#i.fill(void 0),this.#d&&this.#b&&(this.#d.fill(0),this.#b.fill(0)),this.#_&&this.#_.fill(0),this.#o=0,this.#h=0,this.#m.length=0,this.#S=0,this.#n=0,this.#f&&this.#r){let e=this.#r,i;for(;i=e?.shift();)this.#w?.(...i)}}};D.LRUCache=M});Object.defineProperty(exports,"__esModule",{value:!0});exports.SmartDns=exports.SmartDnsResolverError=exports.SmartDnsProviderError=exports.DnsProvider=void 0;var Y=q(),E=require("node:dns/promises"),z;(function(o){o[o.CloudFlare=0]="CloudFlare",o[o.Google=1]="Google",o[o.OpenDNS=2]="OpenDNS"})(z||(exports.DnsProvider=z={}));var W=class extends Error{};exports.SmartDnsProviderError=W;var L=class extends Error{};exports.SmartDnsResolverError=L;var N,I=class o{cache;constructor(t,e="ipv4first",i=36e5){this.cache=new Y.LRUCache({max:100,ttl:i}),t&&this.setProvider(t),(0,E.setDefaultResultOrder)(e)}static factory(t,e,i){return N||(N=new o(t,e,i)),N}setProvider(t){switch(t){case z.CloudFlare:(0,E.setServers)(["1.1.1.1","1.0.0.1"]);break;case z.Google:(0,E.setServers)(["8.8.8.8","8.8.4.4"]);break;case z.OpenDNS:(0,E.setServers)(["208.67.222.222","208.67.220.220"]);break;default:throw new W(`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.");try{let e=new URL(t).hostname;if(!this.cache.has(e)){let i=new E.Resolver,[s]=await i.resolve4(e);this.cache.set(e,s)}if(this.cache.has(e)){let i=this.cache.get(e);return{address:i,hostname:e,urlReplaced:t.replace(e,i)}}return}catch(e){throw e}}setServers(t){(0,E.setServers)(t)}};exports.SmartDns=I;
2
+ /**
3
+ * @author Dario Casertano <dario@casertano.name>
4
+ * @copyright Copyright (c) 2024 Casertano Dario – All rights reserved.
5
+ * @license MIT
6
+ */
7
+ //# sourceMappingURL=index.min.js.map