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/).

160 lines (148 loc) 4.57 kB
import type { RequestContext } from '../../../src/utils/requestContext'; import { applyHeaders, createRouteRequest, createMutableResponse, applySearchParams, } from './http'; export type MatchedSetHeaders = { /** * The headers present on a source route. * Gets applied to the final response before the response headers from running a function. */ normal: Headers; /** * The *important* headers - the ones present on a source route that specifies `important: true`. * Gets applied to the final response after the response headers from running a function. */ important: Headers; /** * Tracks if a location header is found, and what the value is, after running a middleware function. */ middlewareLocation?: string | null; }; export type MatchedSet = { path: string; status: number | undefined; headers: MatchedSetHeaders; searchParams: URLSearchParams; body: BodyInit | undefined | null; }; /** * Gets the next phase of the routing process. * * Determines which phase should follow the `none`, `filesystem`, `rewrite`, or `resource` phases. * Falls back to `miss`. * * @param phase Current phase of the routing process. * @returns Next phase of the routing process. */ export function getNextPhase(phase: VercelPhase): VercelHandleValue { switch (phase) { // `none` applied headers/redirects/middleware/`beforeFiles` rewrites. It checked non-dynamic routes and static assets. case 'none': { return 'filesystem'; } // `filesystem` applied `afterFiles` rewrites. It checked those rewritten routes. case 'filesystem': { return 'rewrite'; } // `rewrite` applied dynamic params to requests. It checked dynamic routes. case 'rewrite': { return 'resource'; } // `resource` applied `fallback` rewrites. It checked the final routes. case 'resource': { return 'miss'; } default: { return 'miss'; } } } /** * Runs or fetches a build output item. * * @param item Build output item to run or fetch. * @param request Request object. * @param match Matched route details. * @param assets Fetcher for static assets. * @param ctx Execution context for the request. * @returns Response object. */ export async function runOrFetchBuildOutputItem( item: VercelBuildOutputItem | undefined, { request, assetsFetcher, ctx }: RequestContext, { path, searchParams }: Omit<MatchedSet, 'body'>, ) { let resp: Response | undefined = undefined; // Apply the search params from matching the route to the request URL. const url = new URL(request.url); applySearchParams(url.searchParams, searchParams); const req = new Request(url, request); try { switch (item?.type) { case 'function': case 'middleware': { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const edgeFunction: EdgeFunction = item.handler; try { resp = await edgeFunction.default(req, ctx); } catch (e) { const err = e as Error; if ( err.name === 'TypeError' && err.message.endsWith('default is not a function') ) { throw new Error( `An error occurred while evaluating the target edge function (${item.entrypoint})`, ); } throw e; } break; } case 'override': { resp = createMutableResponse( await assetsFetcher.fetch(createRouteRequest(req, item.path ?? path)), ); if (item.headers) { applyHeaders(resp.headers, item.headers); } break; } case 'static': { resp = await assetsFetcher.fetch(createRouteRequest(req, path)); break; } default: { resp = new Response('Not Found', { status: 404 }); } } } catch (e) { // eslint-disable-next-line no-console console.error(e); return new Response('Internal Server Error', { status: 500 }); } return createMutableResponse(resp); } /** * Checks if a source route's matcher uses the regex format for locales with a trailing slash, where * the locales specified are known. * * Determines whether a matcher is in the format of `^//?(?:en|fr|nl)/(.*)$`. * * @param src Source route `src` regex value. * @param locales Known available locales. * @returns Whether the source route matches the regex for a locale with a trailing slash. */ export function isLocaleTrailingSlashRegex(src: string, locales: Set<string>) { const prefix = '^//?(?:'; const suffix = ')/(.*)$'; if (!src.startsWith(prefix) || !src.endsWith(suffix)) { return false; } const foundLocales = src.slice(prefix.length, -suffix.length).split('|'); return foundLocales.every(locale => locales.has(locale)); }