import { canonicalFieldGroupHash, parseFieldDefinition, parseFieldDefinitionVersion, parseFieldGroupDefinition } from "./schema.js";
import { i as escapeFieldPathSegment, r as canonicalFieldsMigrationHash } from "./migrate-EWZxeEIR.js";
import { sql } from "drizzle-orm";
import { getTransactionIdentity, isTransactionCapabilityError } from "@platform-modules/db";
//#region src/errors.ts
var FieldValidationError = class extends Error {
	field;
	detail;
	name = "FieldValidationError";
	constructor(field, detail) {
		super(`field invalid: ${field} — ${detail}`);
		this.field = field;
		this.detail = detail;
	}
};
var FieldGroupConflictError = class extends Error {
	key;
	detail;
	name = "FieldGroupConflictError";
	constructor(key, detail) {
		super(`group conflict: ${key} — ${detail}`);
		this.key = key;
		this.detail = detail;
	}
};
var FieldAuthorizationError = class extends Error {
	actorId;
	action;
	name = "FieldAuthorizationError";
	constructor(actorId, action) {
		super(`actor ${actorId} cannot ${action}`);
		this.actorId = actorId;
		this.action = action;
	}
};
var FieldStoreError = class extends Error {
	detail;
	name = "FieldStoreError";
	constructor(detail) {
		super(`store error: ${detail}`);
		this.detail = detail;
	}
};
const hasName = (e, n) => typeof e === "object" && e !== null && e.name === n;
const isFieldValidationError = (e) => hasName(e, "FieldValidationError") && "field" in e && "detail" in e;
const isFieldGroupConflictError = (e) => hasName(e, "FieldGroupConflictError") && "key" in e;
const isFieldAuthorizationError = (e) => hasName(e, "FieldAuthorizationError") && "actorId" in e;
const isFieldStoreError = (e) => hasName(e, "FieldStoreError") && "detail" in e;
//#endregion
//#region src/definitions.ts
var FieldDefinitionIntegrityError = class extends Error {
	code;
	groupKey;
	revision;
	detail;
	name = "FieldDefinitionIntegrityError";
	constructor(code, groupKey, revision, detail) {
		super(`field definition ${code}: ${groupKey}@${revision} — ${detail}`);
		this.code = code;
		this.groupKey = groupKey;
		this.revision = revision;
		this.detail = detail;
	}
};
function isFieldDefinitionIntegrityError(error) {
	if (typeof error !== "object" || error === null) return false;
	const candidate = error;
	return (candidate.code === "definition-not-found" || candidate.code === "definition-corrupt") && typeof candidate.groupKey === "string" && typeof candidate.revision === "number" && typeof candidate.detail === "string";
}
function definitionPayload(value) {
	if (typeof value !== "string") return value;
	try {
		return JSON.parse(value);
	} catch {
		throw new TypeError("definition payload is not valid JSON");
	}
}
async function resolveFieldDefinitionVersion(db, groupKey, revision) {
	const result = await db.execute(sql`
    SELECT
      group_key AS "groupKey",
      revision,
      canonical_hash AS "canonicalHash",
      definition,
      created_at AS "createdAt",
      origin
    FROM field_definition_versions
    WHERE group_key = ${groupKey} AND revision = ${revision}
    LIMIT 1
  `);
	const row = (Array.isArray(result) ? result : typeof result === "object" && result !== null && Array.isArray(result.rows) ? result.rows : [])[0];
	if (!row) throw new FieldDefinitionIntegrityError("definition-not-found", groupKey, revision, "immutable definition version is missing");
	try {
		return await parseFieldDefinitionVersion({
			groupKey: row.groupKey,
			revision: Number(row.revision),
			canonicalHash: row.canonicalHash,
			definition: definitionPayload(row.definition),
			createdAt: row.createdAt,
			origin: row.origin
		});
	} catch {
		throw new FieldDefinitionIntegrityError("definition-corrupt", groupKey, revision, "persisted definition bytes do not match their canonical hash");
	}
}
//#endregion
//#region src/values.ts
const DEFAULT_LIMITS = Object.freeze({
	maxBytes: 1048576,
	maxDepth: 12,
	maxNodes: 1e3
});
const PRESENTATION_TYPES = /* @__PURE__ */ new Set([
	"message",
	"accordion",
	"tab"
]);
function fail$1(field, detail) {
	throw new FieldValidationError(field, detail);
}
function obj(value, field) {
	if (typeof value !== "object" || value === null || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype) fail$1(field, "must be a plain object");
	return value;
}
function str(value, field, max = 8192) {
	if (typeof value !== "string" || value.length > max) fail$1(field, `must be a string up to ${max} characters`);
	return value;
}
function nonempty(value, field, max = 4096) {
	const s = str(value, field, max);
	if (!s.length) fail$1(field, "must not be empty");
	return s;
}
function finite(value, field) {
	if (typeof value !== "number" || !Number.isFinite(value)) fail$1(field, "must be a finite number");
	return value;
}
function serializable(value, limits = DEFAULT_LIMITS, field = "value", depth = 0, budget = {
	nodes: 0,
	bytes: 0
}) {
	if (depth > limits.maxDepth) fail$1(field, `exceeds maximum depth ${limits.maxDepth}`);
	if (value === null || typeof value === "boolean") return value;
	if (typeof value === "number") {
		if (!Number.isFinite(value)) fail$1(field, "contains non-finite number");
		budget.bytes += 8;
		return value;
	}
	if (typeof value === "string") {
		budget.bytes += new TextEncoder().encode(value).byteLength;
		if (budget.bytes > limits.maxBytes) fail$1(field, `exceeds maximum size ${limits.maxBytes}`);
		return value;
	}
	if (++budget.nodes > limits.maxNodes) fail$1(field, `exceeds maximum node count ${limits.maxNodes}`);
	if (Array.isArray(value)) return Object.freeze(value.map((item, i) => serializable(item, limits, `${field}.${i}`, depth + 1, budget)));
	const source = obj(value, field), out = {};
	for (const key of Object.keys(source).sort()) {
		if ([
			"__proto__",
			"prototype",
			"constructor"
		].includes(key)) fail$1(`${field}.${key}`, "is forbidden");
		out[key] = serializable(source[key], limits, `${field}.${key}`, depth + 1, budget);
	}
	return Object.freeze(out);
}
function settings(value) {
	return obj(value ?? {}, "settings");
}
function pattern(value, setting, field) {
	if (setting === void 0) return;
	const p = obj(setting, "settings.pattern"), source = nonempty(p.source, "settings.pattern.source", 512), flags = p.flags === void 0 ? "" : str(p.flags, "settings.pattern.flags", 16);
	let rx;
	try {
		rx = new RegExp(source, flags);
	} catch {
		fail$1("settings.pattern", "is invalid");
	}
	if (!rx.test(value)) fail$1(field, "does not match the required pattern");
}
function parseUrl(value, s, field = "value") {
	const raw = nonempty(value, field, 8192);
	if (s.allowRelative === true && /^(?:\/|\.\/|\.\.\/)/.test(raw)) return raw;
	let url;
	try {
		url = new URL(raw);
	} catch {
		fail$1(field, "must be a valid URL");
	}
	const schemes = Array.isArray(s.schemes) ? s.schemes.map(String) : [];
	if (schemes.length && !schemes.includes(url.protocol.replace(/:$/, ""))) fail$1(field, "uses a disallowed URL scheme");
	return url.toString();
}
function choice(value, field) {
	if (typeof value !== "string" && typeof value !== "number") fail$1(field, "must be string or number");
	if (typeof value === "number" && !Number.isFinite(value)) fail$1(field, "must be finite");
	return value;
}
function assertChoiceAllowed(value, s, field) {
	const choices = obj(s.choices ?? {}, "settings.choices");
	if (s.allowCustom !== true && !Object.prototype.hasOwnProperty.call(choices, String(value))) fail$1(field, "is not an allowed choice");
}
function ref(value, field) {
	const v = obj(value, field), allowed = /* @__PURE__ */ new Set([
		"entityType",
		"id",
		"taxonomy",
		"kind",
		"mimeType"
	]), out = {};
	for (const key of Object.keys(v)) {
		if (!allowed.has(key)) fail$1(`${field}.${key}`, "is not allowed");
		out[key] = nonempty(v[key], `${field}.${key}`, 256);
	}
	if (!out.id) fail$1(`${field}.id`, "is required");
	return Object.freeze(out);
}
function bounds(length, s, field, defaultMax = 100) {
	const min = typeof s.min === "number" ? s.min : 0, max = typeof s.max === "number" ? Math.min(s.max, defaultMax) : defaultMax;
	if (length < min || length > max) fail$1(field, `must contain ${min}..${max} items`);
}
function parseMap(fields, input, limits, write, depth) {
	if (depth > limits.maxDepth) fail$1("value", `exceeds maximum depth ${limits.maxDepth}`);
	const value = obj(input, "value"), byKey = new Map(fields.map((field) => [field.key, field])), out = {};
	for (const key of Object.keys(value)) if (!byKey.has(key)) fail$1(`value.${key}`, "is not defined");
	for (const field of fields) {
		if (PRESENTATION_TYPES.has(field.type)) continue;
		if (!Object.prototype.hasOwnProperty.call(value, field.key)) {
			if (field.required) fail$1(`value.${field.key}`, "is required");
			continue;
		}
		out[field.key] = parseBuiltin(field.type, value[field.key], field.settings, limits, write, depth + 1);
	}
	return Object.freeze(out);
}
function parseBuiltin(type, input, settingsValue, limits, write, depth = 0) {
	const s = settings(settingsValue);
	if (PRESENTATION_TYPES.has(type)) fail$1("value", `${type} is presentation-only`);
	if (type === "password") {
		const v = obj(input, "value");
		if (!write) {
			if (typeof v.configured !== "boolean" || Object.keys(v).length !== 1) fail$1("value", "password reads expose only configured:boolean");
			return Object.freeze({ configured: v.configured });
		}
		if (v.operation === "clear" || v.operation === "unchanged") {
			if (Object.keys(v).length !== 1) fail$1("value", "password clear/unchanged contain no value");
			return Object.freeze({ operation: v.operation });
		}
		if (v.operation !== "set") fail$1("value.operation", "must be set, clear, or unchanged");
		const raw = nonempty(v.value, "value.value", typeof s.maxLength === "number" ? s.maxLength : 4096);
		if (typeof s.minLength === "number" && raw.length < s.minLength) fail$1("value.value", `must contain at least ${s.minLength} characters`);
		return Object.freeze({
			operation: "set",
			value: raw
		});
	}
	if (type === "text" || type === "textarea" || type === "richText") {
		const value = str(input, "value", typeof s.maxLength === "number" ? s.maxLength : 1e6);
		pattern(value, s.pattern, "value");
		return value;
	}
	if (type === "email") {
		const value = nonempty(input, "value", 320);
		if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) fail$1("value", "must be an email address");
		return value.toLowerCase();
	}
	if (type === "url") return parseUrl(input, s);
	if (type === "number" || type === "range") {
		const value = finite(input, "value");
		if (s.integer === true && !Number.isSafeInteger(value)) fail$1("value", "must be a safe integer");
		if (typeof s.min === "number" && value < s.min) fail$1("value", `must be >= ${s.min}`);
		if (typeof s.max === "number" && value > s.max) fail$1("value", `must be <= ${s.max}`);
		if (typeof s.step === "number" && s.step > 0) {
			const ratio = (value - (typeof s.min === "number" ? s.min : 0)) / s.step;
			if (Math.abs(ratio - Math.round(ratio)) > 1e-9) fail$1("value", `must align to step ${s.step}`);
		}
		return value;
	}
	if (type === "boolean") {
		if (typeof input !== "boolean") fail$1("value", "must be boolean");
		return input;
	}
	if (type === "select" || type === "radio" || type === "buttonGroup") {
		if (input === null && s.allowNull === true) return null;
		if (s.multiple === true) {
			if (!Array.isArray(input)) fail$1("value", "must be an array");
			const values = [...new Set(input.map((v, i) => choice(v, `value.${i}`)))];
			values.forEach((v) => assertChoiceAllowed(v, s, "value"));
			bounds(values.length, s, "value", 1e3);
			return Object.freeze(values);
		}
		const value = choice(input, "value");
		assertChoiceAllowed(value, s, "value");
		return value;
	}
	if (type === "checkbox") {
		if (!Array.isArray(input)) fail$1("value", "must be an array");
		const values = [...new Set(input.map((v, i) => choice(v, `value.${i}`)))];
		values.forEach((v) => assertChoiceAllowed(v, s, "value"));
		bounds(values.length, s, "value", 1e3);
		return Object.freeze(values);
	}
	if (type === "oembed") {
		const v = obj(input, "value"), url = parseUrl(v.url, { schemes: ["http", "https"] }, "value.url"), metadata = v.metadata === void 0 ? void 0 : serializable(v.metadata, limits, "value.metadata");
		return Object.freeze({
			url,
			...metadata === void 0 ? {} : { metadata }
		});
	}
	if (type === "link") {
		if (input === null) return null;
		const v = obj(input, "value"), url = parseUrl(v.url, { schemes: s.schemes ?? ["http", "https"] }, "value.url"), title = str(v.title, "value.title", 4096), target = v.target;
		if (target !== void 0 && target !== "_self" && target !== "_blank") fail$1("value.target", "must be _self or _blank");
		return Object.freeze({
			url,
			title,
			...target === void 0 ? {} : { target }
		});
	}
	if (type === "image" || type === "file") {
		if (input === null) return null;
		const r = ref(input, "value");
		if (r.kind !== type) fail$1("value.kind", `must be ${type}`);
		return r;
	}
	if (type === "gallery") {
		if (!Array.isArray(input)) fail$1("value", "must be an array");
		const refs = input.map((item, i) => {
			const r = ref(item, `value.${i}`);
			if (r.kind !== "image") fail$1(`value.${i}.kind`, "must be image");
			return r;
		});
		bounds(refs.length, s, "value");
		return Object.freeze(refs);
	}
	if (type === "entity" || type === "entityLink") {
		if (input === null) return null;
		const r = ref(input, "value");
		if (!r.entityType) fail$1("value.entityType", "is required");
		const allowed = Array.isArray(s.entityTypes) ? s.entityTypes.map(String) : [];
		if (allowed.length && !allowed.includes(r.entityType)) fail$1("value.entityType", "is not allowed");
		return r;
	}
	if (type === "relationship") {
		if (!Array.isArray(input)) fail$1("value", "must be an array");
		const refs = input.map((item, i) => {
			const r = ref(item, `value.${i}`);
			if (!r.entityType) fail$1(`value.${i}.entityType`, "is required");
			const allowed = Array.isArray(s.entityTypes) ? s.entityTypes.map(String) : [];
			if (allowed.length && !allowed.includes(r.entityType)) fail$1(`value.${i}.entityType`, "is not allowed");
			return r;
		});
		const seen = /* @__PURE__ */ new Set();
		for (const r of refs) {
			const key = `${r.entityType}:${r.id}`;
			if (seen.has(key)) fail$1("value", "contains duplicate relationship target");
			seen.add(key);
		}
		bounds(refs.length, s, "value");
		return Object.freeze(refs);
	}
	if (type === "taxonomy") {
		if (input === null) return null;
		const one = (item, field) => {
			const r = ref(item, field);
			if (!r.taxonomy) fail$1(`${field}.taxonomy`, "is required");
			const allowed = Array.isArray(s.taxonomies) ? s.taxonomies.map(String) : [];
			if (allowed.length && !allowed.includes(r.taxonomy)) fail$1(`${field}.taxonomy`, "is not allowed");
			return r;
		};
		if (s.multiple === true) {
			if (!Array.isArray(input)) fail$1("value", "must be an array");
			return Object.freeze(input.map((item, i) => one(item, `value.${i}`)));
		}
		return one(input, "value");
	}
	if (type === "user") {
		if (input === null) return null;
		const one = (item, field) => Object.freeze({ id: nonempty(obj(item, field).id, `${field}.id`, 256) });
		if (s.multiple === true) {
			if (!Array.isArray(input)) fail$1("value", "must be an array");
			return Object.freeze(input.map((item, i) => one(item, `value.${i}`)));
		}
		return one(input, "value");
	}
	if (type === "date") {
		if (input === null) return null;
		const value = str(input, "value", 64);
		if (!/^\d{4}-\d{2}-\d{2}$/.test(value) || Number.isNaN(Date.parse(`${value}T00:00:00Z`))) fail$1("value", "must be YYYY-MM-DD");
		return value;
	}
	if (type === "time") {
		if (input === null) return null;
		const value = str(input, "value", 64);
		if (!/^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d{1,3})?)?$/.test(value)) fail$1("value", "must be canonical local time");
		return value;
	}
	if (type === "dateTime") {
		if (input === null) return null;
		const value = str(input, "value", 128), date = new Date(value);
		if (Number.isNaN(date.getTime())) fail$1("value", "must be valid date-time");
		return date.toISOString();
	}
	if (type === "color") {
		if (input === null) return null;
		const value = str(input, "value", 32).toLowerCase();
		if (!(s.alpha === true ? /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/ : /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/).test(value)) fail$1("value", "must be canonical hex color");
		return value;
	}
	if (type === "icon") {
		if (input === null && s.allowNull === true) return null;
		const v = obj(input, "value"), set = nonempty(v.set, "value.set", 128), name = nonempty(v.name, "value.name", 256), allowed = Array.isArray(s.sets) ? s.sets.map(String) : [];
		if (allowed.length && !allowed.includes(set)) fail$1("value.set", "is not allowed");
		return Object.freeze({
			set,
			name
		});
	}
	if (type === "map") {
		if (input === null) return null;
		const v = obj(input, "value"), latitude = finite(v.latitude, "value.latitude"), longitude = finite(v.longitude, "value.longitude");
		if (latitude < -90 || latitude > 90) fail$1("value.latitude", "must be between -90 and 90");
		if (longitude < -180 || longitude > 180) fail$1("value.longitude", "must be between -180 and 180");
		const address = v.address === void 0 ? void 0 : str(v.address, "value.address", 4096), zoom = v.zoom === void 0 ? void 0 : finite(v.zoom, "value.zoom"), metadata = v.metadata === void 0 ? void 0 : serializable(v.metadata, limits, "value.metadata");
		return Object.freeze({
			latitude,
			longitude,
			...address === void 0 ? {} : { address },
			...zoom === void 0 ? {} : { zoom },
			...metadata === void 0 ? {} : { metadata }
		});
	}
	if (type === "group") return parseMap(Array.isArray(s.fields) ? s.fields : [], input, limits, write, depth + 1);
	if (type === "repeater") {
		if (!Array.isArray(input)) fail$1("value", "must be array");
		bounds(input.length, s, "value");
		const fields = Array.isArray(s.fields) ? s.fields : [], ids = /* @__PURE__ */ new Set();
		return Object.freeze(input.map((raw, i) => {
			const row = obj(raw, `value.${i}`), rowId = nonempty(row.rowId, `value.${i}.rowId`, 256);
			if (ids.has(rowId)) fail$1(`value.${i}.rowId`, "must be unique");
			ids.add(rowId);
			return Object.freeze({
				rowId,
				values: parseMap(fields, row.values, limits, write, depth + 1)
			});
		}));
	}
	if (type === "flexible") {
		if (!Array.isArray(input)) fail$1("value", "must be array");
		bounds(input.length, s, "value");
		const layouts = Array.isArray(s.layouts) ? s.layouts : [], layoutMap = new Map(layouts.map((l) => [String(l.key), l])), ids = /* @__PURE__ */ new Set();
		return Object.freeze(input.map((raw, i) => {
			const row = obj(raw, `value.${i}`), rowId = nonempty(row.rowId, `value.${i}.rowId`, 256), layoutKey = nonempty(row.layoutKey, `value.${i}.layoutKey`, 256);
			if (ids.has(rowId)) fail$1(`value.${i}.rowId`, "must be unique");
			ids.add(rowId);
			const layout = layoutMap.get(layoutKey);
			if (!layout) fail$1(`value.${i}.layoutKey`, "is not registered");
			return Object.freeze({
				rowId,
				layoutKey,
				values: parseMap(Array.isArray(layout.fields) ? layout.fields : [], row.values, limits, write, depth + 1)
			});
		}));
	}
	if (type === "clone") return serializable(input, limits);
	fail$1("type", `unsupported field type ${type}`);
}
const BUILTIN_TYPES = Object.freeze([
	"text",
	"textarea",
	"number",
	"range",
	"email",
	"url",
	"password",
	"boolean",
	"select",
	"checkbox",
	"radio",
	"buttonGroup",
	"richText",
	"oembed",
	"link",
	"message",
	"image",
	"file",
	"gallery",
	"entity",
	"entityLink",
	"relationship",
	"taxonomy",
	"user",
	"date",
	"dateTime",
	"time",
	"color",
	"icon",
	"map",
	"accordion",
	"tab",
	"group",
	"repeater",
	"flexible",
	"clone"
]);
function digest(seed) {
	let a = 2166136261, b = 2654435769;
	for (let round = 0; round < 8; round++) {
		for (let i = 0; i < seed.length; i++) {
			a = Math.imul(a ^ seed.charCodeAt(i) + round, 16777619);
			b = Math.imul(b ^ (seed.charCodeAt(i) << i % 8) + round, 2246822507);
		}
		seed = `${seed}:${(a >>> 0).toString(16)}:${(b >>> 0).toString(16)}`;
	}
	return `${(a >>> 0).toString(16).padStart(8, "0")}${(b >>> 0).toString(16).padStart(8, "0")}`.repeat(4).slice(0, 64);
}
function parseDefinitionFor(type, input) {
	const parsed = parseFieldDefinition(input);
	if (parsed.type !== type) fail$1("definition.type", `must be ${type}`);
	return Object.freeze({
		key: parsed.key,
		name: parsed.name,
		label: parsed.label,
		type,
		settings: parsed.settings,
		...parsed.required === void 0 ? {} : { required: parsed.required },
		...parsed.readOnly === void 0 ? {} : { readOnly: parsed.readOnly }
	});
}
function builtinSchema(type, s) {
	const nullable = [
		"link",
		"image",
		"file",
		"entity",
		"entityLink",
		"taxonomy",
		"user",
		"date",
		"dateTime",
		"time",
		"color",
		"icon",
		"map"
	].includes(type);
	return Object.freeze({
		type,
		nullable,
		readOnly: PRESENTATION_TYPES.has(type),
		constraints: serializable(s ?? {}, DEFAULT_LIMITS, "settings")
	});
}
async function builtinFormat(type, value, context) {
	if (type === "richText") {
		if (typeof value !== "string") fail$1("value", "richText formatter requires a string");
		return Object.freeze({
			kind: "sanitizedHtml",
			value: await sanitizeFieldHtml(value, context)
		});
	}
	if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null) return Object.freeze({
		kind: "text",
		value: value === null ? "" : String(value)
	});
	return Object.freeze({
		kind: "structured",
		value: serializable(value)
	});
}
function createBuiltinFieldTypeDescriptors() {
	return Object.freeze(BUILTIN_TYPES.map((type) => Object.freeze({
		type,
		contractVersion: "1",
		schemaHash: digest(`schema:${type}:1`),
		codecHash: digest(`codec:${type}:1`),
		parseDefinition: (input) => parseDefinitionFor(type, input),
		parseValue: (input, s, limits) => parseBuiltin(type, input, s, limits, false),
		parseWrite: (input, s, limits) => parseBuiltin(type, input, s, limits, true),
		serialize: (value) => serializable(value),
		deserialize: (value, s) => parseBuiltin(type, value, s, DEFAULT_LIMITS, false),
		format: (value, _s, context) => builtinFormat(type, value, context),
		schema: (s) => builtinSchema(type, s),
		redactForRevision: (value) => type === "password" ? Object.freeze({ configured: Boolean(value?.configured) }) : PRESENTATION_TYPES.has(type) ? "omit" : serializable(value)
	})));
}
function descriptorFor(definition, registry) {
	const descriptor = registry.resolve(definition.type);
	if (!descriptor) fail$1("definition.type", `unregistered field type ${definition.type}`);
	return descriptor;
}
function fieldSettings(definition) {
	return definition.settings;
}
function refsFromValue(definition, value) {
	if (definition.type === "entity" || definition.type === "entityLink") return value === null ? [] : [value];
	if (definition.type === "relationship") return value;
	return [];
}
async function validateMedia(definition, value, resolver) {
	if (![
		"image",
		"file",
		"gallery"
	].includes(definition.type) || value === null) return;
	if (!resolver) fail$1("mediaMetadata", "is required to validate media values");
	const s = settings(definition.settings), refs = definition.type === "gallery" ? value : [value];
	for (const r of refs) {
		const meta = await resolver.resolve(r);
		if (!meta) fail$1("mediaMetadata", "is unavailable for a referenced item");
		const mimes = Array.isArray(s.mimeTypes) ? s.mimeTypes.map(String) : [];
		if (mimes.length && !mimes.some((allowed) => allowed.endsWith("/*") ? meta.mimeType.startsWith(allowed.slice(0, -1)) : meta.mimeType === allowed)) fail$1("value", "uses disallowed media MIME type");
		if (typeof s.minBytes === "number" && meta.bytes < s.minBytes) fail$1("value", "media is below minimum byte size");
		if (typeof s.maxBytes === "number" && meta.bytes > s.maxBytes) fail$1("value", "media exceeds maximum byte size");
		if (definition.type !== "file") for (const [key, actual] of [
			["minWidth", meta.width],
			["maxWidth", meta.width],
			["minHeight", meta.height],
			["maxHeight", meta.height]
		]) {
			const bound = s[key];
			if (typeof bound === "number" && actual === void 0) fail$1("mediaMetadata", `missing ${key.includes("Width") ? "width" : "height"}`);
			if (typeof bound === "number" && key.startsWith("min") && actual < bound) fail$1("value", `media violates ${key}`);
			if (typeof bound === "number" && key.startsWith("max") && actual > bound) fail$1("value", `media violates ${key}`);
		}
	}
}
async function validateFieldValue(definition, input, registry, context = {}, limits = DEFAULT_LIMITS) {
	let value;
	if (definition.type === "clone" && context.cloneResolver) value = parseMap(context.cloneResolver.resolve(definition), input, limits, true, 0);
	else value = descriptorFor(definition, registry).parseWrite(input, fieldSettings(definition), limits);
	if (definition.type === "richText") {
		if (!context.sanitizer) fail$1("sanitizer", "is required to validate richText");
		const sanitized = await context.sanitizer.sanitizeHtml(String(value));
		if (typeof sanitized !== "string") fail$1("sanitizer", "must return a string");
		value = sanitized;
	}
	await validateMedia(definition, value, context.mediaMetadata);
	const auth = context.authorization;
	if (auth) for (const r of refsFromValue(definition, value)) await auth.assertTarget(r, "readTarget");
	return value;
}
function projectMode(definition) {
	return typeof definition.settings === "object" && definition.settings !== null ? "return" in definition.settings ? String(definition.settings.return) : void 0 : void 0;
}
async function projectRef(definition, value, resolvers) {
	const mode = projectMode(definition);
	if (mode === void 0 || mode === "ref") return value;
	if (definition.type === "image" || definition.type === "file") return value === null ? null : resolvers.media(value, mode);
	if (definition.type === "gallery") return Promise.all(value.map((r) => resolvers.media(r, mode)));
	if (definition.type === "entity" || definition.type === "entityLink") return value === null ? null : resolvers.entity(value, mode);
	if (definition.type === "relationship") return Promise.all(value.map((r) => resolvers.entity(r, mode)));
	if (definition.type === "taxonomy") {
		if (value === null) return null;
		return Array.isArray(value) ? Promise.all(value.map((r) => resolvers.term(r, mode))) : resolvers.term(value, mode);
	}
	if (definition.type === "user") {
		if (value === null) return null;
		return Array.isArray(value) ? Promise.all(value.map((r) => resolvers.user(r, mode))) : resolvers.user(value, mode);
	}
	return value;
}
async function formatFieldValue(definition, value, registry, resolvers, context = {}) {
	if (definition.type === "group" || definition.type === "repeater" || definition.type === "flexible" || definition.type === "clone") return Object.freeze({
		kind: "structured",
		value: serializable(value)
	});
	if (context.authorization) for (const target of refsFromValue(definition, value)) await context.authorization.assertTarget(target, "readTarget");
	const projected = await projectRef(definition, value, resolvers);
	return assertSerializableFieldPresentation(await descriptorFor(definition, registry).format(projected, fieldSettings(definition), context));
}
function serializeFieldValue(definition, value, registry) {
	return descriptorFor(definition, registry).serialize(value, fieldSettings(definition));
}
function deserializeFieldValue(definition, value, registry) {
	return descriptorFor(definition, registry).deserialize(value, fieldSettings(definition));
}
function redactFieldValueForRevision(definition, value, registry) {
	return descriptorFor(definition, registry).redactForRevision(value, fieldSettings(definition));
}
function* repeaterRows(value) {
	for (const row of value) yield row;
}
function* flexibleRows(value, layoutKey) {
	for (const row of value) if (layoutKey === void 0 || row.layoutKey === layoutKey) yield row;
}
function pathField(parent, key) {
	return `${parent}/f:${escapeFieldPathSegment(key)}`;
}
function pathRow(parent, rowId) {
	return `${parent}/r:${escapeFieldPathSegment(rowId)}`;
}
function pathLayout(parent, layoutKey) {
	return `${parent}/l:${escapeFieldPathSegment(layoutKey)}`;
}
function leafLane(value) {
	const empty = {
		valueText: null,
		valueNumber: null,
		valueBoolean: null,
		valueDateTime: null,
		valueRef: null,
		valueJson: null
	};
	if (value === null) return {
		isNull: true,
		...empty
	};
	if (typeof value === "string") return {
		isNull: false,
		...empty,
		valueText: value
	};
	if (typeof value === "number") return {
		isNull: false,
		...empty,
		valueNumber: value
	};
	if (typeof value === "boolean") return {
		isNull: false,
		...empty,
		valueBoolean: value
	};
	return {
		isNull: false,
		...empty,
		valueJson: JSON.stringify(serializable(value))
	};
}
function encodeFieldValueNodes(group, values, options) {
	const nodes = [];
	const seenPaths = /* @__PURE__ */ new Set();
	const add = (row) => {
		if (seenPaths.has(row.path)) fail$1(row.path, "resolves to a duplicate materialized path");
		seenPaths.add(row.path);
		nodes.push(Object.freeze(row));
	};
	const structural = (field, path, parent, kind, ordinal, rowId = null, layoutKey = null) => add({
		nodeId: options.nodeIdForPath(path),
		entityType: options.entityType,
		entityId: options.entityId,
		groupKey: group.key,
		definitionRevision: options.definitionRevision,
		fieldKey: field.key,
		path,
		parentNodeId: parent,
		rowId,
		layoutKey,
		nodeKind: kind,
		ordinal,
		isNull: false,
		valueText: null,
		valueNumber: null,
		valueBoolean: null,
		valueDateTime: null,
		valueRef: null,
		valueJson: null
	});
	const walkFields = (fields, map, parentPath, parentId) => {
		fields.forEach((field, ordinal) => {
			if (PRESENTATION_TYPES.has(field.type)) return;
			const value = map[field.key], path = pathField(parentPath, field.key);
			if (field.type === "group") {
				structural(field, path, parentId, "group", ordinal);
				walkFields(field.settings.fields, value ?? {}, path, options.nodeIdForPath(path));
				return;
			}
			if (field.type === "repeater") {
				structural(field, path, parentId, "group", ordinal);
				const baseId = options.nodeIdForPath(path);
				for (const [rowOrdinal, row] of (value ?? []).entries()) {
					const rp = pathRow(path, row.rowId);
					structural(field, rp, baseId, "repeaterRow", rowOrdinal, row.rowId);
					walkFields(field.settings.fields, row.values, rp, options.nodeIdForPath(rp));
				}
				return;
			}
			if (field.type === "flexible") {
				structural(field, path, parentId, "group", ordinal);
				const baseId = options.nodeIdForPath(path);
				for (const [rowOrdinal, row] of (value ?? []).entries()) {
					const rp = pathLayout(pathRow(path, row.rowId), row.layoutKey), layout = field.settings.layouts.find((item) => item.key === row.layoutKey);
					if (!layout) fail$1(path, "contains unknown layout");
					structural(field, rp, baseId, "flexibleRow", rowOrdinal, row.rowId, row.layoutKey);
					walkFields(layout.fields, row.values, rp, options.nodeIdForPath(rp));
				}
				return;
			}
			if (field.type === "clone") {
				if (!options.cloneResolver) fail$1(path, "clone resolver is required");
				structural(field, path, parentId, "group", ordinal);
				walkFields(options.cloneResolver.resolve(field), value, path, options.nodeIdForPath(path));
				return;
			}
			const lane = leafLane(value === void 0 ? null : value);
			add({
				nodeId: options.nodeIdForPath(path),
				entityType: options.entityType,
				entityId: options.entityId,
				groupKey: group.key,
				definitionRevision: options.definitionRevision,
				fieldKey: field.key,
				path,
				parentNodeId: parentId,
				rowId: null,
				layoutKey: null,
				nodeKind: "leaf",
				ordinal,
				...lane
			});
		});
	};
	walkFields(group.fields, values, "", null);
	if (nodes.length > 1e3) fail$1("values", "exceeds maximum materialized node count 1000");
	return Object.freeze(nodes);
}
function decodeLane(node) {
	if (node.nodeKind !== "leaf") fail$1(node.path, "is not a leaf node");
	const lanes = [
		node.valueText !== null,
		node.valueNumber !== null,
		node.valueBoolean !== null,
		node.valueDateTime !== null,
		node.valueRef !== null,
		node.valueJson !== null
	].filter(Boolean).length;
	if (node.isNull) {
		if (lanes !== 0) fail$1(node.path, "null leaf contains a value lane");
		return null;
	}
	if (lanes !== 1) fail$1(node.path, "leaf must contain exactly one value lane");
	if (node.valueText !== null) return node.valueText;
	if (node.valueNumber !== null) return node.valueNumber;
	if (node.valueBoolean !== null) return node.valueBoolean;
	if (node.valueDateTime !== null) return node.valueDateTime;
	if (node.valueRef !== null) try {
		return JSON.parse(node.valueRef);
	} catch {
		return node.valueRef;
	}
	try {
		return JSON.parse(node.valueJson);
	} catch {
		fail$1(node.path, "contains invalid JSON lane");
	}
}
function assertNodeShape(node, group, revision) {
	if (node.groupKey !== group.key) fail$1(node.path, "belongs to another field group");
	if (node.definitionRevision !== revision) fail$1(node.path, "mixes immutable definition revisions");
	if (node.ordinal < 0 || !Number.isSafeInteger(node.ordinal)) fail$1(node.path, "has invalid ordinal");
	if (node.nodeKind === "flexibleRow" && (!node.rowId || !node.layoutKey)) fail$1(node.path, "flexible row requires row/layout identity");
	if (node.nodeKind === "repeaterRow" && !node.rowId) fail$1(node.path, "repeater row requires row identity");
	if ((node.nodeKind === "leaf" || node.nodeKind === "group") && (node.rowId !== null || node.layoutKey !== null)) fail$1(node.path, "non-row node carries row/layout identity");
}
function isCanonicalFieldValuePath(path) {
	return path.length > 0 && /^(?:\/(?:f|r|l):(?:[^~/]|~[01])+)+$/.test(path);
}
function decodeFieldValueNodes(group, nodes, options) {
	const byId = /* @__PURE__ */ new Map(), children = /* @__PURE__ */ new Map(), paths = /* @__PURE__ */ new Set();
	for (const node of nodes) {
		assertNodeShape(node, group, options.definitionRevision);
		if (!isCanonicalFieldValuePath(node.path)) fail$1(node.path, "is not a canonical typed field path");
		if (byId.has(node.nodeId)) fail$1(node.path, "duplicates node id");
		if (paths.has(node.path)) fail$1(node.path, "duplicates materialized path");
		byId.set(node.nodeId, node);
		paths.add(node.path);
		const list = children.get(node.parentNodeId) ?? [];
		list.push(node);
		children.set(node.parentNodeId, list);
	}
	for (const list of children.values()) {
		list.sort((a, b) => a.ordinal - b.ordinal || a.path.localeCompare(b.path));
		for (let i = 1; i < list.length; i++) if (list[i - 1].ordinal === list[i].ordinal) fail$1(list[i].path, "duplicates sibling ordinal");
	}
	for (const node of nodes) if (node.parentNodeId !== null && !byId.has(node.parentNodeId)) fail$1(node.path, "references missing parent");
	const fieldsByKey = (fields) => new Map(fields.map((field) => [field.key, field]));
	const readFields = (fields, parentId, parentPath) => {
		const out = {}, defs = fieldsByKey(fields);
		for (const node of children.get(parentId) ?? []) {
			const definition = defs.get(node.fieldKey);
			if (!definition) fail$1(node.path, "references a field absent from the pinned definition");
			const expected = pathField(parentPath, definition.key);
			if (definition.type === "group") {
				if (node.nodeKind !== "group" || node.path !== expected) fail$1(node.path, "has invalid group path/kind");
				out[definition.key] = readFields(definition.settings.fields, node.nodeId, node.path);
				continue;
			}
			if (definition.type === "repeater") {
				if (node.nodeKind !== "group" || node.path !== expected) fail$1(node.path, "has invalid repeater root");
				const rows = [];
				for (const rowNode of children.get(node.nodeId) ?? []) {
					if (rowNode.nodeKind !== "repeaterRow" || !rowNode.rowId || rowNode.path !== pathRow(node.path, rowNode.rowId)) fail$1(rowNode.path, "has invalid repeater row path");
					rows.push(Object.freeze({
						rowId: rowNode.rowId,
						values: readFields(definition.settings.fields, rowNode.nodeId, rowNode.path)
					}));
				}
				out[definition.key] = Object.freeze(rows);
				continue;
			}
			if (definition.type === "flexible") {
				if (node.nodeKind !== "group" || node.path !== expected) fail$1(node.path, "has invalid flexible root");
				const rows = [];
				for (const rowNode of children.get(node.nodeId) ?? []) {
					if (rowNode.nodeKind !== "flexibleRow" || !rowNode.rowId || !rowNode.layoutKey || rowNode.path !== pathLayout(pathRow(node.path, rowNode.rowId), rowNode.layoutKey)) fail$1(rowNode.path, "has invalid flexible row path");
					const layout = definition.settings.layouts.find((item) => item.key === rowNode.layoutKey);
					if (!layout) fail$1(rowNode.path, "references unknown flexible layout");
					rows.push(Object.freeze({
						rowId: rowNode.rowId,
						layoutKey: rowNode.layoutKey,
						values: readFields(layout.fields, rowNode.nodeId, rowNode.path)
					}));
				}
				out[definition.key] = Object.freeze(rows);
				continue;
			}
			if (definition.type === "clone") {
				if (node.nodeKind !== "group" || node.path !== expected) fail$1(node.path, "has invalid clone root");
				if (!options.cloneResolver) fail$1(node.path, "clone resolver is required");
				out[definition.key] = readFields(options.cloneResolver.resolve(definition), node.nodeId, node.path);
				continue;
			}
			if (node.nodeKind !== "leaf" || node.path !== expected) fail$1(node.path, "has invalid leaf path/kind");
			out[definition.key] = decodeLane(node);
		}
		return Object.freeze(out);
	};
	const result = readFields(group.fields, null, "");
	const consumed = /* @__PURE__ */ new Set();
	const mark = (parent) => {
		for (const child of children.get(parent) ?? []) {
			consumed.add(child.nodeId);
			mark(child.nodeId);
		}
	};
	mark(null);
	if (consumed.size !== nodes.length) fail$1("values", "contains unreachable nodes");
	return result;
}
async function authorizeRelationshipReplacement(definition, before, after, authorization) {
	if (definition.type !== "relationship") return;
	const key = (ref) => `${ref.entityType}:${ref.id}`, beforeMap = new Map(before.map((ref) => [key(ref), ref])), afterMap = new Map(after.map((ref) => [key(ref), ref]));
	for (const ref of after) await authorization.assertTarget(ref, "readTarget");
	if (typeof definition.settings === "object" && definition.settings !== null && "bidirectional" in definition.settings && definition.settings.bidirectional !== void 0) {
		for (const [id, ref] of beforeMap) if (!afterMap.has(id)) await authorization.assertTarget(ref, "writeReverseTarget");
		for (const [id, ref] of afterMap) if (!beforeMap.has(id)) await authorization.assertTarget(ref, "writeReverseTarget");
	}
}
//#endregion
//#region src/types.ts
const sanitizedFieldHtmlBrand = Symbol("sanitized-field-html");
function requireAuthorizedFieldsContext(context) {
	const authorization = context.authorization;
	if (!context.principal || !authorization || typeof authorization.assert !== "function" || typeof authorization.assertDefinitionMigration !== "function") throw new FieldValidationError("context", "principal and authorization are required");
	return context;
}
const customFieldDefinitionBrand = Symbol("custom-field-definition");
const CUSTOM_TYPE_RE = /^[a-z][a-z0-9-]*:[a-z][a-z0-9._-]*$/;
const HEX64 = /^[a-f0-9]{64}$/i;
const FIELD_DEFINITION_LIMITS = Object.freeze({
	maxBytes: 262144,
	maxDepth: 12,
	maxChildren: 1e3
});
const FIELD_VALUE_LIMITS = Object.freeze({
	maxBytes: 1048576,
	maxDepth: 12,
	maxNodes: 1e3
});
function fail(field, detail) {
	throw new FieldValidationError(field, detail);
}
function object(input, field) {
	if (typeof input !== "object" || input === null || Array.isArray(input) || Object.getPrototypeOf(input) !== Object.prototype) fail(field, "must be a plain object");
	return input;
}
function string(input, field, max = 4096) {
	if (typeof input !== "string" || input.length === 0 || input.length > max) fail(field, `must be a non-empty string up to ${max} characters`);
	return input;
}
function json(value, limits, field = "value", depth = 0, budget = {
	nodes: 0,
	bytes: 0
}) {
	if (depth > limits.maxDepth) fail(field, `exceeds maximum depth ${limits.maxDepth}`);
	if (value === null || typeof value === "boolean") return value;
	if (typeof value === "number") {
		if (!Number.isFinite(value)) fail(field, "contains a non-finite number");
		budget.bytes += 8;
		return value;
	}
	if (typeof value === "string") {
		budget.bytes += new TextEncoder().encode(value).byteLength;
		if (budget.bytes > limits.maxBytes) fail(field, `exceeds maximum size ${limits.maxBytes}`);
		return value;
	}
	if (++budget.nodes > limits.maxNodes) fail(field, `exceeds maximum node count ${limits.maxNodes}`);
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => json(item, limits, `${field}.${index}`, depth + 1, budget)));
	const source = object(value, field), out = {};
	for (const key of Object.keys(source).sort()) {
		if (key === "__proto__" || key === "prototype" || key === "constructor") fail(`${field}.${key}`, "contains a forbidden key");
		out[key] = json(source[key], limits, `${field}.${key}`, depth + 1, budget);
	}
	return Object.freeze(out);
}
function validateDescriptor(descriptor) {
	if (!CUSTOM_TYPE_RE.test(descriptor.type)) fail("descriptor.type", "extension type must use an adopter-owned namespace such as vendor:field");
	if (!descriptor.contractVersion || descriptor.contractVersion.length > 128) fail("descriptor.contractVersion", "must be a bounded non-empty string");
	if (!HEX64.test(descriptor.schemaHash)) fail("descriptor.schemaHash", "must be a 64-character hexadecimal digest");
	if (!HEX64.test(descriptor.codecHash)) fail("descriptor.codecHash", "must be a 64-character hexadecimal digest");
	for (const method of [
		"parseDefinition",
		"parseValue",
		"parseWrite",
		"serialize",
		"deserialize",
		"format",
		"schema",
		"redactForRevision"
	]) if (typeof descriptor[method] !== "function") fail(`descriptor.${method}`, "must be a function");
	json(descriptor.schema({}), FIELD_VALUE_LIMITS, "descriptor.schema");
}
function descriptorHash(seed) {
	let a = 2166136261, b = 2654435769;
	for (let round = 0; round < 8; round++) {
		for (let i = 0; i < seed.length; i++) {
			a = Math.imul(a ^ seed.charCodeAt(i) + round, 16777619);
			b = Math.imul(b ^ (seed.charCodeAt(i) << i % 8) + round, 2246822507);
		}
		seed = `${seed}:${(a >>> 0).toString(16)}:${(b >>> 0).toString(16)}`;
	}
	return `${(a >>> 0).toString(16).padStart(8, "0")}${(b >>> 0).toString(16).padStart(8, "0")}`.repeat(4).slice(0, 64);
}
function version(descriptors) {
	return `fields-registry-v1:${descriptorHash(descriptors.map((d) => `${d.type}:${d.contractVersion}:${d.schemaHash}:${d.codecHash}`).join("|"))}`;
}
function createFieldTypeRegistry(input = {}) {
	const builtIns = createBuiltinFieldTypeDescriptors();
	const builtInTypes = new Set(builtIns.map((descriptor) => descriptor.type));
	const extensions = [...input.extensions ?? []];
	const seen = new Set(builtInTypes);
	for (const descriptor of extensions) {
		validateDescriptor(descriptor);
		if (seen.has(descriptor.type)) fail("descriptor.type", `duplicate or reserved field type ${descriptor.type}`);
		seen.add(descriptor.type);
	}
	extensions.sort((left, right) => left.type.localeCompare(right.type));
	const ordered = Object.freeze([...builtIns, ...extensions.map((descriptor) => Object.freeze(descriptor))]);
	const map = new Map(ordered.map((descriptor) => [descriptor.type, descriptor]));
	return Object.freeze({
		version: version(ordered),
		builtInTypes,
		has: (type) => map.has(type),
		resolve: (type) => map.get(type),
		parseDefinition(input, limits) {
			const type = string(object(input, "definition").type, "definition.type", 256), descriptor = map.get(type);
			if (!descriptor) fail("definition.type", `unregistered field type ${type}`);
			return descriptor.parseDefinition(input, limits);
		}
	});
}
function defineCustomField(descriptor, definition) {
	validateDescriptor(descriptor);
	if (definition.type !== descriptor.type) fail("definition.type", "must match descriptor type");
	const parsed = descriptor.parseDefinition(definition, FIELD_DEFINITION_LIMITS);
	if (parsed.type !== descriptor.type || parsed.key !== definition.key) fail("definition", "descriptor parser changed immutable type/key identity");
	return Object.freeze({
		...definition,
		[customFieldDefinitionBrand]: true
	});
}
function isSanitizedFieldHtml(value) {
	return typeof value === "object" && value !== null && value[sanitizedFieldHtmlBrand] === true && typeof value.html === "string";
}
async function sanitizeFieldHtml(input, context) {
	if (!context.sanitizer) fail("sanitizer", "is required for sanitized HTML output");
	const html = await context.sanitizer.sanitizeHtml(input);
	if (typeof html !== "string") fail("sanitizer", "must return a string");
	return Object.freeze({
		html,
		[sanitizedFieldHtmlBrand]: true
	});
}
function assertSerializableFieldPresentation(value) {
	const p = object(value, "presentation");
	if (p.kind === "text") {
		if (typeof p.value !== "string") fail("presentation.value", "text presentation requires string");
		return Object.freeze({
			kind: "text",
			value: p.value
		});
	}
	if (p.kind === "structured") return Object.freeze({
		kind: "structured",
		value: json(p.value, FIELD_VALUE_LIMITS, "presentation.value")
	});
	if (p.kind === "sanitizedHtml" && isSanitizedFieldHtml(p.value)) return Object.freeze({
		kind: "sanitizedHtml",
		value: p.value
	});
	fail("presentation.kind", "must be text, structured, or branded sanitizedHtml");
}
//#endregion
//#region src/definition-lifecycle.ts
var FieldsLifecycleError = class extends Error {
	code;
	detail;
	field;
	name = "FieldsLifecycleError";
	constructor(code, detail, field) {
		super(`fields lifecycle ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
function freezeStorage(value, field = "result", depth = 0) {
	if (depth > 20) throw new FieldsLifecycleError("integrity", "stored payload exceeds maximum depth", field);
	if (value === null || typeof value === "string" || typeof value === "boolean") return value;
	if (typeof value === "number") {
		if (!Number.isFinite(value)) throw new FieldsLifecycleError("integrity", "stored payload contains a non-finite number", field);
		return value;
	}
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => freezeStorage(item, `${field}.${index}`, depth + 1)));
	if (typeof value === "object") {
		const output = {};
		for (const key of Object.keys(value).sort()) {
			if (key === "__proto__" || key === "prototype" || key === "constructor") throw new FieldsLifecycleError("integrity", "stored payload contains a forbidden key", `${field}.${key}`);
			const child = value[key];
			if (child !== void 0) output[key] = freezeStorage(child, `${field}.${key}`, depth + 1);
		}
		return Object.freeze(output);
	}
	throw new FieldsLifecycleError("integrity", `stored payload contains unsupported ${typeof value}`, field);
}
function assertActiveFieldsTransaction(tx, expectedIdentity) {
	try {
		const identity = getTransactionIdentity(tx);
		if (expectedIdentity !== void 0 && identity !== expectedIdentity) throw new FieldsLifecycleError("transaction-capability", "transaction identity does not match the parent composite");
		return identity;
	} catch (error) {
		if (error instanceof FieldsLifecycleError) throw error;
		if (isTransactionCapabilityError(error)) throw new FieldsLifecycleError("transaction-capability", error.reason);
		throw error;
	}
}
function authorizedFieldsContext(context) {
	try {
		return requireAuthorizedFieldsContext(context);
	} catch {
		throw new FieldsLifecycleError("access-denied", "fields operation is unavailable");
	}
}
async function assertFieldsAuthorized(context, action, ref) {
	const authorized = authorizedFieldsContext(context);
	try {
		await authorized.authorization.assert(authorized.principal, action, ref);
	} catch {
		throw new FieldsLifecycleError("access-denied", "fields operation is unavailable");
	}
	return authorized;
}
function assertPrincipalCapability(context, capability) {
	if (!context.principal.capabilities.has(capability)) throw new FieldsLifecycleError("access-denied", "fields operation is unavailable");
}
async function assertDefinitionMigration(context, entityTypes) {
	const authorized = authorizedFieldsContext(context);
	try {
		await authorized.authorization.assert(authorized.principal, "manageDefinitions", {
			entityType: "fields-definition",
			entityId: "*"
		});
		const result = await authorized.authorization.assertDefinitionMigration(authorized.principal, Object.freeze([...new Set(entityTypes)].sort()));
		if (!result || typeof result.policyVersion !== "string" || result.policyVersion.length === 0) throw new Error("invalid policy version");
		return {
			context: authorized,
			policyVersion: result.policyVersion
		};
	} catch {
		throw new FieldsLifecycleError("access-denied", "fields operation is unavailable");
	}
}
function principalScope(context) {
	return `${context.principal.system === true ? "system" : "principal"}:${context.principal.id}`;
}
async function fieldsRequestHash(value) {
	return canonicalFieldsMigrationHash(value);
}
async function readFieldsReceipt(db, operationId) {
	const row = lifecycleRows(await db.execute(sql`SELECT kind, principal_scope AS "principalScope", request_hash AS "requestHash", result
    FROM fields_operation_receipts WHERE operation_id = ${operationId}`))[0];
	if (!row) return null;
	const result = typeof row.result === "string" ? (() => {
		try {
			return JSON.parse(row.result);
		} catch {
			return row.result;
		}
	})() : row.result;
	return Object.freeze({
		kind: row.kind,
		principalScope: row.principalScope,
		requestHash: row.requestHash,
		result: freezeStorage(result)
	});
}
async function writeFieldsReceipt(tx, input) {
	await tx.execute(sql`INSERT INTO fields_operation_receipts (operation_id, kind, principal_scope, request_hash, result, created_at)
    VALUES (${input.operationId}, ${input.kind}, ${principalScope(input.context)}, ${input.requestHash}, ${JSON.stringify(input.result)}, ${(/* @__PURE__ */ new Date()).toISOString()})`);
}
function assertReceiptReplay(receipt, input) {
	if (receipt.kind !== input.kind || receipt.principalScope !== principalScope(input.context) || receipt.requestHash !== input.requestHash) throw new FieldsLifecycleError("operation-conflict", "operation id was already used with different input or scope");
}
async function verifyFieldsBackup(tx, input, backups) {
	let manifest;
	try {
		manifest = await backups.verify(tx, input.backupId, input.expectedScopeHash, input.corpusVersion, input.corpusHash, input.counts);
	} catch {
		throw new FieldsLifecycleError("backup-invalid", "backup manifest does not match the destructive scope");
	}
	if (!manifest || manifest.immutable !== true || manifest.id !== input.backupId || manifest.scopeHash !== input.expectedScopeHash || manifest.corpusVersion !== input.corpusVersion || manifest.corpusHash !== input.corpusHash || !Number.isSafeInteger(manifest.byteCount) || manifest.byteCount < 0) throw new FieldsLifecycleError("backup-invalid", "backup manifest does not match the destructive scope");
	if (JSON.stringify(Object.entries(input.counts).sort()) !== JSON.stringify(Object.entries(manifest.itemCounts).sort())) throw new FieldsLifecycleError("backup-invalid", "backup counts do not cover the complete corpus");
	return Object.freeze({
		...manifest,
		itemCounts: Object.freeze({ ...manifest.itemCounts })
	});
}
function lifecycleRows(value) {
	if (Array.isArray(value)) return value;
	if (typeof value === "object" && value !== null && Array.isArray(value.rows)) return value.rows;
	throw new FieldsLifecycleError("integrity", "database adapter returned an invalid row result");
}
async function lifecycleExecute(db, query) {
	return lifecycleRows(await db.execute(query));
}
function lifecycleJson(value, field) {
	if (typeof value !== "string") return value;
	try {
		return JSON.parse(value);
	} catch {
		throw new FieldsLifecycleError("integrity", `${field} contains invalid JSON`);
	}
}
function lifecycleBool(value) {
	return value === true || value === 1;
}
function lifecycleRecord(value, field) {
	const parsed = lifecycleJson(value, field);
	if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new FieldsLifecycleError("integrity", `${field} is malformed`);
	return parsed;
}
async function normalizeFinalGroup(value) {
	return parseFieldGroupDefinition(value);
}
function resolvedFinalGroup(row) {
	const definition = parseFieldGroupDefinition(lifecycleJson(row.definition, "field group definition"));
	if (definition.key !== row.key) throw new FieldsLifecycleError("integrity", "field group definition key mismatch");
	return Object.freeze({
		...definition,
		active: lifecycleBool(row.active),
		origin: row.origin === "code" ? "code" : "db",
		version: Number(row.version),
		revision: Number(row.currentRevision),
		...row.shadowedDbVersion === null ? {} : { shadowedDbVersion: Number(row.shadowedDbVersion) }
	});
}
async function finalGroupRows(db) {
	return lifecycleExecute(db, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM field_group_definitions ORDER BY key`);
}
async function finalGroupRow(db, key) {
	return (await lifecycleExecute(db, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM field_group_definitions WHERE key=${key} LIMIT 1`))[0] ?? null;
}
function normalizedGroupKey(value) {
	if (typeof value !== "string" || !/^[a-z][a-z0-9_]*$/.test(value)) throw new FieldsLifecycleError("validation", "group key must be normalized", "key");
	return value;
}
function codeGroupDefinition(value) {
	const { origin: _origin, version: _version, revision: _revision, shadowedDbVersion: _shadowedDbVersion, ...definition } = value;
	return parseFieldGroupDefinition(definition);
}
function defineFinalFieldGroup(definition) {
	return Object.freeze({
		...codeGroupDefinition(definition),
		origin: "code"
	});
}
async function resolveFinalFieldGroups(db, input = {}) {
	const rows = await finalGroupRows(db), output = /* @__PURE__ */ new Map();
	for (const row of rows) output.set(row.key, resolvedFinalGroup(row));
	const seen = /* @__PURE__ */ new Set();
	for (const raw of input.codeGroups ?? []) {
		const definition = parseFieldGroupDefinition(raw);
		if (seen.has(definition.key)) throw new FieldsLifecycleError("validation", "duplicate code field-group key", definition.key);
		seen.add(definition.key);
		const previous = output.get(definition.key);
		output.set(definition.key, Object.freeze({
			...definition,
			origin: "code",
			version: previous?.version ?? 1,
			revision: previous?.revision ?? 1,
			active: true,
			...previous?.origin === "db" ? { shadowedDbVersion: previous.version } : previous?.shadowedDbVersion === void 0 ? {} : { shadowedDbVersion: previous.shadowedDbVersion }
		}));
	}
	return Object.freeze([...output.values()].sort((left, right) => (left.order ?? 0) - (right.order ?? 0) || left.key.localeCompare(right.key)));
}
function objectMentionsGroup(value, groupKey) {
	const parsed = lifecycleJson(value, "document");
	const visit = (item) => {
		if (Array.isArray(item)) return item.some(visit);
		if (typeof item !== "object" || item === null) return false;
		const record = item;
		if (record.groupKey === groupKey) return true;
		return Object.values(record).some(visit);
	};
	return visit(parsed);
}
async function groupCorpus(db, groupKey) {
	const nodes = await lifecycleExecute(db, sql`SELECT node_id AS "nodeId",entity_type AS "entityType",entity_id AS "entityId",group_key AS "groupKey",definition_revision AS "definitionRevision",field_key AS "fieldKey",path,parent_node_id AS "parentNodeId",row_id AS "rowId",layout_key AS "layoutKey",node_kind AS "nodeKind",ordinal,is_null AS "isNull",value_text AS "valueText",value_number AS "valueNumber",value_boolean AS "valueBoolean",value_date_time AS "valueDateTime",value_ref AS "valueRef",value_json AS "valueJson" FROM field_value_nodes WHERE group_key=${groupKey} ORDER BY entity_type,entity_id,path`);
	const revisions = (await lifecycleExecute(db, sql`SELECT id,entity_type AS "entityType",entity_id AS "entityId",definition_versions AS "definitionVersions","values" AS "values",block_document AS "blockDocument" FROM field_revisions ORDER BY entity_type,entity_id,id`)).filter((row) => {
		const versions = lifecycleRecord(row.definitionVersions, "revision definitionVersions");
		return Object.prototype.hasOwnProperty.call(versions, groupKey) || objectMentionsGroup(row.blockDocument, groupKey);
	});
	const currentDocuments = await lifecycleExecute(db, sql`SELECT entity_type AS "entityType",entity_id AS "entityId",version,document,definition_versions AS "definitionVersions" FROM field_block_documents ORDER BY entity_type,entity_id`);
	const reusableDocuments = await lifecycleExecute(db, sql`SELECT id,version,document,definition_versions AS "definitionVersions" FROM field_reusable_blocks ORDER BY id`);
	const documents = [];
	for (const row of currentDocuments) if (objectMentionsGroup(row.document, groupKey) || Object.prototype.hasOwnProperty.call(lifecycleRecord(row.definitionVersions, "block definitionVersions"), `group:${groupKey}`)) documents.push({
		section: "current",
		identity: `${String(row.entityType)}:${String(row.entityId)}`,
		entityType: String(row.entityType),
		entityId: String(row.entityId),
		version: row.version,
		document: lifecycleJson(row.document, "block document"),
		definitionVersions: lifecycleJson(row.definitionVersions, "block definitionVersions")
	});
	for (const row of reusableDocuments) if (objectMentionsGroup(row.document, groupKey) || Object.prototype.hasOwnProperty.call(lifecycleRecord(row.definitionVersions, "reusable definitionVersions"), `group:${groupKey}`)) documents.push({
		section: "reusable",
		identity: String(row.id),
		entityType: "reusableBlock",
		entityId: null,
		version: row.version,
		document: lifecycleJson(row.document, "reusable document"),
		definitionVersions: lifecycleJson(row.definitionVersions, "reusable definitionVersions")
	});
	documents.sort((a, b) => a.section.localeCompare(b.section) || a.identity.localeCompare(b.identity));
	const entityTypes = new Set(nodes.map((row) => row.entityType));
	for (const row of revisions) entityTypes.add(row.entityType);
	for (const row of documents) entityTypes.add(row.entityType);
	const entities = new Set(nodes.map((row) => `${row.entityType}\u0000${row.entityId}`));
	const counts = Object.freeze({
		nodes: nodes.length,
		entities: entities.size,
		revisions: revisions.length,
		documents: documents.length
	});
	const version = await fieldsRequestHash({
		nodes: nodes.map((row) => ({
			nodeId: row.nodeId,
			entityType: row.entityType,
			entityId: row.entityId,
			path: row.path,
			revision: Number(row.definitionRevision)
		})),
		revisions: revisions.map((row) => row.id),
		documents: documents.map((row) => ({
			section: row.section,
			identity: row.identity,
			version: row.version
		}))
	});
	const hash = await fieldsRequestHash({
		nodes,
		revisions,
		documents
	});
	return Object.freeze({
		version,
		hash,
		nodes: Object.freeze(nodes),
		revisions: Object.freeze(revisions),
		documents: Object.freeze(documents),
		entityTypes: Object.freeze([...entityTypes].sort()),
		counts
	});
}
function groupPaths(fields, prefix = []) {
	const output = /* @__PURE__ */ new Map();
	const visit = (definitions, parent) => {
		for (const definition of definitions) {
			const path = [...parent, definition.key];
			output.set(JSON.stringify(path), definition);
			if (definition.type === "group" || definition.type === "repeater") visit(definition.settings.fields, path);
			if (definition.type === "flexible") for (const layout of definition.settings.layouts) visit(layout.fields, [...path, layout.key]);
		}
	};
	visit(fields, prefix);
	return output;
}
async function groupIncompatibilities(current, next, corpus) {
	if (corpus.nodes.length === 0 && corpus.documents.length === 0 && corpus.revisions.length === 0) return Object.freeze([]);
	const before = groupPaths(current.fields), after = groupPaths(next.fields), output = [];
	if (current.active && !next.active) output.push("deactivate-with-data");
	for (const [path, definition] of before) {
		const replacement = after.get(path);
		if (!replacement) output.push(`removed:${path}`);
		else if (await fieldsRequestHash(definition) !== await fieldsRequestHash(replacement)) output.push(`changed:${path}`);
	}
	return Object.freeze([...new Set(output)].sort());
}
function groupTokenEncode(payload) {
	const bytes = new TextEncoder().encode(JSON.stringify(payload)), hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
	return fieldsRequestHash(payload).then((hash) => `${hex}.${hash}`);
}
async function groupTokenDecode(token) {
	const match = /^([a-f0-9]+)\.([a-f0-9]{64})$/i.exec(token);
	if (!match || match[1].length % 2 || match[1].length > 128e3) throw new FieldsLifecycleError("validation", "field-group impact token is invalid");
	let value;
	try {
		value = JSON.parse(new TextDecoder().decode(new Uint8Array(match[1].match(/../g).map((pair) => Number.parseInt(pair, 16)))));
	} catch {
		throw new FieldsLifecycleError("validation", "field-group impact token is invalid");
	}
	if (typeof value !== "object" || value === null || Array.isArray(value) || await fieldsRequestHash(value) !== match[2].toLowerCase()) throw new FieldsLifecycleError("validation", "field-group impact token integrity check failed");
	return value;
}
function normalizeGroupStrategy(strategy) {
	if (strategy.kind === "reject" || strategy.kind === "deactivate" || strategy.kind === "retainValues") return Object.freeze({ kind: strategy.kind });
	if (strategy.kind === "purgeValues") {
		if (!strategy.backupId || strategy.backupId.length > 512) throw new FieldsLifecycleError("validation", "backupId is required", "strategy.backupId");
		return Object.freeze({
			kind: "purgeValues",
			backupId: strategy.backupId
		});
	}
	if (strategy.kind === "migrateValues") {
		if (!Array.isArray(strategy.mappings) || strategy.mappings.length > 500) throw new FieldsLifecycleError("validation", "field mappings must be bounded", "strategy.mappings");
		const seen = /* @__PURE__ */ new Set(), mappings = strategy.mappings.map((mapping, index) => {
			if (!Array.isArray(mapping.from) || mapping.from.length === 0 || mapping.from.length > 64) throw new FieldsLifecycleError("validation", "mapping source path is invalid", `strategy.mappings.${index}.from`);
			if (mapping.to !== null && (!Array.isArray(mapping.to) || mapping.to.length === 0 || mapping.to.length > 64)) throw new FieldsLifecycleError("validation", "mapping destination path is invalid", `strategy.mappings.${index}.to`);
			const identity = JSON.stringify(mapping.from);
			if (seen.has(identity)) throw new FieldsLifecycleError("validation", "mapping source path is duplicated", `strategy.mappings.${index}.from`);
			seen.add(identity);
			return Object.freeze({
				from: Object.freeze([...mapping.from]),
				to: mapping.to === null ? null : Object.freeze([...mapping.to])
			});
		});
		return Object.freeze({
			kind: "migrateValues",
			mappings: Object.freeze(mappings)
		});
	}
	throw new FieldsLifecycleError("validation", "unknown field-group change strategy");
}
function groupDefinitionRef(key) {
	return Object.freeze({
		entityType: "fields-group-definition",
		entityId: key
	});
}
async function createFieldGroup(tx, definition, context, input) {
	assertActiveFieldsTransaction(tx);
	const normalized = await normalizeFinalGroup(definition), key = normalizedGroupKey(normalized.key);
	const authorized = await assertFieldsAuthorized(context, "manageDefinitions", groupDefinitionRef(key));
	if ((input.codeGroups ?? []).some((group) => group.key === key)) throw new FieldsLifecycleError("validation", "effective field-group key is owned by code", key);
	const canonicalHash = await canonicalFieldGroupHash(normalized);
	const requestHash = await fieldsRequestHash({
		kind: "create-field-group",
		canonicalHash,
		codeKeys: (input.codeGroups ?? []).map((group) => group.key).sort()
	});
	const replay = await readFieldsReceipt(tx, input.operationId);
	if (replay) {
		assertReceiptReplay(replay, {
			kind: "fields:create-field-group",
			context: authorized,
			requestHash
		});
		const row = await finalGroupRow(tx, key);
		if (!row) throw new FieldsLifecycleError("integrity", "committed group receipt has no definition");
		return resolvedFinalGroup(row);
	}
	if (await finalGroupRow(tx, key)) throw new FieldsLifecycleError("validation", "field-group key already exists", key);
	const now = (/* @__PURE__ */ new Date()).toISOString();
	await tx.execute(sql`INSERT INTO field_group_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${key},'db',1,${normalized.active},1,${canonicalHash},${JSON.stringify(normalized)},${now},${now})`);
	await tx.execute(sql`INSERT INTO field_definition_versions (group_key,revision,canonical_hash,definition,origin,created_at) VALUES (${key},1,${canonicalHash},${JSON.stringify(normalized)},'db',${now})`);
	const result = Object.freeze({
		...normalized,
		origin: "db",
		version: 1,
		revision: 1
	});
	await writeFieldsReceipt(tx, {
		operationId: input.operationId,
		kind: "fields:create-field-group",
		context: authorized,
		requestHash,
		result: Object.freeze({
			key,
			version: 1,
			revision: 1
		})
	});
	return result;
}
async function previewFieldGroupChange(db, key, expectedVersion, patch, strategyInput, context) {
	const groupKey = normalizedGroupKey(key);
	await assertFieldsAuthorized(context, "manageDefinitions", groupDefinitionRef(groupKey));
	const row = await finalGroupRow(db, groupKey);
	if (!row) throw new FieldsLifecycleError("not-found", "field-group definition is unavailable");
	const current = resolvedFinalGroup(row);
	if (current.origin === "code") throw new FieldsLifecycleError("validation", "code-owned field groups change only through registry reconciliation");
	if (current.version !== expectedVersion) throw new FieldsLifecycleError("stale-version", "field-group version changed");
	const strategy = normalizeGroupStrategy(strategyInput);
	const next = parseFieldGroupDefinition({
		...codeGroupDefinition(current),
		...patch,
		key: groupKey,
		active: strategy.kind === "deactivate" ? false : patch.active ?? current.active
	});
	const corpus = await groupCorpus(db, groupKey);
	const migration = await assertDefinitionMigration(context, corpus.entityTypes.length ? corpus.entityTypes : ["fields-definition"]);
	const incompatibilities = await groupIncompatibilities(current, next, corpus);
	const payload = Object.freeze({
		kind: "field-group-change",
		groupKey,
		expectedVersion,
		authorizationPolicyVersion: migration.policyVersion,
		valueCorpusVersion: corpus.version,
		valueCorpusHash: corpus.hash,
		affectedCounts: corpus.counts,
		nextDefinition: freezeStorage(next, "nextDefinition"),
		strategy: freezeStorage(strategy, "strategy"),
		incompatibilities: Object.freeze(incompatibilities),
		entityTypes: Object.freeze(corpus.entityTypes)
	});
	return Object.freeze({
		token: await groupTokenEncode(payload),
		groupKey,
		expectedVersion,
		authorizationPolicyVersion: migration.policyVersion,
		valueCorpusVersion: corpus.version,
		valueCorpusHash: corpus.hash,
		affectedCounts: corpus.counts,
		incompatibilities
	});
}
function corpusNode(row) {
	return Object.freeze({
		nodeId: row.nodeId,
		entityType: row.entityType,
		entityId: row.entityId,
		groupKey: row.groupKey,
		definitionRevision: Number(row.definitionRevision),
		fieldKey: row.fieldKey,
		path: row.path,
		parentNodeId: row.parentNodeId,
		rowId: row.rowId,
		layoutKey: row.layoutKey,
		nodeKind: row.nodeKind,
		ordinal: Number(row.ordinal),
		isNull: row.isNull === true || row.isNull === 1,
		valueText: row.valueText,
		valueNumber: row.valueNumber === null ? null : Number(row.valueNumber),
		valueBoolean: row.valueBoolean === null ? null : row.valueBoolean === true || row.valueBoolean === 1,
		valueDateTime: row.valueDateTime,
		valueRef: row.valueRef,
		valueJson: row.valueJson
	});
}
function pathKey(path) {
	return JSON.stringify(path);
}
function deepClone(value) {
	if (value === null || typeof value !== "object") return value;
	if (Array.isArray(value)) return value.map(deepClone);
	const out = {};
	for (const [key, child] of Object.entries(value)) out[key] = deepClone(child);
	return out;
}
function pathGet(root, path) {
	let current = root;
	for (const segment of path) if (typeof segment === "number") {
		if (!Array.isArray(current) || segment < 0 || segment >= current.length) return {
			present: false,
			value: void 0
		};
		current = current[segment];
	} else {
		if (typeof current !== "object" || current === null || Array.isArray(current) || !Object.prototype.hasOwnProperty.call(current, segment)) return {
			present: false,
			value: void 0
		};
		current = current[segment];
	}
	return {
		present: true,
		value: current
	};
}
function pathDelete(root, path) {
	if (path.length === 0) return;
	let current = root;
	for (let i = 0; i < path.length - 1; i++) {
		const segment = path[i];
		if (typeof segment === "number") {
			if (!Array.isArray(current) || segment < 0 || segment >= current.length) return;
			current = current[segment];
		} else {
			if (typeof current !== "object" || current === null || Array.isArray(current)) return;
			current = current[segment];
		}
	}
	const last = path[path.length - 1];
	if (typeof last === "number") {
		if (Array.isArray(current) && last >= 0 && last < current.length) current.splice(last, 1);
	} else if (typeof current === "object" && current !== null && !Array.isArray(current)) delete current[last];
}
function pathSet(root, path, value) {
	if (path.length === 0) throw new FieldsLifecycleError("validation", "mapping destination path must not be empty");
	let current = root;
	for (let i = 0; i < path.length - 1; i++) {
		const segment = path[i], next = path[i + 1];
		if (typeof segment === "number") {
			if (!Array.isArray(current) || segment < 0) throw new FieldsLifecycleError("validation", "mapping destination crosses a non-array value");
			while (current.length <= segment) current.push(typeof next === "number" ? [] : {});
			if (current[segment] === null || typeof current[segment] !== "object") current[segment] = typeof next === "number" ? [] : {};
			current = current[segment];
		} else {
			if (typeof current !== "object" || current === null || Array.isArray(current)) throw new FieldsLifecycleError("validation", "mapping destination crosses a non-object value");
			const record = current;
			if (record[segment] === void 0) record[segment] = typeof next === "number" ? [] : {};
			if (record[segment] === null || typeof record[segment] !== "object") record[segment] = typeof next === "number" ? [] : {};
			current = record[segment];
		}
	}
	const last = path[path.length - 1];
	if (typeof last === "number") {
		if (!Array.isArray(current) || last < 0) throw new FieldsLifecycleError("validation", "mapping destination is not an array");
		while (current.length < last) current.push(null);
		current[last] = deepClone(value);
	} else {
		if (typeof current !== "object" || current === null || Array.isArray(current)) throw new FieldsLifecycleError("validation", "mapping destination is not an object");
		current[last] = deepClone(value);
	}
}
function applyMappings(values, mappings) {
	const output = deepClone(values);
	for (const mapping of mappings) {
		const found = pathGet(values, mapping.from);
		if (!found.present) continue;
		pathDelete(output, mapping.from);
		if (mapping.to !== null) pathSet(output, mapping.to, found.value);
	}
	return Object.freeze(output);
}
function ensureMappings(current, next, strategy, incompatibilities) {
	const before = groupPaths(current.fields), after = groupPaths(next.fields), mappingBySource = new Map(strategy.mappings.map((mapping) => [pathKey(mapping.from), mapping]));
	for (const issue of incompatibilities) {
		const raw = issue.slice(issue.indexOf(":") + 1), mapping = mappingBySource.get(raw);
		if (!mapping) throw new FieldsLifecycleError("validation", `migration does not cover ${issue}`);
		if (mapping.to !== null && !after.has(pathKey(mapping.to))) throw new FieldsLifecycleError("validation", `migration target for ${issue} does not exist`);
	}
	for (const mapping of strategy.mappings) {
		if (!before.has(pathKey(mapping.from))) throw new FieldsLifecycleError("validation", "migration source path does not exist", pathKey(mapping.from));
		if (mapping.to !== null && !after.has(pathKey(mapping.to))) throw new FieldsLifecycleError("validation", "migration target path does not exist", pathKey(mapping.to));
	}
}
async function writeMigratedNodes(tx, groupKey, next, nextRevision, corpus, mappings, context) {
	const buckets = /* @__PURE__ */ new Map();
	for (const row of corpus.nodes) {
		const id = `${row.entityType}\u0000${row.entityId}`;
		const list = buckets.get(id) ?? [];
		list.push(row);
		buckets.set(id, list);
	}
	for (const [identity, rows] of buckets) {
		const revisions = [...new Set(rows.map((row) => Number(row.definitionRevision)))];
		if (revisions.length !== 1) throw new FieldsLifecycleError("integrity", "current group value tree mixes immutable definition revisions");
		const oldRevision = revisions[0], oldDefinition = (await resolveFieldDefinitionVersion(tx, groupKey, oldRevision)).definition;
		const migrated = applyMappings(decodeFieldValueNodes(oldDefinition, rows.map(corpusNode), {
			definitionRevision: oldRevision,
			...context.cloneResolver ? { cloneResolver: { resolve: (definition) => context.cloneResolver.resolve(definition) } } : {}
		}), mappings);
		const [entityType, entityId] = identity.split("\0");
		const ids = /* @__PURE__ */ new Map(), nodeIdForPath = (path) => {
			let id = ids.get(path);
			if (!id) {
				id = crypto.randomUUID();
				ids.set(path, id);
			}
			return id;
		};
		const encoded = encodeFieldValueNodes(next, migrated, {
			entityType,
			entityId,
			definitionRevision: nextRevision,
			nodeIdForPath,
			...context.cloneResolver ? { cloneResolver: { resolve: (definition) => context.cloneResolver.resolve(definition) } } : {}
		});
		await tx.execute(sql`DELETE FROM field_value_nodes WHERE entity_type=${entityType} AND entity_id=${entityId} AND group_key=${groupKey}`);
		for (const row of encoded) await tx.execute(sql`INSERT INTO field_value_nodes (node_id,entity_type,entity_id,group_key,definition_revision,field_key,path,parent_node_id,row_id,layout_key,node_kind,ordinal,is_null,value_text,value_number,value_boolean,value_date_time,value_ref,value_json,created_at,updated_at) VALUES (${row.nodeId},${row.entityType},${row.entityId},${row.groupKey},${row.definitionRevision},${row.fieldKey},${row.path},${row.parentNodeId},${row.rowId},${row.layoutKey},${row.nodeKind},${row.ordinal},${row.isNull},${row.valueText},${row.valueNumber},${row.valueBoolean},${row.valueDateTime},${row.valueRef},${row.valueJson},${(/* @__PURE__ */ new Date()).toISOString()},${(/* @__PURE__ */ new Date()).toISOString()})`);
	}
}
function migrateGroupInDocument(value, groupKey, nextRevision, mappings) {
	const walk = (item) => {
		if (Array.isArray(item)) return item.map(walk);
		if (typeof item !== "object" || item === null) return item;
		const record = item, out = {};
		for (const [key, value] of Object.entries(record)) out[key] = walk(value);
		if (record.groupKey === groupKey && typeof record.values === "object" && record.values !== null && !Array.isArray(record.values)) {
			out.definitionRevision = nextRevision;
			out.values = applyMappings(record.values, mappings);
		}
		return out;
	};
	return walk(lifecycleJson(value, "block document"));
}
function definitionVersionsWithGroup(value, groupKey, revision) {
	const out = { ...lifecycleRecord(value, "definitionVersions") };
	if (Object.prototype.hasOwnProperty.call(out, `group:${groupKey}`)) out[`group:${groupKey}`] = revision;
	if (Object.prototype.hasOwnProperty.call(out, groupKey)) out[groupKey] = revision;
	return Object.freeze(out);
}
async function migrateCurrentDocuments(tx, groupKey, nextRevision, corpus, mappings) {
	for (const entry of corpus.documents) {
		const document = migrateGroupInDocument(entry.document, groupKey, nextRevision, mappings), versions = definitionVersionsWithGroup(entry.definitionVersions, groupKey, nextRevision);
		if (entry.section === "current") await tx.execute(sql`UPDATE field_block_documents SET document=${JSON.stringify(document)},definition_versions=${JSON.stringify(versions)},version=version+1,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE entity_type=${entry.entityType} AND entity_id=${entry.entityId}`);
		else await tx.execute(sql`UPDATE field_reusable_blocks SET document=${JSON.stringify(document)},definition_versions=${JSON.stringify(versions)},version=version+1,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE id=${entry.identity}`);
	}
}
async function purgeGroupCorpus(tx, groupKey, corpus) {
	await tx.execute(sql`DELETE FROM field_value_nodes WHERE group_key=${groupKey}`);
	for (const revision of corpus.revisions) await tx.execute(sql`DELETE FROM field_revisions WHERE id=${revision.id}`);
	for (const document of corpus.documents) if (document.section === "current") await tx.execute(sql`DELETE FROM field_block_documents WHERE entity_type=${document.entityType} AND entity_id=${document.entityId}`);
	else await tx.execute(sql`DELETE FROM field_reusable_blocks WHERE id=${document.identity}`);
}
function groupCountsEqual(left, right) {
	if (typeof right !== "object" || right === null || Array.isArray(right)) return false;
	const normalized = {};
	for (const [key, value] of Object.entries(right)) {
		const number = Number(value);
		if (!Number.isSafeInteger(number) || number < 0) return false;
		normalized[key] = number;
	}
	return JSON.stringify(Object.entries(left).sort()) === JSON.stringify(Object.entries(normalized).sort());
}
function parseTokenGroupDefinition(value, groupKey) {
	const definition = parseFieldGroupDefinition(value);
	if (definition.key !== groupKey) throw new FieldsLifecycleError("validation", "impact token field-group key mismatch");
	return definition;
}
function groupStrategyEqual(left, right) {
	try {
		return JSON.stringify(freezeStorage(left, "strategy")) === JSON.stringify(freezeStorage(right, "strategy"));
	} catch {
		return false;
	}
}
async function applyFieldGroupChange(tx, impactToken, strategyInput, operationId, context, destructive) {
	assertActiveFieldsTransaction(tx);
	const token = await groupTokenDecode(impactToken);
	if (token.kind !== "field-group-change" || typeof token.groupKey !== "string") throw new FieldsLifecycleError("validation", "field-group impact token has wrong operation kind");
	const groupKey = normalizedGroupKey(token.groupKey), strategy = normalizeGroupStrategy(strategyInput);
	if (!groupStrategyEqual(strategy, token.strategy)) throw new FieldsLifecycleError("operation-conflict", "field-group strategy differs from preview");
	const authorized = await assertFieldsAuthorized(context, "manageDefinitions", groupDefinitionRef(groupKey));
	const entityTypes = Array.isArray(token.entityTypes) ? token.entityTypes.map((value, index) => {
		if (typeof value !== "string" || !value || value.length > 256) throw new FieldsLifecycleError("validation", "impact token entity type is invalid", `entityTypes.${index}`);
		return value;
	}) : [];
	const migration = await assertDefinitionMigration(context, entityTypes.length ? entityTypes : ["fields-definition"]);
	if (token.authorizationPolicyVersion !== migration.policyVersion) throw new FieldsLifecycleError("corpus-drift", "authorization policy changed since preview");
	const requestHash = await fieldsRequestHash({
		impactToken,
		strategy
	});
	const replay = await readFieldsReceipt(tx, operationId);
	if (replay) {
		assertReceiptReplay(replay, {
			kind: "fields:apply-field-group-change",
			context: authorized,
			requestHash
		});
		const row = await finalGroupRow(tx, groupKey);
		return row ? resolvedFinalGroup(row) : null;
	}
	const row = await finalGroupRow(tx, groupKey);
	if (!row) throw new FieldsLifecycleError("not-found", "field-group definition is unavailable");
	const current = resolvedFinalGroup(row);
	if (current.origin === "code") throw new FieldsLifecycleError("validation", "code-owned field groups change only through registry reconciliation");
	if (Number(token.expectedVersion) !== current.version) throw new FieldsLifecycleError("stale-version", "field-group version changed");
	const corpus = await groupCorpus(tx, groupKey);
	if (token.valueCorpusVersion !== corpus.version || token.valueCorpusHash !== corpus.hash || !groupCountsEqual(corpus.counts, token.affectedCounts)) throw new FieldsLifecycleError("corpus-drift", "field-group value corpus changed since preview");
	if (JSON.stringify([...corpus.entityTypes].sort()) !== JSON.stringify([...entityTypes].sort())) throw new FieldsLifecycleError("corpus-drift", "field-group authorization scope changed since preview");
	const next = parseTokenGroupDefinition(token.nextDefinition, groupKey);
	const incompatibilities = await groupIncompatibilities(current, next, corpus);
	const tokenIncompatibilities = Array.isArray(token.incompatibilities) ? token.incompatibilities.map(String).sort() : [];
	if (JSON.stringify([...incompatibilities].sort()) !== JSON.stringify(tokenIncompatibilities)) throw new FieldsLifecycleError("corpus-drift", "field-group compatibility facts changed since preview");
	if (strategy.kind === "reject" && incompatibilities.length > 0) throw new FieldsLifecycleError("validation", "reject strategy cannot apply an incompatible field-group change");
	if (strategy.kind === "migrateValues") ensureMappings(current, next, strategy, incompatibilities);
	const nextHash = await canonicalFieldGroupHash(next), definitionChanged = nextHash !== row.canonicalHash;
	const nextRevision = definitionChanged ? current.revision + 1 : current.revision;
	const nextVersion = current.version + 1;
	if (definitionChanged) await tx.execute(sql`INSERT INTO field_definition_versions (group_key,revision,canonical_hash,definition,origin,created_at) VALUES (${groupKey},${nextRevision},${nextHash},${JSON.stringify(next)},'db',${(/* @__PURE__ */ new Date()).toISOString()})`);
	if (strategy.kind === "migrateValues") {
		await writeMigratedNodes(tx, groupKey, next, nextRevision, corpus, strategy.mappings, context);
		await migrateCurrentDocuments(tx, groupKey, nextRevision, corpus, strategy.mappings);
	} else if (strategy.kind === "purgeValues") {
		if (!destructive) throw new FieldsLifecycleError("backup-invalid", "destructive dependencies are required");
		const scopeHash = await fieldsRequestHash({
			definitionKind: "group",
			definitionKey: groupKey,
			strategy,
			authorizationPolicyVersion: migration.policyVersion,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			previewToken: impactToken,
			affectedCounts: corpus.counts
		});
		const backup = await verifyFieldsBackup(tx, {
			backupId: strategy.backupId,
			expectedScopeHash: scopeHash,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			counts: corpus.counts
		}, destructive.backups);
		const event = Object.freeze({
			operationId,
			principalId: authorized.principal.id,
			definitionKind: "group",
			definitionKey: groupKey,
			strategy: freezeStorage(strategy, "strategy"),
			authorizationPolicyVersion: migration.policyVersion,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			previewToken: impactToken,
			affectedCounts: corpus.counts,
			backup
		});
		await destructive.effects.audit.record(tx, event);
		await destructive.effects.outbox.enqueue(tx, event);
		await purgeGroupCorpus(tx, groupKey, corpus);
	}
	await tx.execute(sql`UPDATE field_group_definitions SET version=${nextVersion},active=${next.active},current_revision=${nextRevision},canonical_hash=${nextHash},definition=${JSON.stringify(next)},updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE key=${groupKey} AND version=${current.version}`);
	const result = Object.freeze({
		...next,
		origin: "db",
		version: nextVersion,
		revision: nextRevision,
		...current.shadowedDbVersion === void 0 ? {} : { shadowedDbVersion: current.shadowedDbVersion }
	});
	await writeFieldsReceipt(tx, {
		operationId,
		kind: "fields:apply-field-group-change",
		context: authorized,
		requestHash,
		result: Object.freeze({
			key: groupKey,
			version: nextVersion,
			revision: nextRevision
		})
	});
	return result;
}
async function normalizeCodeSnapshot(input) {
	if (typeof input.version !== "string" || input.version.length === 0 || input.version.length > 256) throw new FieldsLifecycleError("validation", "code registry version must be bounded", "version");
	const groups = [], groupKeys = /* @__PURE__ */ new Set();
	for (const raw of input.groups) {
		const group = defineFinalFieldGroup(raw);
		if (groupKeys.has(group.key)) throw new FieldsLifecycleError("validation", "duplicate code field-group key", group.key);
		groupKeys.add(group.key);
		groups.push(group);
	}
	const optionsModule = await import("./index.js").then((n) => n.n), optionsPages = [], optionKeys = /* @__PURE__ */ new Set();
	for (const raw of input.optionsPages) {
		const page = optionsModule.defineOptionsPage(raw);
		if (optionKeys.has(page.key)) throw new FieldsLifecycleError("validation", "duplicate code options-page key", page.key);
		optionKeys.add(page.key);
		optionsPages.push(page);
	}
	const blocksModule = await import("./index.js").then((n) => n.t), blocks = [], blockKeys = /* @__PURE__ */ new Set();
	for (const raw of input.blocks) {
		const block = blocksModule.defineFieldBlock(raw);
		if (blockKeys.has(block.key)) throw new FieldsLifecycleError("validation", "duplicate code block key", block.key);
		blockKeys.add(block.key);
		blocks.push(block);
	}
	const normalized = Object.freeze({
		version: input.version,
		canonicalHash: "",
		groups: Object.freeze(groups.sort((a, b) => a.key.localeCompare(b.key))),
		optionsPages: Object.freeze(optionsPages.sort((a, b) => a.key.localeCompare(b.key))),
		blocks: Object.freeze(blocks.sort((a, b) => a.key.localeCompare(b.key)))
	});
	const canonicalHash = await fieldsRequestHash({
		version: normalized.version,
		groups: normalized.groups,
		optionsPages: normalized.optionsPages,
		blocks: normalized.blocks
	});
	if (input.canonicalHash !== canonicalHash) throw new FieldsLifecycleError("validation", "code registry canonicalHash does not match normalized bytes", "canonicalHash");
	return Object.freeze({
		...normalized,
		canonicalHash
	});
}
async function currentFieldsCodeRegistryVersion(db) {
	return fieldsRequestHash({
		groups: (await finalGroupRows(db)).filter((row) => row.origin === "code").map((row) => ({
			key: row.key,
			version: Number(row.version),
			revision: Number(row.currentRevision),
			hash: row.canonicalHash,
			active: lifecycleBool(row.active)
		})),
		options: await lifecycleExecute(db, sql`SELECT key,version,current_revision AS revision,canonical_hash AS hash,active FROM field_options_definitions WHERE origin='code' ORDER BY key`),
		blocks: await lifecycleExecute(db, sql`SELECT key,version,current_revision AS revision,canonical_hash AS hash,active FROM field_block_definitions WHERE origin='code' ORDER BY key`)
	});
}
function strategyMapStorage(value) {
	return freezeStorage(value, "strategies");
}
function impactMetaStorage(value) {
	return freezeStorage(value, "impact");
}
function codePlanEncode(plan) {
	const bytes = new TextEncoder().encode(JSON.stringify(plan));
	if (bytes.byteLength > 1048576) throw new FieldsLifecycleError("validation", "code reconciliation plan exceeds token limit");
	const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
	return fieldsRequestHash(plan).then((hash) => `${hex}.${hash}`);
}
async function codePlanDecode(token) {
	const match = /^([a-f0-9]+)\.([a-f0-9]{64})$/i.exec(token);
	if (!match || match[1].length % 2 || match[1].length > 2097152) throw new FieldsLifecycleError("validation", "code reconciliation token is invalid");
	let value;
	try {
		value = JSON.parse(new TextDecoder().decode(new Uint8Array(match[1].match(/../g).map((pair) => Number.parseInt(pair, 16)))));
	} catch {
		throw new FieldsLifecycleError("validation", "code reconciliation token is invalid");
	}
	if (typeof value !== "object" || value === null || Array.isArray(value) || await fieldsRequestHash(value) !== match[2].toLowerCase()) throw new FieldsLifecycleError("validation", "code reconciliation token integrity check failed");
	const plan = value;
	if (plan.kind !== "fields-code-reconciliation") throw new FieldsLifecycleError("validation", "code reconciliation token has wrong kind");
	return plan;
}
function numericCounts(value) {
	return Object.values(value).reduce((sum, count) => sum + count, 0);
}
function metaPublicGroup(meta, token) {
	return Object.freeze({
		token,
		groupKey: meta.key,
		expectedVersion: meta.expectedVersion,
		authorizationPolicyVersion: meta.policyVersion,
		valueCorpusVersion: meta.corpusVersion,
		valueCorpusHash: meta.corpusHash,
		affectedCounts: meta.counts,
		incompatibilities: meta.incompatibilities
	});
}
function metaPublicOptions(meta, token) {
	return Object.freeze({
		token,
		pageKey: meta.key,
		expectedVersion: meta.expectedVersion,
		authorizationPolicyVersion: meta.policyVersion,
		valueCorpusVersion: meta.corpusVersion,
		valueCorpusHash: meta.corpusHash,
		affectedCounts: meta.counts
	});
}
function metaPublicBlock(meta, token) {
	return Object.freeze({
		token,
		blockKey: meta.key,
		expectedVersion: meta.expectedVersion,
		authorizationPolicyVersion: meta.policyVersion,
		documentCorpusVersion: meta.corpusVersion,
		documentCorpusHash: meta.corpusHash,
		affectedDocuments: meta.counts.documents ?? 0,
		affectedDefinitionVersions: meta.counts.definitionVersions ?? 0,
		incompatibilities: meta.incompatibilities
	});
}
async function reconciliationImpactToken(meta, strategy, nextDefinition) {
	return fieldsRequestHash({
		kind: "fields-code-definition-impact",
		meta,
		strategy,
		nextDefinition
	});
}
async function previewFieldsCodeReconciliation(db, context, input) {
	await assertFieldsAuthorized(context, "manageDefinitions", {
		entityType: "fields-definition",
		entityId: "*"
	});
	const fromVersion = await currentFieldsCodeRegistryVersion(db);
	if (input.expectedCurrentVersion !== fromVersion) throw new FieldsLifecycleError("stale-version", "code fields registry version changed");
	const next = await normalizeCodeSnapshot(input.next);
	const nextGroups = new Map(next.groups.map((group) => [group.key, group]));
	const nextOptions = new Map(next.optionsPages.map((page) => [page.key, page]));
	const nextBlocks = new Map(next.blocks.map((block) => [block.key, block]));
	const currentGroups = await finalGroupRows(db);
	const optionsModule = await import("./index.js").then((n) => n.n);
	const blocksModule = await import("./index.js").then((n) => n.t);
	const currentOptions = await optionsModule.__optionsLifecycleInternals.readOptionRows(db);
	const currentBlocks = await blocksModule.__fieldBlockLifecycleInternals.readCurrentRows(db);
	const effectiveGroups = /* @__PURE__ */ new Set();
	for (const row of currentGroups) if (lifecycleBool(row.active) && row.origin !== "code" && !nextGroups.has(row.key)) effectiveGroups.add(row.key);
	for (const group of next.groups) {
		if (group.active !== true) throw new FieldsLifecycleError("validation", "code field groups must be active", group.key);
		effectiveGroups.add(group.key);
	}
	for (const block of next.blocks) for (const groupKey of block.fieldGroupKeys) if (!effectiveGroups.has(groupKey)) throw new FieldsLifecycleError("validation", "code block references missing effective field group", `${block.key}:${groupKey}`);
	const effectiveOptionRows = currentOptions.filter((row) => row.origin !== "code" && !nextOptions.has(row.key));
	optionsModule.__optionsLifecycleInternals.mergePages(effectiveOptionRows, next.optionsPages);
	const effectiveBlockRows = currentBlocks.filter((row) => row.origin !== "code" && !nextBlocks.has(row.key));
	const mergedBlocks = blocksModule.__fieldBlockLifecycleInternals.mergeCurrent(effectiveBlockRows, next.blocks);
	blocksModule.__fieldBlockLifecycleInternals.validateDefinitionGraph(mergedBlocks.blocks);
	const groupImpacts = [];
	const optionsImpacts = [];
	const blockImpacts = [];
	const metas = [];
	const authorityTypes = /* @__PURE__ */ new Set();
	for (const row of currentGroups) {
		const nextDefinition = nextGroups.get(row.key);
		const removing = row.origin === "code" && nextDefinition === void 0;
		const nextHash = nextDefinition ? await canonicalFieldGroupHash(codeGroupDefinition(nextDefinition)) : void 0;
		const changing = nextDefinition !== void 0 && (row.origin !== "code" || row.canonicalHash !== nextHash || !lifecycleBool(row.active));
		if (!removing && !changing) continue;
		const current = resolvedFinalGroup(row);
		const proposed = nextDefinition ? codeGroupDefinition(nextDefinition) : parseFieldGroupDefinition({
			...codeGroupDefinition(current),
			active: false
		});
		const corpus = await groupCorpus(db, row.key);
		const migration = await assertDefinitionMigration(context, corpus.entityTypes.length ? corpus.entityTypes : ["fields-definition"]);
		for (const type of corpus.entityTypes) authorityTypes.add(type);
		const incompatibilities = await groupIncompatibilities(current, proposed, corpus);
		const strategy = normalizeGroupStrategy(input.groupStrategies[row.key] ?? { kind: "reject" });
		if (incompatibilities.length > 0 && input.groupStrategies[row.key] === void 0) throw new FieldsLifecycleError("validation", `code field group ${row.key} requires an explicit migration strategy`);
		if (strategy.kind === "reject" && incompatibilities.length > 0) {}
		const meta = Object.freeze({
			kind: "group",
			key: row.key,
			expectedVersion: Number(row.version),
			policyVersion: migration.policyVersion,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			counts: corpus.counts,
			incompatibilities,
			entityTypes: corpus.entityTypes
		});
		metas.push(meta);
		groupImpacts.push(metaPublicGroup(meta, await reconciliationImpactToken(meta, strategy, proposed)));
	}
	for (const row of currentOptions) {
		const nextDefinition = nextOptions.get(row.key);
		const removing = row.origin === "code" && nextDefinition === void 0;
		const normalizedNext = nextDefinition ? optionsModule.__optionsLifecycleInternals.normalizeOptionsPage(nextDefinition) : null;
		const nextHash = normalizedNext ? await fieldsRequestHash(normalizedNext) : void 0;
		const changing = normalizedNext !== null && (row.origin !== "code" || row.canonicalHash !== nextHash || !lifecycleBool(row.active));
		if (!removing && !changing) continue;
		const corpus = await optionsModule.__optionsLifecycleInternals.optionsCorpus(db, row.key);
		const migration = await assertDefinitionMigration(context, ["options"]);
		authorityTypes.add("options");
		const strategy = input.optionsStrategies[row.key] ?? { kind: "retain" };
		if (strategy.kind !== "retain" && strategy.kind !== "purge") throw new FieldsLifecycleError("validation", "unknown options reconciliation strategy", row.key);
		if (removing && numericCounts(corpus.counts) > 0 && input.optionsStrategies[row.key] === void 0) throw new FieldsLifecycleError("validation", `code options page ${row.key} requires an explicit deactivation strategy`);
		const incompatibilities = Object.freeze(removing && numericCounts(corpus.counts) > 0 ? ["options-page-in-use"] : []);
		const meta = Object.freeze({
			kind: "optionsPage",
			key: row.key,
			expectedVersion: Number(row.version),
			policyVersion: migration.policyVersion,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			counts: corpus.counts,
			incompatibilities,
			entityTypes: Object.freeze(["options"])
		});
		metas.push(meta);
		optionsImpacts.push(metaPublicOptions(meta, await reconciliationImpactToken(meta, strategy, normalizedNext)));
	}
	for (const row of currentBlocks) {
		const nextDefinition = nextBlocks.get(row.key);
		const removing = row.origin === "code" && nextDefinition === void 0;
		const normalizedNext = nextDefinition ? blocksModule.__fieldBlockLifecycleInternals.normalizeDefinition(nextDefinition) : null;
		const nextHash = normalizedNext ? await fieldsRequestHash(normalizedNext) : void 0;
		const changing = normalizedNext !== null && (row.origin !== "code" || row.canonicalHash !== nextHash || !lifecycleBool(row.active));
		if (!removing && !changing) continue;
		const current = blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock ? await blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock(db, row.key) : null;
		if (!current) throw new FieldsLifecycleError("integrity", "current block disappeared during reconciliation preview");
		const corpus = await blocksModule.__fieldBlockLifecycleInternals.blockCorpus(db, row.key);
		const migration = await assertDefinitionMigration(context, corpus.entityTypes.length ? corpus.entityTypes : ["fields-definition"]);
		for (const type of corpus.entityTypes) authorityTypes.add(type);
		const strategy = input.blockStrategies[row.key] ?? { kind: "reject" };
		const replacement = strategy.kind === "mapDefinition" ? await blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock(db, strategy.replacementKey) : null;
		const incompatibilities = [...blocksModule.__fieldBlockLifecycleInternals.blockChangeIncompatibilities(current.block, normalizedNext, corpus, strategy, removing, false, replacement?.block)];
		if (incompatibilities.length > 0 && input.blockStrategies[row.key] === void 0) throw new FieldsLifecycleError("validation", `code block ${row.key} requires an explicit change strategy`);
		const counts = Object.freeze({
			documents: corpus.entries.length,
			definitionVersions: corpus.affectedDefinitionVersions
		});
		const meta = Object.freeze({
			kind: "block",
			key: row.key,
			expectedVersion: Number(row.version),
			policyVersion: migration.policyVersion,
			corpusVersion: corpus.version,
			corpusHash: corpus.hash,
			counts,
			incompatibilities: Object.freeze([...new Set(incompatibilities)].sort()),
			entityTypes: corpus.entityTypes
		});
		metas.push(meta);
		blockImpacts.push(metaPublicBlock(meta, await reconciliationImpactToken(meta, strategy, normalizedNext)));
	}
	const plan = Object.freeze({
		kind: "fields-code-reconciliation",
		fromVersion,
		nextCanonicalHash: next.canonicalHash,
		next: freezeStorage(next, "next"),
		groupStrategies: strategyMapStorage(input.groupStrategies),
		optionsStrategies: strategyMapStorage(input.optionsStrategies),
		blockStrategies: strategyMapStorage(input.blockStrategies),
		impacts: Object.freeze(metas.map(impactMetaStorage)),
		authorityTypes: Object.freeze([...authorityTypes].sort())
	});
	return Object.freeze({
		token: await codePlanEncode(plan),
		fromVersion,
		nextCanonicalHash: next.canonicalHash,
		groupImpacts: Object.freeze(groupImpacts),
		optionsImpacts: Object.freeze(optionsImpacts),
		blockImpacts: Object.freeze(blockImpacts)
	});
}
function parseImpactMeta(value) {
	const record = lifecycleRecord(value, "reconciliation impact");
	if (record.kind !== "group" && record.kind !== "optionsPage" && record.kind !== "block") throw new FieldsLifecycleError("integrity", "reconciliation impact kind is invalid");
	const key = typeof record.key === "string" ? record.key : "";
	const expectedVersion = Number(record.expectedVersion);
	const policyVersion = typeof record.policyVersion === "string" ? record.policyVersion : "";
	const corpusVersion = typeof record.corpusVersion === "string" ? record.corpusVersion : "";
	const corpusHash = typeof record.corpusHash === "string" ? record.corpusHash : "";
	if (!key || key.length > 256 || !Number.isSafeInteger(expectedVersion) || expectedVersion < 1 || !policyVersion || !corpusVersion || !corpusHash) throw new FieldsLifecycleError("integrity", "reconciliation impact identity is malformed");
	const countsRecord = lifecycleRecord(record.counts, "reconciliation impact counts"), counts = {};
	for (const [name, raw] of Object.entries(countsRecord)) {
		const number = Number(raw);
		if (!Number.isSafeInteger(number) || number < 0) throw new FieldsLifecycleError("integrity", "reconciliation impact count is invalid");
		counts[name] = number;
	}
	if (!Array.isArray(record.incompatibilities) || !record.incompatibilities.every((item) => typeof item === "string")) throw new FieldsLifecycleError("integrity", "reconciliation incompatibilities are malformed");
	if (!Array.isArray(record.entityTypes) || !record.entityTypes.every((item) => typeof item === "string" && item.length > 0 && item.length <= 256)) throw new FieldsLifecycleError("integrity", "reconciliation entity types are malformed");
	return Object.freeze({
		kind: record.kind,
		key,
		expectedVersion,
		policyVersion,
		corpusVersion,
		corpusHash,
		counts: Object.freeze(counts),
		incompatibilities: Object.freeze([...record.incompatibilities]),
		entityTypes: Object.freeze([...record.entityTypes])
	});
}
function optionsStrategyAt(map, key) {
	const strategy = map[key] ?? { kind: "retain" };
	if (strategy.kind !== "retain" && strategy.kind !== "purge") throw new FieldsLifecycleError("validation", "unknown options reconciliation strategy", key);
	if (strategy.kind === "purge" && (!strategy.backupId || strategy.backupId.length > 512)) throw new FieldsLifecycleError("validation", "options purge backupId is invalid", key);
	return Object.freeze({ ...strategy });
}
function blockStrategyAt(map, key) {
	const strategy = map[key] ?? { kind: "reject" };
	if (strategy.kind === "reject" || strategy.kind === "retainUnknown") return Object.freeze({ kind: strategy.kind });
	if (strategy.kind === "mapDefinition") {
		if (!/^[a-z][a-z0-9_-]*$/.test(strategy.replacementKey)) throw new FieldsLifecycleError("validation", "block replacement key is invalid", key);
		return Object.freeze({
			kind: "mapDefinition",
			replacementKey: strategy.replacementKey
		});
	}
	if (strategy.kind === "purgeWithBackup") {
		if (!strategy.backupId || strategy.backupId.length > 512) throw new FieldsLifecycleError("validation", "block purge backupId is invalid", key);
		return Object.freeze({
			kind: "purgeWithBackup",
			backupId: strategy.backupId
		});
	}
	throw new FieldsLifecycleError("validation", "unknown block reconciliation strategy", key);
}
async function applyFieldsCodeReconciliation(tx, context, input, effects, destructive) {
	assertActiveFieldsTransaction(tx);
	const authorized = await assertFieldsAuthorized(context, "manageDefinitions", {
		entityType: "fields-definition",
		entityId: "*"
	});
	const plan = await codePlanDecode(input.planToken);
	const next = await normalizeCodeSnapshot(input.next);
	if (next.canonicalHash !== plan.nextCanonicalHash || await fieldsRequestHash(freezeStorage(next, "next")) !== await fieldsRequestHash(plan.next)) throw new FieldsLifecycleError("operation-conflict", "next code registry differs from preview");
	if (await fieldsRequestHash(strategyMapStorage(input.groupStrategies)) !== await fieldsRequestHash(plan.groupStrategies) || await fieldsRequestHash(strategyMapStorage(input.optionsStrategies)) !== await fieldsRequestHash(plan.optionsStrategies) || await fieldsRequestHash(strategyMapStorage(input.blockStrategies)) !== await fieldsRequestHash(plan.blockStrategies)) throw new FieldsLifecycleError("operation-conflict", "code reconciliation strategies differ from preview");
	const requestHash = await fieldsRequestHash({
		planToken: input.planToken,
		nextCanonicalHash: next.canonicalHash,
		groupStrategies: input.groupStrategies,
		optionsStrategies: input.optionsStrategies,
		blockStrategies: input.blockStrategies
	});
	const replay = await readFieldsReceipt(tx, input.operationId);
	if (replay) {
		assertReceiptReplay(replay, {
			kind: "fields:reconcile-code",
			context: authorized,
			requestHash
		});
		return next;
	}
	if (await currentFieldsCodeRegistryVersion(tx) !== plan.fromVersion) throw new FieldsLifecycleError("corpus-drift", "code fields registry changed since preview");
	const nextGroups = new Map(next.groups.map((group) => [group.key, group]));
	const nextOptions = new Map(next.optionsPages.map((page) => [page.key, page]));
	const nextBlocks = new Map(next.blocks.map((block) => [block.key, block]));
	const metas = plan.impacts.map(parseImpactMeta);
	const optionsModule = await import("./index.js").then((n) => n.n);
	const blocksModule = await import("./index.js").then((n) => n.t);
	const plannedAuthorityTypes = [...new Set(metas.flatMap((meta) => meta.entityTypes))].sort();
	if (JSON.stringify(plannedAuthorityTypes) !== JSON.stringify([...plan.authorityTypes].sort())) throw new FieldsLifecycleError("integrity", "code reconciliation authority scope is inconsistent");
	const graphGroups = await finalGroupRows(tx);
	const effectiveGroups = /* @__PURE__ */ new Set();
	for (const row of graphGroups) if (lifecycleBool(row.active) && row.origin !== "code" && !nextGroups.has(row.key)) effectiveGroups.add(row.key);
	for (const group of next.groups) effectiveGroups.add(group.key);
	for (const block of next.blocks) for (const groupKey of block.fieldGroupKeys) if (!effectiveGroups.has(groupKey)) throw new FieldsLifecycleError("corpus-drift", `effective field group ${groupKey} disappeared after preview`);
	const graphOptions = await optionsModule.__optionsLifecycleInternals.readOptionRows(tx);
	optionsModule.__optionsLifecycleInternals.mergePages(graphOptions.filter((row) => row.origin !== "code" && !nextOptions.has(row.key)), next.optionsPages);
	const graphBlocks = await blocksModule.__fieldBlockLifecycleInternals.readCurrentRows(tx);
	const graphMergedBlocks = blocksModule.__fieldBlockLifecycleInternals.mergeCurrent(graphBlocks.filter((row) => row.origin !== "code" && !nextBlocks.has(row.key)), next.blocks);
	blocksModule.__fieldBlockLifecycleInternals.validateDefinitionGraph(graphMergedBlocks.blocks);
	const verifiedGroups = [];
	const verifiedOptions = [];
	const verifiedBlocks = [];
	const corpusHashes = [];
	const affectedCounts = {};
	for (const meta of metas) {
		if ((await assertDefinitionMigration(context, meta.entityTypes.length ? meta.entityTypes : ["fields-definition"])).policyVersion !== meta.policyVersion) throw new FieldsLifecycleError("corpus-drift", `authorization policy changed for ${meta.kind}:${meta.key}`);
		corpusHashes.push(meta.corpusHash);
		for (const [metric, count] of Object.entries(meta.counts)) affectedCounts[`${meta.kind}:${meta.key}:${metric}`] = count;
		if (meta.kind === "group") {
			const row = await finalGroupRow(tx, meta.key);
			if (!row || Number(row.version) !== meta.expectedVersion) throw new FieldsLifecycleError("corpus-drift", `field group ${meta.key} changed since preview`);
			const current = resolvedFinalGroup(row), nextCode = nextGroups.get(meta.key), nextDefinition = nextCode ? codeGroupDefinition(nextCode) : null;
			const proposed = nextDefinition ?? parseFieldGroupDefinition({
				...codeGroupDefinition(current),
				active: false
			});
			const corpus = await groupCorpus(tx, meta.key);
			if (corpus.version !== meta.corpusVersion || corpus.hash !== meta.corpusHash || !groupCountsEqual(corpus.counts, meta.counts) || JSON.stringify(corpus.entityTypes) !== JSON.stringify(meta.entityTypes)) throw new FieldsLifecycleError("corpus-drift", `field group ${meta.key} corpus changed since preview`);
			const incompatibilities = await groupIncompatibilities(current, proposed, corpus);
			if (JSON.stringify([...incompatibilities].sort()) !== JSON.stringify([...meta.incompatibilities].sort())) throw new FieldsLifecycleError("corpus-drift", `field group ${meta.key} compatibility changed since preview`);
			const strategy = normalizeGroupStrategy(input.groupStrategies[meta.key] ?? { kind: "reject" });
			if (strategy.kind === "reject" && incompatibilities.length > 0) throw new FieldsLifecycleError("validation", `field group ${meta.key} has unresolved incompatibilities`);
			if (strategy.kind === "migrateValues") ensureMappings(current, proposed, strategy, incompatibilities);
			const impactToken = await reconciliationImpactToken(meta, strategy, proposed);
			let backup;
			if (strategy.kind === "purgeValues") {
				if (!destructive) throw new FieldsLifecycleError("backup-invalid", "destructive dependencies are required");
				const scopeHash = await fieldsRequestHash({
					definitionKind: "group",
					definitionKey: meta.key,
					strategy,
					authorizationPolicyVersion: meta.policyVersion,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					previewToken: impactToken,
					affectedCounts: meta.counts
				});
				backup = await verifyFieldsBackup(tx, {
					backupId: strategy.backupId,
					expectedScopeHash: scopeHash,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					counts: meta.counts
				}, destructive.backups);
			}
			verifiedGroups.push(Object.freeze({
				meta,
				row,
				current,
				next: nextDefinition,
				strategy,
				corpus,
				impactToken,
				...backup ? { backup } : {}
			}));
		} else if (meta.kind === "optionsPage") {
			const current = await optionsModule.__optionsLifecycleInternals.readDbPage(tx, meta.key);
			if (!current || current.page.version !== meta.expectedVersion) throw new FieldsLifecycleError("corpus-drift", `options page ${meta.key} changed since preview`);
			const corpus = await optionsModule.__optionsLifecycleInternals.optionsCorpus(tx, meta.key);
			if (corpus.version !== meta.corpusVersion || corpus.hash !== meta.corpusHash || !groupCountsEqual(corpus.counts, meta.counts)) throw new FieldsLifecycleError("corpus-drift", `options page ${meta.key} corpus changed since preview`);
			const nextCode = nextOptions.get(meta.key) ?? null;
			const incompatibilities = Object.freeze(!nextCode && numericCounts(corpus.counts) > 0 ? ["options-page-in-use"] : []);
			if (JSON.stringify(incompatibilities) !== JSON.stringify(meta.incompatibilities)) throw new FieldsLifecycleError("corpus-drift", `options page ${meta.key} compatibility changed since preview`);
			const strategy = optionsStrategyAt(input.optionsStrategies, meta.key);
			const impactToken = await reconciliationImpactToken(meta, strategy, nextCode ? optionsModule.__optionsLifecycleInternals.normalizeOptionsPage(nextCode) : null);
			let backup;
			if (strategy.kind === "purge") {
				if (!destructive) throw new FieldsLifecycleError("backup-invalid", "destructive dependencies are required");
				const scopeHash = await fieldsRequestHash({
					definitionKind: "optionsPage",
					definitionKey: meta.key,
					strategy,
					authorizationPolicyVersion: meta.policyVersion,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					previewToken: impactToken,
					affectedCounts: meta.counts
				});
				backup = await verifyFieldsBackup(tx, {
					backupId: strategy.backupId,
					expectedScopeHash: scopeHash,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					counts: meta.counts
				}, destructive.backups);
			}
			verifiedOptions.push(Object.freeze({
				meta,
				row: current.row,
				next: nextCode,
				strategy,
				corpus,
				impactToken,
				...backup ? { backup } : {}
			}));
		} else {
			const current = await blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock(tx, meta.key);
			if (!current || current.block.version !== meta.expectedVersion) throw new FieldsLifecycleError("corpus-drift", `block ${meta.key} changed since preview`);
			const corpus = await blocksModule.__fieldBlockLifecycleInternals.blockCorpus(tx, meta.key);
			if (corpus.version !== meta.corpusVersion || corpus.hash !== meta.corpusHash || (meta.counts.documents ?? 0) !== corpus.entries.length || (meta.counts.definitionVersions ?? 0) !== corpus.affectedDefinitionVersions || JSON.stringify(corpus.entityTypes) !== JSON.stringify(meta.entityTypes)) throw new FieldsLifecycleError("corpus-drift", `block ${meta.key} corpus changed since preview`);
			const nextCode = nextBlocks.get(meta.key) ?? null, strategy = blockStrategyAt(input.blockStrategies, meta.key);
			const replacement = strategy.kind === "mapDefinition" ? await blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock(tx, strategy.replacementKey) : null;
			const nextDefinition = nextCode ? blocksModule.__fieldBlockLifecycleInternals.normalizeDefinition(nextCode) : null;
			const incompatibilities = [...blocksModule.__fieldBlockLifecycleInternals.blockChangeIncompatibilities(current.block, nextDefinition, corpus, strategy, nextCode === null, false, replacement?.block)];
			if (strategy.kind === "mapDefinition" && replacement) {
				if (JSON.stringify(replacement.block.parent ?? []) !== JSON.stringify(current.block.parent ?? [])) incompatibilities.push("replacement parent constraints differ from source");
				if (JSON.stringify(replacement.block.ancestor ?? []) !== JSON.stringify(current.block.ancestor ?? [])) incompatibilities.push("replacement ancestor constraints differ from source");
				if (replacement.block.supports?.innerBlocks !== current.block.supports?.innerBlocks) incompatibilities.push("replacement inner-block support differs from source");
			}
			const normalizedIncompatibilities = [...new Set(incompatibilities)].sort();
			if (JSON.stringify(normalizedIncompatibilities) !== JSON.stringify([...meta.incompatibilities].sort())) throw new FieldsLifecycleError("corpus-drift", `block ${meta.key} compatibility changed since preview`);
			if (normalizedIncompatibilities.length > 0) throw new FieldsLifecycleError("validation", `block ${meta.key} has unresolved incompatibilities: ${normalizedIncompatibilities.join("; ")}`);
			const impactToken = await reconciliationImpactToken(meta, strategy, nextDefinition);
			let backup;
			if (strategy.kind === "purgeWithBackup") {
				if (!destructive) throw new FieldsLifecycleError("backup-invalid", "destructive dependencies are required");
				const scopeHash = await fieldsRequestHash({
					definitionKind: "block",
					definitionKey: meta.key,
					strategy,
					authorizationPolicyVersion: meta.policyVersion,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					previewToken: impactToken,
					affectedCounts: meta.counts
				});
				backup = await verifyFieldsBackup(tx, {
					backupId: strategy.backupId,
					expectedScopeHash: scopeHash,
					corpusVersion: meta.corpusVersion,
					corpusHash: meta.corpusHash,
					counts: meta.counts
				}, destructive.backups);
			}
			verifiedBlocks.push(Object.freeze({
				meta,
				current,
				next: nextCode,
				strategy,
				corpus,
				replacement,
				impactToken,
				...backup ? { backup } : {}
			}));
		}
	}
	for (const item of verifiedGroups) {
		const proposed = item.next ?? parseFieldGroupDefinition({
			...codeGroupDefinition(item.current),
			active: false
		});
		const nextHash = await canonicalFieldGroupHash(proposed);
		const nextRevision = item.next && (item.row.origin !== "code" || item.row.canonicalHash !== nextHash) ? Number(item.row.currentRevision) + 1 : Number(item.row.currentRevision);
		if (item.strategy.kind === "migrateValues") {
			await writeMigratedNodes(tx, item.meta.key, proposed, nextRevision, item.corpus, item.strategy.mappings, context);
			await migrateCurrentDocuments(tx, item.meta.key, nextRevision, item.corpus, item.strategy.mappings);
		} else if (item.strategy.kind === "purgeValues") {
			if (!destructive || !item.backup) throw new FieldsLifecycleError("backup-invalid", "verified destructive dependencies disappeared");
			const event = Object.freeze({
				operationId: input.operationId,
				principalId: authorized.principal.id,
				definitionKind: "group",
				definitionKey: item.meta.key,
				strategy: freezeStorage(item.strategy, "strategy"),
				authorizationPolicyVersion: item.meta.policyVersion,
				corpusVersion: item.meta.corpusVersion,
				corpusHash: item.meta.corpusHash,
				previewToken: item.impactToken,
				affectedCounts: item.meta.counts,
				backup: item.backup
			});
			await destructive.effects.audit.record(tx, event);
			await destructive.effects.outbox.enqueue(tx, event);
			await purgeGroupCorpus(tx, item.meta.key, item.corpus);
		}
	}
	for (const item of verifiedOptions) {
		if (item.strategy.kind !== "purge") continue;
		if (!destructive || !item.backup) throw new FieldsLifecycleError("backup-invalid", "verified destructive dependencies disappeared");
		const event = Object.freeze({
			operationId: input.operationId,
			principalId: authorized.principal.id,
			definitionKind: "optionsPage",
			definitionKey: item.meta.key,
			strategy: freezeStorage(item.strategy, "strategy"),
			authorizationPolicyVersion: item.meta.policyVersion,
			corpusVersion: item.meta.corpusVersion,
			corpusHash: item.meta.corpusHash,
			previewToken: item.impactToken,
			affectedCounts: item.meta.counts,
			backup: item.backup
		});
		await destructive.effects.audit.record(tx, event);
		await destructive.effects.outbox.enqueue(tx, event);
		await tx.execute(sql`DELETE FROM field_value_nodes WHERE entity_type='options' AND entity_id=${item.meta.key}`);
		await tx.execute(sql`DELETE FROM field_revisions WHERE entity_type='options' AND entity_id=${item.meta.key}`);
	}
	for (const item of verifiedBlocks) if (item.strategy.kind === "mapDefinition") {
		if (!item.replacement) throw new FieldsLifecycleError("validation", "replacement block disappeared after verification");
		await blocksModule.__fieldBlockLifecycleInternals.applyBlockMap(tx, item.corpus, item.meta.key, item.replacement);
	} else if (item.strategy.kind === "purgeWithBackup") {
		if (!destructive || !item.backup) throw new FieldsLifecycleError("backup-invalid", "verified destructive dependencies disappeared");
		const event = Object.freeze({
			operationId: input.operationId,
			principalId: authorized.principal.id,
			definitionKind: "block",
			definitionKey: item.meta.key,
			strategy: freezeStorage(item.strategy, "strategy"),
			authorizationPolicyVersion: item.meta.policyVersion,
			corpusVersion: item.meta.corpusVersion,
			corpusHash: item.meta.corpusHash,
			previewToken: item.impactToken,
			affectedCounts: item.meta.counts,
			backup: item.backup
		});
		await destructive.effects.audit.record(tx, event);
		await destructive.effects.outbox.enqueue(tx, event);
		await blocksModule.__fieldBlockLifecycleInternals.purgeBlockCorpus(tx, item.corpus);
	}
	const changedKeys = [];
	const currentGroupRows = await finalGroupRows(tx);
	for (const code of next.groups) {
		const definition = codeGroupDefinition(code), canonicalHash = await canonicalFieldGroupHash(definition), existing = currentGroupRows.find((row) => row.key === definition.key), now = (/* @__PURE__ */ new Date()).toISOString();
		if (!existing) {
			await tx.execute(sql`INSERT INTO field_group_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${definition.key},'code',1,true,1,${canonicalHash},${JSON.stringify(definition)},${now},${now})`);
			await tx.execute(sql`INSERT INTO field_definition_versions (group_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},1,${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			changedKeys.push(`group:${definition.key}`);
		} else if (existing.origin !== "code" || existing.canonicalHash !== canonicalHash || !lifecycleBool(existing.active)) {
			const version = Number(existing.version) + 1;
			const revisionChanged = existing.origin !== "code" || existing.canonicalHash !== canonicalHash;
			const revision = Number(existing.currentRevision) + (revisionChanged ? 1 : 0);
			if (revisionChanged) await tx.execute(sql`INSERT INTO field_definition_versions (group_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},${revision},${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			const shadowed = existing.origin === "db" ? Number(existing.version) : existing.shadowedDbVersion;
			await tx.execute(sql`UPDATE field_group_definitions SET origin='code',version=${version},active=true,current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(definition)},shadowed_db_version=${shadowed},updated_at=${now} WHERE key=${definition.key}`);
			changedKeys.push(`group:${definition.key}`);
		}
	}
	for (const existing of currentGroupRows.filter((row) => row.origin === "code" && lifecycleBool(row.active) && !nextGroups.has(row.key))) {
		await tx.execute(sql`UPDATE field_group_definitions SET version=${Number(existing.version) + 1},active=false,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE key=${existing.key} AND version=${Number(existing.version)}`);
		changedKeys.push(`group:${existing.key}`);
	}
	const currentOptionRows = await optionsModule.__optionsLifecycleInternals.readOptionRows(tx);
	for (const code of next.optionsPages) {
		const definition = optionsModule.__optionsLifecycleInternals.normalizeOptionsPage(code), canonicalHash = await fieldsRequestHash(definition), existing = currentOptionRows.find((row) => row.key === definition.key), now = (/* @__PURE__ */ new Date()).toISOString();
		if (!existing) {
			await tx.execute(sql`INSERT INTO field_options_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${definition.key},'code',1,true,1,${canonicalHash},${JSON.stringify(definition)},${now},${now})`);
			await tx.execute(sql`INSERT INTO field_options_definition_versions (options_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},1,${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			changedKeys.push(`options:${definition.key}`);
		} else if (existing.origin !== "code" || existing.canonicalHash !== canonicalHash || !lifecycleBool(existing.active)) {
			const version = Number(existing.version) + 1, revisionChanged = existing.origin !== "code" || existing.canonicalHash !== canonicalHash, revision = Number(existing.currentRevision) + (revisionChanged ? 1 : 0);
			if (revisionChanged) await tx.execute(sql`INSERT INTO field_options_definition_versions (options_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},${revision},${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			const shadowed = existing.origin === "db" ? Number(existing.version) : existing.shadowedDbVersion;
			await tx.execute(sql`UPDATE field_options_definitions SET origin='code',version=${version},active=true,current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(definition)},shadowed_db_version=${shadowed},updated_at=${now} WHERE key=${definition.key}`);
			changedKeys.push(`options:${definition.key}`);
		}
	}
	for (const existing of currentOptionRows.filter((row) => row.origin === "code" && lifecycleBool(row.active) && !nextOptions.has(row.key))) {
		await tx.execute(sql`UPDATE field_options_definitions SET version=${Number(existing.version) + 1},active=false,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE key=${existing.key} AND version=${Number(existing.version)}`);
		changedKeys.push(`options:${existing.key}`);
	}
	const currentBlockRows = await blocksModule.__fieldBlockLifecycleInternals.readCurrentRows(tx);
	for (const code of next.blocks) {
		const definition = blocksModule.__fieldBlockLifecycleInternals.normalizeDefinition(code), canonicalHash = await fieldsRequestHash(definition), existing = currentBlockRows.find((row) => row.key === definition.key), now = (/* @__PURE__ */ new Date()).toISOString();
		if (!existing) {
			await tx.execute(sql`INSERT INTO field_block_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${definition.key},'code',1,true,1,${canonicalHash},${JSON.stringify(definition)},${now},${now})`);
			await tx.execute(sql`INSERT INTO field_block_definition_versions (block_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},1,${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			changedKeys.push(`block:${definition.key}`);
		} else if (existing.origin !== "code" || existing.canonicalHash !== canonicalHash || !lifecycleBool(existing.active)) {
			const version = Number(existing.version) + 1, revisionChanged = existing.origin !== "code" || existing.canonicalHash !== canonicalHash, revision = Number(existing.currentRevision) + (revisionChanged ? 1 : 0);
			if (revisionChanged) await tx.execute(sql`INSERT INTO field_block_definition_versions (block_key,revision,canonical_hash,definition,origin,created_at) VALUES (${definition.key},${revision},${canonicalHash},${JSON.stringify(definition)},'code',${now})`);
			const shadowed = existing.origin === "db" ? Number(existing.version) : existing.shadowedDbVersion;
			await tx.execute(sql`UPDATE field_block_definitions SET origin='code',version=${version},active=true,current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(definition)},shadowed_db_version=${shadowed},updated_at=${now} WHERE key=${definition.key}`);
			changedKeys.push(`block:${definition.key}`);
		}
	}
	for (const existing of currentBlockRows.filter((row) => row.origin === "code" && lifecycleBool(row.active) && !nextBlocks.has(row.key))) {
		await tx.execute(sql`UPDATE field_block_definitions SET version=${Number(existing.version) + 1},active=false,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE key=${existing.key} AND version=${Number(existing.version)}`);
		changedKeys.push(`block:${existing.key}`);
	}
	await writeFieldsReceipt(tx, {
		operationId: input.operationId,
		kind: "fields:reconcile-code",
		context: authorized,
		requestHash,
		result: freezeStorage(next, "result")
	});
	const event = Object.freeze({
		id: crypto.randomUUID(),
		version: 1,
		kind: "codeRegistryReconciled",
		operationId: input.operationId,
		principalId: authorized.principal.id,
		fromVersion: plan.fromVersion,
		toVersion: next.version,
		changedKeys: Object.freeze([...new Set(changedKeys)].sort()),
		strategiesHash: await fieldsRequestHash({
			groupStrategies: input.groupStrategies,
			optionsStrategies: input.optionsStrategies,
			blockStrategies: input.blockStrategies
		}),
		corpusHashes: Object.freeze([...new Set(corpusHashes)].sort()),
		affectedCounts: Object.freeze(affectedCounts)
	});
	await effects.audit(tx, event);
	await effects.enqueue(tx, event);
	return next;
}
function backupString(value, field, max = 512) {
	if (typeof value !== "string" || value.length === 0 || value.length > max) throw new FieldsLifecycleError("backup-invalid", `${field} must be a bounded non-empty string`);
	return value;
}
function backupRef(value, field) {
	const record = lifecycleRecord(value, field);
	return Object.freeze({
		entityType: backupString(record.entityType, `${field}.entityType`, 256),
		entityId: backupString(record.entityId, `${field}.entityId`, 512)
	});
}
function backupVersions(value, field) {
	const record = lifecycleRecord(value, field), output = {};
	for (const [key, raw] of Object.entries(record)) {
		const revision = Number(raw);
		if (!Number.isSafeInteger(revision) || revision < 1) throw new FieldsLifecycleError("backup-invalid", `${field}.${key} must be a positive revision`);
		output[key] = revision;
	}
	return Object.freeze(output);
}
function backupArray(value, field, max = 5e3) {
	if (value === void 0) return Object.freeze([]);
	if (!Array.isArray(value) || value.length > max) throw new FieldsLifecycleError("backup-invalid", `${field} must be a bounded array`);
	return value;
}
async function parseFieldsBackupPayload(value) {
	const root = lifecycleRecord(value, "backup payload");
	if (root.version !== 1) throw new FieldsLifecycleError("backup-invalid", "backup payload version must be 1");
	const groups = [], groupKeys = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.groupDefinitions, "groupDefinitions").entries()) {
		const item = lifecycleRecord(raw, `groupDefinitions.${index}`), definition = parseFieldGroupDefinition(item.definition), key = backupString(item.key, `groupDefinitions.${index}.key`, 128);
		if (definition.key !== key || groupKeys.has(key)) throw new FieldsLifecycleError("backup-invalid", "backup group definition identity is invalid");
		groupKeys.add(key);
		groups.push(Object.freeze({
			key,
			definition
		}));
	}
	const optionsModule = await import("./index.js").then((n) => n.n), options = [], optionKeys = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.optionsDefinitions, "optionsDefinitions").entries()) {
		const item = lifecycleRecord(raw, `optionsDefinitions.${index}`), key = backupString(item.key, `optionsDefinitions.${index}.key`, 128);
		const definition = optionsModule.__optionsLifecycleInternals.normalizeOptionsPage(item.definition);
		if (definition.key !== key || optionKeys.has(key) || typeof item.active !== "boolean") throw new FieldsLifecycleError("backup-invalid", "backup options definition identity is invalid");
		optionKeys.add(key);
		options.push(Object.freeze({
			key,
			definition,
			active: item.active
		}));
	}
	const blocksModule = await import("./index.js").then((n) => n.t), blocks = [], blockKeys = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.blockDefinitions, "blockDefinitions").entries()) {
		const item = lifecycleRecord(raw, `blockDefinitions.${index}`), key = backupString(item.key, `blockDefinitions.${index}.key`, 128);
		const definition = blocksModule.__fieldBlockLifecycleInternals.normalizeDefinition(item.definition);
		if (definition.key !== key || blockKeys.has(key) || typeof item.active !== "boolean") throw new FieldsLifecycleError("backup-invalid", "backup block definition identity is invalid");
		blockKeys.add(key);
		blocks.push(Object.freeze({
			key,
			definition,
			active: item.active
		}));
	}
	const values = [], valueKeys = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.values, "values", 2e4).entries()) {
		const item = lifecycleRecord(raw, `values.${index}`), ref = backupRef(item.ref, `values.${index}.ref`), groupKey = normalizedGroupKey(item.groupKey), definitionRevision = Number(item.definitionRevision);
		if (!Number.isSafeInteger(definitionRevision) || definitionRevision < 1) throw new FieldsLifecycleError("backup-invalid", "backup value definition revision is invalid");
		const identity = `${ref.entityType}\u0000${ref.entityId}\u0000${groupKey}`;
		if (valueKeys.has(identity)) throw new FieldsLifecycleError("backup-invalid", "backup contains duplicate value entity/group snapshot");
		valueKeys.add(identity);
		values.push(Object.freeze({
			ref,
			groupKey,
			definitionRevision,
			values: freezeStorage(item.values, `values.${index}.values`)
		}));
	}
	const blockDocuments = [], documentKeys = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.blockDocuments, "blockDocuments", 1e4).entries()) {
		const item = lifecycleRecord(raw, `blockDocuments.${index}`), ref = backupRef(item.ref, `blockDocuments.${index}.ref`), identity = `${ref.entityType}\u0000${ref.entityId}`;
		if (documentKeys.has(identity)) throw new FieldsLifecycleError("backup-invalid", "backup contains duplicate block document snapshot");
		documentKeys.add(identity);
		blockDocuments.push(Object.freeze({
			ref,
			document: freezeStorage(item.document, `blockDocuments.${index}.document`),
			definitionVersions: backupVersions(item.definitionVersions, `blockDocuments.${index}.definitionVersions`),
			parentRevisionId: backupString(item.parentRevisionId, `blockDocuments.${index}.parentRevisionId`)
		}));
	}
	const reusableBlocks = [], reusableIds = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.reusableBlocks, "reusableBlocks", 1e4).entries()) {
		const item = lifecycleRecord(raw, `reusableBlocks.${index}`), id = backupString(item.id, `reusableBlocks.${index}.id`);
		if (reusableIds.has(id)) throw new FieldsLifecycleError("backup-invalid", "backup contains duplicate reusable block");
		reusableIds.add(id);
		reusableBlocks.push(Object.freeze({
			id,
			document: freezeStorage(item.document, `reusableBlocks.${index}.document`),
			definitionVersions: backupVersions(item.definitionVersions, `reusableBlocks.${index}.definitionVersions`)
		}));
	}
	const revisions = [], revisionIds = /* @__PURE__ */ new Set();
	for (const [index, raw] of backupArray(root.revisions, "revisions", 2e4).entries()) {
		const item = lifecycleRecord(raw, `revisions.${index}`), id = backupString(item.id, `revisions.${index}.id`), ref = backupRef(item.ref, `revisions.${index}.ref`);
		if (revisionIds.has(id) || item.kind !== "revision" && item.kind !== "autosave") throw new FieldsLifecycleError("backup-invalid", "backup revision identity is invalid");
		revisionIds.add(id);
		const createdAt = backupString(item.createdAt, `revisions.${index}.createdAt`), date = new Date(createdAt);
		if (Number.isNaN(date.getTime())) throw new FieldsLifecycleError("backup-invalid", "backup revision timestamp is invalid");
		revisions.push(Object.freeze({
			id,
			ref,
			parentRevisionId: backupString(item.parentRevisionId, `revisions.${index}.parentRevisionId`),
			...item.parentAutosaveId === void 0 ? {} : { parentAutosaveId: backupString(item.parentAutosaveId, `revisions.${index}.parentAutosaveId`) },
			kind: item.kind,
			...item.retentionClass === void 0 ? {} : { retentionClass: backupString(item.retentionClass, `revisions.${index}.retentionClass`, 128) },
			definitionVersions: backupVersions(item.definitionVersions, `revisions.${index}.definitionVersions`),
			values: freezeStorage(item.values, `revisions.${index}.values`),
			...item.blockDocument === void 0 || item.blockDocument === null ? {} : { blockDocument: freezeStorage(item.blockDocument, `revisions.${index}.blockDocument`) },
			createdAt: date.toISOString(),
			createdBy: backupString(item.createdBy, `revisions.${index}.createdBy`),
			sourceVersion: backupString(item.sourceVersion, `revisions.${index}.sourceVersion`)
		}));
	}
	return Object.freeze({
		version: 1,
		...groups.length ? { groupDefinitions: Object.freeze(groups) } : {},
		...options.length ? { optionsDefinitions: Object.freeze(options) } : {},
		...blocks.length ? { blockDefinitions: Object.freeze(blocks) } : {},
		...values.length ? { values: Object.freeze(values) } : {},
		...blockDocuments.length ? { blockDocuments: Object.freeze(blockDocuments) } : {},
		...reusableBlocks.length ? { reusableBlocks: Object.freeze(reusableBlocks) } : {},
		...revisions.length ? { revisions: Object.freeze(revisions) } : {}
	});
}
function restoreTargetKey(ref, groupKey) {
	return `${ref.entityType}\u0000${ref.entityId}${groupKey === void 0 ? "" : `\u0000${groupKey}`}`;
}
async function fieldsBackupDestinationState(db, payload) {
	const groups = [];
	for (const item of [...payload.groupDefinitions ?? []].sort((a, b) => a.key.localeCompare(b.key))) {
		const row = await finalGroupRow(db, item.key);
		groups.push(freezeStorage(row ? {
			key: row.key,
			origin: row.origin,
			version: Number(row.version),
			active: lifecycleBool(row.active),
			revision: Number(row.currentRevision),
			hash: row.canonicalHash
		} : {
			key: item.key,
			missing: true
		}, "destination.group"));
	}
	const options = [];
	for (const item of [...payload.optionsDefinitions ?? []].sort((a, b) => a.key.localeCompare(b.key))) {
		const row = (await lifecycleExecute(db, sql`SELECT key,origin,version,active,current_revision AS revision,canonical_hash AS hash FROM field_options_definitions WHERE key=${item.key} LIMIT 1`))[0];
		options.push(freezeStorage(row ? {
			key: row.key,
			origin: row.origin,
			version: Number(row.version),
			active: lifecycleBool(row.active),
			revision: Number(row.revision),
			hash: row.hash
		} : {
			key: item.key,
			missing: true
		}, "destination.options"));
	}
	const blocks = [];
	for (const item of [...payload.blockDefinitions ?? []].sort((a, b) => a.key.localeCompare(b.key))) {
		const row = (await lifecycleExecute(db, sql`SELECT key,origin,version,active,current_revision AS revision,canonical_hash AS hash FROM field_block_definitions WHERE key=${item.key} LIMIT 1`))[0];
		blocks.push(freezeStorage(row ? {
			key: row.key,
			origin: row.origin,
			version: Number(row.version),
			active: lifecycleBool(row.active),
			revision: Number(row.revision),
			hash: row.hash
		} : {
			key: item.key,
			missing: true
		}, "destination.blocks"));
	}
	const values = [];
	for (const item of [...payload.values ?? []].sort((a, b) => restoreTargetKey(a.ref, a.groupKey).localeCompare(restoreTargetKey(b.ref, b.groupKey)))) {
		const rows = await lifecycleExecute(db, sql`SELECT node_id AS "nodeId",definition_revision AS "definitionRevision",field_key AS "fieldKey",path,parent_node_id AS "parentNodeId",row_id AS "rowId",layout_key AS "layoutKey",node_kind AS "nodeKind",ordinal,is_null AS "isNull",value_text AS "valueText",value_number AS "valueNumber",value_boolean AS "valueBoolean",value_date_time AS "valueDateTime",value_ref AS "valueRef",value_json AS "valueJson" FROM field_value_nodes WHERE entity_type=${item.ref.entityType} AND entity_id=${item.ref.entityId} AND group_key=${item.groupKey} ORDER BY path`);
		values.push(freezeStorage({
			ref: item.ref,
			groupKey: item.groupKey,
			rows
		}, "destination.values"));
	}
	const documents = [];
	for (const item of [...payload.blockDocuments ?? []].sort((a, b) => restoreTargetKey(a.ref).localeCompare(restoreTargetKey(b.ref)))) {
		const rows = await lifecycleExecute(db, sql`SELECT version,document,definition_versions AS "definitionVersions",parent_revision_id AS "parentRevisionId" FROM field_block_documents WHERE entity_type=${item.ref.entityType} AND entity_id=${item.ref.entityId} LIMIT 1`);
		documents.push(freezeStorage({
			ref: item.ref,
			current: rows[0] ?? null
		}, "destination.documents"));
	}
	const reusable = [];
	for (const item of [...payload.reusableBlocks ?? []].sort((a, b) => a.id.localeCompare(b.id))) {
		const rows = await lifecycleExecute(db, sql`SELECT id,version,document,definition_versions AS "definitionVersions",deleted_at AS "deletedAt" FROM field_reusable_blocks WHERE id=${item.id} LIMIT 1`);
		reusable.push(freezeStorage({
			id: item.id,
			current: rows[0] ?? null
		}, "destination.reusable"));
	}
	const revisions = [];
	for (const item of [...payload.revisions ?? []].sort((a, b) => a.id.localeCompare(b.id))) {
		const rows = await lifecycleExecute(db, sql`SELECT id,entity_type AS "entityType",entity_id AS "entityId",kind,parent_revision_id AS "parentRevisionId",parent_autosave_id AS "parentAutosaveId",definition_versions AS "definitionVersions","values" AS "values",block_document AS "blockDocument",source_version AS "sourceVersion" FROM field_revisions WHERE id=${item.id} LIMIT 1`);
		revisions.push(freezeStorage({
			id: item.id,
			current: rows[0] ?? null
		}, "destination.revisions"));
	}
	return Object.freeze({
		version: 1,
		groups: Object.freeze(groups),
		options: Object.freeze(options),
		blocks: Object.freeze(blocks),
		values: Object.freeze(values),
		documents: Object.freeze(documents),
		reusable: Object.freeze(reusable),
		revisions: Object.freeze(revisions)
	});
}
async function fieldsBackupDestinationHash(db, payload) {
	return fieldsRequestHash(await fieldsBackupDestinationState(db, payload));
}
function manifestsEqual(left, right) {
	return left.id === right.id && left.scopeHash === right.scopeHash && left.corpusVersion === right.corpusVersion && left.corpusHash === right.corpusHash && left.byteCount === right.byteCount && left.immutable === true && right.immutable === true && JSON.stringify(Object.entries(left.itemCounts).sort()) === JSON.stringify(Object.entries(right.itemCounts).sort());
}
function remapDefinitionVersions(value, groupRevisions, blockRevisions) {
	const out = { ...value };
	for (const [key, revision] of groupRevisions) {
		if (Object.prototype.hasOwnProperty.call(out, key)) out[key] = revision;
		if (Object.prototype.hasOwnProperty.call(out, `group:${key}`)) out[`group:${key}`] = revision;
	}
	for (const [key, revision] of blockRevisions) if (Object.prototype.hasOwnProperty.call(out, `block:${key}`)) out[`block:${key}`] = revision;
	return Object.freeze(out);
}
function remapBlockDocument(value, groupRevisions, blockRevisions) {
	const walk = (item) => {
		if (Array.isArray(item)) return item.map(walk);
		if (typeof item !== "object" || item === null) return item;
		const record = item, out = {};
		for (const [key, child] of Object.entries(record)) out[key] = walk(child);
		if (record.kind === "inline" && typeof record.type === "string" && blockRevisions.has(record.type)) out.blockDefinitionRevision = blockRevisions.get(record.type);
		if (typeof record.groupKey === "string" && groupRevisions.has(record.groupKey)) out.definitionRevision = groupRevisions.get(record.groupKey);
		return out;
	};
	return walk(value);
}
function fieldsContainPrivateCredential(fields, context) {
	for (const field of fields) {
		if (field.type === "password") return true;
		if (field.type === "group" || field.type === "repeater") {
			if (fieldsContainPrivateCredential(field.settings.fields, context)) return true;
		}
		if (field.type === "flexible") {
			for (const layout of field.settings.layouts) if (fieldsContainPrivateCredential(layout.fields, context)) return true;
		}
		if (field.type === "clone") {
			if (!context.cloneResolver) return true;
			if (fieldsContainPrivateCredential(context.cloneResolver.resolve(field), context)) return true;
		}
	}
	return false;
}
function backupPayloadEntityTypes(payload) {
	const types = /* @__PURE__ */ new Set();
	for (const item of payload.values ?? []) types.add(item.ref.entityType);
	for (const item of payload.blockDocuments ?? []) types.add(item.ref.entityType);
	for (const item of payload.revisions ?? []) types.add(item.ref.entityType);
	if ((payload.optionsDefinitions?.length ?? 0) > 0) types.add("options");
	if ((payload.reusableBlocks?.length ?? 0) > 0) types.add("reusableBlock");
	if (types.size === 0) types.add("fields-definition");
	return Object.freeze([...types].sort());
}
function restoredPayloadCounts(payload) {
	return Object.freeze({
		groupDefinitions: payload.groupDefinitions?.length ?? 0,
		optionsDefinitions: payload.optionsDefinitions?.length ?? 0,
		blockDefinitions: payload.blockDefinitions?.length ?? 0,
		values: payload.values?.length ?? 0,
		blockDocuments: payload.blockDocuments?.length ?? 0,
		reusableBlocks: payload.reusableBlocks?.length ?? 0,
		revisions: payload.revisions?.length ?? 0
	});
}
async function writeRestoredValueSnapshot(tx, item, definition, definitionRevision, context) {
	if (fieldsContainPrivateCredential(definition.fields, context)) throw new FieldsLifecycleError("capability-unavailable", "restoring current password-bearing values requires a private credential restore adapter");
	const values = await (await import("./index.js").then((n) => n.t)).__fieldBlockLifecycleInternals.validateBlockFieldMap(definition.fields, item.values, context, `backup.values.${definition.key}`);
	const ids = /* @__PURE__ */ new Map();
	const rows = encodeFieldValueNodes(definition, values, {
		entityType: item.ref.entityType,
		entityId: item.ref.entityId,
		definitionRevision,
		nodeIdForPath: (path) => {
			let id = ids.get(path);
			if (!id) {
				id = crypto.randomUUID();
				ids.set(path, id);
			}
			return id;
		},
		...context.cloneResolver ? { cloneResolver: { resolve: (field) => context.cloneResolver.resolve(field) } } : {}
	});
	await tx.execute(sql`DELETE FROM field_value_nodes WHERE entity_type=${item.ref.entityType} AND entity_id=${item.ref.entityId} AND group_key=${item.groupKey}`);
	for (const row of rows) await tx.execute(sql`
    INSERT INTO field_value_nodes
      (node_id,entity_type,entity_id,group_key,definition_revision,field_key,path,parent_node_id,row_id,layout_key,node_kind,ordinal,is_null,value_text,value_number,value_boolean,value_date_time,value_ref,value_json,created_at,updated_at)
    VALUES
      (${row.nodeId},${row.entityType},${row.entityId},${row.groupKey},${row.definitionRevision},${row.fieldKey},${row.path},${row.parentNodeId},${row.rowId},${row.layoutKey},${row.nodeKind},${row.ordinal},${row.isNull},${row.valueText},${row.valueNumber},${row.valueBoolean},${row.valueDateTime},${row.valueRef},${row.valueJson},${(/* @__PURE__ */ new Date()).toISOString()},${(/* @__PURE__ */ new Date()).toISOString()})
  `);
}
async function requireRestoredDefinitionVersions(db, versions) {
	const blocksModule = await import("./index.js").then((n) => n.t);
	for (const [identity, revision] of Object.entries(versions)) if (identity.startsWith("block:")) {
		if (!await blocksModule.__fieldBlockLifecycleInternals.readBlockVersion(db, identity.slice(6), revision)) throw new FieldsLifecycleError("backup-invalid", `restored snapshot references missing block definition ${identity}@${revision}`);
	} else {
		const groupKey = identity.startsWith("group:") ? identity.slice(6) : identity;
		try {
			await resolveFieldDefinitionVersion(db, groupKey, revision);
		} catch {
			throw new FieldsLifecycleError("backup-invalid", `restored snapshot references missing field definition ${groupKey}@${revision}`);
		}
	}
}
async function restoreFieldsBackup(tx, manifest, destinationCorpusHash, operationId, context, effects, backups) {
	assertActiveFieldsTransaction(tx);
	const authorized = await assertFieldsAuthorized(context, "manageDefinitions", {
		entityType: "fields-definition",
		entityId: manifest.id
	});
	let verified;
	try {
		verified = await backups.verify(tx, manifest.id, manifest.scopeHash, manifest.corpusVersion, manifest.corpusHash, manifest.itemCounts);
	} catch {
		throw new FieldsLifecycleError("backup-invalid", "backup manifest verification failed");
	}
	if (!manifestsEqual(manifest, verified)) throw new FieldsLifecycleError("backup-invalid", "backup manifest identity changed");
	let snapshot;
	try {
		snapshot = await backups.read(tx, verified);
	} catch {
		throw new FieldsLifecycleError("backup-invalid", "backup payload could not be read");
	}
	if (!snapshot || !manifestsEqual(snapshot.manifest, verified)) throw new FieldsLifecycleError("backup-invalid", "backup payload manifest does not match verified manifest");
	const payload = await parseFieldsBackupPayload(snapshot.payload);
	const migration = await assertDefinitionMigration(context, backupPayloadEntityTypes(payload));
	const requestHash = await fieldsRequestHash({
		manifestId: manifest.id,
		destinationCorpusHash
	});
	const replay = await readFieldsReceipt(tx, operationId);
	if (replay) {
		assertReceiptReplay(replay, {
			kind: "fields:restore-backup",
			context: authorized,
			requestHash
		});
		const result = lifecycleRecord(replay.result, "backup restore receipt");
		if (result.operationId !== operationId || result.manifestId !== manifest.id || result.destinationCorpusHash !== destinationCorpusHash) throw new FieldsLifecycleError("integrity", "backup restore receipt is malformed");
		const restoredCounts = lifecycleRecord(result.restoredCounts, "backup restore counts"), counts = {};
		for (const [key, value] of Object.entries(restoredCounts)) {
			const number = Number(value);
			if (!Number.isSafeInteger(number) || number < 0) throw new FieldsLifecycleError("integrity", "backup restore receipt count is invalid");
			counts[key] = number;
		}
		return Object.freeze({
			operationId,
			manifestId: manifest.id,
			destinationCorpusHash,
			restoredCounts: Object.freeze(counts)
		});
	}
	if (await fieldsBackupDestinationHash(tx, payload) !== destinationCorpusHash) throw new FieldsLifecycleError("corpus-drift", "backup restore destination changed");
	const refs = /* @__PURE__ */ new Map();
	for (const item of payload.values ?? []) refs.set(restoreTargetKey(item.ref), item.ref);
	for (const item of payload.blockDocuments ?? []) refs.set(restoreTargetKey(item.ref), item.ref);
	for (const item of payload.revisions ?? []) refs.set(restoreTargetKey(item.ref), item.ref);
	for (const ref of refs.values()) await assertFieldsAuthorized(context, "write", ref);
	for (const item of payload.reusableBlocks ?? []) await assertFieldsAuthorized(context, "write", {
		entityType: "reusableBlock",
		entityId: item.id
	});
	const currentGroupRows = await finalGroupRows(tx);
	const availableGroups = new Set(currentGroupRows.filter((row) => lifecycleBool(row.active)).map((row) => row.key));
	for (const item of payload.groupDefinitions ?? []) availableGroups.add(item.key);
	const currentBlockRows = await lifecycleExecute(tx, sql`SELECT key,active FROM field_block_definitions`);
	const availableBlocks = new Set(currentBlockRows.filter((row) => lifecycleBool(row.active)).map((row) => String(row.key)));
	for (const item of payload.blockDefinitions ?? []) availableBlocks.add(item.key);
	for (const item of payload.blockDefinitions ?? []) {
		for (const groupKey of item.definition.fieldGroupKeys) if (!availableGroups.has(groupKey)) throw new FieldsLifecycleError("backup-invalid", `backup block ${item.key} references missing field group ${groupKey}`);
		for (const parent of item.definition.parent ?? []) if (!availableBlocks.has(parent)) throw new FieldsLifecycleError("backup-invalid", `backup block ${item.key} references missing parent ${parent}`);
		for (const ancestor of item.definition.ancestor ?? []) if (!availableBlocks.has(ancestor)) throw new FieldsLifecycleError("backup-invalid", `backup block ${item.key} references missing ancestor ${ancestor}`);
	}
	const currentOptionsRows = await lifecycleExecute(tx, sql`SELECT key FROM field_options_definitions WHERE active=true`), availableOptions = new Set(currentOptionsRows.map((row) => String(row.key)));
	for (const item of payload.optionsDefinitions ?? []) availableOptions.add(item.key);
	for (const item of payload.optionsDefinitions ?? []) if (item.definition.parentKey && !availableOptions.has(item.definition.parentKey)) throw new FieldsLifecycleError("backup-invalid", `backup options page ${item.key} references missing parent ${item.definition.parentKey}`);
	const groupRevisions = /* @__PURE__ */ new Map(), blockRevisions = /* @__PURE__ */ new Map();
	for (const item of payload.groupDefinitions ?? []) {
		const existing = await finalGroupRow(tx, item.key), canonicalHash = await canonicalFieldGroupHash(item.definition), revision = existing ? Number(existing.currentRevision) + 1 : 1, version = existing ? Number(existing.version) + 1 : 1, now = (/* @__PURE__ */ new Date()).toISOString();
		await tx.execute(sql`INSERT INTO field_definition_versions (group_key,revision,canonical_hash,definition,origin,created_at) VALUES (${item.key},${revision},${canonicalHash},${JSON.stringify(item.definition)},'db',${now})`);
		if (existing) await tx.execute(sql`UPDATE field_group_definitions SET origin='db',version=${version},active=${item.definition.active},current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(item.definition)},shadowed_db_version=NULL,updated_at=${now} WHERE key=${item.key}`);
		else await tx.execute(sql`INSERT INTO field_group_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${item.key},'db',1,${item.definition.active},1,${canonicalHash},${JSON.stringify(item.definition)},${now},${now})`);
		groupRevisions.set(item.key, revision);
	}
	const optionsModule = await import("./index.js").then((n) => n.n);
	for (const item of payload.optionsDefinitions ?? []) {
		const definition = optionsModule.__optionsLifecycleInternals.normalizeOptionsPage(item.definition), canonicalHash = await fieldsRequestHash(definition), current = await optionsModule.__optionsLifecycleInternals.readDbPage(tx, item.key), revision = current ? Number(current.row.currentRevision) + 1 : 1, version = current ? Number(current.row.version) + 1 : 1, now = (/* @__PURE__ */ new Date()).toISOString();
		await tx.execute(sql`INSERT INTO field_options_definition_versions (options_key,revision,canonical_hash,definition,origin,created_at) VALUES (${item.key},${revision},${canonicalHash},${JSON.stringify(definition)},'db',${now})`);
		if (current) await tx.execute(sql`UPDATE field_options_definitions SET origin='db',version=${version},active=${item.active},current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(definition)},shadowed_db_version=NULL,updated_at=${now} WHERE key=${item.key}`);
		else await tx.execute(sql`INSERT INTO field_options_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${item.key},'db',1,${item.active},1,${canonicalHash},${JSON.stringify(definition)},${now},${now})`);
	}
	const blocksModule = await import("./index.js").then((n) => n.t);
	for (const item of payload.blockDefinitions ?? []) {
		const definition = blocksModule.__fieldBlockLifecycleInternals.normalizeDefinition(item.definition), canonicalHash = await fieldsRequestHash(definition), current = await blocksModule.__fieldBlockLifecycleInternals.readCurrentBlock(tx, item.key), revision = current ? Number(current.row.currentRevision) + 1 : 1, version = current ? Number(current.row.version) + 1 : 1, now = (/* @__PURE__ */ new Date()).toISOString();
		await tx.execute(sql`INSERT INTO field_block_definition_versions (block_key,revision,canonical_hash,definition,origin,created_at) VALUES (${item.key},${revision},${canonicalHash},${JSON.stringify(definition)},'db',${now})`);
		if (current) await tx.execute(sql`UPDATE field_block_definitions SET origin='db',version=${version},active=${item.active},current_revision=${revision},canonical_hash=${canonicalHash},definition=${JSON.stringify(definition)},shadowed_db_version=NULL,updated_at=${now} WHERE key=${item.key}`);
		else await tx.execute(sql`INSERT INTO field_block_definitions (key,origin,version,active,current_revision,canonical_hash,definition,created_at,updated_at) VALUES (${item.key},'db',1,${item.active},1,${canonicalHash},${JSON.stringify(definition)},${now},${now})`);
		blockRevisions.set(item.key, revision);
	}
	for (const item of payload.values ?? []) {
		const restoredRevision = groupRevisions.get(item.groupKey) ?? item.definitionRevision;
		const definition = groupRevisions.has(item.groupKey) ? (payload.groupDefinitions ?? []).find((candidate) => candidate.key === item.groupKey)?.definition : (await resolveFieldDefinitionVersion(tx, item.groupKey, item.definitionRevision)).definition;
		if (!definition) throw new FieldsLifecycleError("backup-invalid", `backup value references missing field group ${item.groupKey}`);
		await writeRestoredValueSnapshot(tx, item, definition, restoredRevision, context);
	}
	const remappedReusable = /* @__PURE__ */ new Map();
	for (const item of payload.reusableBlocks ?? []) {
		const document = remapBlockDocument(item.document, groupRevisions, blockRevisions);
		remappedReusable.set(item.id, {
			document,
			version: 1
		});
	}
	const persistedReusableResolver = blocksModule.createReusableBlockResolver(tx);
	const reusableResolver = { resolve: async (id, ctx) => remappedReusable.get(id) ?? persistedReusableResolver.resolve(id, ctx) };
	const registry = await blocksModule.resolveFieldBlocks(tx);
	for (const item of payload.blockDocuments ?? []) {
		const document = remapBlockDocument(item.document, groupRevisions, blockRevisions);
		const validated = await blocksModule.validateBlockDocument(document, registry, reusableResolver, context, blocksModule.DEFAULT_BLOCK_POLICY);
		const versions = remapDefinitionVersions(item.definitionVersions, groupRevisions, blockRevisions);
		const current = await lifecycleExecute(tx, sql`SELECT version FROM field_block_documents WHERE entity_type=${item.ref.entityType} AND entity_id=${item.ref.entityId} LIMIT 1`), version = Number(current[0]?.version ?? 0) + 1, now = (/* @__PURE__ */ new Date()).toISOString();
		await tx.execute(sql`INSERT INTO field_block_documents (entity_type,entity_id,version,document,definition_versions,parent_revision_id,updated_by,updated_at) VALUES (${item.ref.entityType},${item.ref.entityId},${version},${blocksModule.serializeBlockDocument(validated)},${JSON.stringify(versions)},${item.parentRevisionId},${authorized.principal.id},${now}) ON CONFLICT (entity_type,entity_id) DO UPDATE SET version=EXCLUDED.version,document=EXCLUDED.document,definition_versions=EXCLUDED.definition_versions,parent_revision_id=EXCLUDED.parent_revision_id,updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at`);
	}
	for (const item of payload.reusableBlocks ?? []) {
		const document = remappedReusable.get(item.id).document;
		const validated = await blocksModule.validateBlockDocument(document, registry, reusableResolver, context, blocksModule.DEFAULT_BLOCK_POLICY);
		const versions = remapDefinitionVersions(item.definitionVersions, groupRevisions, blockRevisions);
		const current = await lifecycleExecute(tx, sql`SELECT version FROM field_reusable_blocks WHERE id=${item.id} LIMIT 1`), version = Number(current[0]?.version ?? 0) + 1, now = (/* @__PURE__ */ new Date()).toISOString();
		await tx.execute(sql`INSERT INTO field_reusable_blocks (id,version,document,definition_versions,deleted_at,updated_by,updated_at) VALUES (${item.id},${version},${blocksModule.serializeBlockDocument(validated)},${JSON.stringify(versions)},NULL,${authorized.principal.id},${now}) ON CONFLICT (id) DO UPDATE SET version=EXCLUDED.version,document=EXCLUDED.document,definition_versions=EXCLUDED.definition_versions,deleted_at=NULL,updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at`);
	}
	for (const item of payload.revisions ?? []) {
		if ((await lifecycleExecute(tx, sql`SELECT id FROM field_revisions WHERE id=${item.id} LIMIT 1`)).length > 0) throw new FieldsLifecycleError("corpus-drift", `backup revision ${item.id} already exists at destination`);
		const versions = remapDefinitionVersions(item.definitionVersions, groupRevisions, blockRevisions);
		await requireRestoredDefinitionVersions(tx, versions);
		const blockDocument = item.blockDocument === void 0 ? null : remapBlockDocument(item.blockDocument, groupRevisions, blockRevisions);
		if (blockDocument !== null) await blocksModule.validateBlockDocument(blockDocument, registry, reusableResolver, context, blocksModule.DEFAULT_BLOCK_POLICY);
		await tx.execute(sql`INSERT INTO field_revisions (id,entity_type,entity_id,parent_revision_id,parent_autosave_id,kind,retention_class,definition_versions,"values",block_document,created_at,created_by,source_version) VALUES (${item.id},${item.ref.entityType},${item.ref.entityId},${item.parentRevisionId},${item.parentAutosaveId ?? null},${item.kind},${item.retentionClass ?? null},${JSON.stringify(versions)},${JSON.stringify(item.values)},${blockDocument === null ? null : JSON.stringify(blockDocument)},${item.createdAt},${item.createdBy},${item.sourceVersion})`);
	}
	const restoredCounts = restoredPayloadCounts(payload);
	const result = Object.freeze({
		operationId,
		manifestId: manifest.id,
		destinationCorpusHash,
		restoredCounts
	});
	const event = Object.freeze({
		kind: "backupRestored",
		operationId,
		principalId: authorized.principal.id,
		authorizationPolicyVersion: migration.policyVersion,
		manifest: verified,
		destinationCorpusHash,
		restoredCounts
	});
	await effects.audit.record(tx, event);
	await effects.outbox.enqueue(tx, event);
	await writeFieldsReceipt(tx, {
		operationId,
		kind: "fields:restore-backup",
		context: authorized,
		requestHash,
		result: freezeStorage(result, "restore result")
	});
	return result;
}
//#endregion
export { authorizeRelationshipReplacement as A, validateFieldValue as B, FIELD_VALUE_LIMITS as C, isSanitizedFieldHtml as D, defineCustomField as E, formatFieldValue as F, FieldGroupConflictError as G, isFieldDefinitionIntegrityError as H, isCanonicalFieldValuePath as I, isFieldAuthorizationError as J, FieldStoreError as K, redactFieldValueForRevision as L, deserializeFieldValue as M, encodeFieldValueNodes as N, requireAuthorizedFieldsContext as O, flexibleRows as P, repeaterRows as R, FIELD_DEFINITION_LIMITS as S, createFieldTypeRegistry as T, resolveFieldDefinitionVersion as U, FieldDefinitionIntegrityError as V, FieldAuthorizationError as W, isFieldStoreError as X, isFieldGroupConflictError as Y, isFieldValidationError as Z, readFieldsReceipt as _, assertDefinitionMigration as a, verifyFieldsBackup as b, assertReceiptReplay as c, defineFinalFieldGroup as d, fieldsBackupDestinationHash as f, principalScope as g, previewFieldsCodeReconciliation as h, assertActiveFieldsTransaction as i, decodeFieldValueNodes as j, sanitizeFieldHtml as k, authorizedFieldsContext as l, previewFieldGroupChange as m, applyFieldGroupChange as n, assertFieldsAuthorized as o, fieldsRequestHash as p, FieldValidationError as q, applyFieldsCodeReconciliation as r, assertPrincipalCapability as s, FieldsLifecycleError as t, createFieldGroup as u, resolveFinalFieldGroups as v, assertSerializableFieldPresentation as w, writeFieldsReceipt as x, restoreFieldsBackup as y, serializeFieldValue as z };
