globalThis.process ??= {};
globalThis.process.env ??= {};
import { a as __toESM } from "./rolldown-runtime_-UtK6b3T.mjs";
import { c as renderSlot, d as renderTemplate, i as renderComponent, m as addAttribute, p as renderHead, t as spreadAttributes, w as createAstro, x as unescapeHTML } from "./server_DAChoow1.mjs";
import { t as require_react } from "./react_BkIQlPcV.mjs";
import { t as createComponent } from "./compiler_CLrjY88v.mjs";
import { h as getAllSettings, m as SETTINGS_KEYS, w as parseSiteIdentity, x as parseHideModeToggle, y as parseConsentConfig } from "./crypto_CY2zBtG3.mjs";
import { n as getFullDb } from "./db_DCN9iNkm.mjs";
import { a as resolveMenuHref, l as getMenuTree, n as getMenusDb, t as DEFAULT_PRIMARY } from "./menus_Gno2rDek.mjs";
import { h as require_jsx_runtime, m as resolveShell, t as resolveModTheme } from "./registry_Ct1ay9LR.mjs";
import { r as parseConsent, t as defaultConsent } from "./privacy_BpywF6sm.mjs";
import { o as parseActiveSelection, r as MOD_CMS_PALETTE_SET, s as themeCss } from "./theme_BaEzwWHZ.mjs";
import { env } from "cloudflare:workers";
//#region ../../packages/content-react/dist/index.js
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
var import_jsx_runtime = require_jsx_runtime();
/** Typed boundary error when a workflow action requires a persisted entry id. */
var ContentEntryNotSavedError = class extends Error {
	action;
	name = "ContentEntryNotSavedError";
	constructor(action) {
		super(`cannot ${action}: entry has not been saved yet`);
		this.action = action;
	}
};
/** Stable JSON key for effect deps — query object identity is not stable across renders. */
function stableSerializeQuery(query) {
	if (!query) return "";
	const keys = Object.keys(query).sort();
	const sorted = {};
	for (const k of keys) sorted[k] = query[k];
	return JSON.stringify(sorted);
}
function useContentList(client, query) {
	const [entries, setEntries] = (0, import_react.useState)([]);
	const [loading, setLoading] = (0, import_react.useState)(true);
	const [error, setError] = (0, import_react.useState)(null);
	const [reloadToken, setReloadToken] = (0, import_react.useState)(0);
	const queryKey = stableSerializeQuery(query);
	const clientRef = (0, import_react.useRef)(client);
	clientRef.current = client;
	const queryRef = (0, import_react.useRef)(query);
	queryRef.current = query;
	const reload = (0, import_react.useCallback)(() => {
		setReloadToken((t) => t + 1);
	}, []);
	(0, import_react.useEffect)(() => {
		let cancelled = false;
		setLoading(true);
		setError(null);
		clientRef.current.list(queryRef.current).then((rows) => {
			if (!cancelled) {
				setEntries(rows);
				setLoading(false);
			}
		}).catch((e) => {
			if (!cancelled) {
				setError(e instanceof Error ? e : new Error(String(e)));
				setLoading(false);
			}
		});
		return () => {
			cancelled = true;
		};
	}, [queryKey, reloadToken]);
	return {
		entries,
		loading,
		error,
		reload
	};
}
function entryToInput(ref) {
	return {
		id: ref.id,
		slug: ref.slug,
		type: ref.type,
		title: ref.title,
		body: ref.body,
		visibility: ref.visibility,
		termIds: ref.terms.map((term) => term.id)
	};
}
function emptyInput() {
	return {
		slug: "",
		type: "",
		title: "",
		body: "",
		visibility: "public"
	};
}
function requireId(entry, action) {
	if (!entry?.id) throw new ContentEntryNotSavedError(action);
	return entry.id;
}
function useContentEntry(client, ref) {
	const [entry, setEntry] = (0, import_react.useState)(ref);
	const [draft, setDraft] = (0, import_react.useState)(() => ref ? entryToInput(ref) : emptyInput());
	const [loading, setLoading] = (0, import_react.useState)(false);
	const [error, setError] = (0, import_react.useState)(null);
	const clientRef = (0, import_react.useRef)(client);
	clientRef.current = client;
	(0, import_react.useEffect)(() => {
		setEntry(ref);
		setDraft(ref ? entryToInput(ref) : emptyInput());
		setError(null);
	}, [ref]);
	const run = (0, import_react.useCallback)(async (fn) => {
		setLoading(true);
		setError(null);
		try {
			const result = await fn();
			setLoading(false);
			return result;
		} catch (e) {
			const err = e instanceof Error ? e : new Error(String(e));
			setError(err);
			setLoading(false);
			throw err;
		}
	}, []);
	return {
		entry,
		loading,
		error,
		save: (0, import_react.useCallback)(async (input) => {
			const payload = input ?? draft;
			const saved = await run(() => clientRef.current.put(payload));
			if (saved) {
				setEntry(saved);
				setDraft(entryToInput(saved));
			}
			return saved;
		}, [draft, run]),
		publish: (0, import_react.useCallback)(async () => {
			return run(async () => {
				const id = requireId(entry, "publish");
				return clientRef.current.publish(id);
			});
		}, [entry, run]),
		schedule: (0, import_react.useCallback)(async (at) => {
			return run(async () => {
				const id = requireId(entry, "schedule");
				return clientRef.current.schedule(id, at);
			});
		}, [entry, run]),
		unpublish: (0, import_react.useCallback)(async () => {
			return run(async () => {
				const id = requireId(entry, "unpublish");
				return clientRef.current.unpublish(id);
			});
		}, [entry, run]),
		trash: (0, import_react.useCallback)(async () => {
			return run(async () => {
				const id = requireId(entry, "trash");
				return clientRef.current.trash(id);
			});
		}, [entry, run]),
		restore: (0, import_react.useCallback)(async () => {
			return run(async () => {
				const id = requireId(entry, "restore");
				return clientRef.current.restore(id);
			});
		}, [entry, run]),
		setVisibility: (0, import_react.useCallback)(async (visibility) => {
			const result = await run(async () => {
				const id = requireId(entry, "setVisibility");
				return clientRef.current.setVisibility(id, visibility);
			});
			if (result && entry) setEntry({
				...entry,
				visibility
			});
			return result;
		}, [entry, run]),
		remove: (0, import_react.useCallback)(async () => {
			return run(async () => {
				const id = requireId(entry, "remove");
				return clientRef.current.remove(id);
			});
		}, [entry, run])
	};
}
var DEFAULT_KEY = "mod-consent";
/**
* Default localStorage-backed storage. LAZY: constructs with no `localStorage` access (safe to evaluate
* as a default during SSR); touches `window.localStorage` only inside load()/save(), each guarded so a
* SecurityError (storage disabled / private mode) degrades to null / no-op, never a throw.
*/
function createLocalStorageConsentStorage(key = DEFAULT_KEY) {
	return {
		load() {
			try {
				return window.localStorage.getItem(key);
			} catch {
				return null;
			}
		},
		save(value) {
			try {
				window.localStorage.setItem(key, value);
			} catch {}
		}
	};
}
/** Read + parse + version-gate. Fail-safe: any throw or mismatch → null (no-consent), never a crash. */
function readStored(storage, version) {
	let raw;
	try {
		raw = storage.load();
	} catch {
		return null;
	}
	if (raw == null) return null;
	let parsed;
	try {
		parsed = JSON.parse(raw);
	} catch {
		return null;
	}
	const state = parseConsent(parsed);
	if (state == null) return null;
	return state.version === version ? state : null;
}
function useConsent(options) {
	const { version } = options;
	const [storage] = (0, import_react.useState)(() => options.storage ?? createLocalStorageConsentStorage());
	const [ready, setReady] = (0, import_react.useState)(false);
	const [consent, setConsent] = (0, import_react.useState)(null);
	(0, import_react.useEffect)(() => {
		setConsent(readStored(storage, version));
		setReady(true);
	}, [storage, version]);
	const persist = (0, import_react.useCallback)((categories) => {
		const state = {
			categories: {
				...categories,
				necessary: true
			},
			recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
			version
		};
		storage.save(JSON.stringify(state));
		setConsent(state);
		return state;
	}, [storage, version]);
	return {
		ready,
		consent,
		save: (0, import_react.useCallback)((categories) => persist(categories), [persist]),
		acceptAll: (0, import_react.useCallback)(() => persist({
			necessary: true,
			analytics: true,
			marketing: true,
			preferences: true
		}), [persist]),
		rejectAll: (0, import_react.useCallback)(() => persist({
			necessary: true,
			analytics: false,
			marketing: false,
			preferences: false
		}), [persist])
	};
}
var DEFAULT_CATEGORIES = [
	"analytics",
	"marketing",
	"preferences"
];
function safePolicyHref(href) {
	if (href == null) return void 0;
	const cleaned = href.replace(/[\u0000-\u0020]+/g, "");
	const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(cleaned);
	if (!scheme) return href;
	const s = scheme[1].toLowerCase();
	return s === "http" || s === "https" || s === "mailto" ? href : void 0;
}
var DEFAULT_CATEGORY_LABELS = {
	necessary: "Strictly necessary",
	analytics: "Analytics",
	marketing: "Marketing",
	preferences: "Preferences"
};
function ConsentBanner({ version, storage, categories = DEFAULT_CATEGORIES, policyHref, labels, open, onChange, className }) {
	const { ready, consent, save, acceptAll, rejectAll } = useConsent({
		version,
		storage
	});
	const [selection, setSelection] = (0, import_react.useState)(() => defaultConsent().categories);
	if (!(open ?? (ready && consent == null))) return null;
	const title = labels?.title ?? "Cookie preferences";
	const description = labels?.description ?? "We use cookies to run this site. Choose which categories to allow. Necessary cookies are always on.";
	const catLabel = (c) => labels?.categoryLabels?.[c] ?? DEFAULT_CATEGORY_LABELS[c];
	const href = safePolicyHref(policyHref);
	const handleAcceptAll = () => {
		const state = acceptAll();
		onChange?.(state);
	};
	const handleRejectAll = () => {
		const state = rejectAll();
		onChange?.(state);
	};
	const handleSave = () => {
		const state = save(selection);
		onChange?.(state);
	};
	return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
		role: "region",
		"aria-label": title,
		className,
		children: [
			/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
			/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: description }),
			href ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
				href,
				children: labels?.policyLink ?? "Privacy policy"
			}) }) : null,
			/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("fieldset", { children: [
				/* @__PURE__ */ (0, import_jsx_runtime.jsx)("legend", { children: "Cookie categories" }),
				/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
					type: "checkbox",
					checked: true,
					disabled: true,
					"aria-label": catLabel("necessary"),
					readOnly: true
				}), catLabel("necessary")] }),
				categories.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
					type: "checkbox",
					"aria-label": catLabel(c),
					checked: selection[c] ?? false,
					onChange: (e) => setSelection((s) => ({
						...s,
						[c]: e.target.checked
					}))
				}), catLabel(c)] }, c))
			] }),
			/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
				/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
					type: "button",
					onClick: handleAcceptAll,
					children: labels?.acceptAll ?? "Accept all"
				}),
				/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
					type: "button",
					onClick: handleRejectAll,
					children: labels?.rejectAll ?? "Reject all"
				}),
				/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
					type: "button",
					onClick: handleSave,
					children: labels?.save ?? "Save preferences"
				})
			] })
		]
	});
}
//#endregion
//#region src/layouts/base-chrome.ts
function assembleBaseChrome(args) {
	const { settings, resolvedNav, selectionProp } = args;
	const selectionFromSettings = parseActiveSelection(settings?.[SETTINGS_KEYS.theme]);
	return {
		selection: selectionProp ?? selectionFromSettings,
		identity: parseSiteIdentity(settings?.[SETTINGS_KEYS.siteName], settings?.[SETTINGS_KEYS.siteLogoUrl]),
		consent: parseConsentConfig(settings?.[SETTINGS_KEYS.consent]),
		hideModeToggle: parseHideModeToggle(settings?.[SETTINGS_KEYS.hideModeToggle]),
		navLinks: resolvedNav && resolvedNav.length > 0 ? resolvedNav : DEFAULT_PRIMARY
	};
}
//#endregion
//#region src/layouts/Base.astro
createAstro("https://astro.build");
var $$Base = createComponent(async ($$result, $$props, $$slots) => {
	const Astro = $$result.createAstro($$props, $$slots);
	Astro.self = $$Base;
	const { title, description = "mod-cms — a content distribution built on the platform", noindex = false, minimal = false, selection: selectionProp } = Astro.props;
	let settings = null;
	try {
		settings = await getAllSettings(getFullDb(env).db);
	} catch {
		settings = null;
	}
	let resolvedNav = null;
	try {
		const { db: contentDb } = getFullDb(env);
		const menusDb = getMenusDb(env);
		const tree = await getMenuTree(menusDb, "primary");
		if (tree && tree.items.length > 0) {
			const links = (await Promise.all(tree.items.map(async (item) => {
				const href = await resolveMenuHref(item, { db: contentDb });
				return href ? {
					label: item.label,
					href
				} : null;
			}))).filter((link) => link != null);
			if (links.length > 0) resolvedNav = links;
		}
	} catch {
		resolvedNav = null;
	}
	const { selection, identity, consent, navLinks, hideModeToggle } = assembleBaseChrome({
		settings,
		resolvedNav,
		selectionProp
	});
	const Shell = resolveShell(resolveModTheme(selection.themeId));
	const htmlThemeAttrs = {
		"data-theme": MOD_CMS_PALETTE_SET.id,
		"data-palette": selection.paletteId,
		...selection.mode === "system" ? {} : { "data-mode": selection.mode }
	};
	return renderTemplate`<html lang="en"${spreadAttributes(htmlThemeAttrs)}><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description"${addAttribute(description, "content")}>${noindex ? renderTemplate`<meta name="robots" content="noindex">` : null}<title>${title}</title>${minimal ? renderTemplate`<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..700;1,9..144,300..700&family=Schibsted+Grotesk:wght@400;500&display=swap">` : null}<style>${unescapeHTML(themeCss)}</style>${renderHead($$result)}</head><body${addAttribute(minimal ? "install-body" : void 0, "class")}>${minimal ? renderTemplate`<main class="install-main">${renderSlot($$result, $$slots["default"])}</main>` : renderTemplate`${renderComponent($$result, "Shell", Shell, {
		"siteName": identity.name,
		"logoUrl": identity.logoUrl,
		"hideModeToggle": hideModeToggle,
		"navLinks": navLinks
	}, { "default": ($$result) => renderTemplate`<main>${renderSlot($$result, $$slots["default"])}</main>` })}`}${!minimal && !hideModeToggle ? renderTemplate`<script>
      (function () {
        var root = document.documentElement;
        var key = 'mod-cms-theme';
        var stored = localStorage.getItem(key);
        if (stored === 'light' || stored === 'dark') root.dataset.mode = stored;
        var btn = document.getElementById('theme-toggle');
        if (!btn) return;
        btn.addEventListener('click', function () {
          // Resolve current effective mode: explicit data-mode, else the OS preference.
          var current = root.dataset.mode
            || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
          var next = current === 'dark' ? 'light' : 'dark';
          root.dataset.mode = next;
          localStorage.setItem(key, next);
        });
      })();
    <\/script>` : null}${!minimal && consent.enabled ? renderTemplate`${renderComponent($$result, "ConsentBanner", ConsentBanner, {
		"client:idle": true,
		"version": consent.version,
		"categories": consent.categories,
		"policyHref": consent.policyHref,
		"client:component-hydration": "idle",
		"client:component-path": "@platform-modules/content-react",
		"client:component-export": "ConsentBanner"
	})}` : null}</body></html>`;
}, "/home/user/runs/content-model-t15-final-build/repo/apps/mod-cms/src/layouts/Base.astro", void 0);
//#endregion
export { useContentEntry as n, useContentList as r, $$Base as t };
