import './globals';
import { adapter } from './adapter';
import { IncrementalCache } from '../lib/incremental-cache';
import { RouteMatcher } from '../route-matchers/route-matcher';
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';
/**
 * EdgeRouteModuleWrapper is a wrapper around a route module.
 *
 * Note that this class should only be used in the edge runtime.
 */ export class EdgeRouteModuleWrapper {
    /**
   * The constructor is wrapped with private to ensure that it can only be
   * constructed by the static wrap method.
   *
   * @param routeModule the route module to wrap
   */ constructor(routeModule, nextConfig){
        this.routeModule = routeModule;
        this.nextConfig = nextConfig;
        // TODO: (wyattjoh) possibly allow the module to define it's own matcher
        this.matcher = new RouteMatcher(routeModule.definition);
    }
    /**
   * This will wrap a module with the EdgeModuleWrapper and return a function
   * that can be used as a handler for the edge runtime.
   *
   * @param module the module to wrap
   * @param options any options that should be passed to the adapter and
   *                override the ones passed from the runtime
   * @returns a function that can be used as a handler for the edge runtime
   */ static wrap(routeModule, options) {
        // Create the module wrapper.
        const wrapper = new EdgeRouteModuleWrapper(routeModule, options.nextConfig);
        // Return the wrapping function.
        return (opts)=>{
            return adapter({
                ...opts,
                IncrementalCache,
                // Bind the handler method to the wrapper so it still has context.
                handler: wrapper.handler.bind(wrapper)
            });
        };
    }
    async handler(request, evt) {
        const utils = getServerUtils({
            pageIsDynamic: this.matcher.isDynamic,
            page: this.matcher.definition.pathname,
            basePath: request.nextUrl.basePath,
            // We don't need the `handleRewrite` util, so can just pass an empty object
            rewrites: {},
            // only used for rewrites, so setting an arbitrary default value here
            caseSensitive: false
        });
        const { params } = utils.normalizeDynamicRouteParams(searchParamsToUrlQuery(request.nextUrl.searchParams), false);
        const waitUntil = evt.waitUntil.bind(evt);
        const closeController = new CloseController();
        const previewProps = getEdgePreviewProps();
        // Create the context for the handler. This contains the params from the
        // match (if any).
        const context = {
            params,
            prerenderManifest: {
                version: 4,
                routes: {},
                dynamicRoutes: {},
                preview: previewProps,
                notFoundRoutes: []
            },
            renderOpts: {
                supportsDynamicResponse: true,
                waitUntil,
                onClose: closeController.onClose.bind(closeController),
                onAfterTaskError: undefined,
                experimental: {
                    cacheComponents: !!process.env.__NEXT_CACHE_COMPONENTS,
                    authInterrupts: !!process.env.__NEXT_EXPERIMENTAL_AUTH_INTERRUPTS
                },
                cacheLifeProfiles: this.nextConfig.experimental.cacheLife
            },
            sharedContext: {
                buildId: ''
            }
        };
        // Get the response from the handler.
        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) {
            // we can delay running it until a bit later --
            // if it's needed, we'll have a `waitUntil` lock anyway.
            setTimeout(()=>closeController.dispatchClose(), 0);
        } else {
            // NOTE: if this is a streaming response, onClose may be called later,
            // so we can't rely on `closeController.listeners` -- it might be 0 at this point.
            const trackedBody = trackStreamConsumed(res.body, ()=>closeController.dispatchClose());
            res = new Response(trackedBody, {
                status: res.status,
                statusText: res.statusText,
                headers: res.headers
            });
        }
        return res;
    }
}

//# sourceMappingURL=edge-route-module-wrapper.js.map