import { performance } from "node:perf_hooks";
import { createDefu, defu } from "defu";
import { applyDefaults } from "untyped";
import { consola } from "consola";
import { AsyncLocalStorage } from "node:async_hooks";
import { getContext } from "unctx";
import satisfies from "semver/functions/satisfies.js";
import { readPackageJSON, resolvePackageJSON } from "pkg-types";
import { existsSync, lstatSync, promises, readFileSync } from "node:fs";
import { fileURLToPath, pathToFileURL } from "node:url";
import { basename, dirname, isAbsolute, join, normalize, parse, relative, resolve } from "pathe";
import { createJiti } from "jiti";
import { interopDefault, lookupNodeModuleSubpath, parseNodeModulePath, resolveModuleExportNames } from "mlly";
import { resolveModulePath, resolveModuleURL } from "exsolve";
import { isRelative, withTrailingSlash, withoutTrailingSlash } from "ufo";
import { read, update } from "rc9";
import semver, { gte } from "semver";
import { captureStackTrace } from "errx";
import process from "node:process";
import { glob } from "tinyglobby";
import { resolveAlias as resolveAlias$1, reverseResolveAlias } from "pathe/utils";
import ignore from "ignore";
import { loadConfig, setupDotenv } from "c12";
import destr from "destr";
import { kebabCase, pascalCase, snakeCase } from "scule";
import { klona } from "klona";
import { hash } from "ohash";
import { isAbsolute as isAbsolute$1 } from "node:path";
const logger = consola;
function useLogger(tag, options = {}) {
	return tag ? logger.create(options).withTag(tag) : logger;
}
const nuxtCtx = getContext("nuxt");
const asyncNuxtStorage = getContext("asyncNuxtStorage", {
	asyncContext: true,
	AsyncLocalStorage
});
const getNuxtCtx = () => asyncNuxtStorage.tryUse();
function useNuxt() {
	const instance = asyncNuxtStorage.tryUse() || nuxtCtx.tryUse();
	if (!instance) throw new Error("Nuxt instance is unavailable!");
	return instance;
}
function tryUseNuxt() {
	return asyncNuxtStorage.tryUse() || nuxtCtx.tryUse();
}
function runWithNuxtContext(nuxt, fn) {
	return asyncNuxtStorage.call(nuxt, fn);
}
const SEMANTIC_VERSION_RE = /-\d+\.[0-9a-f]+/;
function normalizeSemanticVersion(version) {
	return version.replace(SEMANTIC_VERSION_RE, "");
}
const builderMap = {
	"@nuxt/rspack-builder": "rspack",
	"@nuxt/vite-builder": "vite",
	"@nuxt/webpack-builder": "webpack"
};
function checkNuxtVersion(version, nuxt = useNuxt()) {
	return satisfies(normalizeSemanticVersion(getNuxtVersion(nuxt)), version, { includePrerelease: true });
}
async function checkNuxtCompatibility(constraints, nuxt = useNuxt()) {
	const issues = [];
	if (constraints.nuxt) {
		const nuxtVersion = getNuxtVersion(nuxt);
		if (!checkNuxtVersion(constraints.nuxt, nuxt)) issues.push({
			name: "nuxt",
			message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\``
		});
	}
	if (constraints.builder && typeof nuxt.options.builder === "string") {
		const currentBuilder = builderMap[nuxt.options.builder] || nuxt.options.builder;
		if (currentBuilder in constraints.builder) {
			const constraint = constraints.builder[currentBuilder];
			if (constraint === false) issues.push({
				name: "builder",
				message: `Not compatible with \`${nuxt.options.builder}\`.`
			});
			else for (const parent of [
				nuxt.options.rootDir,
				nuxt.options.workspaceDir,
				import.meta.url
			]) {
				const builderVersion = await readPackageJSON(nuxt.options.builder, { parent }).then((r) => r.version).catch(() => void 0);
				if (builderVersion) {
					if (!satisfies(normalizeSemanticVersion(builderVersion), constraint, { includePrerelease: true })) issues.push({
						name: "builder",
						message: `Not compatible with \`${builderVersion}\` of \`${currentBuilder}\`. This module requires \`${constraint}\`.`
					});
					break;
				}
			}
		}
	}
	await nuxt.callHook("kit:compatibility", constraints, issues);
	issues.toString = () => issues.map((issue) => ` - [${issue.name}] ${issue.message}`).join("\n");
	return issues;
}
async function assertNuxtCompatibility(constraints, nuxt = useNuxt()) {
	const issues = await checkNuxtCompatibility(constraints, nuxt);
	if (issues.length) throw new Error("Nuxt compatibility issues found:\n" + issues.toString());
	return true;
}
async function hasNuxtCompatibility(constraints, nuxt = useNuxt()) {
	return !(await checkNuxtCompatibility(constraints, nuxt)).length;
}
function isNuxtMajorVersion(majorVersion, nuxt = useNuxt()) {
	const version = getNuxtVersion(nuxt);
	return version[0] === majorVersion.toString() && version[1] === ".";
}
function isNuxt2(nuxt = useNuxt()) {
	return isNuxtMajorVersion(2, nuxt);
}
function isNuxt3(nuxt = useNuxt()) {
	return isNuxtMajorVersion(3, nuxt);
}
const NUXT_VERSION_RE = /^v/g;
function getNuxtVersion(nuxt = useNuxt()) {
	const rawVersion = nuxt?._version || nuxt?.version || nuxt?.constructor?.version;
	if (typeof rawVersion !== "string") throw new TypeError("Cannot determine nuxt version! Is current instance passed?");
	return rawVersion.replace(NUXT_VERSION_RE, "");
}
function defineNuxtModule(definition) {
	if (definition) return _defineNuxtModule(definition);
	return { with: (definition) => _defineNuxtModule(definition) };
}
function _defineNuxtModule(definition) {
	if (typeof definition === "function") return _defineNuxtModule({ setup: definition });
	const module = defu(definition, { meta: {} });
	module.meta.configKey ||= module.meta.name;
	async function getOptions(inlineOptions, nuxt = useNuxt()) {
		const nuxtConfigOptionsKey = module.meta.configKey || module.meta.name;
		let options = defu(inlineOptions, nuxtConfigOptionsKey && nuxtConfigOptionsKey in nuxt.options ? nuxt.options[nuxtConfigOptionsKey] : {}, module.defaults instanceof Function ? await module.defaults(nuxt) : module.defaults ?? {});
		if (module.schema) options = await applyDefaults(module.schema, options);
		return Promise.resolve(options);
	}
	function getModuleDependencies(nuxt = useNuxt()) {
		if (typeof module.moduleDependencies === "function") return module.moduleDependencies(nuxt);
		return module.moduleDependencies;
	}
	async function normalizedModule(inlineOptions, nuxt = tryUseNuxt()) {
		if (!nuxt) throw new TypeError(`Cannot use ${module.meta.name || "module"} outside of Nuxt context`);
		const uniqueKey = module.meta.name || module.meta.configKey;
		if (uniqueKey) {
			nuxt.options._requiredModules ||= {};
			if (nuxt.options._requiredModules[uniqueKey]) return false;
			nuxt.options._requiredModules[uniqueKey] = true;
		}
		if (module.meta.compatibility) {
			const issues = await checkNuxtCompatibility(module.meta.compatibility, nuxt);
			if (issues.length) {
				const errorMessage = `Module \`${module.meta.name}\` is disabled due to incompatibility issues:\n${issues.toString()}`;
				if (nuxt.options.experimental.enforceModuleCompatibility) {
					const error = new Error(errorMessage);
					error.name = "ModuleCompatibilityError";
					throw error;
				}
				logger.warn(errorMessage);
				return;
			}
		}
		const _options = await getOptions(inlineOptions, nuxt);
		if (module.hooks) nuxt.hooks.addHooks(module.hooks);
		const moduleName = uniqueKey || module.meta.name || "<no name>";
		nuxt._perf?.startPhase(`module:${moduleName}`);
		const start = performance.now();
		let res = {};
		try {
			res = await module.setup?.call(null, _options, nuxt) ?? {};
		} finally {
			nuxt._perf?.endPhase(`module:${moduleName}`);
		}
		const perf = performance.now() - start;
		const setupTime = Math.round(perf * 100) / 100;
		if (setupTime > 5e3 && uniqueKey !== "@nuxt/telemetry") logger.warn(`Slow module \`${moduleName}\` took \`${setupTime}ms\` to setup.`);
		else if (nuxt.options.debug && nuxt.options.debug.modules) logger.info(`Module \`${moduleName}\` took \`${setupTime}ms\` to setup.`);
		if (res === false) return false;
		return defu(res, { timings: { setup: setupTime } });
	}
	normalizedModule.getMeta = () => Promise.resolve(module.meta);
	normalizedModule.getOptions = getOptions;
	normalizedModule.getModuleDependencies = getModuleDependencies;
	normalizedModule.onInstall = module.onInstall;
	normalizedModule.onUpgrade = module.onUpgrade;
	return normalizedModule;
}
const distURL = import.meta.url.replace(/\/dist\/.*$/, "/");
function getUserCaller() {
	if (!import.meta.dev) return null;
	const { source, line, column } = captureStackTrace().find((entry) => !entry.source.startsWith(distURL)) ?? {};
	if (!source) return null;
	return {
		source: source.replace(/^file:\/\//, ""),
		line,
		column
	};
}
const warnings = /* @__PURE__ */ new Set();
function warn(warning) {
	if (!warnings.has(warning)) {
		console.warn(warning);
		warnings.add(warning);
	}
}
const layerMap = /* @__PURE__ */ new WeakMap();
function getLayerDirectories(nuxt = useNuxt()) {
	return nuxt.options._layers.map((layer) => {
		if (layerMap.has(layer)) return layerMap.get(layer);
		const config = withTrailingSlash$2(layer.config.rootDir) === withTrailingSlash$2(nuxt.options.rootDir) ? nuxt.options : layer.config;
		const src = withTrailingSlash$2(config.srcDir || layer.cwd);
		const root = withTrailingSlash$2(config.rootDir || layer.cwd);
		const directories = {
			root,
			shared: withTrailingSlash$2(resolve(root, resolveAlias(config.dir?.shared || "shared", nuxt.options.alias))),
			server: withTrailingSlash$2(resolve(src, resolveAlias(config.serverDir || "server", nuxt.options.alias))),
			modules: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.modules || "modules", nuxt.options.alias))),
			public: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.public || "public", nuxt.options.alias))),
			app: src,
			appLayouts: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.layouts || "layouts", nuxt.options.alias))),
			appMiddleware: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.middleware || "middleware", nuxt.options.alias))),
			appPages: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.pages || "pages", nuxt.options.alias))),
			appPlugins: withTrailingSlash$2(resolve(src, resolveAlias(config.dir?.plugins || "plugins", nuxt.options.alias)))
		};
		layerMap.set(layer, directories);
		return directories;
	});
}
function withTrailingSlash$2(dir) {
	return dir.replace(/[^/]$/, "$&/");
}
function createIsIgnored(nuxt = tryUseNuxt()) {
	return (pathname, stats) => isIgnored(pathname, stats, nuxt);
}
const layerRootsCache = /* @__PURE__ */ new WeakMap();
function isIgnored(pathname, _stats, nuxt = tryUseNuxt()) {
	if (!nuxt) return false;
	if (!nuxt._ignore) {
		nuxt._ignore = ignore(nuxt.options.ignoreOptions);
		nuxt._ignore.add(resolveIgnorePatterns());
	}
	let cwds = layerRootsCache.get(nuxt);
	if (!cwds) {
		cwds = getLayerDirectories(nuxt).map((dirs) => dirs.root).sort((a, b) => b.length - a.length);
		layerRootsCache.set(nuxt, cwds);
	}
	for (const cwd of cwds) if (pathname.startsWith(cwd)) {
		const relativePath = pathname.slice(cwd.length);
		return !!(relativePath && nuxt._ignore.ignores(relativePath));
	}
	const relativePath = relative(nuxt.options.rootDir, pathname);
	if (relativePath[0] === "." && relativePath[1] === ".") return false;
	return !!(relativePath && nuxt._ignore.ignores(relativePath));
}
const NEGATION_RE = /^(!?)(.*)$/;
function resolveIgnorePatterns(relativePath) {
	const nuxt = tryUseNuxt();
	if (!nuxt) return [];
	const ignorePatterns = nuxt.options.ignore.flatMap((s) => resolveGroupSyntax(s));
	const nuxtignoreFile = join(nuxt.options.rootDir, ".nuxtignore");
	if (existsSync(nuxtignoreFile)) {
		const contents = readFileSync(nuxtignoreFile, "utf-8");
		ignorePatterns.push(...contents.trim().split(/\r?\n/));
	}
	if (relativePath) return ignorePatterns.map((p) => {
		const [_, negation = "", pattern] = p.match(NEGATION_RE) || [];
		if (pattern && pattern[0] === "*") return p;
		return negation + relative(relativePath, resolve(nuxt.options.rootDir, pattern || p));
	});
	return ignorePatterns;
}
function resolveGroupSyntax(group) {
	let groups = [group];
	while (groups.some((group) => group.includes("{"))) groups = groups.flatMap((group) => {
		const [head, ...tail] = group.split("{");
		if (tail.length) {
			const [body = "", ...rest] = tail.join("{").split("}");
			return body.split(",").map((part) => `${head}${part}${rest.join("")}`);
		}
		return group;
	});
	return groups;
}
function toArray(value) {
	return Array.isArray(value) ? value : [value];
}
function filterInPlace(array, predicate) {
	for (let i = array.length; i--;) if (!predicate(array[i], i, array)) array.splice(i, 1);
	return array;
}
const MODE_RE = /\.(server|client)(\.\w+)*$/;
const distDirURL = new URL(".", import.meta.url);
async function resolvePath(path, opts = {}) {
	const { type = "file" } = opts;
	const res = await _resolvePathGranularly(path, {
		...opts,
		type
	});
	if (res.type === type) return res.path;
	return opts.fallbackToOriginal ? path : res.path;
}
async function findPath(paths, opts, pathType = "file") {
	for (const path of toArray(paths)) {
		const type = opts?.type || pathType;
		const res = await _resolvePathGranularly(path, {
			...opts,
			type
		});
		if (!res.type || res.type !== type) continue;
		if (res.virtual || await existsSensitive(res.path)) return res.path;
	}
	return null;
}
function resolveAlias(path, alias) {
	alias ||= tryUseNuxt()?.options.alias || {};
	return resolveAlias$1(path, alias);
}
function createResolver(base) {
	if (!base) throw new Error("`base` argument is missing for createResolver(base)!");
	base = base.toString();
	if (base.startsWith("file://")) base = dirname(fileURLToPath(base));
	return {
		resolve: (...path) => resolve(base, ...path),
		resolvePath: (path, opts) => resolvePath(path, {
			cwd: base,
			...opts
		})
	};
}
async function resolveNuxtModule(base, paths) {
	const resolved = [];
	const resolver = createResolver(base);
	for (const path of paths) {
		if (path.startsWith(base)) {
			resolved.push(path.split("/index.ts")[0]);
			continue;
		}
		const resolvedPath = await resolver.resolvePath(path);
		const dir = parseNodeModulePath(resolvedPath).dir;
		if (dir) {
			resolved.push(dir);
			continue;
		}
		const index = resolvedPath.lastIndexOf(path);
		resolved.push(index === -1 ? dirname(resolvedPath) : resolvedPath.slice(0, index + path.length));
	}
	return resolved;
}
async function _resolvePathType(path, opts = {}, skipFs = false) {
	if (opts?.virtual && existsInVFS(path)) return {
		path,
		type: "file",
		virtual: true
	};
	if (skipFs) return;
	const fd = await promises.open(path, "r").catch(() => null);
	try {
		const stats = await fd?.stat();
		if (stats) return {
			path,
			type: stats.isFile() ? "file" : "dir",
			virtual: false
		};
	} finally {
		fd?.close();
	}
}
function normalizeExtension(ext) {
	return ext.startsWith(".") ? ext : `.${ext}`;
}
async function _resolvePathGranularly(path, opts = { type: "file" }) {
	const _path = path;
	path = normalize(path);
	if (isAbsolute(path)) {
		const res = await _resolvePathType(path, opts);
		if (res && res.type === opts.type) return res;
	}
	const nuxt = tryUseNuxt();
	const cwd = opts.cwd || (nuxt ? nuxt.options.rootDir : process.cwd());
	const extensions = opts.extensions || (nuxt ? nuxt.options.extensions : [
		".ts",
		".mjs",
		".cjs",
		".json"
	]);
	const modulesDir = nuxt ? nuxt.options.modulesDir : [];
	path = resolveAlias$1(path, opts.alias ?? nuxt?.options.alias ?? {});
	if (!isAbsolute(path)) path = resolve(cwd, path);
	const res = await _resolvePathType(path, opts);
	if (res && res.type === opts.type) return res;
	if (opts.type === "file") {
		for (const ext of extensions) {
			const normalizedExt = normalizeExtension(ext);
			const extPath = await _resolvePathType(path + normalizedExt, opts);
			if (extPath && extPath.type === "file") return extPath;
			const indexPath = await _resolvePathType(join(path, "index" + normalizedExt), opts, res?.type !== "dir");
			if (indexPath && indexPath.type === "file") return indexPath;
		}
		const resolvedModulePath = resolveModulePath(_path, {
			try: true,
			suffixes: ["", "index"],
			from: [cwd, ...modulesDir].map((d) => directoryToURL(d))
		});
		if (resolvedModulePath) return {
			path: resolvedModulePath,
			type: "file",
			virtual: false
		};
	}
	return { path };
}
async function existsSensitive(path) {
	return new Set(await promises.readdir(dirname(path)).catch(() => [])).has(basename(path));
}
function existsInVFS(path, nuxt = tryUseNuxt()) {
	if (!nuxt) return false;
	if (path in nuxt.vfs) return true;
	return (nuxt.apps.default?.templates ?? nuxt.options.build.templates).some((template) => template.dst === path);
}
async function resolveFiles(path, pattern, opts = {}) {
	const files = [];
	for (const p of await glob(pattern, {
		cwd: path,
		followSymbolicLinks: opts.followSymbolicLinks ?? true,
		absolute: true,
		ignore: opts.ignore
	})) if (!isIgnored(p)) files.push(p);
	return files.sort();
}
function directoryToURL(dir) {
	return pathToFileURL(dir + "/");
}
function tryResolveModule(id, url = import.meta.url) {
	return Promise.resolve(resolveModulePath(id, {
		from: url,
		suffixes: ["", "index"],
		try: true
	}));
}
function resolveModule(id, options) {
	return resolveModulePath(id, {
		from: options?.url ?? options?.paths ?? [import.meta.url],
		extensions: options?.extensions ?? [
			".js",
			".mjs",
			".cjs",
			".ts",
			".mts",
			".cts"
		]
	});
}
async function importModule(id, opts) {
	return await import(pathToFileURL(resolveModule(id, opts)).href).then((r) => opts?.interopDefault !== false ? interopDefault(r) : r);
}
function tryImportModule(id, opts) {
	try {
		return importModule(id, opts).catch(() => void 0);
	} catch {}
}
function requireModule(id, opts) {
	const caller = getUserCaller();
	warn(`[@nuxt/kit] \`requireModule\` is deprecated${caller ? ` (used at \`${resolveAlias(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Please use \`importModule\` instead.`);
	const resolvedPath = resolveModule(id, opts);
	return createJiti(import.meta.url, { interopDefault: opts?.interopDefault !== false })(pathToFileURL(resolvedPath).href);
}
function tryRequireModule(id, opts) {
	try {
		return requireModule(id, opts);
	} catch {}
}
const NODE_MODULES_RE = /[/\\]node_modules[/\\]/;
const ignoredConfigKeys = new Set([
	"components",
	"imports",
	"pages",
	"devtools",
	"telemetry"
]);
async function installModules(modulesToInstall, resolvedModulePaths, nuxt = useNuxt()) {
	const localLayerModuleDirs = [];
	for (const l of nuxt.options._layers) {
		const srcDir = l.config.srcDir || l.cwd;
		if (!NODE_MODULES_RE.test(srcDir)) localLayerModuleDirs.push(resolve(srcDir, l.config?.dir?.modules || "modules").replace(/\/?$/, "/"));
	}
	nuxt._moduleOptionsFunctions ||= /* @__PURE__ */ new Map();
	const resolvedModules = [];
	const modulesByMetaName = /* @__PURE__ */ new Map();
	const moduleLoadCache = /* @__PURE__ */ new Map();
	for (const [key] of modulesToInstall) moduleLoadCache.set(key, loadNuxtModuleInstance(key, nuxt));
	const inlineConfigKeys = new Set(await Promise.all([...modulesToInstall].map(async ([mod]) => {
		if (typeof mod === "string") return;
		const meta = await Promise.resolve(mod.getMeta?.());
		if (meta?.name) modulesByMetaName.set(meta.name, mod);
		if (meta?.configKey) {
			if (meta.configKey !== meta.name) modulesByMetaName.set(meta.configKey, mod);
			return meta.configKey;
		}
	})));
	let error;
	const dependencyMap = /* @__PURE__ */ new Map();
	for (const [key, options] of modulesToInstall) {
		const res = await (moduleLoadCache.get(key) || loadNuxtModuleInstance(key, nuxt)).catch((err) => {
			if (dependencyMap.has(key) && typeof key === "string") err.cause = `Could not resolve \`${key}\` (specified as a dependency of ${dependencyMap.get(key)}).`;
			throw err;
		});
		const dependencyMeta = await res.nuxtModule.getModuleDependencies?.(nuxt) || {};
		for (const [name, value] of Object.entries(dependencyMeta)) {
			if (!value.overrides && !value.defaults && !value.version && value.optional) continue;
			const resolvedModule = modulesByMetaName.has(name) ? resolveModuleWithOptions(modulesByMetaName.get(name), nuxt) : resolveModuleWithOptions(name, nuxt);
			const moduleToAttribute = typeof key === "string" ? `\`${key}\`` : "a module in `nuxt.options`";
			if (!resolvedModule?.module) {
				const message = `Could not resolve \`${name}\` (specified as a dependency of ${moduleToAttribute}).`;
				error = new TypeError(message);
				continue;
			}
			if (value.version) {
				const pkg = await readPackageJSON(name, { from: [res.resolvedModulePath, ...nuxt.options.modulesDir].filter(Boolean) }).catch(() => null);
				if (pkg?.version && !semver.satisfies(pkg.version, value.version, { includePrerelease: true })) {
					const message = `Module \`${name}\` version (\`${pkg.version}\`) does not satisfy \`${value.version}\` (requested by ${moduleToAttribute}).`;
					error = new TypeError(message);
				}
			}
			if (value.overrides || value.defaults) {
				const currentFns = nuxt._moduleOptionsFunctions.get(resolvedModule.module) || [];
				nuxt._moduleOptionsFunctions.set(resolvedModule.module, [...currentFns, () => ({
					defaults: value.defaults,
					overrides: value.overrides
				})]);
			}
			if (value.optional === true) continue;
			nuxt.options.typescript.hoist.push(name);
			if (resolvedModule && !modulesToInstall.has(resolvedModule.module) && (!resolvedModule.resolvedPath || !resolvedModulePaths.has(resolvedModule.resolvedPath))) {
				if (typeof resolvedModule.module === "string" && inlineConfigKeys.has(resolvedModule.module)) continue;
				modulesToInstall.set(resolvedModule.module, resolvedModule.options);
				dependencyMap.set(resolvedModule.module, moduleToAttribute);
				const path = resolvedModule.resolvedPath || resolvedModule.module;
				if (typeof path === "string") resolvedModulePaths.add(path);
			}
		}
		resolvedModules.push({
			moduleToInstall: key,
			meta: await res.nuxtModule.getMeta?.(),
			nuxtModule: res.nuxtModule,
			buildTimeModuleMeta: res.buildTimeModuleMeta,
			resolvedModulePath: res.resolvedModulePath,
			inlineOptions: options
		});
	}
	if (error) throw error;
	for (const { nuxtModule, meta = {}, moduleToInstall, buildTimeModuleMeta, resolvedModulePath, inlineOptions } of resolvedModules) {
		const configKey = meta.configKey;
		const optionsFns = new Set([
			...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [],
			...meta?.name ? nuxt._moduleOptionsFunctions.get(meta.name) || [] : [],
			...configKey ? nuxt._moduleOptionsFunctions.get(configKey) || [] : []
		]);
		if (optionsFns.size > 0) {
			const overrides = [];
			const defaults = [];
			for (const fn of optionsFns) {
				const options = fn();
				overrides.push(options.overrides);
				defaults.push(options.defaults);
			}
			if (configKey) nuxt.options[configKey] = defu(...overrides, nuxt.options[configKey], ...defaults);
		}
		const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false;
		if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, inlineOptions, nuxt);
		const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0;
		await callModule(nuxt, nuxtModule, inlineOptions, {
			meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta),
			nameOrPath: path,
			modulePath: resolvedModulePath || path,
			localLayerModuleDirs
		});
	}
	delete nuxt._moduleOptionsFunctions;
}
async function installModule(moduleToInstall, inlineOptions, nuxt = useNuxt()) {
	const { nuxtModule, buildTimeModuleMeta, resolvedModulePath } = await loadNuxtModuleInstance(moduleToInstall, nuxt);
	const localLayerModuleDirs = [];
	for (const dirs of getLayerDirectories(nuxt)) if (!NODE_MODULES_RE.test(dirs.app)) localLayerModuleDirs.push(dirs.modules);
	const meta = await nuxtModule.getMeta?.();
	let mergedOptions = inlineOptions;
	const configKey = meta?.configKey;
	if (configKey && nuxt._moduleOptionsFunctions) {
		const optionsFns = [...nuxt._moduleOptionsFunctions.get(moduleToInstall) || [], ...nuxt._moduleOptionsFunctions.get(configKey) || []];
		if (optionsFns.length > 0) {
			const overrides = [];
			const defaults = [];
			for (const fn of optionsFns) {
				const options = fn();
				overrides.push(options.overrides);
				defaults.push(options.defaults);
			}
			mergedOptions = defu(inlineOptions, ...overrides, nuxt.options[configKey], ...defaults);
			nuxt.options[configKey] = mergedOptions;
		}
	}
	const isDisabled = configKey && !ignoredConfigKeys.has(configKey) && nuxt.options[configKey] === false;
	if (!isDisabled) await callLifecycleHooks(nuxtModule, meta, mergedOptions, nuxt);
	const path = typeof moduleToInstall === "string" ? moduleToInstall : void 0;
	await callModule(nuxt, nuxtModule, mergedOptions, {
		meta: defu({ disabled: isDisabled }, meta, buildTimeModuleMeta),
		nameOrPath: path,
		modulePath: resolvedModulePath || path,
		localLayerModuleDirs
	});
}
function resolveModuleWithOptions(definition, nuxt) {
	const [module, options = {}] = Array.isArray(definition) ? definition : [definition, {}];
	if (!module) return;
	if (typeof module !== "string") return {
		module,
		options
	};
	const modAlias = resolveAlias(module, nuxt.options.alias);
	return {
		module,
		resolvedPath: resolveModulePath(modAlias, {
			try: true,
			from: nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/"))),
			suffixes: [
				"nuxt",
				"nuxt/index",
				"module",
				"module/index",
				"",
				"index"
			],
			extensions: [
				".js",
				".mjs",
				".cjs",
				".ts",
				".mts",
				".cts"
			]
		}) || modAlias,
		options
	};
}
let _jitiCache;
function getSharedJiti(nuxt) {
	_jitiCache ||= /* @__PURE__ */ new WeakMap();
	let jiti = _jitiCache.get(nuxt);
	if (!jiti) {
		jiti = createJiti(nuxt.options.rootDir, { alias: nuxt.options.alias });
		_jitiCache.set(nuxt, jiti);
	}
	return jiti;
}
async function loadNuxtModuleInstance(nuxtModule, nuxt = useNuxt()) {
	let buildTimeModuleMeta = {};
	if (typeof nuxtModule === "function") return {
		nuxtModule,
		buildTimeModuleMeta
	};
	if (typeof nuxtModule !== "string") throw new TypeError(`Nuxt module should be a function or a string to import. Received: ${nuxtModule}.`);
	const jiti = getSharedJiti(nuxt);
	nuxtModule = resolveAlias(nuxtModule, nuxt.options.alias);
	if (isRelative(nuxtModule)) nuxtModule = resolve(nuxt.options.rootDir, nuxtModule);
	try {
		const src = resolveModuleURL(nuxtModule, {
			from: nuxt.options.modulesDir.map((m) => directoryToURL(m.replace(/\/node_modules\/?$/, "/"))),
			suffixes: [
				"nuxt",
				"nuxt/index",
				"module",
				"module/index",
				"",
				"index"
			],
			extensions: [
				".js",
				".mjs",
				".cjs",
				".ts",
				".mts",
				".cts"
			]
		});
		const resolvedModulePath = fileURLToPath(src);
		const resolvedNuxtModule = await jiti.import(src, { default: true });
		if (typeof resolvedNuxtModule !== "function") throw new TypeError(`Nuxt module should be a function: ${nuxtModule}.`);
		const moduleMetadataPath = new URL("module.json", src);
		if (existsSync(moduleMetadataPath)) buildTimeModuleMeta = JSON.parse(await promises.readFile(moduleMetadataPath, "utf-8"));
		return {
			nuxtModule: resolvedNuxtModule,
			buildTimeModuleMeta,
			resolvedModulePath
		};
	} catch (error) {
		const code = error.code;
		if (code === "ERR_PACKAGE_PATH_NOT_EXPORTED" || code === "ERR_UNSUPPORTED_DIR_IMPORT" || code === "ENOTDIR") throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`);
		if (code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND") {
			const module = MissingModuleMatcher.exec(error.message)?.[1];
			if (module && !module.includes(nuxtModule)) throw new TypeError(`Error while importing module \`${nuxtModule}\`: ${error}`);
		}
	}
	throw new TypeError(`Could not load \`${nuxtModule}\`. Is it installed?`);
}
function getDirectory(p) {
	try {
		return isAbsolute(p) && lstatSync(p).isFile() ? dirname(p) : p;
	} catch {}
	return p;
}
const normalizeModuleTranspilePath = (p) => {
	return getDirectory(p).split("node_modules/").pop();
};
const MissingModuleMatcher = /Cannot find module\s+['"]?([^'")\s]+)['"]?/i;
async function callLifecycleHooks(nuxtModule, meta = {}, inlineOptions, nuxt = useNuxt()) {
	if (!meta.name || !meta.version) return;
	if (!nuxtModule.onInstall && !nuxtModule.onUpgrade) return;
	const previousVersion = read({
		dir: nuxt.options.rootDir,
		name: ".nuxtrc"
	})?.setups?.[meta.name];
	try {
		if (!previousVersion) await nuxtModule.onInstall?.(nuxt);
		else if (semver.gt(meta.version, previousVersion)) await nuxtModule.onUpgrade?.(nuxt, inlineOptions, previousVersion);
		if (previousVersion !== meta.version) update({ setups: { [meta.name]: meta?.version } }, {
			dir: nuxt.options.rootDir,
			name: ".nuxtrc"
		});
	} catch (e) {
		logger.error(`Error while executing ${!previousVersion ? "install" : "upgrade"} hook for module \`${meta.name}\`: ${e}`);
	}
}
async function callModule(nuxt, nuxtModule, moduleOptions = {}, options) {
	const modulePath = options.modulePath;
	const nameOrPath = options.nameOrPath;
	const localLayerModuleDirs = options.localLayerModuleDirs;
	const fn = () => nuxt.options.experimental?.debugModuleMutation && nuxt._asyncLocalStorageModule ? nuxt._asyncLocalStorageModule.run(nuxtModule, () => nuxtModule(moduleOptions, nuxt)) : nuxtModule(moduleOptions, nuxt);
	const res = options.meta.disabled ? false : await fn();
	let entryPath;
	if (typeof modulePath === "string") {
		const parsed = parseNodeModulePath(modulePath);
		if (parsed.name) {
			const subpath = await lookupNodeModuleSubpath(modulePath) || ".";
			entryPath = join(parsed.name, subpath === "./" ? "." : subpath);
		}
		if (res !== false) {
			const moduleRoot = parsed.dir ? parsed.dir + parsed.name : await resolvePackageJSON(modulePath, { try: true }).then((r) => r ? dirname(r) : modulePath);
			nuxt.options.build.transpile.push(normalizeModuleTranspilePath(moduleRoot));
			const directory = moduleRoot.replace(/\/?$/, "/");
			if (moduleRoot !== nameOrPath && !localLayerModuleDirs.some((dir) => directory.startsWith(dir))) nuxt.options.modulesDir.push(join(moduleRoot, "node_modules"));
		}
	}
	if (nameOrPath) {
		entryPath ||= resolveAlias(nameOrPath, nuxt.options.alias);
		if (entryPath !== nameOrPath) options.meta.rawPath = nameOrPath;
	}
	nuxt.options._installedModules ||= [];
	nuxt.options._installedModules.push({
		meta: options.meta,
		module: nuxtModule,
		timings: (res || {}).timings,
		entryPath
	});
}
function resolveNuxtModuleEntryName(m) {
	if (typeof m === "object" && !Array.isArray(m)) return m.name;
	if (Array.isArray(m)) return resolveNuxtModuleEntryName(m[0]);
	return m || false;
}
function hasNuxtModule(moduleName, nuxt = useNuxt()) {
	return nuxt.options._installedModules.some(({ meta }) => meta.name === moduleName) || nuxt.options.modules.some((m) => moduleName === resolveNuxtModuleEntryName(m));
}
async function hasNuxtModuleCompatibility(module, semverVersion, nuxt = useNuxt()) {
	const version = await getNuxtModuleVersion(module, nuxt);
	if (!version) return false;
	return satisfies(normalizeSemanticVersion(version), semverVersion, { includePrerelease: true });
}
async function getNuxtModuleVersion(module, nuxt = useNuxt()) {
	const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
	if (moduleMeta.version) return moduleMeta.version;
	if (!moduleMeta.name) return false;
	for (const m of nuxt.options._installedModules) if (m.meta.name === moduleMeta.name && m.meta.version) return m.meta.version;
	if (hasNuxtModule(moduleMeta.name)) {
		const { nuxtModule, buildTimeModuleMeta } = await loadNuxtModuleInstance(moduleMeta.name, nuxt);
		return buildTimeModuleMeta.version || await nuxtModule.getMeta?.().then((r) => r.version) || false;
	}
	return false;
}
const merger = createDefu((obj, key, value) => {
	if (Array.isArray(obj[key]) && Array.isArray(value)) {
		obj[key] = obj[key].concat(value);
		return true;
	}
});
async function loadNuxtConfig(opts) {
	const localLayers = (await glob("layers/*", {
		onlyDirectories: true,
		cwd: opts.cwd || process.cwd()
	})).map((d) => withTrailingSlash(d)).sort((a, b) => b.localeCompare(a));
	opts.overrides = defu(opts.overrides, { _extends: localLayers });
	if (opts.dotenv !== false) await setupDotenv({
		cwd: opts.cwd || process.cwd(),
		...typeof opts.dotenv === "object" ? opts.dotenv : {}
	});
	const schemaPromise = loadNuxtSchema(opts.cwd || process.cwd());
	const { configFile, layers = [], cwd, config: nuxtConfig, meta } = await withDefineNuxtConfig(() => loadConfig({
		name: "nuxt",
		configFile: "nuxt.config",
		rcFile: ".nuxtrc",
		extend: { extendKey: [
			"theme",
			"_extends",
			"extends"
		] },
		globalRc: true,
		merger,
		...opts,
		dotenv: false
	}));
	nuxtConfig.rootDir ||= cwd;
	nuxtConfig._nuxtConfigFile = configFile;
	nuxtConfig._nuxtConfigFiles = [configFile];
	nuxtConfig._loadOptions = opts;
	nuxtConfig.alias ||= {};
	if (meta?.name) {
		const alias = `#layers/${meta.name}`;
		nuxtConfig.alias[alias] ||= withTrailingSlash(nuxtConfig.rootDir);
	}
	const defaultBuildDir = join(nuxtConfig.rootDir, ".nuxt");
	if (!opts.overrides?._prepare && !nuxtConfig.dev && !nuxtConfig.buildDir && existsSync(defaultBuildDir)) nuxtConfig.buildDir = join(nuxtConfig.rootDir, "node_modules/.cache/nuxt/.nuxt");
	const NuxtConfigSchema = await schemaPromise;
	const layerSchemaKeys = [
		"future",
		"srcDir",
		"rootDir",
		"serverDir",
		"dir"
	];
	const layerSchema = Object.create(null);
	for (const key of layerSchemaKeys) if (key in NuxtConfigSchema) layerSchema[key] = NuxtConfigSchema[key];
	const _layers = [];
	const processedLayers = /* @__PURE__ */ new Set();
	const localRelativePaths = new Set(localLayers.map((layer) => withoutTrailingSlash(layer)));
	for (const layer of layers) {
		const resolvedRootDir = layer.config?.rootDir ?? layer.cwd;
		layer.config = {
			...layer.config || {},
			rootDir: resolvedRootDir
		};
		if (processedLayers.has(resolvedRootDir)) continue;
		processedLayers.add(resolvedRootDir);
		layer.config = await applyDefaults(layerSchema, layer.config);
		if (!layer.configFile || layer.configFile.endsWith(".nuxtrc")) continue;
		if (layer.cwd && cwd && localRelativePaths.has(relative(cwd, layer.cwd))) {
			layer.meta ||= {};
			layer.meta.name ||= basename(layer.cwd);
		}
		if (layer.meta?.name) {
			const alias = `#layers/${layer.meta.name}`;
			nuxtConfig.alias[alias] ||= withTrailingSlash(layer.config.rootDir || layer.cwd);
		}
		_layers.push(layer);
	}
	nuxtConfig._layers = _layers;
	if (!_layers.length) _layers.push({
		cwd,
		config: {
			rootDir: cwd,
			srcDir: cwd
		}
	});
	return await applyDefaults(NuxtConfigSchema, nuxtConfig);
}
function loadNuxtSchema(cwd) {
	const url = directoryToURL(cwd);
	const urls = [url];
	const nuxtPath = resolveModuleURL("nuxt", {
		try: true,
		from: url
	}) ?? resolveModuleURL("nuxt-nightly", {
		try: true,
		from: url
	});
	if (nuxtPath) urls.unshift(nuxtPath);
	return import(resolveModuleURL("@nuxt/schema", {
		try: true,
		from: urls
	}) ?? "@nuxt/schema").then((r) => r.NuxtConfigSchema);
}
async function withDefineNuxtConfig(fn) {
	const key = "defineNuxtConfig";
	const globalSelf = globalThis;
	if (!globalSelf[key]) {
		globalSelf[key] = (c) => c;
		globalSelf[key].count = 0;
	}
	globalSelf[key].count++;
	try {
		return await fn();
	} finally {
		globalSelf[key].count--;
		if (!globalSelf[key].count) delete globalSelf[key];
	}
}
function extendNuxtSchema(def) {
	useNuxt().hook("schema:extend", (schemas) => {
		schemas.push(typeof def === "function" ? def() : def);
	});
}
async function loadNuxt(opts) {
	opts.cwd = resolve(opts.cwd || opts.rootDir || ".");
	opts.overrides ||= opts.config || {};
	opts.overrides.dev = !!opts.dev;
	const resolvedPath = ["nuxt-nightly", "nuxt"].reduce((resolvedPath, pkg) => {
		const path = resolveModulePath(pkg, {
			try: true,
			from: [directoryToURL(opts.cwd)]
		});
		return path && path.length > resolvedPath.length ? path : resolvedPath;
	}, "");
	if (!resolvedPath) throw new Error(`Cannot find any nuxt version from ${opts.cwd}`);
	const { loadNuxt } = await import(pathToFileURL(resolvedPath).href).then((r) => interopDefault(r));
	return await loadNuxt(opts);
}
async function buildNuxt(nuxt) {
	const rootURL = directoryToURL(nuxt.options.rootDir);
	const { build } = await tryImportModule("nuxt-nightly", { url: rootURL }) || await importModule("nuxt", { url: rootURL });
	return runWithNuxtContext(nuxt, () => build(nuxt));
}
function setGlobalHead(head) {
	const nuxt = useNuxt();
	nuxt.options.app.head = defu(head, nuxt.options.app.head);
}
function addImports(imports) {
	useNuxt().hook("imports:extend", (_imports) => {
		_imports.push(...toArray(imports));
	});
}
function addImportsDir(dirs, opts = {}) {
	useNuxt().hook("imports:dirs", (_dirs) => {
		for (const dir of toArray(dirs)) _dirs[opts.prepend ? "unshift" : "push"](dir);
	});
}
function addImportsSources(presets) {
	useNuxt().hook("imports:sources", (_presets) => {
		for (const preset of toArray(presets)) _presets.push(preset);
	});
}
const HANDLER_METHOD_RE = /\.(get|head|patch|post|put|delete|connect|options|trace)(\.\w+)*$/;
function normalizeHandlerMethod(handler) {
	const [, method = void 0] = handler.handler.match(HANDLER_METHOD_RE) || [];
	return {
		method: method?.toUpperCase(),
		...handler,
		handler: normalize(handler.handler)
	};
}
function addServerHandler(handler) {
	useNuxt().options.serverHandlers.push(normalizeHandlerMethod(handler));
}
function addDevServerHandler(handler) {
	useNuxt().options.devServerHandlers.push(handler);
}
function addServerPlugin(plugin) {
	const nuxt = useNuxt();
	nuxt.options.nitro.plugins ||= [];
	nuxt.options.nitro.plugins.push(normalize(plugin));
}
function addPrerenderRoutes(routes) {
	const nuxt = useNuxt();
	routes = toArray(routes).filter(Boolean);
	if (!routes.length) return;
	nuxt.hook("prerender:routes", (ctx) => {
		for (const route of routes) ctx.routes.add(route);
	});
}
function useNitro() {
	const nuxt = useNuxt();
	if (!nuxt._nitro) throw new Error("Nitro is not initialized yet. You can call `useNitro()` only after `ready` hook.");
	return nuxt._nitro;
}
function addServerImports(imports) {
	const nuxt = useNuxt();
	const _imports = toArray(imports);
	nuxt.hook("nitro:config", (config) => {
		config.imports ||= {};
		config.imports.imports ||= [];
		config.imports.imports.push(..._imports);
	});
}
function addServerImportsDir(dirs, opts = {}) {
	const nuxt = useNuxt();
	const _dirs = toArray(dirs);
	nuxt.hook("nitro:config", (config) => {
		config.imports ||= {};
		config.imports.dirs ||= [];
		config.imports.dirs[opts.prepend ? "unshift" : "push"](..._dirs);
	});
}
function addServerScanDir(dirs, opts = {}) {
	useNuxt().hook("nitro:config", (config) => {
		config.scanDirs ||= [];
		for (const dir of toArray(dirs)) config.scanDirs[opts.prepend ? "unshift" : "push"](dir);
	});
}
function useRuntimeConfig() {
	const nuxt = useNuxt();
	return applyEnv(klona(nuxt.options.nitro.runtimeConfig), {
		prefix: "NITRO_",
		altPrefix: "NUXT_",
		envExpansion: nuxt.options.nitro.experimental?.envExpansion ?? !!process.env.NITRO_ENV_EXPANSION
	});
}
function updateRuntimeConfig(runtimeConfig) {
	const nuxt = useNuxt();
	Object.assign(nuxt.options.nitro.runtimeConfig, defu(runtimeConfig, nuxt.options.nitro.runtimeConfig));
	try {
		return useNitro().updateConfig({ runtimeConfig });
	} catch {}
}
function getEnv(key, opts, env = process.env) {
	const envKey = snakeCase(key).toUpperCase();
	return destr(env[opts.prefix + envKey] ?? env[opts.altPrefix + envKey]);
}
function _isObject(input) {
	return typeof input === "object" && !Array.isArray(input);
}
function applyEnv(obj, opts, parentKey = "") {
	for (const key in obj) {
		const subKey = parentKey ? `${parentKey}_${key}` : key;
		const envValue = getEnv(subKey, opts);
		if (_isObject(obj[key])) if (_isObject(envValue)) {
			obj[key] = {
				...obj[key],
				...envValue
			};
			applyEnv(obj[key], opts, subKey);
		} else if (envValue === void 0) applyEnv(obj[key], opts, subKey);
		else obj[key] = envValue ?? obj[key];
		else obj[key] = envValue ?? obj[key];
		if (opts.envExpansion && typeof obj[key] === "string") obj[key] = _expandFromEnv(obj[key]);
	}
	return obj;
}
const envExpandRx = /\{\{([^{}]*)\}\}/g;
function _expandFromEnv(value, env = process.env) {
	return value.replace(envExpandRx, (match, key) => {
		return env[key] || match;
	});
}
const extendWebpackCompatibleConfig = (builder) => (fn, options = {}) => {
	const nuxt = useNuxt();
	if (options.dev === false && nuxt.options.dev) return;
	if (options.build === false && nuxt.options.build) return;
	nuxt.hook(`${builder}:config`, async (configs) => {
		if (options.server !== false) {
			const config = configs.find((i) => i.name === "server");
			if (config) await fn(config);
		}
		if (options.client !== false) {
			const config = configs.find((i) => i.name === "client");
			if (config) await fn(config);
		}
	});
};
const extendWebpackConfig = extendWebpackCompatibleConfig("webpack");
const extendRspackConfig = extendWebpackCompatibleConfig("rspack");
function extendViteConfig(fn, options = {}) {
	const nuxt = useNuxt();
	if (options.dev === false && nuxt.options.dev) return;
	if (options.build === false && nuxt.options.build) return;
	if (options.server === false || options.client === false) {
		const caller = getUserCaller();
		warn(`[@nuxt/kit] calling \`extendViteConfig\` with only server/client environment is deprecated${caller ? ` (used at \`${resolveAlias(caller.source)}:${caller.line}:${caller.column}\`)` : ""}. Nuxt 5+ will use the Vite Environment API which shares a configuration between environments. You can likely use a Vite plugin to achieve the same result.`);
	}
	return nuxt.hook("vite:extend", ({ config }) => fn(config));
}
function addWebpackPlugin(pluginOrGetter, options) {
	extendWebpackConfig(async (config) => {
		const method = options?.prepend ? "unshift" : "push";
		const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter;
		config.plugins ||= [];
		config.plugins[method](...toArray(plugin));
	}, options);
}
function addRspackPlugin(pluginOrGetter, options) {
	extendRspackConfig(async (config) => {
		const method = options?.prepend ? "unshift" : "push";
		const plugin = typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter;
		config.plugins ||= [];
		config.plugins[method](...toArray(plugin));
	}, options);
}
function addVitePlugin(pluginOrGetter, options = {}) {
	const nuxt = useNuxt();
	if (options.dev === false && nuxt.options.dev) return;
	if (options.build === false && nuxt.options.build) return;
	let needsEnvInjection = false;
	nuxt.hook("vite:extend", async ({ config }) => {
		config.plugins ||= [];
		const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter);
		if (options.server !== false && options.client !== false) {
			const method = options?.prepend ? "unshift" : "push";
			config.plugins[method](...plugin);
			return;
		}
		if (!config.environments?.ssr || !config.environments.client) {
			needsEnvInjection = true;
			return;
		}
		const environmentName = options.server === false ? "client" : "ssr";
		const pluginName = plugin.map((p) => p.name).join("|");
		config.plugins.push({
			name: `${pluginName}:wrapper`,
			enforce: options?.prepend ? "pre" : "post",
			applyToEnvironment(environment) {
				if (environment.name === environmentName) return plugin;
			}
		});
	});
	nuxt.hook("vite:extendConfig", async (config, env) => {
		if (!needsEnvInjection) return;
		const plugin = toArray(typeof pluginOrGetter === "function" ? await pluginOrGetter() : pluginOrGetter);
		const method = options?.prepend ? "unshift" : "push";
		if (env.isClient && options.server === false) config.plugins[method](...plugin);
		if (env.isServer && options.client === false) config.plugins[method](...plugin);
	});
}
function addBuildPlugin(pluginFactory, options) {
	if (pluginFactory.vite) addVitePlugin(pluginFactory.vite, options);
	if (pluginFactory.webpack) addWebpackPlugin(pluginFactory.webpack, options);
	if (pluginFactory.rspack) addRspackPlugin(pluginFactory.rspack, options);
}
function addComponentsDir(dir, opts = {}) {
	const nuxt = useNuxt();
	nuxt.options.components ||= [];
	dir.priority ||= 0;
	nuxt.hook("components:dirs", (dirs) => {
		dirs[opts.prepend ? "unshift" : "push"](dir);
	});
}
function addComponentExports(opts) {
	const nuxt = useNuxt();
	const components = [];
	nuxt.hook("components:dirs", async () => {
		const names = await resolveModuleExportNames(await resolvePath(opts.filePath), { extensions: nuxt.options.extensions });
		components.length = 0;
		for (const name of names) components.push(normalizeComponent({
			name: pascalCase([opts.prefix || "", name === "default" ? "" : name]),
			export: name,
			...opts
		}));
	});
	addComponents(components);
}
function addComponent(opts) {
	addComponents([normalizeComponent(opts)]);
}
function addComponents(addedComponents) {
	const nuxt = useNuxt();
	nuxt.options.components ||= [];
	nuxt.hook("components:extend", (components) => {
		for (const component of addedComponents) {
			const existingComponentIndex = components.findIndex((c) => (c.pascalName === component.pascalName || c.kebabName === component.kebabName) && c.mode === component.mode);
			if (existingComponentIndex !== -1) {
				const existingComponent = components[existingComponentIndex];
				const existingPriority = existingComponent.priority ?? 0;
				const newPriority = component.priority ?? 0;
				if (newPriority < existingPriority) continue;
				if (newPriority === existingPriority) {
					const name = existingComponent.pascalName || existingComponent.kebabName;
					logger.warn(`Overriding ${name} component. You can specify a \`priority\` option when calling \`addComponent\` to avoid this warning.`);
				}
				components.splice(existingComponentIndex, 1, component);
			} else components.push(component);
		}
	});
}
function normalizeComponent(opts) {
	if (!opts.mode) {
		const [, mode = "all"] = opts.filePath.match(MODE_RE) || [];
		opts.mode = mode;
	}
	return {
		export: opts.export || "default",
		chunkName: "components/" + kebabCase(opts.name),
		global: opts.global ?? false,
		kebabName: kebabCase(opts.name || ""),
		pascalName: pascalCase(opts.name || ""),
		prefetch: false,
		preload: false,
		mode: "all",
		shortPath: opts.filePath,
		priority: 0,
		meta: {},
		...opts
	};
}
function addTemplate(_template) {
	const nuxt = useNuxt();
	const template = normalizeTemplate(_template);
	filterInPlace(nuxt.options.build.templates, (p) => (p.dst || normalizeTemplate(p).dst) !== template.dst);
	try {
		const distDir = distDirURL.toString();
		const { source } = captureStackTrace().find((e) => e.source && !e.source.startsWith(distDir)) ?? {};
		if (source) {
			const path = normalize(fileURLToPath(source));
			if (existsSync(path)) template._path = path;
		}
	} catch {}
	nuxt.options.build.templates.push(template);
	return template;
}
function addServerTemplate(template) {
	const nuxt = useNuxt();
	nuxt.options.nitro.virtual ||= {};
	nuxt.options.nitro.virtual[template.filename] = template.getContents;
	return template;
}
function addTypeTemplate(_template, context) {
	const nuxt = useNuxt();
	const template = addTemplate(_template);
	if (!template.filename.endsWith(".d.ts")) throw new Error(`Invalid type template. Filename must end with .d.ts : "${template.filename}"`);
	if (!context || context.nuxt) nuxt.hook("prepare:types", (payload) => {
		payload.references ||= [];
		payload.references.push({ path: template.dst });
	});
	if (context?.node) nuxt.hook("prepare:types", (payload) => {
		payload.nodeReferences ||= [];
		payload.nodeReferences.push({ path: template.dst });
	});
	if (context?.shared) nuxt.hook("prepare:types", (payload) => {
		payload.sharedReferences ||= [];
		payload.sharedReferences.push({ path: template.dst });
	});
	if (!context || context.nuxt || context.shared) nuxt.options.vite.vue = defu(nuxt.options.vite.vue, { script: { globalTypeFiles: [template.dst] } });
	if (context?.nitro) nuxt.hook("nitro:prepare:types", (payload) => {
		payload.references ||= [];
		payload.references.push({ path: template.dst });
	});
	return template;
}
function normalizeTemplate(template, buildDir) {
	if (!template) throw new Error("Invalid template: " + JSON.stringify(template));
	if (typeof template === "string") template = { src: template };
	else template = { ...template };
	if (template.src) {
		if (!existsSync(template.src)) throw new Error("Template not found: " + template.src);
		if (!template.filename) {
			const srcPath = parse(template.src);
			template.filename = template.fileName || `${basename(srcPath.dir)}.${srcPath.name}.${hash(template.src).replace(/-/g, "_")}${srcPath.ext}`;
		}
	}
	if (!template.src && !template.getContents) throw new Error("Invalid template. Either `getContents` or `src` should be provided: " + JSON.stringify(template));
	if (!template.filename) throw new Error("Invalid template. `filename` must be provided: " + JSON.stringify(template));
	if (template.filename.endsWith(".d.ts")) template.write = true;
	template.dst ||= resolve(buildDir ?? useNuxt().options.buildDir, template.filename);
	return template;
}
async function updateTemplates(options) {
	await tryUseNuxt()?.hooks.callHook("builder:generateApp", options);
}
function resolveLayerPaths(dirs, projectBuildDir) {
	const relativeRootDir = relativeWithDot(projectBuildDir, dirs.root);
	const relativeSrcDir = relativeWithDot(projectBuildDir, dirs.app);
	const relativeModulesDir = relativeWithDot(projectBuildDir, dirs.modules);
	const relativeSharedDir = relativeWithDot(projectBuildDir, dirs.shared);
	return {
		nuxt: [
			join(relativeSrcDir, "**/*"),
			join(relativeModulesDir, `*/runtime/**/*`),
			join(relativeRootDir, `test/nuxt/**/*`),
			join(relativeRootDir, `tests/nuxt/**/*`),
			join(relativeRootDir, `layers/*/app/**/*`),
			join(relativeRootDir, `layers/*/modules/*/runtime/**/*`)
		],
		nitro: [
			join(relativeModulesDir, `*/runtime/server/**/*`),
			join(relativeRootDir, `layers/*/server/**/*`),
			join(relativeRootDir, `layers/*/modules/*/runtime/server/**/*`)
		],
		node: [
			join(relativeModulesDir, `*.*`),
			join(relativeRootDir, `nuxt.config.*`),
			join(relativeRootDir, `.config/nuxt.*`),
			join(relativeRootDir, `layers/*/nuxt.config.*`),
			join(relativeRootDir, `layers/*/.config/nuxt.*`),
			join(relativeRootDir, `layers/*/modules/**/*`)
		],
		shared: [
			join(relativeSharedDir, `**/*`),
			join(relativeModulesDir, `*/shared/**/*`),
			join(relativeRootDir, `layers/*/shared/**/*`)
		],
		sharedDeclarations: [
			join(relativeSharedDir, `**/*.d.ts`),
			join(relativeModulesDir, `*/shared/**/*.d.ts`),
			join(relativeRootDir, `layers/*/shared/**/*.d.ts`)
		],
		globalDeclarations: [join(relativeRootDir, `*.d.ts`), join(relativeRootDir, `layers/*/*.d.ts`)]
	};
}
const STRIPPABLE_EXT_RE = /\b\.(?:d\.ts|tsx?|jsx?)$/;
const RUNTIME_EXT_RE = /\.([cm])(?:ts|js)$/;
async function getPathSubstitution(absolutePath, buildDir) {
	const stripped = absolutePath.replace(STRIPPABLE_EXT_RE, "");
	if (stripped !== absolutePath) return relativeWithDot(buildDir, stripped);
	const runtimeMatch = absolutePath.match(RUNTIME_EXT_RE);
	if (runtimeMatch) {
		const base = absolutePath.slice(0, -runtimeMatch[0].length);
		if (await promises.stat(`${base}.d.ts`).then((s) => s.isFile(), () => false)) return relativeWithDot(buildDir, base);
		const declaration = `${base}.d.${runtimeMatch[1]}ts`;
		if (await promises.stat(declaration).then((s) => s.isFile(), () => false)) return relativeWithDot(buildDir, declaration);
	}
	return relativeWithDot(buildDir, absolutePath);
}
const excludedAlias = [/^@vue\/.*$/, /^#internal\/nuxt/];
async function _generateTypes(nuxt) {
	const include = new Set(["./nuxt.d.ts"]);
	const nodeInclude = new Set(["./nuxt.node.d.ts"]);
	const sharedInclude = new Set(["./nuxt.shared.d.ts"]);
	const legacyInclude = new Set([...include, ...nodeInclude]);
	const exclude = /* @__PURE__ */ new Set();
	const nodeExclude = /* @__PURE__ */ new Set();
	const sharedExclude = /* @__PURE__ */ new Set();
	const legacyExclude = /* @__PURE__ */ new Set();
	if (nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.srcDir) {
		include.add(join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), "**/*"));
		legacyInclude.add(join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), "**/*"));
	}
	const layerDirs = getLayerDirectories(nuxt);
	const sourceDirs = layerDirs.map((layer) => layer.app);
	for (const dir of nuxt.options.modulesDir) {
		if (!sourceDirs.some((srcDir) => dir.startsWith(srcDir))) exclude.add(relativeWithDot(nuxt.options.buildDir, dir));
		nodeExclude.add(relativeWithDot(nuxt.options.buildDir, dir));
		legacyExclude.add(relativeWithDot(nuxt.options.buildDir, dir));
	}
	for (const dir of ["dist", ".data"]) {
		exclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
		nodeExclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
		legacyExclude.add(relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, dir)));
	}
	const rootDirWithSlash = withTrailingSlash$1(nuxt.options.rootDir);
	for (const dirs of layerDirs) if (!dirs.app.startsWith(rootDirWithSlash) || dirs.root === rootDirWithSlash || dirs.app.includes("node_modules")) {
		const rootGlob = join(relativeWithDot(nuxt.options.buildDir, dirs.root), "**/*");
		const paths = resolveLayerPaths(dirs, nuxt.options.buildDir);
		for (const path of paths.nuxt) {
			include.add(path);
			legacyInclude.add(path);
			if (path !== rootGlob) nodeExclude.add(path);
		}
		for (const path of paths.nitro) {
			exclude.add(path);
			nodeExclude.add(path);
			legacyExclude.add(path);
		}
		for (const path of paths.node) {
			nodeInclude.add(path);
			legacyInclude.add(path);
			exclude.add(path);
		}
		for (const path of paths.shared) {
			legacyInclude.add(path);
			sharedInclude.add(path);
		}
		for (const path of paths.sharedDeclarations) include.add(path);
		for (const path of paths.globalDeclarations) {
			include.add(path);
			legacyInclude.add(path);
			sharedInclude.add(path);
		}
	}
	const moduleEntryPaths = [];
	for (const m of nuxt.options._installedModules) {
		const path = m.meta?.rawPath || m.entryPath;
		if (path) moduleEntryPaths.push(getDirectory(path));
	}
	const modulePaths = await resolveNuxtModule(rootDirWithSlash, moduleEntryPaths);
	for (const path of modulePaths) {
		const relative = relativeWithDot(nuxt.options.buildDir, path);
		if (!path.includes("node_modules") && path.startsWith(rootDirWithSlash)) {
			include.add(join(relative, "runtime"));
			include.add(join(relative, "dist/runtime"));
			nodeInclude.add(join(relative, "*.*"));
		}
		legacyInclude.add(join(relative, "runtime"));
		legacyInclude.add(join(relative, "dist/runtime"));
		nodeExclude.add(join(relative, "runtime"));
		nodeExclude.add(join(relative, "dist/runtime"));
		exclude.add(join(relative, "runtime/server"));
		exclude.add(join(relative, "dist/runtime/server"));
		exclude.add(join(relative, "*.*"));
		exclude.add(join(relative, "dist/*.*"));
		legacyExclude.add(join(relative, "runtime/server"));
		legacyExclude.add(join(relative, "dist/runtime/server"));
	}
	const nestedModulesDirs = [];
	for (const dir of nuxt.options.modulesDir.toSorted()) {
		const withSlash = withTrailingSlash$1(dir);
		if (nestedModulesDirs.every((d) => !d.startsWith(withSlash))) nestedModulesDirs.push(withSlash);
	}
	let hasTypescriptVersionWithModulePreserve;
	for (const parent of nestedModulesDirs) hasTypescriptVersionWithModulePreserve ??= await readPackageJSON("typescript", { parent }).then((r) => r?.version && gte(r.version, "5.4.0")).catch(() => void 0);
	hasTypescriptVersionWithModulePreserve ??= true;
	const useDecorators = Boolean(nuxt.options.experimental?.decorators);
	const userExclude = nuxt.options.typescript?.tsConfig?.exclude ?? [];
	const tsConfig = defu(nuxt.options.typescript?.tsConfig, {
		compilerOptions: {
			esModuleInterop: true,
			skipLibCheck: true,
			target: "ESNext",
			allowJs: true,
			resolveJsonModule: true,
			moduleDetection: "force",
			isolatedModules: true,
			verbatimModuleSyntax: true,
			allowArbitraryExtensions: true,
			strict: nuxt.options.typescript?.strict ?? true,
			noUncheckedIndexedAccess: true,
			forceConsistentCasingInFileNames: true,
			noImplicitOverride: true,
			...useDecorators ? { experimentalDecorators: false } : {},
			module: hasTypescriptVersionWithModulePreserve ? "preserve" : "ESNext",
			noEmit: true,
			lib: [
				"ESNext",
				...useDecorators ? ["esnext.decorators"] : [],
				"dom",
				"dom.iterable",
				"webworker"
			],
			jsx: "preserve",
			jsxImportSource: "vue",
			types: [],
			paths: {},
			moduleResolution: nuxt.options.future?.typescriptBundlerResolution || nuxt.options.experimental?.typescriptBundlerResolution ? "Bundler" : "Node",
			useDefineForClassFields: true,
			noImplicitThis: true,
			allowSyntheticDefaultImports: true
		},
		include: [...include],
		exclude: [...exclude]
	});
	const nodeTsConfig = defu(nuxt.options.typescript?.nodeTsConfig, {
		compilerOptions: {
			esModuleInterop: tsConfig.compilerOptions?.esModuleInterop,
			skipLibCheck: tsConfig.compilerOptions?.skipLibCheck,
			target: tsConfig.compilerOptions?.target,
			allowJs: tsConfig.compilerOptions?.allowJs,
			resolveJsonModule: tsConfig.compilerOptions?.resolveJsonModule,
			moduleDetection: tsConfig.compilerOptions?.moduleDetection,
			isolatedModules: tsConfig.compilerOptions?.isolatedModules,
			verbatimModuleSyntax: tsConfig.compilerOptions?.verbatimModuleSyntax,
			allowArbitraryExtensions: tsConfig.compilerOptions?.allowArbitraryExtensions,
			strict: tsConfig.compilerOptions?.strict,
			noUncheckedIndexedAccess: tsConfig.compilerOptions?.noUncheckedIndexedAccess,
			forceConsistentCasingInFileNames: tsConfig.compilerOptions?.forceConsistentCasingInFileNames,
			noImplicitOverride: tsConfig.compilerOptions?.noImplicitOverride,
			module: tsConfig.compilerOptions?.module,
			noEmit: true,
			types: [],
			paths: {},
			moduleResolution: tsConfig.compilerOptions?.moduleResolution,
			useDefineForClassFields: tsConfig.compilerOptions?.useDefineForClassFields,
			noImplicitThis: tsConfig.compilerOptions?.noImplicitThis,
			allowSyntheticDefaultImports: tsConfig.compilerOptions?.allowSyntheticDefaultImports
		},
		include: [...nodeInclude],
		exclude: [...nodeExclude]
	});
	const sharedTsConfig = defu(nuxt.options.typescript?.sharedTsConfig, {
		compilerOptions: {
			esModuleInterop: tsConfig.compilerOptions?.esModuleInterop,
			skipLibCheck: tsConfig.compilerOptions?.skipLibCheck,
			target: tsConfig.compilerOptions?.target,
			allowJs: tsConfig.compilerOptions?.allowJs,
			resolveJsonModule: tsConfig.compilerOptions?.resolveJsonModule,
			moduleDetection: tsConfig.compilerOptions?.moduleDetection,
			isolatedModules: tsConfig.compilerOptions?.isolatedModules,
			verbatimModuleSyntax: tsConfig.compilerOptions?.verbatimModuleSyntax,
			allowArbitraryExtensions: tsConfig.compilerOptions?.allowArbitraryExtensions,
			strict: tsConfig.compilerOptions?.strict,
			noUncheckedIndexedAccess: tsConfig.compilerOptions?.noUncheckedIndexedAccess,
			forceConsistentCasingInFileNames: tsConfig.compilerOptions?.forceConsistentCasingInFileNames,
			noImplicitOverride: tsConfig.compilerOptions?.noImplicitOverride,
			module: tsConfig.compilerOptions?.module,
			noEmit: true,
			types: [],
			paths: {},
			moduleResolution: tsConfig.compilerOptions?.moduleResolution,
			useDefineForClassFields: tsConfig.compilerOptions?.useDefineForClassFields,
			noImplicitThis: tsConfig.compilerOptions?.noImplicitThis,
			allowSyntheticDefaultImports: tsConfig.compilerOptions?.allowSyntheticDefaultImports
		},
		include: [...sharedInclude],
		exclude: [...sharedExclude]
	});
	const aliases = nuxt.options.alias;
	const basePath = tsConfig.compilerOptions.baseUrl ? resolve(nuxt.options.buildDir, tsConfig.compilerOptions.baseUrl) : nuxt.options.buildDir;
	tsConfig.compilerOptions ||= {};
	tsConfig.compilerOptions.paths ||= {};
	tsConfig.include ||= [];
	tsConfig.exclude ||= [];
	const importPaths = nuxt.options.modulesDir.map((d) => directoryToURL(d));
	for (const alias in aliases) {
		if (excludedAlias.some((re) => re.test(alias))) continue;
		let absolutePath = resolve(basePath, aliases[alias]);
		let stats = await promises.stat(absolutePath).catch(() => null);
		if (!stats) {
			const resolvedModule = resolveModulePath(aliases[alias], {
				try: true,
				from: importPaths,
				extensions: [
					...nuxt.options.extensions,
					".d.ts",
					".d.mts",
					".d.cts"
				]
			});
			if (resolvedModule) {
				absolutePath = resolvedModule;
				stats = await promises.stat(resolvedModule).catch(() => null);
			}
		}
		const relativePath = relativeWithDot(nuxt.options.buildDir, absolutePath);
		if (stats?.isDirectory() || aliases[alias].endsWith("/")) {
			tsConfig.compilerOptions.paths[alias] = [relativePath];
			tsConfig.compilerOptions.paths[`${alias}/*`] = [`${relativePath}/*`];
		} else {
			const path = stats?.isFile() ? await getPathSubstitution(absolutePath, nuxt.options.buildDir) : aliases[alias];
			tsConfig.compilerOptions.paths[alias] = [path];
		}
	}
	const references = [];
	const nodeReferences = [];
	const sharedReferences = [];
	await Promise.all([...nuxt.options.modules, ...nuxt.options._modules].map(async (id) => {
		if (typeof id !== "string") return;
		for (const parent of nestedModulesDirs) {
			const pkg = await readPackageJSON(id, { parent }).catch(() => null);
			if (pkg) {
				nodeReferences.push({ types: pkg.name ?? id });
				references.push({ types: pkg.name ?? id });
				return;
			}
		}
		nodeReferences.push({ types: id });
		references.push({ types: id });
	}));
	const declarations = [];
	await nuxt.callHook("prepare:types", {
		references,
		declarations,
		tsConfig,
		nodeTsConfig,
		nodeReferences,
		sharedTsConfig,
		sharedReferences
	});
	const legacyTsConfig = defu({}, {
		...tsConfig,
		include: [...tsConfig.include, ...legacyInclude],
		exclude: [...userExclude, ...legacyExclude]
	});
	async function resolveConfig(tsConfig) {
		for (const alias in tsConfig.compilerOptions.paths) {
			const paths = tsConfig.compilerOptions.paths[alias];
			tsConfig.compilerOptions.paths[alias] = [...new Set(await Promise.all(paths.map(async (path) => {
				if (!isAbsolute(path)) return path;
				return (await promises.stat(path).catch(() => null))?.isFile() ? getPathSubstitution(path, nuxt.options.buildDir) : relativeWithDot(nuxt.options.buildDir, path);
			})))];
		}
		sortTsPaths(tsConfig.compilerOptions.paths);
		tsConfig.include = [...new Set(tsConfig.include.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))];
		tsConfig.exclude = [...new Set(tsConfig.exclude.map((p) => isAbsolute(p) ? relativeWithDot(nuxt.options.buildDir, p) : p))];
	}
	await Promise.all([
		resolveConfig(tsConfig),
		resolveConfig(nodeTsConfig),
		resolveConfig(sharedTsConfig),
		resolveConfig(legacyTsConfig)
	]);
	const declaration = [
		...references.map((ref) => renderReference(ref, nuxt.options.buildDir)),
		...declarations,
		"",
		"export {}",
		""
	].join("\n");
	const nodeDeclaration = [
		...nodeReferences.map((ref) => renderReference(ref, nuxt.options.buildDir)),
		"",
		"export {}",
		""
	].join("\n");
	return {
		declaration,
		sharedTsConfig,
		sharedDeclaration: [
			...sharedReferences.map((ref) => renderReference(ref, nuxt.options.buildDir)),
			"",
			"export {}",
			""
		].join("\n"),
		nodeTsConfig,
		nodeDeclaration,
		tsConfig,
		legacyTsConfig
	};
}
async function writeTypes(nuxt) {
	const { tsConfig, nodeTsConfig, nodeDeclaration, declaration, legacyTsConfig, sharedDeclaration, sharedTsConfig } = await _generateTypes(nuxt);
	const appTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.app.json");
	const legacyTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.json");
	const nodeTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.node.json");
	const sharedTsConfigPath = resolve(nuxt.options.buildDir, "tsconfig.shared.json");
	const declarationPath = resolve(nuxt.options.buildDir, "nuxt.d.ts");
	const nodeDeclarationPath = resolve(nuxt.options.buildDir, "nuxt.node.d.ts");
	const sharedDeclarationPath = resolve(nuxt.options.buildDir, "nuxt.shared.d.ts");
	await promises.mkdir(nuxt.options.buildDir, { recursive: true });
	await Promise.all([
		promises.writeFile(appTsConfigPath, JSON.stringify(tsConfig, null, 2)),
		promises.writeFile(legacyTsConfigPath, JSON.stringify(legacyTsConfig, null, 2)),
		promises.writeFile(nodeTsConfigPath, JSON.stringify(nodeTsConfig, null, 2)),
		promises.writeFile(sharedTsConfigPath, JSON.stringify(sharedTsConfig, null, 2)),
		promises.writeFile(declarationPath, declaration),
		promises.writeFile(nodeDeclarationPath, nodeDeclaration),
		promises.writeFile(sharedDeclarationPath, sharedDeclaration)
	]);
}
function sortTsPaths(paths) {
	for (const pathKey in paths) if (pathKey.startsWith("#build")) {
		const pathValue = paths[pathKey];
		delete paths[pathKey];
		paths[pathKey] = pathValue;
	}
}
function renderReference(ref, baseDir) {
	return `/// <reference ${"path" in ref ? `path="${isAbsolute(ref.path) ? relative(baseDir, ref.path) : ref.path}"` : `types="${ref.types}"`} />`;
}
const RELATIVE_WITH_DOT_RE = /^([^.])/;
function relativeWithDot(from, to) {
	return relative(from, to).replace(RELATIVE_WITH_DOT_RE, "./$1") || ".";
}
function withTrailingSlash$1(dir) {
	return dir.replace(/[^/]$/, "$&/");
}
const LAYOUT_RE = /["']/g;
function addLayout(template, name) {
	const nuxt = useNuxt();
	const { filename, src } = addTemplate(template);
	const layoutName = kebabCase(name || parse(filename).name).replace(LAYOUT_RE, "");
	nuxt.hook("app:templates", (app) => {
		if (layoutName in app.layouts) {
			const relativePath = reverseResolveAlias(app.layouts[layoutName].file, {
				...nuxt?.options.alias || {},
				...strippedAtAliases
			}).pop() || app.layouts[layoutName].file;
			return logger.warn(`Not overriding \`${layoutName}\` (provided by \`${relativePath}\`) with \`${src || filename}\`.`);
		}
		app.layouts[layoutName] = {
			file: join("#build", filename),
			name: layoutName
		};
	});
}
const strippedAtAliases = {
	"@": "",
	"@@": ""
};
function extendPages(cb) {
	useNuxt().hook("pages:extend", cb);
}
function extendRouteRules(route, rule, options = {}) {
	const nuxt = useNuxt();
	for (const opts of [nuxt.options, nuxt.options.nitro]) {
		opts.routeRules ||= {};
		opts.routeRules[route] = options.override ? defu(rule, opts.routeRules[route]) : defu(opts.routeRules[route], rule);
	}
}
function addRouteMiddleware(input, options = {}) {
	const nuxt = useNuxt();
	const middlewares = toArray(input);
	nuxt.hook("app:resolve", (app) => {
		for (const middleware of middlewares) {
			const find = app.middleware.findIndex((item) => item.name === middleware.name);
			if (find >= 0) {
				const foundPath = app.middleware[find].path;
				if (foundPath === middleware.path) continue;
				if (options.override === true) app.middleware[find] = { ...middleware };
				else logger.warn(`'${middleware.name}' middleware already exists at '${foundPath}'. You can set \`override: true\` to replace it.`);
			} else if (options.prepend === true) app.middleware.unshift({ ...middleware });
			else app.middleware.push({ ...middleware });
		}
	});
}
const pluginSymbol = Symbol.for("nuxt plugin");
function normalizePlugin(plugin) {
	if (typeof plugin === "string") plugin = { src: plugin };
	else plugin = { ...plugin };
	if (pluginSymbol in plugin) return plugin;
	if (!plugin.src) throw new Error("Invalid plugin. src option is required: " + JSON.stringify(plugin));
	plugin.src = normalize(resolveAlias(plugin.src));
	if (!existsSync(plugin.src) && isAbsolute$1(plugin.src)) try {
		plugin.src = resolveModulePath(plugin.src, { extensions: tryUseNuxt()?.options.extensions ?? [
			".js",
			".mjs",
			".cjs",
			".ts",
			".tsx",
			".mts",
			".cts"
		] });
	} catch {}
	if (plugin.ssr) plugin.mode = "server";
	if (!plugin.mode) {
		const [, mode = "all"] = plugin.src.match(MODE_RE) || [];
		plugin.mode = mode;
	}
	plugin[pluginSymbol] = true;
	return plugin;
}
function addPlugin(_plugin, opts = {}) {
	const nuxt = useNuxt();
	const plugin = normalizePlugin(_plugin);
	filterInPlace(nuxt.options.plugins, (p) => normalizePlugin(p).src !== plugin.src);
	nuxt.options.plugins[opts.append ? "push" : "unshift"](plugin);
	return plugin;
}
function addPluginTemplate(plugin, opts = {}) {
	return addPlugin(typeof plugin === "string" ? { src: plugin } : {
		...plugin,
		src: addTemplate(plugin).dst
	}, opts);
}
export { addBuildPlugin, addComponent, addComponentExports, addComponentsDir, addDevServerHandler, addImports, addImportsDir, addImportsSources, addLayout, addPlugin, addPluginTemplate, addPrerenderRoutes, addRouteMiddleware, addRspackPlugin, addServerHandler, addServerImports, addServerImportsDir, addServerPlugin, addServerScanDir, addServerTemplate, addTemplate, addTypeTemplate, addVitePlugin, addWebpackPlugin, assertNuxtCompatibility, buildNuxt, checkNuxtCompatibility, createIsIgnored, createResolver, defineNuxtModule, directoryToURL, extendNuxtSchema, extendPages, extendRouteRules, extendRspackConfig, extendViteConfig, extendWebpackConfig, findPath, getDirectory, getLayerDirectories, getNuxtCtx, getNuxtModuleVersion, getNuxtVersion, hasNuxtCompatibility, hasNuxtModule, hasNuxtModuleCompatibility, importModule, installModule, installModules, isIgnored, isNuxt2, isNuxt3, isNuxtMajorVersion, loadNuxt, loadNuxtConfig, loadNuxtModuleInstance, logger, normalizeModuleTranspilePath, normalizePlugin, normalizeSemanticVersion, normalizeTemplate, nuxtCtx, requireModule, resolveAlias, resolveFiles, resolveIgnorePatterns, resolveModule, resolveModuleWithOptions, resolveNuxtModule, resolvePath, runWithNuxtContext, setGlobalHead, tryImportModule, tryRequireModule, tryResolveModule, tryUseNuxt, updateRuntimeConfig, updateTemplates, useLogger, useNitro, useNuxt, useRuntimeConfig, writeTypes };
