import { n as CONTAINER_LOCAL_HOSTNAME, r as CONTAINER_ROOT_DIR } from "./constants-DgZl8nng.js";
import { B as isUnicodeSupported, C as pathEquals, O as runCleanupHandlers, V as randomBookSymbol, _ as isInContainer, a as cwd, c as exec, i as coreVersion, j as toError, l as executeWithCleanupOnInterrupt, y as isValidUri, z as Logger } from "./util-CsmUMRtR.js";
import { a as _usingCtx, c as warnDeprecatedConfig, n as copyAssets, o as loadVivliostyleConfig, u as setupConfigFromFlags } from "./asset-DBj3nifv.js";
import { _ as mergeConfig$1, c as cleanupWorkspace, d as buildWebPublication, g as resolveTaskConfig, h as isWebPubConfig, i as getViewerFullUrl, l as compile, m as runBrowserOperationWithAbort, n as generateCmykReserveMap, p as launchPreview, r as getSourceUrl, t as createViteServer, u as prepareThemeDirectory, v as mergeInlineConfig } from "./server-CbkA4XCo.js";
import { t as resolveViteConfig } from "./vite-C-mM5_eo.js";
import { t as importNodeModule } from "./node-modules-CWZAzWTp.js";
import upath from "upath";
import fs from "node:fs";
import os from "node:os";
import { cyan, gray, green, red } from "yoctocolors";
import { URL as URL$1, fileURLToPath, pathToFileURL } from "node:url";
import terminalLink from "terminal-link";
import { build } from "vite";
import process$1 from "node:process";
import { x } from "tinyexec";
import { v1 } from "uuid";
import decamelize from "decamelize";
//#region src/container.ts
function toContainerPath(urlOrAbsPath) {
	if (isValidUri(urlOrAbsPath)) {
		if (urlOrAbsPath.toLowerCase().startsWith("file")) return pathToFileURL(upath.posix.join(CONTAINER_ROOT_DIR, upath.toUnix(fileURLToPath(urlOrAbsPath)).replace(/^\w:/v, ""))).href;
		return urlOrAbsPath;
	}
	return upath.posix.join(CONTAINER_ROOT_DIR, upath.toUnix(urlOrAbsPath).replace(/^\w:/v, ""));
}
function collectVolumeArgs(mountPoints) {
	return mountPoints.filter((p, i, array) => {
		if (i !== array.indexOf(p)) return false;
		let parent = p;
		while (!pathEquals(parent, upath.dirname(parent))) {
			parent = upath.dirname(parent);
			if (array.includes(parent)) return false;
		}
		return true;
	}).map((p) => `${p}:${toContainerPath(p)}`);
}
async function runContainer({ image, userVolumeArgs, commandArgs, entrypoint, env, workdir, signal }) {
	signal?.throwIfAborted();
	const { default: commandExists } = await importNodeModule("command-exists");
	const dockerExists = await commandExists("docker");
	signal?.throwIfAborted();
	if (!dockerExists) throw new Error(`Docker isn't be installed. To use this feature, you'll need to install Docker.`);
	let version;
	try {
		version = (await exec("docker", [
			"version",
			"--format",
			"{{.Server.Version}}"
		], { signal })).stdout;
	} catch (error) {
		signal?.throwIfAborted();
		throw error;
	}
	signal?.throwIfAborted();
	const [major, minor] = version.split(".").map(Number);
	if (major < 20 || major === 20 && minor < 10) throw new Error(`Docker version ${version} is not supported. Please upgrade to Docker 20.10.0 or later.`);
	try {
		try {
			var _usingCtx$5 = _usingCtx();
			_usingCtx$5.u(Logger.suspendLogging("Launching docker container"));
			const args = [
				"run",
				...Logger.isInteractive ? ["-it"] : [],
				"--rm",
				...entrypoint ? ["--entrypoint", entrypoint] : [],
				...env ? env.flatMap(([k, v]) => ["-e", `${k}=${v}`]) : [],
				...process$1.env.DEBUG ? ["-e", `DEBUG=${process$1.env.DEBUG}`] : [],
				...userVolumeArgs.flatMap((arg) => ["-v", arg]),
				...workdir ? ["-w", workdir] : [],
				image,
				...commandArgs
			];
			Logger.debug(`docker ${args.join(" ")}`);
			const proc = x("docker", args, {
				throwOnError: true,
				signal,
				nodeOptions: { stdio: Logger.isInteractive ? "inherit" : void 0 }
			});
			await executeWithCleanupOnInterrupt("Waiting for Docker process to stop", async () => {
				if (Logger.isInteractive) await proc;
				else for await (const line of proc) Logger.log(line);
			});
			signal?.throwIfAborted();
		} catch (_) {
			_usingCtx$5.e = _;
		} finally {
			_usingCtx$5.d();
		}
	} catch (error) {
		signal?.throwIfAborted();
		throw new Error("An error occurred on the running container. Please see logs above.", { cause: error });
	}
}
async function buildPDFWithContainer({ target, config, inlineConfig }) {
	const sourceUrl = new URL(await getSourceUrl(config));
	if (sourceUrl.origin === config.rootUrl) sourceUrl.hostname = CONTAINER_LOCAL_HOSTNAME;
	const bypassedOption = {
		...inlineConfig,
		input: {
			format: "webbook",
			entry: sourceUrl.href
		},
		output: [{
			...target,
			path: toContainerPath(target.path)
		}],
		host: CONTAINER_LOCAL_HOSTNAME
	};
	await runContainer({
		image: config.image,
		userVolumeArgs: collectVolumeArgs([...typeof config.serverRootDir === "string" ? [config.serverRootDir] : [], upath.dirname(target.path)]),
		env: [["VS_CLI_BUILD_PDF_OPTIONS", JSON.stringify(bypassedOption)]],
		commandArgs: ["build"],
		signal: inlineConfig.signal,
		workdir: typeof config.serverRootDir === "string" ? toContainerPath(config.serverRootDir) : void 0
	});
	return target.path;
}
//#endregion
//#region src/output/pdf-stream.ts
/**
* `SRGBValue.MAX`
* @see https://github.com/vivliostyle/vivliostyle.js/blob/master/packages/core/src/vivliostyle/cmyk-store.ts
*/
const SRGB_MAX = 1e4;
/**
* `CMYKValue.MAX`
* @see https://github.com/vivliostyle/vivliostyle.js/blob/master/packages/core/src/vivliostyle/cmyk-store.ts
*/
const CMYK_MAX = 1e4;
function scanStringLiteral(content, start) {
	const len = content.length;
	let depth = 1;
	let str = "(";
	let i = start + 1;
	while (i < len && depth > 0) {
		if (content[i] === "\\" && i + 1 < len) {
			str += content[i] + content[i + 1];
			i += 2;
			continue;
		}
		if (content[i] === "(") depth++;
		else if (content[i] === ")") depth--;
		str += content[i];
		i++;
	}
	return {
		str,
		next: i
	};
}
/**
* Tokenize PDF content stream
*/
function* tokenize(content) {
	let i = 0;
	const len = content.length;
	while (i < len) {
		while (i < len && /\s/v.test(content[i])) i++;
		if (i >= len) break;
		const c = content[i];
		if (c === "%") {
			const start = i;
			while (i < len && content[i] !== "\n" && content[i] !== "\r") i++;
			yield {
				type: "other",
				raw: content.slice(start, i)
			};
			continue;
		}
		if (c === "(") {
			const scanned = scanStringLiteral(content, i);
			i = scanned.next;
			yield {
				type: "other",
				raw: scanned.str
			};
			continue;
		}
		if (c === "<" && content[i + 1] !== "<") {
			let str = "<";
			i++;
			while (i < len && content[i] !== ">") {
				str += content[i];
				i++;
			}
			if (i < len) {
				str += ">";
				i++;
			}
			yield {
				type: "other",
				raw: str
			};
			continue;
		}
		if (c === "[" || c === "]" || c === "{" || c === "}") {
			yield {
				type: "other",
				raw: c
			};
			i++;
			continue;
		}
		if (c === "<" && content[i + 1] === "<") {
			yield {
				type: "other",
				raw: "<<"
			};
			i += 2;
			continue;
		}
		if (c === ">" && content[i + 1] === ">") {
			yield {
				type: "other",
				raw: ">>"
			};
			i += 2;
			continue;
		}
		if (c === "/") {
			let name = "/";
			i++;
			while (i < len && /[^\s\[\]\(\)<>\{\}\/%]/v.test(content[i])) {
				name += content[i];
				i++;
			}
			yield {
				type: "other",
				raw: name
			};
			continue;
		}
		let token = "";
		while (i < len && /[^\s\[\]\(\)<>\{\}\/%]/v.test(content[i])) {
			token += content[i];
			i++;
		}
		if (/^[+\-]?(\d+\.?\d*|\.\d+)$/v.test(token)) yield {
			type: "number",
			value: Number.parseFloat(token),
			raw: token
		};
		else if (token === "ID") {
			yield {
				type: "operator",
				value: "ID",
				raw: "ID"
			};
			const dataStart = i;
			while (i < len) {
				if (/\s/v.test(content[i]) && content[i + 1] === "E" && content[i + 2] === "I" && (i + 3 >= len || /\s/v.test(content[i + 3]))) {
					yield {
						type: "other",
						raw: content.slice(dataStart, i + 1)
					};
					yield {
						type: "operator",
						value: "EI",
						raw: "EI"
					};
					i += 3;
					break;
				}
				i++;
			}
		} else if (token.length > 0) yield {
			type: "operator",
			value: token,
			raw: token
		};
	}
}
function formatRgbKey(r, g, b) {
	const ri = Math.round(r * SRGB_MAX);
	const gi = Math.round(g * SRGB_MAX);
	const bi = Math.round(b * SRGB_MAX);
	return JSON.stringify([
		ri,
		gi,
		bi
	]);
}
function formatRgbKeyForWarning(r, g, b) {
	const ri = Math.round(r * SRGB_MAX);
	const gi = Math.round(g * SRGB_MAX);
	const bi = Math.round(b * SRGB_MAX);
	return JSON.stringify({
		r: ri,
		g: gi,
		b: bi
	});
}
function warnUnmappedColor(r, g, b, warnedColors) {
	const warnKey = formatRgbKeyForWarning(r, g, b);
	if (!warnedColors.has(warnKey)) {
		warnedColors.add(warnKey);
		Logger.logWarn(`RGB color not mapped to CMYK: ${warnKey}`);
	}
}
/**
* Convert RGB color operators to CMYK in a content stream
*/
function convertStreamColors(content, colorMap, warnUnmapped, warnedColors) {
	const result = [];
	const pendingNumbers = [];
	const flushPendingNumbers = () => {
		for (const num of pendingNumbers) result.push(num.raw);
		pendingNumbers.length = 0;
	};
	const convertRgbOperator = (cmykOp, token) => {
		const b = pendingNumbers.pop();
		const g = pendingNumbers.pop();
		const r = pendingNumbers.pop();
		/* v8 ignore next 3 */
		if (!b || !g || !r) throw new Error("Expected at least three pending numbers for RGB color");
		flushPendingNumbers();
		const cmyk = colorMap[formatRgbKey(r.value, g.value, b.value)];
		if (cmyk) {
			const c = (cmyk.c / CMYK_MAX).toString();
			const m = (cmyk.m / CMYK_MAX).toString();
			const y = (cmyk.y / CMYK_MAX).toString();
			const k = (cmyk.k / CMYK_MAX).toString();
			result.push(`${c} ${m} ${y} ${k} ${cmykOp}`);
			return;
		}
		result.push(r.raw, g.raw, b.raw, token.raw);
		if (warnUnmapped) warnUnmappedColor(r.value, g.value, b.value, warnedColors);
	};
	for (const token of tokenize(content)) if (token.type === "number") pendingNumbers.push({
		value: token.value,
		raw: token.raw
	});
	else if (token.type === "operator") {
		const op = token.value;
		const cmykOp = op === "rg" ? "k" : op === "RG" ? "K" : null;
		if (cmykOp && pendingNumbers.length >= 3) convertRgbOperator(cmykOp, token);
		else {
			flushPendingNumbers();
			result.push(token.raw);
		}
	} else {
		flushPendingNumbers();
		result.push(token.raw);
	}
	flushPendingNumbers();
	return result.join(" ");
}
//#endregion
//#region src/output/cmyk.ts
function disposable$1(obj) {
	return Object.assign(obj, { [Symbol.dispose]() {
		obj.destroy();
	} });
}
function processStream(stream, colorMap, warnUnmapped, warnedColors, mupdf) {
	const converted = convertStreamColors(stream.readStream().asString(), colorMap, warnUnmapped, warnedColors);
	stream.writeStream(new mupdf.Buffer(converted));
}
function processFormXObjects(resources, colorMap, warnUnmapped, warnedColors, mupdf, processed) {
	const xobjects = resources.get("XObject");
	if (!xobjects || !xobjects.isDictionary()) return;
	xobjects.forEach((xobj) => {
		if (!xobj || !xobj.isStream()) return;
		const objNum = xobj.asIndirect();
		if (objNum && processed.has(objNum)) return;
		if (objNum) processed.add(objNum);
		const subtype = xobj.get("Subtype");
		if (!subtype || subtype.toString() !== "/Form") return;
		processStream(xobj, colorMap, warnUnmapped, warnedColors, mupdf);
		const nestedResources = xobj.get("Resources");
		if (nestedResources && nestedResources.isDictionary()) processFormXObjects(nestedResources, colorMap, warnUnmapped, warnedColors, mupdf, processed);
	});
}
function processContents(contents, colorMap, warnUnmapped, warnedColors, mupdf) {
	if (contents.isArray()) for (let i = 0; i < contents.length; i++) {
		const streamObj = contents.get(i);
		if (streamObj && streamObj.isStream()) processStream(streamObj, colorMap, warnUnmapped, warnedColors, mupdf);
	}
	else if (contents.isStream()) processStream(contents, colorMap, warnUnmapped, warnedColors, mupdf);
}
async function convertCmykColors({ pdf, colorMap, warnUnmapped }) {
	try {
		var _usingCtx$4 = _usingCtx();
		const mupdf = await importNodeModule("mupdf");
		const warnedColors = /* @__PURE__ */ new Set();
		const processedXObjects = /* @__PURE__ */ new Set();
		const doc = _usingCtx$4.u(disposable$1(mupdf.PDFDocument.openDocument(pdf, "application/pdf")));
		const pageCount = doc.countPages();
		for (let i = 0; i < pageCount; i++) {
			const pageObj = doc.loadPage(i).getObject().resolve();
			const contents = pageObj.get("Contents");
			if (contents) processContents(contents, colorMap, warnUnmapped, warnedColors, mupdf);
			const resources = pageObj.get("Resources");
			if (resources && resources.isDictionary()) processFormXObjects(resources, colorMap, warnUnmapped, warnedColors, mupdf, processedXObjects);
			const annots = pageObj.get("Annots");
			if (!annots?.isArray()) continue;
			for (let j = 0; j < annots.length; j++) {
				const annot = annots.get(j);
				if (!annot) continue;
				const ap = annot.resolve().get("AP");
				if (!ap?.isDictionary()) continue;
				const n = ap.get("N");
				if (!n) continue;
				if (n.isStream()) processStream(n, colorMap, warnUnmapped, warnedColors, mupdf);
				else if (n.isDictionary()) n.forEach((val) => {
					if (val?.isStream()) processStream(val, colorMap, warnUnmapped, warnedColors, mupdf);
				});
			}
		}
		const outputBuffer = _usingCtx$4.u(disposable$1(doc.saveToBuffer("compress")));
		return new Uint8Array(outputBuffer.asUint8Array());
	} catch (_) {
		_usingCtx$4.e = _;
	} finally {
		_usingCtx$4.d();
	}
}
//#endregion
//#region src/output/image.ts
function disposable(obj) {
	return Object.assign(obj, { [Symbol.dispose]() {
		obj.destroy();
	} });
}
function imagesEqual(a, b) {
	if (a.getWidth() !== b.getWidth() || a.getHeight() !== b.getHeight()) return false;
	const pixmapA = a.toPixmap();
	const pixmapB = b.toPixmap();
	const typeA = pixmapA.getColorSpace();
	const typeB = pixmapB.getColorSpace();
	if (typeA === null || typeB === null || !(typeA.isRGB() && typeB.isRGB() || typeA.isCMYK() && typeB.isCMYK() || typeA.isGray() && typeB.isGray())) return false;
	const pixelsA = pixmapA.getPixels();
	const pixelsB = pixmapB.getPixels();
	return pixelsA.length === pixelsB.length && Buffer.compare(Buffer.from(pixelsA), Buffer.from(pixelsB)) === 0;
}
function replaceImagesInDocument(doc, imagePairs) {
	let replaced = 0;
	let total = 0;
	const pageCount = doc.countPages();
	for (let i = 0; i < pageCount; i++) {
		const pageObj = doc.loadPage(i).getObject().resolve();
		const res = pageObj.get("Resources");
		if (!res || !res.isDictionary()) continue;
		const xobjects = res.get("XObject");
		if (!xobjects || !xobjects.isDictionary()) continue;
		const entries = [];
		xobjects.forEach((value, key) => {
			entries.push({
				key,
				value
			});
		});
		for (const { key, value } of entries) {
			const subtype = value.resolve().get("Subtype");
			if (!subtype || subtype.toString() !== "/Image") continue;
			total++;
			const pdfImage = doc.loadImage(value);
			for (const pair of imagePairs) if (imagesEqual(pdfImage, pair.srcImage)) {
				const newImageRef = doc.addImage(pair.destImage);
				xobjects.put(key, newImageRef);
				replaced++;
				Logger.debug(`  Page ${i + 1}, ref "${key}": ${pair.sourcePath} -> ${pair.replacementPath}`);
				break;
			}
		}
		res.put("XObject", xobjects);
		pageObj.put("Resources", res);
	}
	return {
		replaced,
		total
	};
}
async function replaceImages({ pdf, replaceImageConfig }) {
	try {
		var _usingCtx$3 = _usingCtx();
		if (replaceImageConfig.length === 0) return pdf;
		const mupdf = await importNodeModule("mupdf");
		const imagePairs = [];
		for (const { source, replacement } of replaceImageConfig) {
			let srcImage;
			let destImage;
			try {
				const srcBuffer = fs.readFileSync(source);
				srcImage = new mupdf.Image(srcBuffer);
				Logger.debug(`Loaded source image: ${source} (${srcImage.getWidth()}x${srcImage.getHeight()})`);
			} catch (error) {
				Logger.logWarn(`Failed to load source image: ${source}: ${String(error)}`);
				continue;
			}
			try {
				const destBuffer = fs.readFileSync(replacement);
				destImage = new mupdf.Image(destBuffer);
				Logger.debug(`Loaded replacement image: ${replacement} (${destImage.getWidth()}x${destImage.getHeight()})`);
			} catch (error) {
				Logger.logWarn(`Failed to load replacement image: ${replacement}: ${String(error)}`);
				continue;
			}
			imagePairs.push({
				srcImage,
				destImage,
				sourcePath: source,
				replacementPath: replacement
			});
		}
		if (imagePairs.length === 0) return pdf;
		const doc = _usingCtx$3.u(disposable(mupdf.PDFDocument.openDocument(pdf, "application/pdf")));
		const stats = replaceImagesInDocument(doc, imagePairs);
		Logger.debug(`Replaced ${stats.replaced} of ${stats.total} images`);
		const outputBuffer = _usingCtx$3.u(disposable(doc.saveToBuffer("compress")));
		return new Uint8Array(outputBuffer.asUint8Array());
	} catch (_) {
		_usingCtx$3.e = _;
	} finally {
		_usingCtx$3.d();
	}
}
//#endregion
//#region src/output/pdf-postprocess.ts
const prefixes = {
	dcterms: "http://purl.org/dc/terms/",
	meta: "http://idpf.org/epub/vocab/package/meta/#"
};
const metaTerms = {
	title: `${prefixes.dcterms}title`,
	creator: `${prefixes.dcterms}creator`,
	description: `${prefixes.dcterms}description`,
	subject: `${prefixes.dcterms}subject`,
	contributor: `${prefixes.dcterms}contributor`,
	language: `${prefixes.dcterms}language`,
	role: `${prefixes.meta}role`,
	created: `${prefixes.meta}created`,
	date: `${prefixes.meta}date`
};
async function pressReadyWithContainer({ input, output, preflightOption, image, signal }) {
	await runContainer({
		image,
		entrypoint: "press-ready",
		userVolumeArgs: collectVolumeArgs([upath.dirname(input), upath.dirname(output)]),
		commandArgs: [
			"build",
			"-i",
			toContainerPath(input),
			"-o",
			toContainerPath(output),
			...preflightOption.map((opt) => `--${decamelize(opt, { separator: "-" })}`).filter((str) => /^[\w\-]+/v.test(str))
		],
		signal
	});
}
var PostProcess = class PostProcess {
	static async load(pdf) {
		const { PDFDocument } = await importNodeModule("pdf-lib");
		return new PostProcess(await PDFDocument.load(pdf, { updateMetadata: false }));
	}
	constructor(document) {
		this.document = document;
	}
	async save(output, { preflight, preflightOption, image, cmyk, cmykMap, replaceImage, signal }) {
		let pdf = await this.document.save();
		signal?.throwIfAborted();
		if (cmyk) {
			const mergedMap = { ...cmykMap };
			for (const [rgb, cmykValue] of cmyk.overrideMap) {
				const key = JSON.stringify([
					rgb.r,
					rgb.g,
					rgb.b
				]);
				mergedMap[key] = cmykValue;
			}
			Logger.logInfo("Converting CMYK colors");
			pdf = await convertCmykColors({
				pdf,
				colorMap: mergedMap,
				warnUnmapped: cmyk.warnUnmapped
			});
			signal?.throwIfAborted();
			if (cmyk.mapOutput) {
				const mapOutputDir = upath.dirname(cmyk.mapOutput);
				fs.mkdirSync(mapOutputDir, { recursive: true });
				await fs.promises.writeFile(cmyk.mapOutput, JSON.stringify(mergedMap, null, 2));
				Logger.logInfo(`CMYK color map saved to ${cmyk.mapOutput}`);
			}
		}
		if (replaceImage.length > 0) {
			Logger.logInfo("Replacing images");
			pdf = await replaceImages({
				pdf,
				replaceImageConfig: replaceImage
			});
			signal?.throwIfAborted();
		}
		if (preflight) {
			const input = upath.join(os.tmpdir(), `vivliostyle-cli-${v1()}.pdf`);
			await executeWithCleanupOnInterrupt(`Removing temporary preflight input: ${input}`, async () => {
				await fs.promises.writeFile(input, pdf);
				signal?.throwIfAborted();
				if (preflight === "press-ready-local" || preflight === "press-ready" && isInContainer()) try {
					var _usingCtx$2 = _usingCtx();
					_usingCtx$2.u(Logger.suspendLogging("Running press-ready"));
					const { build } = await importNodeModule("press-ready");
					await build({
						...preflightOption.reduce((acc, opt) => {
							const optName = decamelize(opt, { separator: "-" });
							if (optName.startsWith("no-")) acc[optName.slice(3)] = false;
							else acc[optName] = true;
							return acc;
						}, {}),
						input,
						output
					});
				} catch (_) {
					_usingCtx$2.e = _;
				} finally {
					_usingCtx$2.d();
				}
				else if (preflight === "press-ready") try {
					var _usingCtx3 = _usingCtx();
					_usingCtx3.u(Logger.suspendLogging("Running press-ready"));
					await pressReadyWithContainer({
						input,
						output,
						preflightOption,
						image,
						signal
					});
				} catch (_) {
					_usingCtx3.e = _;
				} finally {
					_usingCtx3.d();
				}
			}, async () => {
				await fs.promises.rm(input, { force: true });
			});
		} else {
			signal?.throwIfAborted();
			await fs.promises.writeFile(output, pdf);
		}
	}
	async metadata(tree, { pageProgression, browserVersion, viewerCoreVersion, disableCreatorOption } = {}) {
		const { ReadingDirection } = await importNodeModule("pdf-lib");
		const title = tree[metaTerms.title]?.[0].v;
		if (title) this.document.setTitle(title);
		const author = tree[metaTerms.creator]?.map((item) => item.v)?.join("; ");
		if (author) this.document.setAuthor(author);
		const subject = tree[metaTerms.description]?.[0].v;
		if (subject) this.document.setSubject(subject);
		const keywords = tree[metaTerms.subject]?.map((item) => item.v);
		if (keywords) this.document.setKeywords(keywords);
		let creatorOpt = `Vivliostyle.js ${viewerCoreVersion ?? coreVersion}`;
		if (browserVersion) creatorOpt += `; ${browserVersion}`;
		this.document.setCreator(disableCreatorOption ? "Vivliostyle" : `Vivliostyle (${creatorOpt})`);
		const language = tree[metaTerms.language]?.[0].v;
		if (language) this.document.setLanguage(language);
		const creation = (tree[metaTerms.created] || tree[metaTerms.date])?.[0].v;
		const creationDate = creation && new Date(creation);
		if (creationDate) this.document.setCreationDate(creationDate);
		if (pageProgression === "rtl") this.document.catalog.getOrCreateViewerPreferences().setReadingDirection(ReadingDirection.R2L);
	}
	async toc(tocItems) {
		const { PDFDict, PDFHexString, PDFName, PDFNumber } = await importNodeModule("pdf-lib");
		if (!tocItems || tocItems.length === 0) return;
		const addRefs = (items, parentRef) => items.map((item) => {
			const ref = this.document.context.nextRef();
			return {
				...item,
				parentRef,
				ref,
				children: addRefs(item.children, ref)
			};
		});
		const countAll = (items) => items.reduce((sum, item) => sum + countAll(item.children), items.length);
		const addObjectsToPDF = (items) => {
			for (const [i, item] of items.entries()) {
				const child = PDFDict.withContext(this.document.context);
				child.set(PDFName.of("Title"), PDFHexString.fromText(item.title));
				child.set(PDFName.of("Dest"), PDFName.of(item.id));
				child.set(PDFName.of("Parent"), item.parentRef);
				const prev = items[i - 1];
				if (prev) child.set(PDFName.of("Prev"), prev.ref);
				const next = items[i + 1];
				if (next) child.set(PDFName.of("Next"), next.ref);
				const lastChild = item.children.at(-1);
				if (lastChild) {
					child.set(PDFName.of("First"), item.children[0].ref);
					child.set(PDFName.of("Last"), lastChild.ref);
					child.set(PDFName.of("Count"), PDFNumber.of(countAll(item.children)));
				}
				this.document.context.assign(item.ref, child);
				addObjectsToPDF(item.children);
			}
		};
		const outlineRef = this.document.context.nextRef();
		const itemsWithRefs = addRefs(tocItems, outlineRef);
		addObjectsToPDF(itemsWithRefs);
		const lastItem = itemsWithRefs.at(-1);
		/* v8 ignore next 3 */
		if (!lastItem) throw new Error("Expected at least one TOC item");
		const outline = PDFDict.withContext(this.document.context);
		outline.set(PDFName.of("First"), itemsWithRefs[0].ref);
		outline.set(PDFName.of("Last"), lastItem.ref);
		outline.set(PDFName.of("Count"), PDFNumber.of(countAll(itemsWithRefs)));
		this.document.context.assign(outlineRef, outline);
		this.document.catalog.set(PDFName.of("Outlines"), outlineRef);
	}
	setPageBoxes(pageSizeData) {
		if (pageSizeData.length + 1 === this.document.getPageCount()) this.document.removePage(pageSizeData.length);
		if (pageSizeData.length !== this.document.getPageCount()) return;
		for (let i = 0; i < pageSizeData.length; i++) {
			const page = this.document.getPage(i);
			const sizeData = pageSizeData[i];
			if (!sizeData.mediaWidth || !sizeData.mediaHeight || Number.isNaN(sizeData.bleedOffset) || Number.isNaN(sizeData.bleedSize)) continue;
			const yOffset = page.getHeight() - sizeData.mediaHeight;
			page.setMediaBox(0, yOffset, sizeData.mediaWidth, sizeData.mediaHeight);
			if (!sizeData.bleedOffset && !sizeData.bleedSize) continue;
			page.setBleedBox(sizeData.bleedOffset, yOffset + sizeData.bleedOffset, sizeData.mediaWidth - sizeData.bleedOffset * 2, sizeData.mediaHeight - sizeData.bleedOffset * 2);
			const trimOffset = sizeData.bleedOffset + sizeData.bleedSize;
			page.setTrimBox(trimOffset, yOffset + trimOffset, sizeData.mediaWidth - trimOffset * 2, sizeData.mediaHeight - trimOffset * 2);
		}
	}
};
//#endregion
//#region src/output/pdf.ts
async function buildPDF({ target, config, signal }) {
	Logger.logUpdate(`Launching PDF build environment`);
	const viewerFullUrl = await getViewerFullUrl(config);
	Logger.debug("viewerFullUrl", viewerFullUrl);
	let lastEntry;
	let paginationProgress;
	let typesettingFinished = false;
	function stringifyEntry(entry) {
		const title = entry.title ? gray(entry.title) : "";
		const source = entry.source ?? entry.template;
		const fileLink = (file) => ({
			path: upath.relative(config.entryContextDir, file),
			href: pathToFileURL(file).href
		});
		let input;
		if (source?.type === "file") input = fileLink(source.pathname);
		else if (source) input = {
			path: source.href,
			href: source.href
		};
		else if ("coverImageSrc" in entry) input = fileLink(entry.coverImageSrc);
		if (!input) return title;
		const label = cyan(input.path);
		const link = terminalLink(label, input.href, { fallback: () => label });
		return title ? `${link} ${title}` : link;
	}
	function entryText() {
		return lastEntry ? stringifyEntry(lastEntry) : "Building pages";
	}
	function renderBuildingText() {
		const base = entryText();
		if (!paginationProgress) return base;
		const percent = Math.min(100, Math.round(paginationProgress.fraction * 100));
		return `${base} ${gray(`(${paginationProgress.pages} pages, ${percent}%)`)}`;
	}
	function findEntryByHref(href) {
		if (!URL$1.canParse(href)) return;
		const url = new URL$1(href);
		return config.entries.find((candidate) => {
			if (url.protocol === "file:") return pathEquals(candidate.target, decodeURI(url.pathname));
			const basePrefix = `${config.base}/`;
			return url.pathname.startsWith(basePrefix) && pathEquals(upath.relative(config.workspaceDir, candidate.target), decodeURI(url.pathname.slice(basePrefix.length)));
		});
	}
	function handlePaginationProgress(pages, fraction, href) {
		if (typesettingFinished || !Number.isFinite(pages) || !Number.isFinite(fraction)) return;
		paginationProgress = {
			pages,
			fraction
		};
		const entry = href ? findEntryByHref(href) : void 0;
		if (entry && entry !== lastEntry) {
			if (lastEntry) {
				Logger.logInfo(stringifyEntry(lastEntry));
				lastEntry = entry;
				Logger.startLogging(renderBuildingText());
			} else {
				lastEntry = entry;
				Logger.logUpdateProgress(renderBuildingText());
				Logger.logInfo("Building pages");
			}
			return;
		}
		Logger.logUpdateProgress(renderBuildingText());
	}
	const { browser, page, closeBrowser } = await launchPreview({
		mode: "build",
		url: viewerFullUrl,
		signal,
		config,
		onBrowserOpen: () => {
			Logger.logUpdate("Building pages");
		},
		onPageOpen: async (openedPage) => {
			openedPage.on("pageerror", (error) => {
				Logger.logError(red(toError(error).message));
			});
			openedPage.on("console", (msg) => {
				switch (msg.type()) {
					case "error":
						if (msg.location().url?.endsWith("/vivliostyle-viewer.js")) {
							Logger.logError(msg.text());
							throw new Error(msg.text());
						}
						return;
					case "debug":
						if (/time slice/v.test(msg.text())) return;
						break;
					default: break;
				}
				if (msg.type() === "error") Logger.logVerbose(red("console.error()"), msg.text());
				else Logger.logVerbose(gray(`console.${msg.type()}()`), msg.text());
			});
			openedPage.on("response", (response) => {
				Logger.debug(gray("viewer:response"), green(response.status().toString()), response.url());
				if (400 > response.status() && 200 <= response.status()) return;
				if (response.url().startsWith("file://") && response.ok()) return;
				Logger.logError(red(`${response.status()}`), response.url());
			});
			try {
				await openedPage.exposeFunction("__vsCliReportPaginationProgress", handlePaginationProgress);
				await openedPage.evaluateOnNewDocument(() => {
					/* v8 ignore start */
					let tick = 0;
					const timer = setInterval(() => {
						if (!window.coreViewer) {
							if (++tick > 600) clearInterval(timer);
							return;
						}
						clearInterval(timer);
						window.coreViewer.addListener("paginationprogress", (payload) => {
							window.__vsCliReportPaginationProgress?.(payload.pages ?? 0, payload.fraction ?? 0, payload.href);
						});
					}, 100);
					/* v8 ignore stop */
				});
			} catch (error) {
				Logger.debug("Failed to set up pagination progress reporting", error);
			}
			openedPage.setDefaultTimeout(config.timeout);
		}
	});
	const browserResult = await runBrowserOperationWithAbort({
		signal,
		closeBrowser,
		operation: async () => {
			const browserVersion = await browser.version();
			Logger.debug(green("success"), `browserVersion=${browserVersion}`);
			let remainTime = config.timeout;
			const startTime = Date.now();
			await page.waitForNetworkIdle({ signal });
			await page.waitForFunction(() => !!window.coreViewer, { signal });
			const { protocol } = browser;
			if (protocol === "cdp") await page.emulateMediaType("print");
			await page.waitForFunction(
				/* v8 ignore next */
				() => window.coreViewer.readyState === "complete",
				{
					polling: 1e3,
					signal
				}
			);
			typesettingFinished = true;
			if (lastEntry) Logger.logInfo(stringifyEntry(lastEntry));
			const pageProgression = await page.evaluate(() => document.querySelector("#vivliostyle-viewer-viewport")?.dataset.vivliostylePageProgression === "rtl" ? "rtl" : "ltr");
			const viewerCoreVersion = await page.evaluate(() => document.querySelector("#vivliostyle-menu_settings .version")?.textContent?.replace(/^.*?: (\d[\-+.\w]+).*$/v, "$1"));
			const metadata = await loadMetadata(page);
			const toc = await loadTOC(page);
			const pageSizeData = await loadPageSizeData(page);
			const cmykMap = target.cmyk ? await loadCmykMap(page) : {};
			remainTime -= Date.now() - startTime;
			if (remainTime <= 0) throw new Error("Typesetting process timed out");
			Logger.debug("Remaining timeout:", remainTime);
			Logger.logUpdate("Building PDF");
			const dimensionSizeForWebDriverBiDi = Number.parseInt(process.env.VS_CLI_PDF_BUILD_PDF_PAGE_SIZE || "", 10) || 3780;
			return {
				browserVersion,
				pageProgression,
				viewerCoreVersion,
				metadata,
				toc,
				pageSizeData,
				cmykMap,
				pdf: await page.pdf({
					margin: {
						top: 0,
						bottom: 0,
						right: 0,
						left: 0
					},
					printBackground: true,
					tagged: true,
					...protocol === "webDriverBiDi" ? {
						width: dimensionSizeForWebDriverBiDi,
						height: dimensionSizeForWebDriverBiDi
					} : { preferCSSPageSize: true }
				})
			};
		}
	});
	await closeBrowser();
	signal?.throwIfAborted();
	Logger.logUpdate("Processing PDF");
	fs.mkdirSync(upath.dirname(target.path), { recursive: true });
	const post = await PostProcess.load(browserResult.pdf);
	await post.metadata(browserResult.metadata, {
		pageProgression: browserResult.pageProgression,
		browserVersion: browserResult.browserVersion,
		viewerCoreVersion: browserResult.viewerCoreVersion,
		disableCreatorOption: !!config.viewer && !browserResult.viewerCoreVersion
	});
	await post.toc(browserResult.toc);
	post.setPageBoxes(browserResult.pageSizeData);
	await post.save(target.path, {
		preflight: target.preflight,
		preflightOption: target.preflightOption,
		image: config.image,
		cmyk: target.cmyk,
		cmykMap: browserResult.cmykMap,
		replaceImage: target.replaceImage,
		signal
	});
	return target.path;
}
function loadMetadata(page) {
	return page.evaluate(() => window.coreViewer.getMetadata());
}
function loadTOC(page) {
	/* v8 ignore start */
	return page.evaluate(() => new Promise((resolve) => {
		function listener(payload) {
			if (payload.a !== "toc") return;
			window.coreViewer.removeListener("done", listener);
			window.coreViewer.showTOC(false);
			resolve(window.coreViewer.getTOC());
		}
		window.coreViewer.addListener("done", listener);
		window.coreViewer.showTOC(true);
	}));
	/* v8 ignore stop */
}
function loadPageSizeData(page) {
	/* v8 ignore start */
	return page.evaluate(() => {
		const sizeData = [];
		const pageContainers = document.querySelectorAll("#vivliostyle-viewer-viewport > div > div > div[data-vivliostyle-page-container]");
		for (const pageContainer of pageContainers) {
			const bleedBox = pageContainer.querySelector("div[data-vivliostyle-bleed-box]");
			sizeData.push({
				mediaWidth: Number.parseFloat(pageContainer.style.width) * .75,
				mediaHeight: Number.parseFloat(pageContainer.style.height) * .75,
				bleedOffset: Number.parseFloat(bleedBox?.style.left ?? "") * .75,
				bleedSize: Number.parseFloat(bleedBox?.style.paddingLeft ?? "") * .75
			});
		}
		return sizeData;
	});
	/* v8 ignore stop */
}
function loadCmykMap(page) {
	/* v8 ignore next 3 */
	return page.evaluate(() => window.coreViewer.getCmykMap?.() ?? {});
}
//#endregion
//#region src/core/build.ts
async function build$1(inlineConfig, { containerForkMode = false } = {}) {
	Logger.setLogOptions({
		...inlineConfig,
		containerForkMode
	});
	if (containerForkMode) Logger.setLogPrefix(gray("[Docker]"));
	Logger.debug("build > inlineConfig %O", inlineConfig);
	let vivliostyleConfig = await loadVivliostyleConfig(inlineConfig) ?? setupConfigFromFlags(inlineConfig);
	warnDeprecatedConfig(vivliostyleConfig);
	vivliostyleConfig = mergeInlineConfig(vivliostyleConfig, {
		...inlineConfig,
		quick: false
	});
	const { inlineOptions } = vivliostyleConfig;
	Logger.debug("build > vivliostyleConfig %O", vivliostyleConfig);
	for (const [i, task] of vivliostyleConfig.tasks.entries()) try {
		var _usingCtx$1 = _usingCtx();
		_usingCtx$1.u(Logger.startLogging("Start building"));
		let config = resolveTaskConfig(task, inlineOptions);
		Logger.debug("build > config %O", config);
		const viteConfig = await resolveViteConfig({
			...config,
			mode: "build"
		});
		let server;
		if (!containerForkMode) {
			Logger.debug("build > viteConfig.configFile %s", viteConfig.configFile);
			if (viteConfig.configFile && typeof config.serverRootDir === "string") try {
				var _usingCtx3 = _usingCtx();
				_usingCtx3.u(Logger.suspendLogging("Building Vite project"));
				await build({
					configFile: viteConfig.configFile,
					root: config.serverRootDir
				});
			} catch (_) {
				_usingCtx3.e = _;
			} finally {
				_usingCtx3.d();
			}
			if (!inlineConfig.disableServerStartup) {
				server = await createViteServer({
					config,
					viteConfig,
					inlineConfig,
					mode: "build"
				});
				const addressInfo = server.httpServer?.address();
				if (addressInfo && typeof addressInfo !== "string") {
					const actualPort = addressInfo.port;
					vivliostyleConfig = mergeConfig$1(vivliostyleConfig, {
						temporaryFilePrefix: config.temporaryFilePrefix,
						server: {
							...server.config.preview,
							port: actualPort
						}
					});
					config = resolveTaskConfig(vivliostyleConfig.tasks[i], vivliostyleConfig.inlineOptions);
				}
			}
			if (isWebPubConfig(config)) {
				await cleanupWorkspace(config);
				await prepareThemeDirectory(config, inlineConfig.signal);
				await compile(config);
				await copyAssets(config);
			}
			generateCmykReserveMap(config);
		}
		for (const target of config.outputs) {
			let output = null;
			const { format } = target;
			if (format === "pdf") if (!containerForkMode && target.renderMode === "docker") output = await buildPDFWithContainer({
				target,
				config,
				inlineConfig
			});
			else output = await buildPDF({
				target,
				config,
				signal: inlineConfig.signal
			});
			else if (format === "webpub" || format === "epub") output = await buildWebPublication({
				target,
				config
			});
			if (output && !containerForkMode) {
				const formattedOutput = cyan(upath.relative(inlineConfig.cwd ?? cwd, output));
				Logger.logSuccess(`Finished building ${terminalLink(formattedOutput, pathToFileURL(output).href, { fallback: () => formattedOutput })}`);
			}
		}
		await server?.close();
	} catch (_) {
		_usingCtx$1.e = _;
	} finally {
		_usingCtx$1.d();
	}
	await runCleanupHandlers();
	if (!containerForkMode) {
		const num = vivliostyleConfig.tasks.flatMap((t) => t.output ?? []).length;
		const symbol = isUnicodeSupported ? `${num > 1 ? "📚" : randomBookSymbol} ` : "";
		Logger.log(`${symbol}Built successfully!`);
	}
}
//#endregion
export { build$1 as t };

//# sourceMappingURL=build-re0kdc5z.js.map