|
| 1 | +import { fetch as f, fetcher } from "@fetch-impl/fetcher"; |
| 2 | +import debug from "debug"; |
| 3 | +import type { Browser } from "puppeteer"; |
| 4 | + |
| 5 | +export const log = debug("fetch:puppeteer"); |
| 6 | + |
| 7 | +/** |
| 8 | + * Configures the `fetch` implementation to use Puppeteer for making HTTP requests. |
| 9 | + * |
| 10 | + * @param _browser - The Puppeteer browser instance or a promise that resolves to a browser instance. |
| 11 | + * @param instance - The fetcher instance to configure. |
| 12 | + */ |
| 13 | +export function usePuppeteer(_browser: Browser | Promise<Browser>, instance = fetcher): void { |
| 14 | + let idx = 0; |
| 15 | + |
| 16 | + instance.set(async (...args) => { |
| 17 | + const i = idx++; |
| 18 | + const url = args[0].toString(); |
| 19 | + log("Fetching", i, url, args[1]); |
| 20 | + |
| 21 | + const browser = await _browser; |
| 22 | + const page = await browser.newPage(); |
| 23 | + await page.goto(url); |
| 24 | + |
| 25 | + const res = await page.evaluate(async (args) => { |
| 26 | + /* c8 ignore next 11 */ |
| 27 | + // v8 coverage is not working for code running in browser |
| 28 | + const res = await fetch(...args); |
| 29 | + const body = Array.from(await res.arrayBuffer().then((buf) => new Uint32Array(buf))); |
| 30 | + |
| 31 | + return { |
| 32 | + body: body, |
| 33 | + status: res.status, |
| 34 | + statusText: res.statusText, |
| 35 | + // @ts-ignore headers is iterable in browser |
| 36 | + headers: Object.fromEntries(res.headers), |
| 37 | + }; |
| 38 | + }, args); |
| 39 | + log("Fetched", i, res.status, res.statusText, res.headers, res.body.length, "bytes"); |
| 40 | + const body = new Uint32Array(res.body).buffer; |
| 41 | + |
| 42 | + page.close().catch(() => log("Failed to close page", i)); |
| 43 | + return new Response(body, res); |
| 44 | + }); |
| 45 | +} |
| 46 | + |
| 47 | +export * from "@fetch-impl/fetcher"; |
| 48 | +export default f; |
0 commit comments