globalThis.process ??= {};
globalThis.process.env ??= {};
import { r as __exportAll } from "./rolldown-runtime_-UtK6b3T.mjs";
import { D as exportContent, O as importContent, d as mapContentError, l as jsonError, u as jsonOk } from "./crypto_CY2zBtG3.mjs";
import { n as getFullDb } from "./db_DCN9iNkm.mjs";
import { n as recordAudit, t as clientIp } from "./audit_C_5e8RPb.mjs";
import { c as assertCsrf, i as requireAdmin } from "./auth_B0DWM0G6.mjs";
import { t as sanitizeContentBody } from "./sanitize_CLHlWQbC.mjs";
import { env } from "cloudflare:workers";
//#region src/pages/api/admin/backup.ts
var backup_exports = /* @__PURE__ */ __exportAll({
	GET: () => GET,
	POST: () => POST,
	prerender: () => false
});
var MAX_IMPORT_BYTES = 5e6;
var PayloadTooLarge = class extends Error {};
async function readCappedText(request, max) {
	const declared = request.headers.get("content-length");
	if (declared && Number(declared) > max) throw new PayloadTooLarge();
	const reader = request.body?.getReader();
	if (!reader) return "";
	const chunks = [];
	let total = 0;
	for (;;) {
		const { done, value } = await reader.read();
		if (done) break;
		if (!value) continue;
		total += value.byteLength;
		if (total > max) {
			await reader.cancel();
			throw new PayloadTooLarge();
		}
		chunks.push(value);
	}
	const merged = new Uint8Array(total);
	let offset = 0;
	for (const chunk of chunks) {
		merged.set(chunk, offset);
		offset += chunk.byteLength;
	}
	return new TextDecoder().decode(merged);
}
var GET = async ({ request, cookies }) => {
	try {
		const { actor } = await requireAdmin(request, env, cookies);
		const { db } = getFullDb(env);
		const archive = await exportContent(db, { actor });
		await recordAudit(db, {
			actorId: actor.id,
			ip: clientIp(request)
		}, {
			action: "content.export",
			entityType: "content",
			entityId: "archive"
		});
		return new Response(JSON.stringify(archive), {
			status: 200,
			headers: {
				"Content-Type": "application/json",
				"Cache-Control": "no-store",
				"Content-Disposition": `attachment; filename="mod-cms-content-${archive.exportedAt}.json"`
			}
		});
	} catch (error) {
		return mapContentError(error);
	}
};
var POST = async ({ request, cookies }) => {
	try {
		const { actor, authMode } = await requireAdmin(request, env, cookies);
		assertCsrf(request, {
			authMode,
			siteOrigin: env.SITE_ORIGIN
		});
		let raw;
		try {
			raw = await readCappedText(request, MAX_IMPORT_BYTES);
		} catch (e) {
			if (e instanceof PayloadTooLarge) return jsonError(413, "payload_too_large", `archive exceeds ${MAX_IMPORT_BYTES} bytes`);
			throw e;
		}
		let parsed;
		try {
			parsed = JSON.parse(raw);
		} catch {
			return jsonError(400, "validation_error", "invalid JSON");
		}
		const { db } = getFullDb(env);
		const report = await importContent(db, parsed, {
			actor,
			mode: "merge",
			sanitize: sanitizeContentBody
		});
		await recordAudit(db, {
			actorId: actor.id,
			ip: clientIp(request)
		}, {
			action: "content.import",
			entityType: "content",
			entityId: "archive"
		});
		return jsonOk(report);
	} catch (error) {
		return mapContentError(error);
	}
};
//#endregion
//#region \0virtual:astro:page:src/pages/api/admin/backup@_@ts
var page = () => backup_exports;
//#endregion
export { page };
