| | import type { |
| | AppRouteRouteHandlerContext, |
| | AppRouteRouteModule, |
| | } from '../route-modules/app-route/module' |
| |
|
| | import './globals' |
| |
|
| | import { adapter, type NextRequestHint, type EdgeHandler } from './adapter' |
| | import { IncrementalCache } from '../lib/incremental-cache' |
| | import { RouteMatcher } from '../route-matchers/route-matcher' |
| | import type { NextFetchEvent } from './spec-extension/fetch-event' |
| | import { internal_getCurrentFunctionWaitUntil } from './internal-edge-wait-until' |
| | import { getServerUtils } from '../server-utils' |
| | import { searchParamsToUrlQuery } from '../../shared/lib/router/utils/querystring' |
| | import { CloseController, trackStreamConsumed } from './web-on-close' |
| | import { getEdgePreviewProps } from './get-edge-preview-props' |
| | import { WebNextRequest } from '../../server/base-http/web' |
| |
|
| | export interface WrapOptions { |
| | page: string |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export class EdgeRouteModuleWrapper { |
| | private readonly matcher: RouteMatcher |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | private constructor(private readonly routeModule: AppRouteRouteModule) { |
| | |
| | this.matcher = new RouteMatcher(routeModule.definition) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static wrap( |
| | routeModule: AppRouteRouteModule, |
| | options: WrapOptions |
| | ): EdgeHandler { |
| | |
| | const wrapper = new EdgeRouteModuleWrapper(routeModule) |
| |
|
| | |
| | return (opts) => { |
| | return adapter({ |
| | ...opts, |
| | IncrementalCache, |
| | |
| | handler: wrapper.handler.bind(wrapper), |
| | page: options.page, |
| | }) |
| | } |
| | } |
| |
|
| | private async handler( |
| | request: NextRequestHint, |
| | evt: NextFetchEvent |
| | ): Promise<Response> { |
| | const utils = getServerUtils({ |
| | pageIsDynamic: this.matcher.isDynamic, |
| | page: this.matcher.definition.pathname, |
| | basePath: request.nextUrl.basePath, |
| | |
| | rewrites: {}, |
| | |
| | caseSensitive: false, |
| | }) |
| |
|
| | const { nextConfig } = this.routeModule.getNextConfigEdge( |
| | new WebNextRequest(request) |
| | ) |
| |
|
| | const { params } = utils.normalizeDynamicRouteParams( |
| | searchParamsToUrlQuery(request.nextUrl.searchParams), |
| | false |
| | ) |
| |
|
| | const waitUntil = evt.waitUntil.bind(evt) |
| | const closeController = new CloseController() |
| |
|
| | const previewProps = getEdgePreviewProps() |
| |
|
| | |
| | |
| | const context: AppRouteRouteHandlerContext = { |
| | params, |
| | prerenderManifest: { |
| | version: 4, |
| | routes: {}, |
| | dynamicRoutes: {}, |
| | preview: previewProps, |
| | notFoundRoutes: [], |
| | }, |
| | renderOpts: { |
| | supportsDynamicResponse: true, |
| | waitUntil, |
| | onClose: closeController.onClose.bind(closeController), |
| | onAfterTaskError: undefined, |
| | cacheComponents: !!process.env.__NEXT_CACHE_COMPONENTS, |
| | experimental: { |
| | authInterrupts: !!process.env.__NEXT_EXPERIMENTAL_AUTH_INTERRUPTS, |
| | }, |
| | cacheLifeProfiles: nextConfig.cacheLife, |
| | }, |
| | sharedContext: { |
| | buildId: '', |
| | }, |
| | } |
| |
|
| | |
| | let res = await this.routeModule.handle(request, context) |
| |
|
| | const waitUntilPromises = [internal_getCurrentFunctionWaitUntil()] |
| | if (context.renderOpts.pendingWaitUntil) { |
| | waitUntilPromises.push(context.renderOpts.pendingWaitUntil) |
| | } |
| | evt.waitUntil(Promise.all(waitUntilPromises)) |
| |
|
| | if (!res.body) { |
| | |
| | |
| | setTimeout(() => closeController.dispatchClose(), 0) |
| | } else { |
| | |
| | |
| | const trackedBody = trackStreamConsumed(res.body, () => |
| | closeController.dispatchClose() |
| | ) |
| | res = new Response(trackedBody, { |
| | status: res.status, |
| | statusText: res.statusText, |
| | headers: res.headers, |
| | }) |
| | } |
| |
|
| | return res |
| | } |
| | } |
| |
|