import { n as hasDependencies, r as installDependencies } from "./installer-Ns4ivVf5.js";
import * as esbuild from "esbuild-wasm/lib/browser.js";
import { parse } from "es-module-lexer/js";
import * as resolveExports from "resolve.exports";
import { parse as parse$1 } from "smol-toml";
import { transform } from "sucrase";
//#region src/resolver.ts
const DEFAULT_EXTENSIONS = [
	".ts",
	".tsx",
	".js",
	".jsx",
	".mts",
	".mjs",
	".json"
];
/**
* Resolve a module specifier to a file path in the virtual file system.
*
* Handles:
* - Relative imports (./foo, ../bar)
* - Package imports (lodash, @scope/pkg)
* - Package.json exports field
* - Extension resolution (.ts, .tsx, .js, etc.)
* - Index file resolution (foo/index.ts)
*
* @param specifier - The import specifier (e.g., './utils', 'lodash')
* @param options - Resolution options
* @returns Resolved path or external marker
*/
function resolveModule(specifier, options) {
	const { files, importer = "", conditions = ["import", "browser"], extensions = DEFAULT_EXTENSIONS } = options;
	if (specifier.startsWith(".") || specifier.startsWith("/")) {
		const resolved = resolveRelative(specifier, importer, files, extensions);
		if (resolved) return {
			path: resolved,
			external: false
		};
		throw new Error(`Cannot resolve relative import '${specifier}' from '${importer}'`);
	}
	return resolvePackage(specifier, files, conditions, extensions);
}
/**
* Resolve a relative import
*/
function resolveRelative(specifier, importer, files, extensions) {
	return resolveWithExtensions(joinPaths(getDirectory$1(importer), specifier), files, extensions);
}
/**
* Resolve a package specifier
*/
function resolvePackage(specifier, files, conditions, extensions) {
	const { packageName, subpath } = parsePackageSpecifier(specifier);
	const packageJsonPath = `node_modules/${packageName}/package.json`;
	const packageJson = files.read(packageJsonPath);
	if (!packageJson) return {
		path: specifier,
		external: true
	};
	let pkg;
	try {
		pkg = JSON.parse(packageJson);
	} catch (error) {
		const detail = error instanceof Error ? error.message : String(error);
		throw new Error(`Invalid package.json at ${packageJsonPath} (for "${packageName}"): ${detail}`);
	}
	const entrySubpath = subpath ? `./${subpath}` : ".";
	try {
		const resolved = resolveExports.resolve(pkg, entrySubpath, { conditions });
		if (resolved && resolved.length > 0) {
			const resolvedPath = resolved[0];
			if (resolvedPath) {
				const fullPath = `node_modules/${packageName}/${normalizeRelativePath(resolvedPath)}`;
				if (files.read(fullPath) !== null) return {
					path: fullPath,
					external: false
				};
			}
		}
	} catch {}
	const legacyEntry = resolveExports.legacy(pkg, { fields: ["module", "main"] });
	if (legacyEntry && typeof legacyEntry === "string") {
		const fullPath = `node_modules/${packageName}/${normalizeRelativePath(legacyEntry)}`;
		if (files.read(fullPath) !== null) return {
			path: fullPath,
			external: false
		};
	}
	const indexPath = resolveWithExtensions(`node_modules/${packageName}${subpath ? `/${subpath}` : ""}`, files, extensions);
	if (indexPath) return {
		path: indexPath,
		external: false
	};
	return {
		path: specifier,
		external: true
	};
}
/**
* Try to resolve a path with various extensions and index files
*/
function resolveWithExtensions(path, files, extensions) {
	const normalized = normalizePath(path);
	if (files.read(normalized) !== null) return normalized;
	for (const ext of extensions) {
		const withExt = normalized + ext;
		if (files.read(withExt) !== null) return withExt;
	}
	for (const ext of extensions) {
		const indexPath = `${normalized}/index${ext}`;
		if (files.read(indexPath) !== null) return indexPath;
	}
}
/**
* Parse a package specifier into package name and subpath
*/
function parsePackageSpecifier(specifier) {
	if (specifier.startsWith("@")) {
		const parts = specifier.split("/");
		if (parts.length >= 2) return {
			packageName: `${parts[0]}/${parts[1]}`,
			subpath: parts.slice(2).join("/") || void 0
		};
	}
	const slashIndex = specifier.indexOf("/");
	if (slashIndex === -1) return {
		packageName: specifier,
		subpath: void 0
	};
	return {
		packageName: specifier.slice(0, slashIndex),
		subpath: specifier.slice(slashIndex + 1)
	};
}
/**
* Get the directory of a file path
*/
function getDirectory$1(filePath) {
	const lastSlash = filePath.lastIndexOf("/");
	if (lastSlash === -1) return "";
	return filePath.slice(0, lastSlash);
}
/**
* Join two paths
*/
function joinPaths(base, relative) {
	if (relative.startsWith("/")) return relative.slice(1);
	const baseParts = base ? base.split("/") : [];
	const relativeParts = relative.split("/");
	for (const part of relativeParts) if (part === "..") baseParts.pop();
	else if (part !== ".") baseParts.push(part);
	return baseParts.join("/");
}
/**
* Normalize a path (remove ./ prefix, handle multiple slashes)
*/
function normalizePath(path) {
	return path.replace(/^\.\//, "").replace(/\/+/g, "/").replace(/\/$/, "");
}
/**
* Normalize a relative path from package.json
*/
function normalizeRelativePath(path) {
	if (path.startsWith("./")) return path.slice(2);
	if (path.startsWith("/")) return path.slice(1);
	return path;
}
/**
* Parse imports from a JavaScript/TypeScript source file.
*
* Uses es-module-lexer for accurate parsing of ES module syntax.
* Falls back to regex for JSX files since es-module-lexer doesn't
* handle JSX syntax (e.g., `<div>` is not valid JavaScript).
*/
function parseImports(code) {
	try {
		const [imports] = parse(code);
		const specifiers = [];
		for (const imp of imports) if (imp.n !== void 0) specifiers.push(imp.n);
		return [...new Set(specifiers)];
	} catch {
		return parseImportsRegex(code);
	}
}
/**
* Regex-based fallback for parsing imports.
* Used when es-module-lexer fails (e.g., on JSX/TSX files).
*/
function parseImportsRegex(code) {
	const imports = [];
	for (const match of code.matchAll(/import\s+(?:(?:[\w*{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g)) {
		const specifier = match[1];
		if (specifier) imports.push(specifier);
	}
	for (const match of code.matchAll(/import\s*\(\s*['"]([^'"]+)['"]\s*\)/g)) {
		const specifier = match[1];
		if (specifier) imports.push(specifier);
	}
	for (const match of code.matchAll(/export\s+(?:[\w*{}\s,]+\s+)?from\s+['"]([^'"]+)['"]/g)) {
		const specifier = match[1];
		if (specifier) imports.push(specifier);
	}
	return [...new Set(imports)];
}
//#endregion
//#region src/bundler.ts
/**
* esbuild-wasm bundling functionality.
*/
/**
* Build a single warning string listing the bundler-only options the caller
* set together with `bundle: false`. Returns `null` if none were set.
*
* `transformAndResolve` is sucrase + naïve module resolution — it cannot apply
* `define` substitution, custom `loader` overrides, package-export `conditions`,
* or esbuild plugins. Silently ignoring these would produce subtly wrong output
* (e.g. `__DEV__` left as a free identifier in the emitted bundle).
*/
function bundlerOnlyOptionsWarning(opts) {
	const set = [];
	if (opts.jsx !== void 0) set.push("jsx");
	if (opts.jsxImportSource !== void 0) set.push("jsxImportSource");
	if (opts.define !== void 0) set.push("define");
	if (opts.loader !== void 0) set.push("loader");
	if (opts.conditions !== void 0) set.push("conditions");
	if (opts.virtualModules !== void 0) set.push("virtualModules");
	if (opts.plugins !== void 0) set.push("__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired");
	if (set.length === 0) return null;
	return `${set.join(", ")} ${set.length === 1 ? "is" : "are"} ignored when \`bundle: false\` (transform-only mode does not run esbuild). Set \`bundle: true\` (the default) to apply them.`;
}
/**
* Bundle files using esbuild-wasm
*/
async function bundleWithEsbuild(options) {
	const { files, entryPoint, externals, target, minify, sourcemap, nodejsCompat, jsx, jsxImportSource, define, loader: loaderOverrides, conditions, virtualModules, plugins: extraPlugins = [] } = options;
	await initializeEsbuild();
	const virtualFsPlugin = {
		name: "virtual-fs",
		setup(build) {
			build.onResolve({ filter: /.*/ }, (args) => {
				if (args.kind === "entry-point") return {
					path: args.path,
					namespace: "virtual"
				};
				if (args.path.startsWith(".")) {
					const resolved = resolveRelativePath(args.resolveDir, args.path, files);
					if (resolved) return {
						path: resolved,
						namespace: "virtual"
					};
				}
				if (!args.path.startsWith("/") && !args.path.startsWith(".")) {
					if (externals.includes(args.path) || externals.some((e) => args.path.startsWith(`${e}/`) || args.path.startsWith(e))) return {
						path: args.path,
						external: true
					};
					try {
						const result = resolveModule(args.path, { files });
						if (!result.external) return {
							path: result.path,
							namespace: "virtual"
						};
					} catch {}
					return {
						path: args.path,
						external: true
					};
				}
				const normalizedPath = args.path.startsWith("/") ? args.path.slice(1) : args.path;
				if (files.read(normalizedPath) !== null) return {
					path: normalizedPath,
					namespace: "virtual"
				};
				return {
					path: args.path,
					external: true
				};
			});
			build.onLoad({
				filter: /.*/,
				namespace: "virtual"
			}, (args) => {
				const content = files.read(args.path);
				if (content === null) return { errors: [{ text: `File not found: ${args.path}` }] };
				const loader = getLoader(args.path, loaderOverrides);
				const lastSlash = args.path.lastIndexOf("/");
				return {
					contents: content,
					loader,
					resolveDir: lastSlash >= 0 ? args.path.slice(0, lastSlash) : ""
				};
			});
		}
	};
	const virtualModulePlugin = virtualModules && Object.keys(virtualModules).length > 0 ? {
		name: "virtual-modules",
		setup(build) {
			build.onResolve({ filter: /.*/ }, (args) => {
				if (Object.hasOwn(virtualModules, args.path)) return {
					path: args.path,
					namespace: "virtual-module"
				};
			});
			build.onLoad({
				filter: /.*/,
				namespace: "virtual-module"
			}, (args) => ({
				contents: virtualModules[args.path] ?? "",
				loader: "js",
				resolveDir: ""
			}));
		}
	} : null;
	for (let i = 0; i < extraPlugins.length; i++) {
		const p = extraPlugins[i];
		if (!p || typeof p !== "object" || typeof p.name !== "string" || typeof p.setup !== "function") throw new TypeError(`__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired[${i}] is not a valid esbuild plugin (expected an object with \`name: string\` and \`setup: (build) => void\`).`);
	}
	const userPlugins = extraPlugins;
	const result = await esbuild.build({
		entryPoints: [entryPoint],
		bundle: true,
		write: false,
		format: "esm",
		platform: nodejsCompat ? "node" : "browser",
		target,
		minify,
		sourcemap: sourcemap ? "inline" : false,
		plugins: [
			...userPlugins,
			...virtualModulePlugin ? [virtualModulePlugin] : [],
			virtualFsPlugin
		],
		outfile: "bundle.js",
		...jsx !== void 0 ? { jsx } : {},
		...jsxImportSource !== void 0 ? { jsxImportSource } : {},
		...define !== void 0 ? { define } : {},
		...conditions !== void 0 ? { conditions } : {}
	});
	const output = result.outputFiles?.[0];
	if (!output) throw new Error(`esbuild produced no output for entry point "${entryPoint}". This usually means a custom plugin (\`__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired\`) intercepted the entry without returning contents, or the entry resolved to an externalised module.`);
	const modules = { "bundle.js": output.text };
	const warnings = result.warnings.map((w) => w.text);
	if (warnings.length > 0) return {
		mainModule: "bundle.js",
		modules,
		warnings
	};
	return {
		mainModule: "bundle.js",
		modules
	};
}
/**
* Resolve a relative path against a directory within the virtual filesystem.
*/
function resolveRelativePath(resolveDir, relativePath, files) {
	const dir = resolveDir.replace(/^\//, "");
	const parts = dir ? dir.split("/") : [];
	const relParts = relativePath.split("/");
	for (const part of relParts) if (part === "..") parts.pop();
	else if (part !== ".") parts.push(part);
	const resolved = parts.join("/");
	if (files.read(resolved) !== null) return resolved;
	const extensions = [
		".ts",
		".tsx",
		".js",
		".jsx",
		".mts",
		".mjs"
	];
	for (const ext of extensions) if (files.read(resolved + ext) !== null) return resolved + ext;
	for (const ext of extensions) {
		const indexPath = `${resolved}/index${ext}`;
		if (files.read(indexPath) !== null) return indexPath;
	}
}
function getLoader(path, overrides) {
	if (overrides) {
		const matched = Object.keys(overrides).filter((ext) => path.endsWith(ext)).sort((a, b) => b.length - a.length)[0];
		if (matched !== void 0) return overrides[matched];
	}
	if (path.endsWith(".ts") || path.endsWith(".mts")) return "ts";
	if (path.endsWith(".tsx")) return "tsx";
	if (path.endsWith(".jsx")) return "jsx";
	if (path.endsWith(".json")) return "json";
	if (path.endsWith(".css")) return "css";
	return "js";
}
let esbuildInitialized = false;
let esbuildInitializePromise = null;
/**
* Detect whether we are running inside the Cloudflare Workers runtime
* (workerd). Both production Workers and the local dev runtime expose
* `navigator.userAgent === "Cloudflare-Workers"`.
*
* Exported so tests can sanity-check the guard without standing up a
* separate Node-only test runner.
*/
function isCloudflareWorkersRuntime() {
	return typeof navigator !== "undefined" && typeof navigator.userAgent === "string" && navigator.userAgent === "Cloudflare-Workers";
}
/**
* Error message thrown when `createWorker` / `createApp` is called outside of
* the Workers runtime. Exported so tests can match against it without
* duplicating the wording.
*/
const NOT_IN_WORKERS_ERROR = "@cloudflare/worker-bundler is only supported inside the Cloudflare Workers runtime (workerd). It cannot run in plain Node.js — including Vitest, Jest or other Node-based test runners — because it bundles via a `WebAssembly.Module` import that only the Workers module loader can resolve. To test code that uses this package, run your tests with @cloudflare/vitest-pool-workers so they execute inside workerd. See https://developers.cloudflare.com/workers/testing/vitest-integration/ for setup.";
/**
* Pre-started promise for the esbuild WASM module load.
*
* Pre-warmed at module evaluation time when (and only when) we're inside
* workerd, so the wasm `Compile` cost runs in parallel with everything else
* the test/handler is doing — matching the implicit behaviour of the static
* `import esbuildWasm from "./esbuild.wasm"` we used to have. Without this,
* the first `bundleWithEsbuild` call paid the full wasm-compile cost
* serially, which was enough to flake the first test of an `app-e2e`-style
* file under vitest's default 5s timeout on slower CI runners.
*
* Outside Workers, we *don't* start the import — Node's ESM-WASM loader
* would try to resolve esbuild's Go-runtime `gojs` import namespace as an
* npm package and crash. `initializeEsbuild()` throws `NOT_IN_WORKERS_ERROR`
* before ever touching the file in that case.
*/
let pendingWasmImport = null;
if (isCloudflareWorkersRuntime()) {
	pendingWasmImport = import("./esbuild.wasm");
	pendingWasmImport.catch(() => {});
}
/**
* Initialize the esbuild bundler.
* This is called automatically when needed.
*/
async function initializeEsbuild() {
	if (esbuildInitialized) return;
	if (esbuildInitializePromise) return esbuildInitializePromise;
	esbuildInitializePromise = (async () => {
		if (!isCloudflareWorkersRuntime() || pendingWasmImport === null) throw new Error(NOT_IN_WORKERS_ERROR);
		try {
			const wasmModule = (await pendingWasmImport).default;
			await esbuild.initialize({
				wasmModule,
				worker: false
			});
			esbuildInitialized = true;
		} catch (error) {
			if (error instanceof Error && error.message.includes("Cannot call \"initialize\" more than once")) {
				esbuildInitialized = true;
				return;
			}
			throw error;
		}
	})();
	try {
		await esbuildInitializePromise;
	} catch (error) {
		esbuildInitializePromise = null;
		throw error;
	}
}
//#endregion
//#region src/config.ts
/**
* Wrangler configuration parsing.
*
* Parses wrangler.toml, wrangler.json, and wrangler.jsonc files
* to extract compatibility settings.
*/
/**
* Parse wrangler configuration from files.
*
* Looks for wrangler.toml, wrangler.json, or wrangler.jsonc in the files
* and extracts compatibility_date and compatibility_flags.
*
* @param files - Virtual file system
* @returns Parsed wrangler config, or undefined if no config file found
*/
function parseWranglerConfig(files) {
	const tomlContent = files.read("wrangler.toml");
	if (tomlContent) return parseWranglerToml(tomlContent);
	const jsonContent = files.read("wrangler.json");
	if (jsonContent) return parseWranglerJson(jsonContent);
	const jsoncContent = files.read("wrangler.jsonc");
	if (jsoncContent) return parseWranglerJsonc(jsoncContent);
}
/**
* Parse wrangler.toml content
*/
function parseWranglerToml(content) {
	try {
		return extractWranglerConfig(parse$1(content));
	} catch {
		return {};
	}
}
/**
* Parse wrangler.json content
*/
function parseWranglerJson(content) {
	try {
		return extractWranglerConfig(JSON.parse(content));
	} catch {
		return {};
	}
}
/**
* Parse wrangler.jsonc content (JSON with comments)
*/
function parseWranglerJsonc(content) {
	try {
		const jsonContent = stripJsonComments(content);
		return extractWranglerConfig(JSON.parse(jsonContent));
	} catch {
		return {};
	}
}
/**
* Extract wrangler config fields from parsed config object.
* Handles both snake_case (toml) and camelCase (json) formats.
*/
function extractWranglerConfig(config) {
	const result = {};
	const main = config["main"];
	if (typeof main === "string") result.main = main;
	const date = config["compatibility_date"] ?? config["compatibilityDate"];
	if (typeof date === "string") result.compatibilityDate = date;
	const flags = config["compatibility_flags"] ?? config["compatibilityFlags"];
	if (Array.isArray(flags) && flags.every((f) => typeof f === "string")) result.compatibilityFlags = flags;
	return result;
}
/**
* Strip comments from JSONC content.
* Handles both single-line (//) and multi-line comments.
*/
function stripJsonComments(content) {
	let result = "";
	let i = 0;
	let inString = false;
	let stringChar = "";
	while (i < content.length) {
		const char = content[i];
		const nextChar = content[i + 1];
		if ((char === "\"" || char === "'") && (i === 0 || content[i - 1] !== "\\")) {
			if (!inString) {
				inString = true;
				stringChar = char;
			} else if (char === stringChar) inString = false;
			result += char;
			i++;
			continue;
		}
		if (inString) {
			result += char;
			i++;
			continue;
		}
		if (char === "/" && nextChar === "/") {
			while (i < content.length && content[i] !== "\n") i++;
			continue;
		}
		if (char === "/" && nextChar === "*") {
			i += 2;
			while (i < content.length - 1 && !(content[i] === "*" && content[i + 1] === "/")) i++;
			i += 2;
			continue;
		}
		result += char;
		i++;
	}
	return result;
}
/**
* Check if nodejs_compat flag is enabled in the config.
*/
function hasNodejsCompat(config) {
	return config?.compatibilityFlags?.includes("nodejs_compat") ?? false;
}
//#endregion
//#region src/transformer.ts
/**
* Transform TypeScript/JSX code to JavaScript using Sucrase.
*
* Sucrase is a super-fast TypeScript transformer that:
* - Strips type annotations
* - Transforms JSX
* - Is ~20x faster than Babel
* - Works in any JS environment (no WASM needed)
*
* @param code - Source code to transform
* @param options - Transform options
* @returns Transformed code
*/
function transformCode(code, options) {
	const { filePath, sourceMap = false, jsxRuntime = "automatic", jsxImportSource = "react", production = false } = options;
	const transforms = [];
	if (isTypeScriptFile(filePath)) transforms.push("typescript");
	if (isJsxFile(filePath)) {
		if (jsxRuntime !== "preserve") transforms.push("jsx");
	}
	if (transforms.length === 0) return { code };
	const transformOptions = {
		transforms,
		filePath,
		jsxRuntime,
		jsxImportSource,
		production,
		preserveDynamicImport: true,
		disableESTransforms: true
	};
	if (sourceMap) transformOptions.sourceMapOptions = { compiledFilename: filePath.replace(/\.(tsx?|mts)$/, ".js") };
	const result = transform(code, transformOptions);
	if (result.sourceMap) return {
		code: result.code,
		sourceMap: JSON.stringify(result.sourceMap)
	};
	return { code: result.code };
}
/**
* Check if a file path is a TypeScript file
*/
function isTypeScriptFile(filePath) {
	return /\.(ts|tsx|mts)$/.test(filePath);
}
/**
* Check if a file path is a JSX file
*/
function isJsxFile(filePath) {
	return /\.(jsx|tsx)$/.test(filePath);
}
/**
* Check if a file path is any JavaScript/TypeScript file
*/
function isJavaScriptFile(filePath) {
	return /\.(js|jsx|ts|tsx|mjs|mts)$/.test(filePath);
}
/**
* Get the output path for a transformed file
*/
function getOutputPath(filePath) {
	return filePath.replace(/\.tsx?$/, ".js").replace(/\.mts$/, ".mjs");
}
/**
* Transform all files and resolve their dependencies.
* This produces multiple modules instead of a single bundle.
*/
async function transformAndResolve(files, entryPoint, externals) {
	const modules = {};
	const warnings = [];
	const processed = /* @__PURE__ */ new Set();
	const toProcess = [entryPoint];
	const pathMap = /* @__PURE__ */ new Map();
	while (toProcess.length > 0) {
		const filePath = toProcess.pop();
		if (!filePath || processed.has(filePath)) continue;
		processed.add(filePath);
		const content = files.read(filePath);
		if (content === null) {
			warnings.push(`File not found: ${filePath}`);
			continue;
		}
		const outputPath = isTypeScriptFile(filePath) ? getOutputPath(filePath) : filePath;
		pathMap.set(filePath, outputPath);
		if (!isJavaScriptFile(filePath)) {
			if (filePath.endsWith(".json")) try {
				modules[filePath] = { json: JSON.parse(content) };
			} catch {
				warnings.push(`Failed to parse JSON file: ${filePath}`);
			}
			else modules[filePath] = { text: content };
			continue;
		}
		const imports = parseImports(content);
		for (const specifier of imports) {
			if (externals.includes(specifier) || externals.some((e) => specifier.startsWith(`${e}/`) || specifier.startsWith(e))) continue;
			try {
				const resolved = resolveModule(specifier, {
					files,
					importer: filePath
				});
				if (!resolved.external && !processed.has(resolved.path)) toProcess.push(resolved.path);
			} catch (error) {
				warnings.push(`Failed to resolve '${specifier}' from ${filePath}: ${error instanceof Error ? error.message : error}`);
			}
		}
	}
	for (const [sourcePath, outputPath] of pathMap) {
		const content = files.read(sourcePath);
		if (content === null || !isJavaScriptFile(sourcePath)) continue;
		let transformedCode;
		if (isTypeScriptFile(sourcePath)) try {
			transformedCode = transformCode(content, { filePath: sourcePath }).code;
		} catch (error) {
			warnings.push(`Failed to transform ${sourcePath}: ${error instanceof Error ? error.message : error}`);
			continue;
		}
		else transformedCode = content;
		transformedCode = rewriteImports(transformedCode, sourcePath, files, pathMap, externals);
		modules[outputPath] = transformedCode;
	}
	const mainModule = isTypeScriptFile(entryPoint) ? getOutputPath(entryPoint) : entryPoint;
	if (warnings.length > 0) return {
		mainModule,
		modules,
		warnings
	};
	return {
		mainModule,
		modules
	};
}
/**
* Rewrite import specifiers to use full output paths.
* This is necessary because the Worker Loader expects imports to match registered module names.
*/
function rewriteImports(code, importer, files, pathMap, externals) {
	const importExportRegex = /(import\s+(?:[\w*{}\s,]+\s+from\s+)?|export\s+(?:[\w*{}\s,]+\s+)?from\s+)(['"])([^'"]+)\2/g;
	const importerOutputPath = pathMap.get(importer) ?? importer;
	return code.replace(importExportRegex, (match, prefix, quote, specifier) => {
		if (externals.includes(specifier) || externals.some((e) => specifier.startsWith(`${e}/`) || specifier.startsWith(e))) return match;
		if (!specifier.startsWith(".") && !specifier.startsWith("/")) try {
			const resolved = resolveModule(specifier, {
				files,
				importer
			});
			if (resolved.external) return match;
			const resolvedOutputPath = pathMap.get(resolved.path) ?? resolved.path;
			if (resolved.path.startsWith("node_modules/")) return `${prefix}${quote}/${resolvedOutputPath}${quote}`;
			return `${prefix}${quote}${calculateRelativePath(importerOutputPath, resolvedOutputPath)}${quote}`;
		} catch {
			return match;
		}
		try {
			const resolved = resolveModule(specifier, {
				files,
				importer
			});
			if (resolved.external) return match;
			return `${prefix}${quote}${calculateRelativePath(importerOutputPath, pathMap.get(resolved.path) ?? resolved.path)}${quote}`;
		} catch {
			return match;
		}
	});
}
/**
* Calculate relative path from one file to another.
*/
function calculateRelativePath(from, to) {
	const fromDir = getDirectory(from);
	const toDir = getDirectory(to);
	const toFile = to.split("/").pop() ?? to;
	if (fromDir === toDir) return `./${toFile}`;
	const fromParts = fromDir ? fromDir.split("/") : [];
	const toParts = toDir ? toDir.split("/") : [];
	let commonLength = 0;
	while (commonLength < fromParts.length && commonLength < toParts.length && fromParts[commonLength] === toParts[commonLength]) commonLength++;
	const upCount = fromParts.length - commonLength;
	const downParts = toParts.slice(commonLength);
	let relativePath = "";
	if (upCount === 0) relativePath = "./";
	else relativePath = "../".repeat(upCount);
	if (downParts.length > 0) relativePath += `${downParts.join("/")}/`;
	return relativePath + toFile;
}
function getDirectory(filePath) {
	const lastSlash = filePath.lastIndexOf("/");
	if (lastSlash === -1) return "";
	return filePath.slice(0, lastSlash);
}
//#endregion
//#region src/utils.ts
/**
* Default entry-point paths searched (in order) when no explicit entry has
* been provided and `wrangler.*` / `package.json` don't declare one.
*
* Exported so the "Could not determine entry point" error messages in
* `index.ts` (createWorker) and `app.ts` (createApp) can reference the same
* source of truth — otherwise the messages drift out of sync the first time
* someone adds a default and forgets to update both error strings.
*/
const DEFAULT_ENTRY_POINTS = [
	"src/index.ts",
	"src/index.js",
	"src/index.mts",
	"src/index.mjs",
	"index.ts",
	"index.js",
	"src/worker.ts",
	"src/worker.js"
];
/**
* Detect entry point from wrangler config, package.json, or use defaults.
* Priority: wrangler main > package.json exports/module/main > default paths
*/
function detectEntryPoint(files, wranglerConfig) {
	if (wranglerConfig?.main) return normalizeEntryPath(wranglerConfig.main);
	const packageJsonContent = files.read("package.json");
	if (packageJsonContent) try {
		const pkg = JSON.parse(packageJsonContent);
		if (pkg.exports) {
			if (typeof pkg.exports === "string") return normalizeEntryPath(pkg.exports);
			const dotExport = pkg.exports["."];
			if (dotExport) {
				if (typeof dotExport === "string") return normalizeEntryPath(dotExport);
				if (typeof dotExport === "object" && dotExport !== null) {
					const exp = dotExport;
					const entry = exp["import"] ?? exp["default"] ?? exp["module"];
					if (typeof entry === "string") return normalizeEntryPath(entry);
				}
			}
		}
		if (pkg.module) return normalizeEntryPath(pkg.module);
		if (pkg.main) return normalizeEntryPath(pkg.main);
	} catch {}
	for (const entry of DEFAULT_ENTRY_POINTS) if (files.read(entry) !== null) return entry;
}
function normalizeEntryPath(path) {
	if (path.startsWith("./")) return path.slice(2);
	return path;
}
/**
* Render the user-provided source files as a short, readable list for use in
* "entry point not found" errors. Skips installed `node_modules/` files
* (which can be tens of thousands of paths and drown out the actually
* relevant signal — the files the user passed in) and truncates the tail.
*/
function formatFileListForError(files, limit = 10) {
	const all = files.list().filter((p) => !p.startsWith("node_modules/")).sort();
	if (all.length === 0) return "(none — `files` is empty or only contains node_modules entries)";
	const shown = all.slice(0, limit).join(", ");
	if (all.length <= limit) return shown;
	return `${shown}, … (+${all.length - limit} more)`;
}
//#endregion
//#region src/experimental.ts
let warningShown = false;
function showExperimentalWarning(fn) {
	if (!warningShown) {
		warningShown = true;
		console.warn(`[worker-bundler] ${fn}(): This package is experimental and its API may change without notice.`);
	}
}
//#endregion
//#region src/file-system.ts
/**
* A simple in-memory filesystem backed by a `Map`. Intended for use in tests
* and build pipelines where persistence is not required.
*/
var InMemoryFileSystem = class {
	/**
	* @param files Optional initial file contents. Accepts either a plain object
	* (keys are paths, values are file contents) or a `Map`. Defaults to an
	* empty filesystem.
	*/
	constructor(files = /* @__PURE__ */ new Map()) {
		this.files = /* @__PURE__ */ new Map();
		this.files = files instanceof Map ? files : new Map(Object.entries(files));
	}
	read(path) {
		return this.files.get(path) ?? null;
	}
	write(path, content) {
		this.files.set(path, content);
	}
	delete(path) {
		this.files.delete(path);
	}
	list(prefix) {
		return Array.from(this.files.keys()).filter((path) => prefix === void 0 || path.startsWith(prefix));
	}
	flush() {
		return Promise.resolve();
	}
};
/**
* A generic write-overlay on top of any `FileSystem`. Not re-exported from the
* package entry point — intended as an implementation detail for higher-level
* filesystem classes.
*
* Writes and deletes are buffered in memory keyed by the raw (untransformed)
* path. Reads are served from the write buffer first; deleted paths return
* `null`; remaining reads are delegated to the inner filesystem. `flush()`
* drains deletes and writes into the inner filesystem, awaits `inner.flush()`,
* and then clears the buffers.
*/
var OverlayFileSystem = class {
	constructor(inner) {
		this.inner = inner;
		this.overlay = null;
		this.deletions = null;
	}
	read(path) {
		if (this.overlay?.has(path)) return this.overlay.get(path) ?? null;
		if (this.deletions?.has(path)) return null;
		return this.inner.read(path);
	}
	write(path, content) {
		if (this.overlay === null) this.overlay = /* @__PURE__ */ new Map();
		this.overlay.set(path, content);
		this.deletions?.delete(path);
	}
	delete(path) {
		this.overlay?.delete(path);
		if (this.deletions === null) this.deletions = /* @__PURE__ */ new Set();
		this.deletions.add(path);
	}
	list(prefix) {
		const innerPaths = this.inner.list(prefix).filter((path) => !this.deletions?.has(path));
		const result = new Set(innerPaths);
		for (const path of this.overlay?.keys() ?? []) if (prefix === void 0 || path.startsWith(prefix)) result.add(path);
		return Array.from(result);
	}
	async flush() {
		if (this.overlay === null && this.deletions === null) return;
		for (const path of this.deletions ?? []) this.inner.delete(path);
		for (const [path, content] of this.overlay ?? []) this.inner.write(path, content);
		await this.inner.flush();
		this.overlay = null;
		this.deletions = null;
	}
};
/**
* A filesystem backed directly by Durable Object KV storage. Every write is
* committed to KV synchronously with no in-memory buffering, and `flush()` is
* a no-op.
*
* Use this when you want immediate, per-write durability and the overhead of
* individual KV writes is acceptable — for example, when seeding a small number
* of files. For bulk write workloads, prefer `DurableObjectKVFileSystem`, which
* batches all writes into a single flush.
*/
var DurableObjectRawFileSystem = class {
	/**
	* @param storage The Durable Object storage instance to persist files to.
	* @param prefix  An optional path prefix prepended to every key stored in KV.
	*                Defaults to `"bundle/"`, which namespaces bundle files away
	*                from any other keys the Durable Object may store.
	*/
	constructor(storage, prefix = "bundle/") {
		this.storage = storage;
		this.prefix = prefix;
	}
	read(path) {
		return this.storage.kv.get(this.formatPath(path)) ?? null;
	}
	write(path, content) {
		this.storage.kv.put(this.formatPath(path), content);
	}
	delete(path) {
		this.storage.kv.delete(this.formatPath(path));
	}
	list(prefix) {
		const formattedPrefix = prefix !== void 0 ? this.formatPath(prefix) : this.prefix;
		const result = [];
		for (const [key] of this.storage.kv.list({ prefix: formattedPrefix })) result.push(key.slice(this.prefix.length));
		return result;
	}
	flush() {
		return Promise.resolve();
	}
	formatPath(path) {
		return `${this.prefix}${path}`;
	}
};
/**
* A filesystem backed by Durable Object KV storage with a write-overlay.
* Writes are buffered in memory and only persisted to KV when `flush()` is
* called, avoiding the cost of a KV write on every individual file operation.
* Reads are served from the overlay when possible, falling back to KV, so
* callers always observe their own writes immediately.
*
* Implemented as an `OverlayFileSystem` wrapping a `DurableObjectRawFileSystem`.
* Use `DurableObjectRawFileSystem` directly if you want immediate per-write KV
* durability without buffering.
*/
var DurableObjectKVFileSystem = class {
	/**
	* @param storage The Durable Object storage instance to persist files to.
	* @param prefix  An optional path prefix prepended to every key stored in KV.
	*                Defaults to `"bundle/"`, which namespaces bundle files away
	*                from any other keys the Durable Object may store.
	*/
	constructor(storage, prefix = "bundle/") {
		this.fs = new OverlayFileSystem(new DurableObjectRawFileSystem(storage, prefix));
	}
	read(path) {
		return this.fs.read(path);
	}
	write(path, content) {
		this.fs.write(path, content);
	}
	delete(path) {
		this.fs.delete(path);
	}
	list(prefix) {
		return this.fs.list(prefix);
	}
	flush() {
		return this.fs.flush();
	}
};
/**
* Creates an `InMemoryFileSystem` from an async source of file entries.
*
* This is the bridge between async storage backends (e.g. a Durable Object
* `Workspace` backed by SQLite/R2) and the synchronous `FileSystem` interface
* required by the bundler and TypeScript language service.
*
* @example
* ```ts
* // Snapshot a Workspace into a bundler-compatible FileSystem
* async function* workspaceFiles(workspace) {
*   for (const entry of workspace.glob("**\/*.{ts,tsx,json}")) {
*     const content = await workspace.readFile(entry.path);
*     if (content !== null) yield [entry.path, content];
*   }
* }
*
* const fs = await createFileSystemSnapshot(workspaceFiles(workspace));
* const { languageService } = await createTypescriptLanguageService({ fileSystem: fs });
* ```
*/
async function createFileSystemSnapshot(entries) {
	const fs = new InMemoryFileSystem();
	for await (const [path, content] of entries) fs.write(path, content);
	return fs;
}
function isFileSystem(obj) {
	return "read" in obj && typeof obj.read === "function" && "delete" in obj && typeof obj.delete === "function";
}
//#endregion
//#region src/mime.ts
/**
* MIME type inference from file extensions.
*/
const MIME_TYPES = {
	".html": "text/html; charset=utf-8",
	".htm": "text/html; charset=utf-8",
	".js": "application/javascript; charset=utf-8",
	".mjs": "application/javascript; charset=utf-8",
	".css": "text/css; charset=utf-8",
	".json": "application/json; charset=utf-8",
	".png": "image/png",
	".jpg": "image/jpeg",
	".jpeg": "image/jpeg",
	".gif": "image/gif",
	".svg": "image/svg+xml",
	".ico": "image/x-icon",
	".webp": "image/webp",
	".avif": "image/avif",
	".woff": "font/woff",
	".woff2": "font/woff2",
	".ttf": "font/ttf",
	".otf": "font/otf",
	".eot": "application/vnd.ms-fontobject",
	".mp3": "audio/mpeg",
	".mp4": "video/mp4",
	".webm": "video/webm",
	".ogg": "audio/ogg",
	".wav": "audio/wav",
	".pdf": "application/pdf",
	".xml": "application/xml",
	".txt": "text/plain; charset=utf-8",
	".csv": "text/csv; charset=utf-8",
	".zip": "application/zip",
	".gz": "application/gzip",
	".tar": "application/x-tar",
	".wasm": "application/wasm",
	".webmanifest": "application/manifest+json",
	".map": "application/json"
};
/**
* Get the file extension from a path (including the dot).
*/
function getExtension(path) {
	const lastDot = path.lastIndexOf(".");
	if (lastDot === -1) return "";
	if (lastDot < path.lastIndexOf("/")) return "";
	return path.slice(lastDot).toLowerCase();
}
/**
* Infer MIME type from a file path.
* Returns undefined if the type is unknown.
*/
function inferContentType(path) {
	return MIME_TYPES[getExtension(path)];
}
/**
* Whether a content type represents a text-based format
* (used to decide text vs binary module storage).
*/
function isTextContentType(contentType) {
	return contentType.startsWith("text/") || contentType.includes("json") || contentType.includes("xml") || contentType.includes("javascript") || contentType.includes("svg");
}
//#endregion
//#region src/asset-handler.ts
/**
* Asset request handler for serving static assets.
*
* Key design: the manifest (routing metadata) is separated from the
* storage (content retrieval). This lets you plug in any backend —
* in-memory, KV, R2, Workspace, etc.
*
* Inspired by Cloudflare's Workers Static Assets behavior and
* cloudflare-asset-worker by Timo Wilhelm.
*/
/**
* Create an in-memory storage backend from a pathname->content map.
* This is the zero-config default for small asset sets.
*/
function createMemoryStorage(assets) {
	const map = new Map(Object.entries(assets));
	return { get(pathname) {
		return Promise.resolve(map.get(pathname) ?? null);
	} };
}
/**
* Normalize user config with defaults.
*/
function normalizeConfig(config) {
	const staticRedirects = {};
	if (config?.redirects?.static) {
		let lineNumber = 1;
		for (const [path, rule] of Object.entries(config.redirects.static)) staticRedirects[path] = {
			...rule,
			lineNumber: lineNumber++
		};
	}
	return {
		html_handling: config?.html_handling ?? "auto-trailing-slash",
		not_found_handling: config?.not_found_handling ?? "none",
		redirects: {
			static: staticRedirects,
			dynamic: config?.redirects?.dynamic ?? {}
		},
		headers: config?.headers ?? {}
	};
}
/**
* Compute a simple hash for ETag generation.
* Uses a fast string hash (FNV-1a) for text, or SHA-256 for binary.
*/
async function computeETag(content) {
	if (typeof content === "string") {
		let hash = 2166136261;
		for (let i = 0; i < content.length; i++) {
			hash ^= content.charCodeAt(i);
			hash = hash * 16777619 >>> 0;
		}
		return hash.toString(16).padStart(8, "0");
	}
	const hashBuffer = await crypto.subtle.digest("SHA-256", content);
	return [...new Uint8Array(hashBuffer).slice(0, 8)].map((b) => b.toString(16).padStart(2, "0")).join("");
}
/**
* Build an AssetManifest from a pathname->content mapping.
* Only computes metadata (content types, ETags) — doesn't store content.
*/
async function buildAssetManifest(assets) {
	const manifest = /* @__PURE__ */ new Map();
	const entries = Object.entries(assets);
	await Promise.all(entries.map(async ([pathname, content]) => {
		const contentType = inferContentType(pathname);
		const etag = await computeETag(content);
		manifest.set(pathname, {
			contentType,
			etag
		});
	}));
	return manifest;
}
/**
* Convenience: build both a manifest and an in-memory storage from assets.
*/
async function buildAssets(assets) {
	return {
		manifest: await buildAssetManifest(assets),
		storage: createMemoryStorage(assets)
	};
}
/**
* Check if a pathname exists in the manifest.
*/
function exists(manifest, pathname) {
	return manifest.get(pathname);
}
const ESCAPE_REGEX_CHARACTERS = /[-/\\^$*+?.()|[\]{}]/g;
const escapeRegex = (s) => s.replaceAll(ESCAPE_REGEX_CHARACTERS, String.raw`\$&`);
const PLACEHOLDER_REGEX = /:([A-Za-z]\w*)/g;
function replacer(str, replacements) {
	for (const [key, value] of Object.entries(replacements)) str = str.replaceAll(`:${key}`, value);
	return str;
}
function generateRuleRegExp(rule) {
	rule = rule.split("*").map((s) => escapeRegex(s)).join("(?<splat>.*)");
	const matches = rule.matchAll(PLACEHOLDER_REGEX);
	for (const match of matches) rule = rule.split(match[0]).join(`(?<${match[1]}>[^/]+)`);
	return new RegExp("^" + rule + "$");
}
function matchStaticRedirects(config, host, pathname) {
	const withHost = config.redirects.static[`https://${host}${pathname}`];
	const withoutHost = config.redirects.static[pathname];
	if (withHost && withoutHost) return withHost.lineNumber < withoutHost.lineNumber ? withHost : withoutHost;
	return withHost || withoutHost;
}
function matchDynamicRedirects(config, request) {
	const { pathname } = new URL(request.url);
	for (const [pattern, rule] of Object.entries(config.redirects.dynamic)) try {
		const result = generateRuleRegExp(pattern).exec(pathname);
		if (result) {
			const target = replacer(rule.to, result.groups || {}).trim();
			return {
				status: rule.status,
				to: target
			};
		}
	} catch {}
}
function handleRedirects(request, config) {
	const url = new URL(request.url);
	const { search, host } = url;
	let { pathname } = url;
	const staticMatch = matchStaticRedirects(config, host, pathname);
	const dynamicMatch = staticMatch ? void 0 : matchDynamicRedirects(config, request);
	const match = staticMatch ?? dynamicMatch;
	let proxied = false;
	if (match) if (match.status === 200) {
		pathname = new URL(match.to, request.url).pathname;
		proxied = true;
	} else {
		const destination = new URL(match.to, request.url);
		const location = destination.origin === url.origin ? `${destination.pathname}${destination.search || search}${destination.hash}` : `${destination.href}`;
		return new Response(null, {
			status: match.status,
			headers: { Location: location }
		});
	}
	return {
		proxied,
		pathname
	};
}
function generateGlobRegExp(pattern) {
	const escaped = pattern.split("*").map((s) => escapeRegex(s)).join(".*");
	return new RegExp("^" + escaped + "$");
}
function attachCustomHeaders(request, response, config) {
	if (Object.keys(config.headers).length === 0) return response;
	const { pathname } = new URL(request.url);
	const setMap = /* @__PURE__ */ new Set();
	for (const [pattern, rules] of Object.entries(config.headers)) {
		try {
			if (!generateGlobRegExp(pattern).test(pathname)) continue;
		} catch {
			continue;
		}
		if (rules.unset) for (const key of rules.unset) response.headers.delete(key);
		if (rules.set) for (const [key, value] of Object.entries(rules.set)) if (setMap.has(key.toLowerCase())) response.headers.append(key, value);
		else {
			response.headers.set(key, value);
			setMap.add(key.toLowerCase());
		}
	}
	return response;
}
function decodePath(pathname) {
	return pathname.split("/").map((segment) => {
		try {
			return decodeURIComponent(segment);
		} catch {
			return segment;
		}
	}).join("/").replaceAll(/\/+/g, "/");
}
function encodePath(pathname) {
	return pathname.split("/").map((segment) => {
		try {
			return encodeURIComponent(segment);
		} catch {
			return segment;
		}
	}).join("/");
}
function getIntent(pathname, manifest, config, skipRedirects = false, acceptsHtml = true) {
	switch (config.html_handling) {
		case "auto-trailing-slash": return htmlAutoTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml);
		case "force-trailing-slash": return htmlForceTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml);
		case "drop-trailing-slash": return htmlDropTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml);
		case "none": return htmlNone(pathname, manifest, config, acceptsHtml);
	}
}
function assetIntent(pathname, meta, status = 200) {
	return {
		type: "asset",
		pathname,
		meta,
		status
	};
}
function redirectIntent(to) {
	return {
		type: "redirect",
		to
	};
}
/**
* Safe redirect: only redirect if the file exists and the destination
* itself resolves to the same asset (avoids redirect loops).
*/
function safeRedirect(file, destination, manifest, config, skip) {
	if (skip) return void 0;
	if (!exists(manifest, destination)) {
		const intent = getIntent(destination, manifest, config, true);
		if (intent?.type === "asset" && intent.meta.etag === exists(manifest, file)?.etag) return redirectIntent(destination);
	}
}
function htmlAutoTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml) {
	let meta;
	let redirect;
	const exactMeta = exists(manifest, pathname);
	if (pathname.endsWith("/index")) {
		if (exactMeta) return assetIntent(pathname, exactMeta);
		if (redirect = safeRedirect(`${pathname}.html`, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -6)}.html`, pathname.slice(0, -6), manifest, config, skipRedirects)) return redirect;
	} else if (pathname.endsWith("/index.html")) {
		if (redirect = safeRedirect(pathname, pathname.slice(0, -10), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -11)}.html`, pathname.slice(0, -11), manifest, config, skipRedirects)) return redirect;
	} else if (pathname.endsWith("/")) {
		const indexPath = `${pathname}index.html`;
		if (meta = exists(manifest, indexPath)) return assetIntent(indexPath, meta);
		if (redirect = safeRedirect(`${pathname.slice(0, -1)}.html`, pathname.slice(0, -1), manifest, config, skipRedirects)) return redirect;
	} else if (pathname.endsWith(".html")) {
		if (redirect = safeRedirect(pathname, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -5)}/index.html`, `${pathname.slice(0, -5)}/`, manifest, config, skipRedirects)) return redirect;
	}
	if (exactMeta) return assetIntent(pathname, exactMeta);
	const htmlPath = `${pathname}.html`;
	if (meta = exists(manifest, htmlPath)) return assetIntent(htmlPath, meta);
	if (redirect = safeRedirect(`${pathname}/index.html`, `${pathname}/`, manifest, config, skipRedirects)) return redirect;
	return notFound(pathname, manifest, config, acceptsHtml);
}
function htmlForceTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml) {
	let meta;
	let redirect;
	const exactMeta = exists(manifest, pathname);
	if (pathname.endsWith("/index")) {
		if (exactMeta) return assetIntent(pathname, exactMeta);
		if (redirect = safeRedirect(`${pathname}.html`, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -6)}.html`, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
	} else if (pathname.endsWith("/index.html")) {
		if (redirect = safeRedirect(pathname, pathname.slice(0, -10), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -11)}.html`, pathname.slice(0, -10), manifest, config, skipRedirects)) return redirect;
	} else if (pathname.endsWith("/")) {
		let p = `${pathname}index.html`;
		if (meta = exists(manifest, p)) return assetIntent(p, meta);
		p = `${pathname.slice(0, -1)}.html`;
		if (meta = exists(manifest, p)) return assetIntent(p, meta);
	} else if (pathname.endsWith(".html")) {
		if (redirect = safeRedirect(pathname, `${pathname.slice(0, -5)}/`, manifest, config, skipRedirects)) return redirect;
		if (exactMeta) return assetIntent(pathname, exactMeta);
		if (redirect = safeRedirect(`${pathname.slice(0, -5)}/index.html`, `${pathname.slice(0, -5)}/`, manifest, config, skipRedirects)) return redirect;
	}
	if (exactMeta) return assetIntent(pathname, exactMeta);
	if (redirect = safeRedirect(`${pathname}.html`, `${pathname}/`, manifest, config, skipRedirects)) return redirect;
	if (redirect = safeRedirect(`${pathname}/index.html`, `${pathname}/`, manifest, config, skipRedirects)) return redirect;
	return notFound(pathname, manifest, config, acceptsHtml);
}
function htmlDropTrailingSlash(pathname, manifest, config, skipRedirects, acceptsHtml) {
	let meta;
	let redirect;
	const exactMeta = exists(manifest, pathname);
	if (pathname.endsWith("/index")) {
		if (exactMeta) return assetIntent(pathname, exactMeta);
		if (pathname === "/index") {
			if (redirect = safeRedirect("/index.html", "/", manifest, config, skipRedirects)) return redirect;
		} else {
			if (redirect = safeRedirect(`${pathname.slice(0, -6)}.html`, pathname.slice(0, -6), manifest, config, skipRedirects)) return redirect;
			if (redirect = safeRedirect(`${pathname}.html`, pathname.slice(0, -6), manifest, config, skipRedirects)) return redirect;
		}
	} else if (pathname.endsWith("/index.html")) if (pathname === "/index.html") {
		if (redirect = safeRedirect("/index.html", "/", manifest, config, skipRedirects)) return redirect;
	} else {
		if (redirect = safeRedirect(pathname, pathname.slice(0, -11), manifest, config, skipRedirects)) return redirect;
		if (exactMeta) return assetIntent(pathname, exactMeta);
		if (redirect = safeRedirect(`${pathname.slice(0, -11)}.html`, pathname.slice(0, -11), manifest, config, skipRedirects)) return redirect;
	}
	else if (pathname.endsWith("/")) if (pathname === "/") {
		if (meta = exists(manifest, "/index.html")) return assetIntent("/index.html", meta);
	} else {
		if (redirect = safeRedirect(`${pathname.slice(0, -1)}.html`, pathname.slice(0, -1), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -1)}/index.html`, pathname.slice(0, -1), manifest, config, skipRedirects)) return redirect;
	}
	else if (pathname.endsWith(".html")) {
		if (redirect = safeRedirect(pathname, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
		if (redirect = safeRedirect(`${pathname.slice(0, -5)}/index.html`, pathname.slice(0, -5), manifest, config, skipRedirects)) return redirect;
	}
	if (exactMeta) return assetIntent(pathname, exactMeta);
	let p = `${pathname}.html`;
	if (meta = exists(manifest, p)) return assetIntent(p, meta);
	p = `${pathname}/index.html`;
	if (meta = exists(manifest, p)) return assetIntent(p, meta);
	return notFound(pathname, manifest, config, acceptsHtml);
}
function htmlNone(pathname, manifest, config, acceptsHtml) {
	const meta = exists(manifest, pathname);
	return meta ? assetIntent(pathname, meta) : notFound(pathname, manifest, config, acceptsHtml);
}
function notFound(pathname, manifest, config, acceptsHtml = true) {
	switch (config.not_found_handling) {
		case "single-page-application": {
			if (!acceptsHtml) return void 0;
			const meta = exists(manifest, "/index.html");
			if (meta) return assetIntent("/index.html", meta, 200);
			return;
		}
		case "404-page": {
			let cwd = pathname;
			while (cwd) {
				cwd = cwd.slice(0, cwd.lastIndexOf("/"));
				const p = `${cwd}/404.html`;
				const meta = exists(manifest, p);
				if (meta) return assetIntent(p, meta, 404);
			}
			return;
		}
		default: return;
	}
}
const CACHE_CONTROL_REVALIDATE = "public, max-age=0, must-revalidate";
const CACHE_CONTROL_IMMUTABLE = "public, max-age=31536000, immutable";
function getCacheControl(pathname) {
	if (/\.[a-f0-9]{8,}\.\w+$/.test(pathname)) return CACHE_CONTROL_IMMUTABLE;
	return CACHE_CONTROL_REVALIDATE;
}
/**
* Handle an asset request. Returns a Response if an asset matches,
* or null if the request should fall through to the user's Worker.
*
* @param request - The incoming HTTP request
* @param manifest - Asset manifest (pathname -> metadata)
* @param storage - Storage backend for fetching content
* @param config - Asset serving configuration
*/
async function handleAssetRequest(request, manifest, storage, config) {
	const normalized = normalizeConfig(config);
	const method = request.method.toUpperCase();
	if (!["GET", "HEAD"].includes(method)) return null;
	const redirectResult = handleRedirects(request, normalized);
	if (redirectResult instanceof Response) return attachCustomHeaders(request, redirectResult, normalized);
	const { pathname } = redirectResult;
	const decodedPathname = decodePath(pathname);
	const intent = getIntent(decodedPathname, manifest, normalized, false, (request.headers.get("Accept") || "").includes("text/html"));
	if (!intent) return null;
	if (intent.type === "redirect") {
		const url = new URL(request.url);
		const encodedDest = encodePath(intent.to);
		return attachCustomHeaders(request, new Response(null, {
			status: 307,
			headers: { Location: encodedDest + url.search }
		}), normalized);
	}
	const encodedPathname = encodePath(decodedPathname);
	if (encodedPathname !== pathname) {
		const url = new URL(request.url);
		return attachCustomHeaders(request, new Response(null, {
			status: 307,
			headers: { Location: encodedPathname + url.search }
		}), normalized);
	}
	const { pathname: assetPath, meta, status } = intent;
	const strongETag = `"${meta.etag}"`;
	const weakETag = `W/${strongETag}`;
	const ifNoneMatch = request.headers.get("If-None-Match") || "";
	const eTags = new Set(ifNoneMatch.split(",").map((t) => t.trim()));
	const headers = new Headers();
	headers.set("ETag", strongETag);
	if (meta.contentType) headers.set("Content-Type", meta.contentType);
	headers.set("Cache-Control", getCacheControl(decodedPathname));
	if (eTags.has(weakETag) || eTags.has(strongETag)) return attachCustomHeaders(request, new Response(null, {
		status: 304,
		headers
	}), normalized);
	let body = null;
	if (method !== "HEAD") body = await storage.get(assetPath);
	return attachCustomHeaders(request, new Response(body, {
		status,
		headers
	}), normalized);
}
//#endregion
//#region src/app.ts
/**
* App bundler: builds a full-stack app (server Worker + client bundle + static assets)
* for the Worker Loader binding.
*
* Assets are returned separately for the host to serve — they are NOT embedded
* in the dynamic isolate. The caller uses handleAssetRequest() on the host side
* and only forwards non-asset requests to the isolate.
*/
/**
* Creates a full-stack app bundle from source files.
*
* This function:
* 1. Bundles client entry point(s) for the browser (if provided)
* 2. Collects static assets and builds the asset manifest
* 3. Bundles the server Worker
* 4. Returns server modules (for the isolate) and assets (for host-side serving) separately
*
* How the output is mounted (module worker, DO class, facet) is the caller's concern.
*/
async function createApp(options) {
	showExperimentalWarning("createApp");
	const { files, bundle = true, externals: rawExternals = [], target = "es2022", minify = false, sourcemap = false, registry, jsx, jsxImportSource, define, loader, conditions, __dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired: plugins } = options;
	const fileSystem = isFileSystem(files) ? files : new InMemoryFileSystem(files);
	const externals = ["cloudflare:", ...rawExternals];
	const wranglerConfig = parseWranglerConfig(fileSystem);
	const nodejsCompat = hasNodejsCompat(wranglerConfig);
	const installWarnings = [];
	if (hasDependencies(fileSystem)) {
		const installResult = await installDependencies(fileSystem, registry ? { registry } : {});
		installWarnings.push(...installResult.warnings);
	}
	const clientEntries = options.client ? Array.isArray(options.client) ? options.client : [options.client] : [];
	const clientOutputs = {};
	const clientBundles = [];
	for (const clientEntry of clientEntries) {
		if (fileSystem.read(clientEntry) === null) throw new Error(`Client entry point "${clientEntry}" was not found in \`files\`. Available files: ${formatFileListForError(fileSystem)}.`);
		const bundleModule = (await bundleWithEsbuild({
			files: fileSystem,
			entryPoint: clientEntry,
			externals,
			target: "es2022",
			minify,
			sourcemap,
			nodejsCompat: false,
			jsx,
			jsxImportSource,
			define,
			loader,
			conditions,
			plugins
		})).modules["bundle.js"];
		if (typeof bundleModule === "string") {
			const outputPath = `/${clientEntry.replace(/^src\//, "").replace(/\.(tsx?|jsx?)$/, ".js")}`;
			clientOutputs[outputPath] = bundleModule;
			clientBundles.push(outputPath);
		}
	}
	const allAssets = {};
	if (options.assets) for (const [pathname, content] of Object.entries(options.assets)) {
		const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
		allAssets[normalizedPath] = content;
	}
	for (const [pathname, content] of Object.entries(clientOutputs)) allAssets[pathname] = content;
	const assetManifest = await buildAssetManifest(allAssets);
	const serverEntry = options.server ?? detectEntryPoint(fileSystem, wranglerConfig);
	if (!serverEntry) throw new Error(`Could not determine server entry point for createApp. Tried (in order): the \`server\` option, \`main\` in wrangler config, \`exports\`/\`module\`/\`main\` in package.json, and the defaults ${DEFAULT_ENTRY_POINTS.join(", ")}. Pass \`server\` explicitly or add one of those files.`);
	if (fileSystem.read(serverEntry) === null) throw new Error(`Server entry point "${serverEntry}" was not found in \`files\`. Available files: ${formatFileListForError(fileSystem)}.`);
	let serverResult;
	if (bundle) serverResult = await bundleWithEsbuild({
		files: fileSystem,
		entryPoint: serverEntry,
		externals,
		target,
		minify,
		sourcemap,
		nodejsCompat,
		jsx,
		jsxImportSource,
		define,
		loader,
		conditions,
		plugins
	});
	else {
		serverResult = await transformAndResolve(fileSystem, serverEntry, externals);
		const bundlerOnly = bundlerOnlyOptionsWarning({
			jsx,
			jsxImportSource,
			define,
			loader,
			conditions,
			plugins
		});
		if (bundlerOnly) serverResult.warnings = [...serverResult.warnings ?? [], bundlerOnly];
	}
	const result = {
		mainModule: serverResult.mainModule,
		modules: serverResult.modules,
		assets: allAssets,
		assetManifest,
		assetConfig: options.assetConfig,
		clientBundles: clientBundles.length > 0 ? clientBundles : void 0
	};
	if (wranglerConfig !== void 0) result.wranglerConfig = wranglerConfig;
	if (installWarnings.length > 0) result.warnings = [...serverResult.warnings ?? [], ...installWarnings];
	else if (serverResult.warnings) result.warnings = serverResult.warnings;
	return result;
}
//#endregion
//#region src/index.ts
/**
* Dynamic Worker Bundler
*
* Creates worker bundles from source files for Cloudflare's Worker Loader binding.
*/
/**
* Creates a worker bundle from source files.
*
* This function performs:
* 1. Entry point detection (from package.json or defaults)
* 2. Auto-installation of npm dependencies (if package.json has dependencies)
* 3. TypeScript/JSX transformation (via Sucrase)
* 4. Module resolution (handling imports/exports)
* 5. Optional bundling (combining all modules into one)
*
* @param options - Configuration options
* @returns The main module path and all modules
*/
async function createWorker(options) {
	showExperimentalWarning("createWorker");
	let { files, bundle = true, externals = [], target = "es2022", minify = false, sourcemap = false, registry, jsx, jsxImportSource, define, loader, conditions, virtualModules, __dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired: plugins } = options;
	let fileSystem;
	if (isFileSystem(files)) fileSystem = files;
	else fileSystem = new InMemoryFileSystem(files);
	externals = ["cloudflare:", ...externals];
	const wranglerConfig = parseWranglerConfig(fileSystem);
	const nodejsCompat = hasNodejsCompat(wranglerConfig);
	const installWarnings = [];
	if (hasDependencies(fileSystem)) {
		const installResult = await installDependencies(fileSystem, registry ? { registry } : {});
		installWarnings.push(...installResult.warnings);
	}
	const entryPoint = options.entryPoint ?? detectEntryPoint(fileSystem, wranglerConfig);
	if (!entryPoint) throw new Error(`Could not determine entry point for createWorker. Tried (in order): the \`entryPoint\` option, \`main\` in wrangler config, \`exports\`/\`module\`/\`main\` in package.json, and the defaults ${DEFAULT_ENTRY_POINTS.join(", ")}. Pass \`entryPoint\` explicitly or add one of those files.`);
	if (fileSystem.read(entryPoint) === null) throw new Error(`Entry point "${entryPoint}" was not found in \`files\`. Available files: ${formatFileListForError(fileSystem)}.`);
	if (bundle) {
		const result = await bundleWithEsbuild({
			files: fileSystem,
			entryPoint,
			externals,
			target,
			minify,
			sourcemap,
			nodejsCompat,
			jsx,
			jsxImportSource,
			define,
			loader,
			conditions,
			virtualModules,
			plugins
		});
		if (wranglerConfig !== void 0) result.wranglerConfig = wranglerConfig;
		if (installWarnings.length > 0) result.warnings = [...result.warnings ?? [], ...installWarnings];
		return result;
	} else {
		const result = await transformAndResolve(fileSystem, entryPoint, externals);
		const bundlerOnly = bundlerOnlyOptionsWarning({
			jsx,
			jsxImportSource,
			define,
			loader,
			conditions,
			virtualModules,
			plugins
		});
		if (wranglerConfig !== void 0) result.wranglerConfig = wranglerConfig;
		const extraWarnings = [...installWarnings, ...bundlerOnly ? [bundlerOnly] : []];
		if (extraWarnings.length > 0) result.warnings = [...result.warnings ?? [], ...extraWarnings];
		return result;
	}
}
//#endregion
export { DurableObjectKVFileSystem, DurableObjectRawFileSystem, InMemoryFileSystem, buildAssetManifest, buildAssets, createApp, createFileSystemSnapshot, createMemoryStorage, createWorker, handleAssetRequest, hasDependencies, inferContentType, installDependencies, isTextContentType };

//# sourceMappingURL=index.js.map