UNPKG

@fleek-platform/next-on-fleek

Version:

`@fleek-platform/next-on-fleek` is a CLI tool that you can use to build and develop [Next.js](https://nextjs.org/) applications so that they can run on [Fleek Functions](https://fleek.xyz/docs/platform/fleek-functions/).

111 lines (94 loc) 3.65 kB
/** * Patches the global fetch in ways necessary for Next.js (/next-on-fleek) applications * to work */ export function patchFetch(): void { const alreadyPatched = (globalThis as GlobalWithPatchSymbol)[patchFlagSymbol]; if (alreadyPatched) return; applyPatch(); (globalThis as GlobalWithPatchSymbol)[patchFlagSymbol] = true; } function applyPatch() { const originalFetch = globalThis.fetch; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore globalThis.fetch = async (...args) => { const request = new Request(...args); const response = await handleInlineAssetRequest(request); if (response) return response; setRequestUserAgentIfNeeded(request); return originalFetch(request); }; } /** * This function checks if a given request is trying to fetch an inline if it is it returns a response containing a stream for the asset, * otherwise returns null (signaling that the request hasn't been handled). * * This is necessary so that users can fetch urls such as: `new URL("file", import.meta.url)` * (used for example with `@vercel/og`) * * Note: this function's aim is to mimic the following Next behavior: * https://github.com/vercel/next.js/blob/6705c803021d3bdea7fec20e5d98f6899e49836d/packages/next/src/server/web/sandbox/fetch-inline-assets.ts * * @param request the request to handle * @returns the response to return to the caller if the request was for an inline asset one (and the file exists), null otherwise */ async function handleInlineAssetRequest(request: Request) { if (request.url.startsWith('blob:')) { try { const url = new URL(request.url); const pathname = url.pathname; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const builtUrl = `https://${process.env.ASSETS_CID}.ipfs.flk-ipfs.xyz/_worker.js/__next-on-fleek-dist__/assets/${pathname}`; const response = await fetch(builtUrl); return Promise.resolve(response); } catch (error) { // eslint-disable-next-line no-console console.log('Failed to fetch from IPFS'); // eslint-disable-next-line no-console console.error(error); } } return null; } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore globalThis.ASSETS = { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore fetch: async req => { try { const { pathname } = new URL(req.url); let assetPath = pathname; if (/\.[^.]+$/.test(assetPath)) { const noExt = pathname.replace(/\.html$/, ''); assetPath = `${noExt.replace(/\/$/, '/index')}.html`; } const response = await fetch( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore `https://${process.env.ASSETS_CID}.ipfs.flk-ipfs.xyz${assetPath}`, ); return Promise.resolve(response); } catch (error) { return Promise.reject(error); } }, }; /** * updates the provided request by adding a Next.js specific user-agent header if the request has no user-agent header * * Note: this is done by the Vercel network, but also in their next dev server as you can see here: * https://github.com/vercel/next.js/blob/6705c803021d3bdea7fec20e5d98f6899e49836d/packages/next/src/server/web/sandbox/context.ts#L318-L320) * @param request the request to update */ function setRequestUserAgentIfNeeded( request: Request<unknown, RequestInitCfProperties>, ): void { if (!request.headers.has('user-agent')) { request.headers.set(`user-agent`, `Next.js Middleware`); } } const patchFlagSymbol = Symbol.for('next-on-pages fetch patch'); type GlobalWithPatchSymbol = typeof globalThis & { [patchFlagSymbol]: boolean };