diff options
Diffstat (limited to 'src/js/thirdparty/node-fetch.ts')
-rw-r--r-- | src/js/thirdparty/node-fetch.ts | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/js/thirdparty/node-fetch.ts b/src/js/thirdparty/node-fetch.ts new file mode 100644 index 000000000..794bdf601 --- /dev/null +++ b/src/js/thirdparty/node-fetch.ts @@ -0,0 +1,97 @@ +import type * as s from "stream"; + +const { Headers, Request, Response: WebResponse, Blob, File = Blob, FormData } = globalThis as any; +const nativeFetch = Bun.fetch; + +const { Readable } = require("node:stream"); + +class Response extends WebResponse { + _body: any; + + get body() { + return this._body ?? (this._body = Readable.fromWeb(super.body)); + } +} + +/** + * `node-fetch` works like the browser-fetch API, except it's a little more strict on some features, + * and uses node streams instead of web streams. + * + * It's overall a positive on speed to override the implementation, since most people will use something + * like `.json()` or `.text()`, which is faster in Bun's native fetch, vs `node-fetch` going + * through `node:http`, a node stream, then processing the data. + */ +async function fetch(url: any, init?: RequestInit & { body?: any }) { + // input node stream -> web stream + let body: s.Readable | undefined = init?.body; + if (body) { + const chunks: any = []; + if (body instanceof Readable) { + // TODO: Bun fetch() doesn't support ReadableStream at all. + for await (const chunk of body) { + chunks.push(chunk); + } + init = { ...init, body: new Blob(chunks) }; + } + } + + const response = await nativeFetch(url, init); + Object.setPrototypeOf(response, Response.prototype); + return response; +} + +class AbortError extends DOMException { + constructor(message) { + super(message, "AbortError"); + } +} + +class FetchBaseError extends Error { + type: string; + + constructor(message, type) { + super(message); + this.type = type; + } +} + +class FetchError extends FetchBaseError { + constructor(message, type, systemError) { + super(message, type); + this.code = systemError?.code; + } +} + +function blobFrom(path, options) { + return Promise.resolve(Bun.file(path, options)); +} + +function blobFromSync(path, options) { + return Bun.file(path, options); +} + +var fileFrom = blobFrom; +var fileFromSync = blobFromSync; + +function isRedirect(code) { + return code === 301 || code === 302 || code === 303 || code === 307 || code === 308; +} + +export default Object.assign(fetch, { + AbortError, + Blob, + FetchBaseError, + FetchError, + File, + FormData, + Headers, + Request, + Response, + blobFrom, + blobFromSync, + fileFrom, + fileFromSync, + isRedirect, + fetch, + default: fetch, +}); |