Comparing version 1.1.0 to 1.2.0
17
index.js
@@ -19,3 +19,2 @@ const dns = require('node:dns'); | ||
const { getService } = require('port-numbers'); | ||
const { request } = require('undici'); | ||
@@ -218,3 +217,3 @@ const pkg = require('./package.json'); | ||
constructor(options = {}) { | ||
constructor(options = {}, request = require('undici').request) { | ||
const timeout = | ||
@@ -229,2 +228,9 @@ options.timeout && options.timeout !== -1 ? options.timeout : 5000; | ||
if (typeof request !== 'function') | ||
throw new Error( | ||
'Request option must be a function (e.g. `undici.request` or `got`)' | ||
); | ||
this.request = request; | ||
this.options = mergeOptions( | ||
@@ -243,4 +249,2 @@ { | ||
servers: new Set(['1.1.1.1', '1.0.0.1']), | ||
// HTTP library function to use | ||
request, | ||
requestOptions: { | ||
@@ -775,3 +779,3 @@ method: 'GET', | ||
debug('request', { url, options }); | ||
const response = await this.options.request(url, options); | ||
const response = await this.request(url, options); | ||
return response; | ||
@@ -819,3 +823,4 @@ } | ||
if (response) { | ||
const { statusCode, body, headers } = response; | ||
const { body, headers } = response; | ||
const statusCode = response.status || response.statusCode; | ||
debug('response', { statusCode, headers }); | ||
@@ -822,0 +827,0 @@ |
{ | ||
"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.1.0", | ||
"version": "1.2.0", | ||
"author": "Forward Email (https://forwardemail.net)", | ||
@@ -22,4 +22,3 @@ "bugs": { | ||
"port-numbers": "^6.0.1", | ||
"semver": "^7.3.8", | ||
"undici": "^5.20.0" | ||
"semver": "^7.3.8" | ||
}, | ||
@@ -50,2 +49,3 @@ "devDependencies": { | ||
"superagent": "^8.0.9", | ||
"undici": "^5.20.0", | ||
"xo": "^0.53.1" | ||
@@ -137,2 +137,10 @@ }, | ||
"main": "index.js", | ||
"peerDependencies": { | ||
"undici": "*" | ||
}, | ||
"peerDependenciesMeta": { | ||
"undici": { | ||
"optional": true | ||
} | ||
}, | ||
"publishConfig": { | ||
@@ -139,0 +147,0 @@ "access": "public" |
@@ -36,3 +36,3 @@ <h1 align="center"> | ||
* [API](#api) | ||
* [`new Tangerine(options)`](#new-tangerineoptions) | ||
* [`new Tangerine(options[, request])`](#new-tangerineoptions-request) | ||
* [`tangerine.cancel()`](#tangerinecancel) | ||
@@ -70,3 +70,3 @@ * [`tangerine.getServers()`](#tangerinegetservers) | ||
```sh | ||
npm install tangerine | ||
npm install tangerine undici | ||
``` | ||
@@ -200,4 +200,32 @@ | ||
### `new Tangerine(options)` | ||
### `new Tangerine(options[, request])` | ||
* The `request` argument is a `Function` that defaults to [undici.request](https://undici.nodejs.org/#/?id=undicirequesturl-options-promise). | ||
* This is an HTTP library request async or Promise returning function to be used for making requests. | ||
* You could alternatively use [got](https://github.com/sindresorhus/got) or any other HTTP library of your choice that accepts `fn(url, options)`. However, we suggest to stick with the default of `undici` due to these [benchmark tests](http-library-benchmarks). | ||
```js | ||
const tangerine = new Tangerine( | ||
{ | ||
requestOptions: { | ||
responseType: 'buffer', | ||
decompress: false, | ||
retry: { | ||
limit: 0 | ||
} | ||
}, | ||
requestTimeout: (ms) => ({ timeout: { request: ms } }) | ||
}, | ||
got | ||
); | ||
``` | ||
* 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 | ||
* See `requestTimeout` function below, as it is required to be set properly if you are using a custom HTTP library function. | ||
* Instance methods of [dns.promises.Resolver](https://nodejs.org/api/dns.html) are mirrored to :tangerine: Tangerine. | ||
@@ -257,25 +285,24 @@ * Resolver methods accept an optional `abortController` argument, which is an instance of [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController). Note that :tangerine: Tangerine manages `AbortController` usage internally – so you most likely won't need to pass your own (see [index.js](https://github.com/forwardemail/tangerine/blob/main/index.js) for more insight). | ||
| 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). | | ||
| 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`. | | ||
| `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). | | ||
@@ -282,0 +309,0 @@ |
1233
606
100781
25
+ Addedundici@7.3.0(transitive)
- Removedundici@^5.20.0
- Removed@fastify/busboy@2.1.1(transitive)
- Removedundici@5.28.5(transitive)