Comparing version 1.0.4 to 1.1.0
40
index.js
@@ -15,3 +15,2 @@ const dns = require('node:dns'); | ||
const pMap = require('p-map'); | ||
const pTimeout = require('p-timeout'); | ||
const pWaitFor = require('p-wait-for'); | ||
@@ -242,3 +241,5 @@ const packet = require('dns-packet'); | ||
servers: new Set(['1.1.1.1', '1.0.0.1']), | ||
undici: { | ||
// HTTP library function to use | ||
request, | ||
requestOptions: { | ||
method: 'GET', | ||
@@ -251,2 +252,3 @@ headers: { | ||
}, | ||
requestTimeout: (ms) => ({ bodyTimeout: ms }), | ||
// | ||
@@ -297,2 +299,10 @@ // NOTE: we set the default to "get" since it is faster from `benchmark` results | ||
// request option method must be either GET or POST | ||
if ( | ||
!['get', 'post'].includes( | ||
this.options.requestOptions.method.toLowerCase() | ||
) | ||
) | ||
throw new Error('Request options method must be either GET or POST'); | ||
// perform validation by re-using `setServers` method | ||
@@ -732,8 +742,3 @@ this.setServers([...this.options.servers]); | ||
// | ||
async #request( | ||
pkt, | ||
server, | ||
abortController, | ||
requestTimeout = this.options.timeout | ||
) { | ||
async #request(pkt, server, abortController, timeout = this.options.timeout) { | ||
// safeguard in case aborted | ||
@@ -754,4 +759,5 @@ if (abortController.signal.aborted) return; | ||
const options = { | ||
signal: abortController.signal, | ||
...this.options.undici | ||
...this.options.requestOptions, | ||
...this.options.requestTimeout(timeout), // returns `{ bodyTimeout: requestTimeout }` | ||
signal: abortController.signal | ||
}; | ||
@@ -763,3 +769,3 @@ | ||
// <https://github.com/hildjj/dohdec/blob/43564118c40f2127af871bdb4d40f615409d4b9c/pkg/dohdec/lib/doh.js#L117-L120> | ||
if (this.options.undici.method === 'GET') { | ||
if (this.options.requestOptions.method.toLowerCase() === 'get') { | ||
if (!dohdec) await pWaitFor(() => Boolean(dohdec)); | ||
@@ -771,6 +777,4 @@ url += `?dns=${dohdec.DNSoverHTTPS.base64urlEncode(pkt)}`; | ||
debug('request', { url, options, requestTimeout }); | ||
const response = await pTimeout(request(url, options), requestTimeout, { | ||
signal: abortController.signal | ||
}); | ||
debug('request', { url, options }); | ||
const response = await this.options.request(url, options); | ||
return response; | ||
@@ -823,4 +827,6 @@ } | ||
if (body && statusCode >= 200 && statusCode < 300) { | ||
// eslint-disable-next-line no-await-in-loop | ||
buffer = await getStream.buffer(body); | ||
buffer = Buffer.isBuffer(body) | ||
? body | ||
: // eslint-disable-next-line no-await-in-loop | ||
await getStream.buffer(body); | ||
// eslint-disable-next-line max-depth | ||
@@ -827,0 +833,0 @@ if (!abortController.signal.aborted) abortController.abort(); |
{ | ||
"name": "tangerine", | ||
"description": "Tangerine is the best Node.js drop-in replacement for dns.promises.Resolver using DNS over HTTPS (\"DoH\") via undici with built-in retries, timeouts, smart server rotation, AbortControllers, and caching support for multiple backends via Keyv.", | ||
"version": "1.0.4", | ||
"version": "1.1.0", | ||
"author": "Forward Email (https://forwardemail.net)", | ||
@@ -20,3 +20,2 @@ "bugs": { | ||
"p-map": "4", | ||
"p-timeout": "4", | ||
"p-wait-for": "3", | ||
@@ -23,0 +22,0 @@ "port-numbers": "^6.0.1", |
@@ -254,23 +254,25 @@ <h1 align="center"> | ||
| Property | Type | Default Value | Description | | ||
| ------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `timeout` | `Number` | `5000` | Number of milliseconds for requests to timeout. | | ||
| `tries` | `Number` | `4` | Number of tries per `server` in `servers` to attempt. | | ||
| `servers` | `Set` or `Array` | `new Set(['1.1.1.1', '1.0.0.1'])` | A Set or Array of [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6) formatted addresses for DNS queries (matches default Node.js dns module behavior). Duplicates will be removed as this is converted to a `Set` internally. Defaults to Cloudflare's of `1.1.1.1` and `1.0.0.1`. If an `Array` is passed, then it will be converted to a `Set`. | | ||
| `undici` | `Object` | Defaults to an Object with `undici.method` and `undici.headers` properties and values below | Default options to pass to [undici](https://github.com/nodejs/undici). | | ||
| `undici.method` | `String` | Defaults to `"GET"` (must be either `"GET"` or `"POST"`). | Default HTTP method to use for DNS over HTTP ("DoH") requests. | | ||
| `undici.headers` | `Object` | Defaults to `{ 'content-type': 'application/dns-message', 'user-agent': pkg.name + "/" + pkg.version, accept: 'application/dns-message' }`. | Default HTTP headers to use for DNS over HTTP ("DoH") requests. | | ||
| `protocol` | `String` | Defaults to `"https"`. | Default HTTP protocol to use for DNS over HTTPS ("DoH") requests. | | ||
| `dnsOrder` | `String` | Defaults to `"verbatim"` for Node.js v17.0.0+ and `"ipv4first"` for older versions. | Sets the default result order of `lookup` invocations (see [dns.setDefaultResultOrder](https://nodejs.org/api/dns.html#dnssetdefaultresultorderorder) for more insight). | | ||
| `logger` | `Object` | `false` | This is the default logger. We recommend using [Cabin](https://github.com/cabinjs) instead of using `console` as your default logger. Set this value to `false` to disable logging entirely (uses noop function). | | ||
| `id` | `Number` or `Function` | `0` | Default `id` to be passed for DNS packet creation. This could alternatively be a synchronous or asynchronous function that returns a `Number` (e.g. `id: () => Tangerine.getRandomInt(1, 65534)`). | | ||
| `concurrency` | `Number` | `os.cpus().length` | Default concurrency to use for `resolveAny` lookup via [p-map](https://github.com/sindresorhus/p-map). The default value is the number of CPU's available to the system using the Node.js `os` module [os.cpus()](https://nodejs.org/api/os.html#oscpus) method. | | ||
| `ipv4` | `String` | `"0.0.0.0"` | Default IPv4 address to use for HTTP agent `localAddress` if DNS `server` was an IPv4 address. | | ||
| `ipv6` | `String` | `"::0"` | Default IPv6 address to use for HTTP agent `localAddress` if DNS `server` was an IPv6 address. | | ||
| `ipv4Port` | `Number` | `undefined` | Default port to use for HTTP agent `localPort` if DNS `server` was an IPv4 address. | | ||
| `ipv6Port` | `Number` | `undefined` | Default port to use for HTTP agent `localPort` if DNS `server` was an IPv6 address. | | ||
| `cache` | `Map` or `Boolean` | `new Map()` | Set this to `false` in order to disable caching. Default `Map` instance to use for caching. Entries are by type, e.g. `map.set('TXT', new Keyv({})`). If cache set values are not provided, then they will default to a new instance of `Keyv`. See cache setup and usage in [index.js](https://github.com/forwardemail/tangerine/blob/main/index.js) for more insight. You can iterate over `Tangerine.TYPES` if necessary to create a similar cache setup. | | ||
| `returnHTTPErrors` | `Boolean` | `false` | Whether to return HTTP errors instead of mapping them to corresponding DNS errors. | | ||
| `smartRotate` | `Boolean` | `true` | Whether to do smart server rotation if servers fail. | | ||
| `defaultHTTPErrorMessage` | `String` | `"Unsuccessful HTTP response"` | Default fallback message if `statusCode` returned from HTTP request was not found in [http.STATUS_CODES](https://nodejs.org/api/http.html#httpstatus_codes). | | ||
| Property | Type | Default Value | Description | | ||
| ------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `timeout` | `Number` | `5000` | Number of milliseconds for requests to timeout. | | ||
| `tries` | `Number` | `4` | Number of tries per `server` in `servers` to attempt. | | ||
| `servers` | `Set` or `Array` | `new Set(['1.1.1.1', '1.0.0.1'])` | A Set or Array of [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6) formatted addresses for DNS queries (matches default Node.js dns module behavior). Duplicates will be removed as this is converted to a `Set` internally. Defaults to Cloudflare's of `1.1.1.1` and `1.0.0.1`. If an `Array` is passed, then it will be converted to a `Set`. | | ||
| `request` | `Function` | [undici.request](https://undici.nodejs.org/#/?id=undicirequesturl-options-promise) | HTTP library request async or Promise returning function to be used for making request (defaults to undici's request method). You could alternatively use `got` or any other HTTP library of your choice that accepts `fn(url, options)`. It should return an object with `body`, `headers`, and either a `status` or `statusCode` property. The `body` property returned should be either a `Buffer` or `Stream`. Specify default request options based off the library under `requestOptions` below (e.g. for `got` you'd set `responseType: 'buffer', retry: { limit: 0 }`) since this library already has built-in retries. See `requestTimeout` function below, as it is required to be set properly if you are using a custom HTTP library function. | | ||
| `requestOptions` | `Object` | Defaults to an Object with `requestOptions.method` and `requestOptions.headers` properties and values below | Default options to pass to [undici](https://github.com/nodejs/undici) (or your custom HTTP library function passed as `request`). | | ||
| `requestOptions.method` | `String` | Defaults to `"GET"` (must be either `"GET"` or `"POST"`, case-insensitive depending on library you use). | Default HTTP method to use for DNS over HTTP ("DoH") requests. | | ||
| `requestOptions.headers` | `Object` | Defaults to `{ 'content-type': 'application/dns-message', 'user-agent': pkg.name + "/" + pkg.version, accept: 'application/dns-message', bodyTimeout: timeout }`. | Default HTTP headers to use for DNS over HTTP ("DoH") requests. | | ||
| `requestTimeout` | `Function` | Defaults to `(ms) => ({ bodyTimeout })` for setting undici timeout properly. | This function accepts an argument `ms` which is the number of milliseconds to wait for the request to timeout (since we use a back-off strategy that mirrors the Node.js DNS module). This function is required to be passed and customized if you are using a custom HTTP library. If you're using a custom HTTP library such as `got`, you'd set this to `requestTimeout: (ms) => ({ timeout: { request: ms } })` | | ||
| `protocol` | `String` | Defaults to `"https"`. | Default HTTP protocol to use for DNS over HTTPS ("DoH") requests. | | ||
| `dnsOrder` | `String` | Defaults to `"verbatim"` for Node.js v17.0.0+ and `"ipv4first"` for older versions. | Sets the default result order of `lookup` invocations (see [dns.setDefaultResultOrder](https://nodejs.org/api/dns.html#dnssetdefaultresultorderorder) for more insight). | | ||
| `logger` | `Object` | `false` | This is the default logger. We recommend using [Cabin](https://github.com/cabinjs) instead of using `console` as your default logger. Set this value to `false` to disable logging entirely (uses noop function). | | ||
| `id` | `Number` or `Function` | `0` | Default `id` to be passed for DNS packet creation. This could alternatively be a synchronous or asynchronous function that returns a `Number` (e.g. `id: () => Tangerine.getRandomInt(1, 65534)`). | | ||
| `concurrency` | `Number` | `os.cpus().length` | Default concurrency to use for `resolveAny` lookup via [p-map](https://github.com/sindresorhus/p-map). The default value is the number of CPU's available to the system using the Node.js `os` module [os.cpus()](https://nodejs.org/api/os.html#oscpus) method. | | ||
| `ipv4` | `String` | `"0.0.0.0"` | Default IPv4 address to use for HTTP agent `localAddress` if DNS `server` was an IPv4 address. | | ||
| `ipv6` | `String` | `"::0"` | Default IPv6 address to use for HTTP agent `localAddress` if DNS `server` was an IPv6 address. | | ||
| `ipv4Port` | `Number` | `undefined` | Default port to use for HTTP agent `localPort` if DNS `server` was an IPv4 address. | | ||
| `ipv6Port` | `Number` | `undefined` | Default port to use for HTTP agent `localPort` if DNS `server` was an IPv6 address. | | ||
| `cache` | `Map` or `Boolean` | `new Map()` | Set this to `false` in order to disable caching. Default `Map` instance to use for caching. Entries are by type, e.g. `map.set('TXT', new Keyv({})`). If cache set values are not provided, then they will default to a new instance of `Keyv`. See cache setup and usage in [index.js](https://github.com/forwardemail/tangerine/blob/main/index.js) for more insight. You can iterate over `Tangerine.TYPES` if necessary to create a similar cache setup. | | ||
| `returnHTTPErrors` | `Boolean` | `false` | Whether to return HTTP errors instead of mapping them to corresponding DNS errors. | | ||
| `smartRotate` | `Boolean` | `true` | Whether to do smart server rotation if servers fail. | | ||
| `defaultHTTPErrorMessage` | `String` | `"Unsuccessful HTTP response"` | Default fallback message if `statusCode` returned from HTTP request was not found in [http.STATUS_CODES](https://nodejs.org/api/http.html#httpstatus_codes). | | ||
@@ -277,0 +279,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
106506
11
1230
579
- Removedp-timeout@4
- Removedp-timeout@4.1.0(transitive)