diff --git a/package.json b/package.json index e11bd07..e2e6679 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "./src/files/glob-source": false, "./test/files/glob-source.spec.js": false, "electron-fetch": false, + "@web-std/fetch": false, "fs": false }, "react-native": { @@ -51,7 +52,7 @@ "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", - "any-signal": "^2.1.0", + "any-signal": "^2.1.2", "buffer": "^6.0.1", "electron-fetch": "^1.7.2", "err-code": "^3.0.1", @@ -62,8 +63,7 @@ "merge-options": "^3.0.4", "nanoid": "^3.1.20", "native-abort-controller": "^1.0.3", - "native-fetch": "^3.0.0", - "node-fetch": "^2.6.1", + "@web-std/fetch": "^2.0.1", "react-native-fetch-api": "^1.0.2", "stream-to-it": "^0.2.2" }, diff --git a/src/fetch.js b/src/fetch.js index d3ee792..7d4c827 100644 --- a/src/fetch.js +++ b/src/fetch.js @@ -1,10 +1,12 @@ 'use strict' -const { isElectronMain } = require('./env') +const { isElectronMain, isNode } = require('./env') if (isElectronMain) { module.exports = require('electron-fetch') +} else if (isNode) { + module.exports = require('@web-std/fetch') } else { -// use window.fetch if it is available, fall back to node-fetch if not - module.exports = require('native-fetch') + const lib = { default: fetch, Response, Request, Headers } + module.exports = lib } diff --git a/src/http.js b/src/http.js index 9ce142c..827637b 100644 --- a/src/http.js +++ b/src/http.js @@ -126,7 +126,7 @@ class HTTP { // @ts-ignore const signal = anySignal([abortController.signal, opts.signal]) - const response = await timeout( + const response = /** @type {ExtendedResponse} */ (await timeout( fetch( url.toString(), { @@ -138,7 +138,7 @@ class HTTP { ), opts.timeout, abortController - ) + )) if (!response.ok && opts.throwHttpErrors) { if (opts.handleError) { @@ -147,8 +147,8 @@ class HTTP { throw new HTTPError(response) } - response.iterator = function () { - return fromStream(response.body) + response.iterator = async function * () { + yield * fromStream(response.body) } response.ndjson = async function * () { diff --git a/src/http/fetch.browser.js b/src/http/fetch.browser.js index ee59420..6de173e 100644 --- a/src/http/fetch.browser.js +++ b/src/http/fetch.browser.js @@ -13,7 +13,7 @@ const { Response, Request, Headers, default: fetch } = require('../fetch') * * @param {string | Request} url * @param {FetchOptions} [options] - * @returns {Promise} + * @returns {Promise} */ const fetchWithProgress = (url, options = {}) => { const request = new XMLHttpRequest() diff --git a/src/http/fetch.node.js b/src/http/fetch.node.js index 32b9d59..130a175 100644 --- a/src/http/fetch.node.js +++ b/src/http/fetch.node.js @@ -29,12 +29,7 @@ const fetch = (url, options = {}) => const withUploadProgress = (options) => { const { onUploadProgress, body } = options if (onUploadProgress && body) { - // This works around the fact that electron-fetch serializes `Uint8Array`s - // and `ArrayBuffer`s to strings. - const content = normalizeBody(body) - - const rsp = new Response(content) - const source = iterateBodyWithProgress(/** @type {NodeReadableStream} */(rsp.body), onUploadProgress) + const source = iterateBodyWithProgress(normalizeBody(body), onUploadProgress) return { ...options, body: toStream.readable(source) @@ -63,9 +58,9 @@ const normalizeBody = (input) => { * and returns async iterable that emits body chunks and emits * `onUploadProgress`. * - * @param {NodeReadableStream | null} body + * @param {Blob | FormData | ReadableStream | NodeReadableStream | Buffer} body * @param {ProgressFn} onUploadProgress - * @returns {AsyncIterable} + * @returns {AsyncIterable} */ const iterateBodyWithProgress = async function * (body, onUploadProgress) { if (body == null) { @@ -76,17 +71,29 @@ const iterateBodyWithProgress = async function * (body, onUploadProgress) { yield body onUploadProgress({ total, loaded: total, lengthComputable }) } else { - const total = 0 - const lengthComputable = false + const progress = estimateTotal(body) + let loaded = 0 - for await (const chunk of body) { + // @ts-ignore - Response does not take node stream + for await (const chunk of new Response(body).body) { loaded += chunk.byteLength yield chunk - onUploadProgress({ total, loaded, lengthComputable }) + onUploadProgress({ ...progress, loaded }) } } } +/** + * @param {any} value + */ +const estimateTotal = (value) => { + if (typeof value.size === 'number') { + return { total: value.size, lengthComputable: true } + } else { + return { total: 0, lengthComputable: false } + } +} + module.exports = { fetch, Request,