text: import Root from '../../generated/root.svelte';
  import { fallback, routes } from '../../generated/manifest.js';
  import { g as get_base_uri } from '../chunks/utils.js';
  import { writable } from 'svelte/store';
  import { init } from './singletons.js';
  import { set_paths } from '../paths.js';
  
  function scroll_state() {
  	return {
  		x: pageXOffset,
  		y: pageYOffset
  	};
  }
  
  /**
   * @param {Node | null} node
   * @returns {HTMLAnchorElement | SVGAElement | null}
   */
  function find_anchor(node) {
  	while (node && node.nodeName.toUpperCase() !== 'A') node = node.parentNode; // SVG <a> elements have a lowercase name
  	return /** @type {HTMLAnchorElement | SVGAElement} */ (node);
  }
  
  class Router {
  	/**
  	 * @param {{
  	 *    base: string;
  	 *    routes: import('types/internal').CSRRoute[];
  	 *    trailing_slash: import('types/internal').TrailingSlash;
  	 *    renderer: import('./renderer').Renderer
  	 * }} opts
  	 */
  	constructor({ base, routes, trailing_slash, renderer }) {
  		this.base = base;
  		this.routes = routes;
  		this.trailing_slash = trailing_slash;
  
  		/** @type {import('./renderer').Renderer} */
  		this.renderer = renderer;
  		renderer.router = this;
  
  		this.enabled = true;
  
  		// make it possible to reset focus
  		document.body.setAttribute('tabindex', '-1');
  
  		// create initial history entry, so we can return here
  		history.replaceState(history.state || {}, '', location.href);
  	}
  
  	init_listeners() {
  		if ('scrollRestoration' in history) {
  			history.scrollRestoration = 'manual';
  		}
  
  		// Adopted from Nuxt.js
  		// Reset scrollRestoration to auto when leaving page, allowing page reload
  		// and back-navigation from other pages to use the browser to restore the
  		// scrolling position.
  		addEventListener('beforeunload', () => {
  			history.scrollRestoration = 'auto';
  		});
  
  		// Setting scrollRestoration to manual again when returning to this page.
  		addEventListener('load', () => {
  			history.scrollRestoration = 'manual';
  		});
  
  		// There's no API to capture the scroll location right before the user
  		// hits the back/forward button, so we listen for scroll events
  
  		/** @type {NodeJS.Timeout} */
  		let scroll_timer;
  		addEventListener('scroll', () => {
  			clearTimeout(scroll_timer);
  			scroll_timer = setTimeout(() => {
  				// Store the scroll location in the history
  				// This will persist even if we navigate away from the site and come back
  				const new_state = {
  					...(history.state || {}),
  					'sveltekit:scroll': scroll_state()
  				};
  				history.replaceState(new_state, document.title, window.location.href);
  			}, 50);
  		});
  
  		/** @param {MouseEvent|TouchEvent} event */
  		const trigger_prefetch = (event) => {
  			const a = find_anchor(/** @type {Node} */ (event.target));
  			if (a && a.href && a.hasAttribute('sveltekit:prefetch')) {
  				this.prefetch(new URL(/** @type {string} */ (a.href)));
  			}
  		};
  
  		/** @type {NodeJS.Timeout} */
  		let mousemove_timeout;
  
  		/** @param {MouseEvent|TouchEvent} event */
  		const handle_mousemove = (event) => {
  			clearTimeout(mousemove_timeout);
  			mousemove_timeout = setTimeout(() => {
  				trigger_prefetch(event);
  			}, 20);
  		};
  
  		addEventListener('touchstart', trigger_prefetch);
  		addEventListener('mousemove', handle_mousemove);
  
  		/** @param {MouseEvent} event */
  		addEventListener('click', (event) => {
  			if (!this.enabled) return;
  
  			// Adapted from https://github.com/visionmedia/page.js
  			// MIT license https://github.com/visionmedia/page.js#license
  			if (event.button || event.which !== 1) return;
  			if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
  			if (event.defaultPrevented) return;
  
  			const a = find_anchor(/** @type {Node} */ (event.target));
  			if (!a) return;
  
  			if (!a.href) return;
  
  			// check if link is inside an svg
  			// in this case, both href and target are always inside an object
  			const svg = typeof a.href === 'object' && a.href.constructor.name === 'SVGAnimatedString';
  			const href = String(svg ? /** @type {SVGAElement} */ (a).href.baseVal : a.href);
  
  			if (href === location.href) {
  				if (!location.hash) event.preventDefault();
  				return;
  			}
  
  			// Ignore if tag has
  			// 1. 'download' attribute
  			// 2. 'rel' attribute includes external
  			const rel = (a.getAttribute('rel') || '').split(/\s+/);
  
  			if (a.hasAttribute('download') || (rel && rel.includes('external'))) {
  				return;
  			}
  
  			// Ignore if <a> has a target
  			if (svg ? /** @type {SVGAElement} */ (a).target.baseVal : a.target) return;
  
  			const url = new URL(href);
  
  			if (!this.owns(url)) return;
  
  			const noscroll = a.hasAttribute('sveltekit:noscroll');
  
  			history.pushState({}, '', url.href);
  			this._navigate(url, noscroll ? scroll_state() : null, false, [], url.hash);
  			event.preventDefault();
  		});
  
  		addEventListener('popstate', (event) => {
  			if (event.state && this.enabled) {
  				const url = new URL(location.href);
  				this._navigate(url, event.state['sveltekit:scroll'], false, []);
  			}
  		});
  	}
  
  	/** @param {URL} url */
  	owns(url) {
  		return url.origin === location.origin && url.pathname.startsWith(this.base);
  	}
  
  	/**
  	 * @param {URL} url
  	 * @returns {import('./types').NavigationInfo | undefined}
  	 */
  	parse(url) {
  		if (this.owns(url)) {
  			const path = decodeURIComponent(url.pathname.slice(this.base.length) || '/');
  
  			const routes = this.routes.filter(([pattern]) => pattern.test(path));
  
  			const query = new URLSearchParams(url.search);
  			const id = `${path}?${query}`;
  
  			return { id, routes, path, query };
  		}
  	}
  
  	/**
  	 * @typedef {Parameters<typeof import('$app/navigation').goto>} GotoParams
  	 *
  	 * @param {GotoParams[0]} href
  	 * @param {GotoParams[1]} opts
  	 * @param {string[]} chain
  	 */
  	async goto(
  		href,
  		{ noscroll = false, replaceState = false, keepfocus = false, state = {} } = {},
  		chain
  	) {
  		const url = new URL(href, get_base_uri(document));
  
  		if (this.enabled && this.owns(url)) {
  			history[replaceState ? 'replaceState' : 'pushState'](state, '', href);
  			return this._navigate(url, noscroll ? scroll_state() : null, keepfocus, chain, url.hash);
  		}
  
  		location.href = url.href;
  		return new Promise(() => {
  			/* never resolves */
  		});
  	}
  
  	enable() {
  		this.enabled = true;
  	}
  
  	disable() {
  		this.enabled = false;
  	}
  
  	/**
  	 * @param {URL} url
  	 * @returns {Promise<import('./types').NavigationResult>}
  	 */
  	async prefetch(url) {
  		const info = this.parse(url);
  
  		if (!info) {
  			throw new Error('Attempted to prefetch a URL that does not belong to this app');
  		}
  
  		return this.renderer.load(info);
  	}
  
  	/**
  	 * @param {URL} url
  	 * @param {{ x: number, y: number }?} scroll
  	 * @param {boolean} keepfocus
  	 * @param {string[]} chain
  	 * @param {string} [hash]
  	 */
  	async _navigate(url, scroll, keepfocus, chain, hash) {
  		const info = this.parse(url);
  
  		if (!info) {
  			throw new Error('Attempted to navigate to a URL that does not belong to this app');
  		}
  
  		// remove trailing slashes
  		if (info.path !== '/') {
  			const has_trailing_slash = info.path.endsWith('/');
  
  			const incorrect =
  				(has_trailing_slash && this.trailing_slash === 'never') ||
  				(!has_trailing_slash &&
  					this.trailing_slash === 'always' &&
  					!(info.path.split('/').pop() || '').includes('.'));
  
  			if (incorrect) {
  				info.path = has_trailing_slash ? info.path.slice(0, -1) : info.path + '/';
  				history.replaceState({}, '', `${this.base}${info.path}${location.search}`);
  			}
  		}
  
  		this.renderer.notify({
  			path: info.path,
  			query: info.query
  		});
  
  		await this.renderer.update(info, chain, false);
  
  		if (!keepfocus) {
  			document.body.focus();
  		}
  
  		const deep_linked = hash && document.getElementById(hash.slice(1));
  		if (scroll) {
  			scrollTo(scroll.x, scroll.y);
  		} else if (deep_linked) {
  			// Here we use `scrollIntoView` on the element instead of `scrollTo`
  			// because it natively supports the `scroll-margin` and `scroll-behavior`
  			// CSS properties.
  			deep_linked.scrollIntoView();
  		} else {
  			scrollTo(0, 0);
  		}
  	}
  }
  
  /**
   * Hash using djb2
   * @param {import('types/hooks').StrictBody} value
   */
  function hash(value) {
  	let hash = 5381;
  	let i = value.length;
  
  	if (typeof value === 'string') {
  		while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
  	} else {
  		while (i) hash = (hash * 33) ^ value[--i];
  	}
  
  	return (hash >>> 0).toString(36);
  }
  
  /**
   * @param {import('types/page').LoadOutput} loaded
   * @returns {import('types/internal').NormalizedLoadOutput}
   */
  function normalize(loaded) {
  	const has_error_status =
  		loaded.status && loaded.status >= 400 && loaded.status <= 599 && !loaded.redirect;
  	if (loaded.error || has_error_status) {
  		const status = loaded.status;
  
  		if (!loaded.error && has_error_status) {
  			return {
  				status: status || 500,
  				error: new Error()
  			};
  		}
  
  		const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
  
  		if (!(error instanceof Error)) {
  			return {
  				status: 500,
  				error: new Error(
  					`"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"`
  				)
  			};
  		}
  
  		if (!status || status < 400 || status > 599) {
  			console.warn('"error" returned from load() without a valid status code — defaulting to 500');
  			return { status: 500, error };
  		}
  
  		return { status, error };
  	}
  
  	if (loaded.redirect) {
  		if (!loaded.status || Math.floor(loaded.status / 100) !== 3) {
  			return {
  				status: 500,
  				error: new Error(
  					'"redirect" property returned from load() must be accompanied by a 3xx status code'
  				)
  			};
  		}
  
  		if (typeof loaded.redirect !== 'string') {
  			return {
  				status: 500,
  				error: new Error('"redirect" property returned from load() must be a string')
  			};
  		}
  	}
  
  	return /** @type {import('types/internal').NormalizedLoadOutput} */ (loaded);
  }
  
  /**
   * @param {unknown} err
   * @return {Error}
   */
  function coalesce_to_error(err) {
  	return err instanceof Error ? err : new Error(JSON.stringify(err));
  }
  
  /** @param {any} value */
  function page_store(value) {
  	const store = writable(value);
  	let ready = true;
  
  	function notify() {
  		ready = true;
  		store.update((val) => val);
  	}
  
  	/** @param {any} new_value */
  	function set(new_value) {
  		ready = false;
  		store.set(new_value);
  	}
  
  	/** @param {(value: any) => void} run */
  	function subscribe(run) {
  		/** @type {any} */
  		let old_value;
  		return store.subscribe((new_value) => {
  			if (old_value === undefined || (ready && new_value !== old_value)) {
  				run((old_value = new_value));
  			}
  		});
  	}
  
  	return { notify, set, subscribe };
  }
  
  /**
   * @param {RequestInfo} resource
   * @param {RequestInit} [opts]
   */
  function initial_fetch(resource, opts) {
  	const url = typeof resource === 'string' ? resource : resource.url;
  
  	let selector = `script[data-type="svelte-data"][data-url="${url}"]`;
  
  	if (opts && typeof opts.body === 'string') {
  		selector += `[data-body="${hash(opts.body)}"]`;
  	}
  
  	const script = document.querySelector(selector);
  	if (script && script.textContent) {
  		const { body, ...init } = JSON.parse(script.textContent);
  		return Promise.resolve(new Response(body, init));
  	}
  
  	return fetch(resource, opts);
  }
  
  /** @typedef {import('types/internal').CSRComponent} CSRComponent */
  
  class Renderer {
  	/** @param {{
  	 *   Root: CSRComponent;
  	 *   fallback: [CSRComponent, CSRComponent];
  	 *   target: Node;
  	 *   session: any;
  	 *   host: string;
  	 * }} opts */
  	constructor({ Root, fallback, target, session, host }) {
  		this.Root = Root;
  		this.fallback = fallback;
  		this.host = host;
  
  		/** @type {import('./router').Router | undefined} */
  		this.router;
  
  		this.target = target;
  
  		this.started = false;
  
  		this.session_id = 1;
  		this.invalid = new Set();
  		this.invalidating = null;
  
  		/** @type {import('./types').NavigationState} */
  		this.current = {
  			// @ts-expect-error
  			page: null,
  			// @ts-expect-error
  			session_id: null,
  			branch: []
  		};
  
  		/** @type {Map<string, import('./types').NavigationResult>} */
  		this.cache = new Map();
  
  		/** @type {{id: string | null, promise: Promise<import('./types').NavigationResult> | null}} */
  		this.loading = {
  			id: null,
  			promise: null
  		};
  
  		this.stores = {
  			page: page_store({}),
  			navigating: writable(null),
  			session: writable(session)
  		};
  
  		this.$session = null;
  
  		this.root = null;
  
  		let ready = false;
  		this.stores.session.subscribe(async (value) => {
  			this.$session = value;
  
  			if (!ready || !this.router) return;
  			this.session_id += 1;
  
  			const info = this.router.parse(new URL(location.href));
  			if (info) this.update(info, [], true);
  		});
  		ready = true;
  	}
  
  	/**
  	 * @param {{
  	 *   status: number;
  	 *   error: Error;
  	 *   nodes: Array<Promise<CSRComponent>>;
  	 *   page: import('types/page').Page;
  	 * }} selected
  	 */
  	async start({ status, error, nodes, page }) {
  		/** @type {Array<import('./types').BranchNode | undefined>} */
  		const branch = [];
  
  		/** @type {Record<string, any>} */
  		let context = {};
  
  		/** @type {import('./types').NavigationResult | undefined} */
  		let result;
  
  		let error_args;
  
  		try {
  			for (let i = 0; i < nodes.length; i += 1) {
  				const is_leaf = i === nodes.length - 1;
  
  				const node = await this._load_node({
  					module: await nodes[i],
  					page,
  					context,
  					status: is_leaf ? status : undefined,
  					error: is_leaf ? error : undefined
  				});
  
  				branch.push(node);
  
  				if (node && node.loaded) {
  					if (node.loaded.error) {
  						if (error) throw node.loaded.error;
  						error_args = {
  							status: node.loaded.status,
  							error: node.loaded.error,
  							path: page.path,
  							query: page.query
  						};
  					} else if (node.loaded.context) {
  						context = {
  							...context,
  							...node.loaded.context
  						};
  					}
  				}
  			}
  
  			result = error_args
  				? await this._load_error(error_args)
  				: await this._get_navigation_result_from_branch({ page, branch });
  		} catch (/** @type {unknown} */ e) {
  			if (error) throw e;
  
  			result = await this._load_error({
  				status: 500,
  				error: coalesce_to_error(e),
  				path: page.path,
  				query: page.query
  			});
  		}
  
  		if (result.redirect) {
  			// this is a real edge case — `load` would need to return
  			// a redirect but only in the browser
  			location.href = new URL(result.redirect, location.href).href;
  			return;
  		}
  
  		this._init(result);
  	}
  
  	/** @param {{ path: string, query: URLSearchParams }} destination */
  	notify({ path, query }) {
  		dispatchEvent(new CustomEvent('sveltekit:navigation-start'));
  
  		if (this.started) {
  			// @ts-expect-error
  			this.stores.navigating.set({
  				from: {
  					path: this.current.page.path,
  					query: this.current.page.query
  				},
  				to: {
  					path,
  					query
  				}
  			});
  		}
  	}
  
  	/**
  	 * @param {import('./types').NavigationInfo} info
  	 * @param {string[]} chain
  	 * @param {boolean} no_cache
  	 */
  	async update(info, chain, no_cache) {
  		const token = (this.token = {});
  		let navigation_result = await this._get_navigation_result(info, no_cache);
  
  		// abort if user navigated during update
  		if (token !== this.token) return;
  
  		this.invalid.clear();
  
  		if (navigation_result.redirect) {
  			if (chain.length > 10 || chain.includes(info.path)) {
  				navigation_result = await this._load_error({
  					status: 500,
  					error: new Error('Redirect loop'),
  					path: info.path,
  					query: info.query
  				});
  			} else {
  				if (this.router) {
  					this.router.goto(navigation_result.redirect, { replaceState: true }, [
  						...chain,
  						info.path
  					]);
  				} else {
  					location.href = new URL(navigation_result.redirect, location.href).href;
  				}
  
  				return;
  			}
  		}
  
  		if (navigation_result.reload) {
  			location.reload();
  		} else if (this.started) {
  			this.current = navigation_result.state;
  
  			this.root.$set(navigation_result.props);
  			this.stores.navigating.set(null);
  
  			await 0;
  		} else {
  			this._init(navigation_result);
  		}
  
  		dispatchEvent(new CustomEvent('sveltekit:navigation-end'));
  		this.loading.promise = null;
  		this.loading.id = null;
  
  		if (!this.router) return;
  		const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1];
  		if (leaf_node && leaf_node.module.router === false) {
  			this.router.disable();
  		} else {
  			this.router.enable();
  		}
  	}
  
  	/**
  	 * @param {import('./types').NavigationInfo} info
  	 * @returns {Promise<import('./types').NavigationResult>}
  	 */
  	load(info) {
  		this.loading.promise = this._get_navigation_result(info, false);
  		this.loading.id = info.id;
  
  		return this.loading.promise;
  	}
  
  	/** @param {string} href */
  	invalidate(href) {
  		this.invalid.add(href);
  
  		if (!this.invalidating) {
  			this.invalidating = Promise.resolve().then(async () => {
  				const info = this.router && this.router.parse(new URL(location.href));
  				if (info) await this.update(info, [], true);
  
  				this.invalidating = null;
  			});
  		}
  
  		return this.invalidating;
  	}
  
  	/** @param {import('./types').NavigationResult} result */
  	_init(result) {
  		this.current = result.state;
  
  		const style = document.querySelector('style[data-svelte]');
  		if (style) style.remove();
  
  		this.root = new this.Root({
  			target: this.target,
  			props: {
  				stores: this.stores,
  				...result.props
  			},
  			hydrate: true
  		});
  
  		this.started = true;
  	}
  
  	/**
  	 * @param {import('./types').NavigationInfo} info
  	 * @param {boolean} no_cache
  	 * @returns {Promise<import('./types').NavigationResult>}
  	 */
  	async _get_navigation_result(info, no_cache) {
  		if (this.loading.id === info.id) {
  			// @ts-expect-error if the id is defined then the promise is too
  			return this.loading.promise;
  		}
  
  		for (let i = 0; i < info.routes.length; i += 1) {
  			const route = info.routes[i];
  
  			// check if endpoint route
  			if (route.length === 1) {
  				return { reload: true, props: {}, state: this.current };
  			}
  
  			// load code for subsequent routes immediately, if they are as
  			// likely to match the current path/query as the current one
  			let j = i + 1;
  			while (j < info.routes.length) {
  				const next = info.routes[j];
  				if (next[0].toString() === route[0].toString()) {
  					// if it's a page route
  					if (next.length !== 1) {
  						next[1].forEach((loader) => loader());
  					}
  					j += 1;
  				} else {
  					break;
  				}
  			}
  
  			const result = await this._load(
  				{
  					route,
  					path: info.path,
  					query: info.query
  				},
  				no_cache
  			);
  			if (result) return result;
  		}
  
  		return await this._load_error({
  			status: 404,
  			error: new Error(`Not found: ${info.path}`),
  			path: info.path,
  			query: info.query
  		});
  	}
  
  	/**
  	 *
  	 * @param {{
  	 *   page: import('types/page').Page;
  	 *   branch: Array<import('./types').BranchNode | undefined>
  	 * }} opts
  	 */
  	async _get_navigation_result_from_branch({ page, branch }) {
  		const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
  
  		/** @type {import('./types').NavigationResult} */
  		const result = {
  			state: {
  				page,
  				branch,
  				session_id: this.session_id
  			},
  			props: {
  				components: filtered.map((node) => node.module.default)
  			}
  		};
  
  		for (let i = 0; i < filtered.length; i += 1) {
  			const loaded = filtered[i].loaded;
  			if (loaded) result.props[`props_${i}`] = await loaded.props;
  		}
  
  		if (
  			!this.current.page ||
  			page.path !== this.current.page.path ||
  			page.query.toString() !== this.current.page.query.toString()
  		) {
  			result.props.page = page;
  		}
  
  		const leaf = filtered[filtered.length - 1];
  		const maxage = leaf.loaded && leaf.loaded.maxage;
  
  		if (maxage) {
  			const key = `${page.path}?${page.query}`;
  			let ready = false;
  
  			const clear = () => {
  				if (this.cache.get(key) === result) {
  					this.cache.delete(key);
  				}
  
  				unsubscribe();
  				clearTimeout(timeout);
  			};
  
  			const timeout = setTimeout(clear, maxage * 1000);
  
  			const unsubscribe = this.stores.session.subscribe(() => {
  				if (ready) clear();
  			});
  
  			ready = true;
  
  			this.cache.set(key, result);
  		}
  
  		return result;
  	}
  
  	/**
  	 * @param {{
  	 *   status?: number;
  	 *   error?: Error;
  	 *   module: CSRComponent;
  	 *   page: import('types/page').Page;
  	 *   context: Record<string, any>;
  	 * }} options
  	 * @returns
  	 */
  	async _load_node({ status, error, module, page, context }) {
  		/** @type {import('./types').BranchNode} */
  		const node = {
  			module,
  			uses: {
  				params: new Set(),
  				path: false,
  				query: false,
  				session: false,
  				context: false,
  				dependencies: []
  			},
  			loaded: null,
  			context
  		};
  
  		/** @type {Record<string, string>} */
  		const params = {};
  		for (const key in page.params) {
  			Object.defineProperty(params, key, {
  				get() {
  					node.uses.params.add(key);
  					return page.params[key];
  				},
  				enumerable: true
  			});
  		}
  
  		const session = this.$session;
  
  		if (module.load) {
  			const { started } = this;
  
  			/** @type {import('types/page').LoadInput | import('types/page').ErrorLoadInput} */
  			const load_input = {
  				page: {
  					host: page.host,
  					params,
  					get path() {
  						node.uses.path = true;
  						return page.path;
  					},
  					get query() {
  						node.uses.query = true;
  						return page.query;
  					}
  				},
  				get session() {
  					node.uses.session = true;
  					return session;
  				},
  				get context() {
  					node.uses.context = true;
  					return { ...context };
  				},
  				fetch(resource, info) {
  					const url = typeof resource === 'string' ? resource : resource.url;
  					const { href } = new URL(url, new URL(page.path, document.baseURI));
  					node.uses.dependencies.push(href);
  
  					return started ? fetch(resource, info) : initial_fetch(resource, info);
  				}
  			};
  
  			if (error) {
  				/** @type {import('types/page').ErrorLoadInput} */ (load_input).status = status;
  				/** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
  			}
  
  			const loaded = await module.load.call(null, load_input);
  
  			// if the page component returns nothing from load, fall through
  			if (!loaded) return;
  
  			node.loaded = normalize(loaded);
  			if (node.loaded.context) node.context = node.loaded.context;
  		}
  
  		return node;
  	}
  
  	/**
  	 * @param {import('./types').NavigationCandidate} selected
  	 * @param {boolean} no_cache
  	 * @returns {Promise<import('./types').NavigationResult | undefined>} undefined if fallthrough
  	 */
  	async _load({ route, path, query }, no_cache) {
  		const key = `${path}?${query}`;
  
  		if (!no_cache) {
  			const cached = this.cache.get(key);
  			if (cached) return cached;
  		}
  
  		const [pattern, a, b, get_params] = route;
  		// @ts-expect-error - the pattern is for the route which we've already matched to this path
  		const params = get_params ? get_params(pattern.exec(path)) : {};
  
  		const changed = this.current.page && {
  			path: path !== this.current.page.path,
  			params: Object.keys(params).filter((key) => this.current.page.params[key] !== params[key]),
  			query: query.toString() !== this.current.page.query.toString(),
  			session: this.session_id !== this.current.session_id
  		};
  
  		/** @type {import('types/page').Page} */
  		const page = { host: this.host, path, query, params };
  
  		/** @type {Array<import('./types').BranchNode | undefined>} */
  		const branch = [];
  
  		/** @type {Record<string, any>} */
  		let context = {};
  		let context_changed = false;
  
  		/** @type {number | undefined} */
  		let status = 200;
  
  		/** @type {Error | undefined} */
  		let error;
  
  		// preload modules
  		a.forEach((loader) => loader());
  
  		load: for (let i = 0; i < a.length; i += 1) {
  			/** @type {import('./types').BranchNode | undefined} */
  			let node;
  
  			try {
  				if (!a[i]) continue;
  
  				const module = await a[i]();
  				const previous = this.current.branch[i];
  
  				const changed_since_last_render =
  					!previous ||
  					module !== previous.module ||
  					(changed.path && previous.uses.path) ||
  					changed.params.some((param) => previous.uses.params.has(param)) ||
  					(changed.query && previous.uses.query) ||
  					(changed.session && previous.uses.session) ||
  					previous.uses.dependencies.some((dep) => this.invalid.has(dep)) ||
  					(context_changed && previous.uses.context);
  
  				if (changed_since_last_render) {
  					node = await this._load_node({
  						module,
  						page,
  						context
  					});
  
  					const is_leaf = i === a.length - 1;
  
  					if (node && node.loaded) {
  						if (node.loaded.error) {
  							status = node.loaded.status;
  							error = node.loaded.error;
  						}
  
  						if (node.loaded.redirect) {
  							return {
  								redirect: node.loaded.redirect,
  								props: {},
  								state: this.current
  							};
  						}
  
  						if (node.loaded.context) {
  							context_changed = true;
  						}
  					} else if (is_leaf && module.load) {
  						// if the leaf node has a `load` function
  						// that returns nothing, fall through
  						return;
  					}
  				} else {
  					node = previous;
  				}
  			} catch (e) {
  				status = 500;
  				error = e;
  			}
  
  			if (error) {
  				while (i--) {
  					if (b[i]) {
  						let error_loaded;
  
  						/** @type {import('./types').BranchNode | undefined} */
  						let node_loaded;
  						let j = i;
  						while (!(node_loaded = branch[j])) {
  							j -= 1;
  						}
  
  						try {
  							error_loaded = await this._load_node({
  								status,
  								error,
  								module: await b[i](),
  								page,
  								context: node_loaded.context
  							});
  
  							if (error_loaded && error_loaded.loaded && error_loaded.loaded.error) {
  								continue;
  							}
  
  							branch.push(error_loaded);
  							break load;
  						} catch (e) {
  							continue;
  						}
  					}
  				}
  
  				return await this._load_error({
  					status,
  					error,
  					path,
  					query
  				});
  			} else {
  				if (node && node.loaded && node.loaded.context) {
  					context = {
  						...context,
  						...node.loaded.context
  					};
  				}
  
  				branch.push(node);
  			}
  		}
  
  		return await this._get_navigation_result_from_branch({ page, branch });
  	}
  
  	/**
  	 * @param {{
  	 *   status?: number;
  	 *   error: Error;
  	 *   path: string;
  	 *   query: URLSearchParams
  	 * }} opts
  	 */
  	async _load_error({ status, error, path, query }) {
  		const page = {
  			host: this.host,
  			path,
  			query,
  			params: {}
  		};
  
  		const node = await this._load_node({
  			module: await this.fallback[0],
  			page,
  			context: {}
  		});
  
  		const branch = [
  			node,
  			await this._load_node({
  				status,
  				error,
  				module: await this.fallback[1],
  				page,
  				context: (node && node.loaded && node.loaded.context) || {}
  			})
  		];
  
  		return await this._get_navigation_result_from_branch({ page, branch });
  	}
  }
  
  // @ts-expect-error
  
  /** @param {{
   *   paths: {
   *     assets: string;
   *     base: string;
   *   },
   *   target: Node;
   *   session: any;
   *   host: string;
   *   route: boolean;
   *   spa: boolean;
   *   trailing_slash: import('types/internal').TrailingSlash;
   *   hydrate: {
   *     status: number;
   *     error: Error;
   *     nodes: Array<Promise<import('types/internal').CSRComponent>>;
   *     page: import('types/page').Page;
   *   };
   * }} opts */
  async function start({ paths, target, session, host, route, spa, trailing_slash, hydrate }) {
  	if (import.meta.env.DEV && !target) {
  		throw new Error('Missing target element. See https://kit.svelte.dev/docs#configuration-target');
  	}
  
  	const renderer = new Renderer({
  		Root,
  		fallback,
  		target,
  		session,
  		host
  	});
  
  	const router = route
  		? new Router({
  				base: paths.base,
  				routes,
  				trailing_slash,
  				renderer
  		  })
  		: null;
  
  	init(router);
  	set_paths(paths);
  
  	if (hydrate) await renderer.start(hydrate);
  	if (router) {
  		if (spa) router.goto(location.href, { replaceState: true }, []);
  		router.init_listeners();
  	}
  
  	dispatchEvent(new CustomEvent('sveltekit:start'));
  }
  
  export { start };
  