async function resolve(event, page_nodes, opts) {
		try {
			if (opts) {
				resolve_opts = {
					transformPageChunk: opts.transformPageChunk || default_transform,
					filterSerializedResponseHeaders: opts.filterSerializedResponseHeaders || default_filter,
					preload: opts.preload || default_preload
				};
			}

			if (options.hash_routing || state.prerendering?.fallback) {
				return await render_response({
					event,
					options,
					manifest,
					state,
					page_config: { ssr: false, csr: true },
					status: 200,
					error: null,
					branch: [],
					fetched: [],
					resolve_opts
				});
			}

			if (route) {
				const method = /** @type {import('types').HttpMethod} */ (event.request.method);

				/** @type {Response} */
				let response;

				if (is_data_request) {
					response = await render_data(
						event,
						route,
						options,
						manifest,
						state,
						invalidated_data_nodes,
						trailing_slash
					);
				} else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
					response = await render_endpoint(event, await route.endpoint(), state);
				} else if (route.page) {
					if (!page_nodes) {
						throw new Error('page_nodes not found. This should never happen');
					} else if (page_methods.has(method)) {
						response = await render_page(
							event,
							route.page,
							options,
							manifest,
							state,
							page_nodes,
							resolve_opts
						);
					} else {
						const allowed_methods = new Set(allowed_page_methods);
						const node = await manifest._.nodes[route.page.leaf]();
						if (node?.server?.actions) {
							allowed_methods.add('POST');
						}

						if (method === 'OPTIONS') {
							// This will deny CORS preflight requests implicitly because we don't
							// add the required CORS headers to the response.
							response = new Response(null, {
								status: 204,
								headers: {
									allow: Array.from(allowed_methods.values()).join(', ')
								}
							});
						} else {
							const mod = [...allowed_methods].reduce((acc, curr) => {
								acc[curr] = true;
								return acc;
							}, /** @type {Record<string, any>} */ ({}));
							response = method_not_allowed(mod, method);
						}
					}
				} else {
					// a route will always have a page or an endpoint, but TypeScript doesn't know that
					throw new Error('Route is neither page nor endpoint. This should never happen');
				}

				// If the route contains a page and an endpoint, we need to add a
				// `Vary: Accept` header to the response because of browser caching
				if (request.method === 'GET' && route.page && route.endpoint) {
					const vary = response.headers
						.get('vary')
						?.split(',')
						?.map((v) => v.trim().toLowerCase());
					if (!(vary?.includes('accept') || vary?.includes('*'))) {
						// the returned response might have immutable headers,
						// so we have to clone them before trying to mutate them
						response = new Response(response.body, {
							status: response.status,
							statusText: response.statusText,
							headers: new Headers(response.headers)
						});
						response.headers.append('Vary', 'Accept');
					}
				}

				return response;
			}

			if (state.error && event.isSubRequest) {
				// avoid overwriting the headers. This could be a same origin fetch request
				// to an external service from the root layout while rendering an error page
				const headers = new Headers(request.headers);
				headers.set('x-sveltekit-error', 'true');
				return await fetch(request, { headers });
			}

			if (state.error) {
				return text('Internal Server Error', {
					status: 500
				});
			}

			// if this request came direct from the user, rather than
			// via our own `fetch`, render a 404 page
			if (state.depth === 0) {
				// In local development, Chrome requests this file for its 'automatic workspace folders' feature,
				// causing console spam. If users want to serve this file they can install
				// https://github.com/ChromeDevTools/vite-plugin-devtools-json
				if (DEV && event.url.pathname === '/.well-known/appspecific/com.chrome.devtools.json') {
					if (!warned_on_devtools_json_request) {
						console.warn(
							`\nGoogle Chrome is requesting ${event.url.pathname} to automatically configure devtools project settings. To serve this file, add this plugin to your Vite config:\n\nhttps://github.com/ChromeDevTools/vite-plugin-devtools-json\n`
						);

						warned_on_devtools_json_request = true;
					}

					return new Response(undefined, { status: 404 });
				}

				return await respond_with_error({
					event,
					options,
					manifest,
					state,
					status: 404,
					error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
					resolve_opts
				});
			}

			if (state.prerendering) {
				return text('not found', { status: 404 });
			}

			// we can't load the endpoint from our own manifest,
			// so we need to make an actual HTTP request
			return await fetch(request);
		} catch (e) {
			// TODO if `e` is instead named `error`, some fucked up Vite transformation happens
			// and I don't even know how to describe it. need to investigate at some point

			// HttpError from endpoint can end up here - TODO should it be handled there instead?
			return await handle_fatal_error(event, options, e);
		} finally {
			event.cookies.set = () => {
				throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
			};

			event.setHeaders = () => {
				throw new Error('Cannot use `setHeaders(...)` after the response has been generated');
			};
		}
	}
@param {import('@sveltejs/kit').RequestEvent} event
@param {PageNodes | undefined} page_nodes
@param {import('@sveltejs/kit').ResolveOptions} [opts]