import { canonicalFieldGroupHash, parseFieldDefinitionVersion } from "./schema.js";
//#region src/definitions-pure.ts
function plainDefault(value) {
	if (value === void 0) return void 0;
	if (value instanceof Date) return value.toISOString();
	if (Array.isArray(value)) return value.map((item) => plainDefault(item));
	if (typeof value === "object" && value !== null) {
		const output = {};
		for (const [key, child] of Object.entries(value)) output[key] = child instanceof Date ? child.toISOString() : child;
		return output;
	}
	return value;
}
function sharedField(field) {
	const defaultValue = plainDefault(field.defaultValue);
	return {
		key: field.key,
		name: field.key,
		label: field.label,
		...field.help ? { instructions: field.help } : {},
		...field.required === void 0 ? {} : { required: field.required },
		...defaultValue === void 0 ? {} : { defaultValue }
	};
}
function legacyFieldToFinalDefinition(field) {
	const shared = sharedField(field);
	switch (field.type) {
		case "text": return {
			...shared,
			type: "text",
			settings: {
				...field.maxLength === void 0 ? {} : { maxLength: field.maxLength },
				...field.pattern === void 0 ? {} : { pattern: { source: field.pattern } }
			}
		};
		case "textarea": return {
			...shared,
			type: "textarea",
			settings: {
				newline: "preserve",
				...field.maxLength === void 0 ? {} : { maxLength: field.maxLength }
			}
		};
		case "number": return {
			...shared,
			type: "number",
			settings: {
				...field.min === void 0 ? {} : { min: field.min },
				...field.max === void 0 ? {} : { max: field.max },
				...field.integer === void 0 ? {} : { integer: field.integer }
			}
		};
		case "boolean": return {
			...shared,
			type: "boolean",
			settings: {}
		};
		case "select": {
			const choices = Object.fromEntries(field.options.map((option) => [option.value, option.label]));
			return {
				...shared,
				type: "select",
				settings: {
					choices,
					...field.multiple === void 0 ? {} : { multiple: field.multiple }
				}
			};
		}
		case "date": return {
			...shared,
			type: "date",
			settings: {
				inputFormat: "yyyy-MM-dd",
				displayFormat: "yyyy-MM-dd",
				returnFormat: "yyyy-MM-dd"
			}
		};
		case "color": return {
			...shared,
			type: "color",
			settings: {}
		};
		case "url": return {
			...shared,
			type: "url",
			settings: { schemes: ["http", "https"] }
		};
		case "email": return {
			...shared,
			type: "email",
			settings: {}
		};
		case "media": {
			const settings = {
				...field.accept?.length ? { mimeTypes: [...field.accept] } : {},
				return: "ref"
			};
			return field.multiple ? {
				...shared,
				type: "gallery",
				settings
			} : {
				...shared,
				type: "file",
				settings
			};
		}
		case "relationship": return {
			...shared,
			type: "relationship",
			settings: {
				entityTypes: [field.targetEntityType],
				return: "ref",
				...field.multiple === false ? { max: 1 } : {}
			}
		};
	}
}
function legacyFieldGroupToFinalDefinition(group) {
	const location = [[{
		parameter: "entityType",
		operator: "eq",
		value: group.location.entityType
	}, ...group.location.subType === void 0 ? [] : [{
		parameter: "subType",
		operator: "eq",
		value: group.location.subType
	}]]];
	return Object.freeze({
		key: group.key,
		title: group.label,
		fields: Object.freeze(group.fields.map(legacyFieldToFinalDefinition)),
		location: Object.freeze(location.map((rules) => Object.freeze(rules))),
		...group.position === void 0 ? {} : { order: group.position },
		active: true
	});
}
async function materializeLegacyFieldDefinitionVersion(group, origin = "db") {
	const definition = legacyFieldGroupToFinalDefinition(group);
	const canonicalHash = await canonicalFieldGroupHash(definition);
	return parseFieldDefinitionVersion({
		groupKey: definition.key,
		revision: 1,
		canonicalHash,
		definition,
		createdAt: /* @__PURE__ */ new Date(0),
		origin
	});
}
function referencedFieldDefinitionVersions(nodes) {
	const refs = /* @__PURE__ */ new Map();
	for (const node of nodes) {
		const key = `${node.groupKey}\u0000${node.definitionRevision}`;
		refs.set(key, Object.freeze({
			groupKey: node.groupKey,
			revision: node.definitionRevision
		}));
	}
	return Object.freeze([...refs.values()].sort((left, right) => left.groupKey.localeCompare(right.groupKey) || left.revision - right.revision));
}
//#endregion
//#region src/migrations/recursive-eav.ts
const FIELDS_RECURSIVE_EAV_MIGRATION_ID = "fields-recursive-eav-v1";
function canonicalJson(value) {
	if (value === null) return "null";
	if (value instanceof Date) return JSON.stringify(value.toISOString());
	if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
	if (typeof value === "number") {
		if (!Number.isFinite(value)) throw new TypeError("fields migration data cannot contain non-finite numbers");
		return JSON.stringify(value);
	}
	if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
	if (typeof value === "object" && value !== null) {
		const record = value;
		return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
	}
	throw new TypeError(`unsupported fields migration value: ${typeof value}`);
}
async function canonicalFieldsMigrationHash(value) {
	const bytes = new TextEncoder().encode(canonicalJson(value));
	const digest = await crypto.subtle.digest("SHA-256", bytes);
	return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
}
function plainFlatRow(row) {
	return {
		id: row.id,
		entityType: row.entityType,
		entityId: row.entityId,
		groupId: row.groupId,
		fieldKey: row.fieldKey,
		ordinal: row.ordinal,
		valueText: row.valueText,
		valueNum: row.valueNum,
		valueBool: row.valueBool,
		valueDate: row.valueDate?.toISOString() ?? null,
		refType: row.refType,
		refId: row.refId,
		refMeta: row.refMeta,
		createdAt: row.createdAt.toISOString(),
		updatedAt: row.updatedAt.toISOString()
	};
}
async function snapshotFlatFieldsCorpus(values) {
	const sorted = [...values].sort((left, right) => left.id.localeCompare(right.id));
	return Object.freeze({
		count: sorted.length,
		hash: await canonicalFieldsMigrationHash(sorted.map(plainFlatRow)),
		lastKey: sorted.at(-1)?.id ?? null
	});
}
function escapeFieldPathSegment(value) {
	return value.replaceAll("~", "~0").replaceAll("/", "~1");
}
function fieldPath(fieldKey) {
	return `/f:${escapeFieldPathSegment(fieldKey)}`;
}
async function deterministicUuid(seed) {
	const bytes = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(seed))).slice(0, 16);
	bytes[6] = bytes[6] & 15 | 80;
	bytes[8] = bytes[8] & 63 | 128;
	const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
	return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
function legacyFieldMap(groups) {
	const map = /* @__PURE__ */ new Map();
	for (const group of groups) for (const field of group.fields) map.set(`${group.key}\u0000${field.key}`, field);
	return map;
}
function oneLane(row) {
	if (row.valueText !== null) return {
		lane: "text",
		value: row.valueText
	};
	if (row.valueNum !== null) return {
		lane: "number",
		value: row.valueNum
	};
	if (row.valueBool !== null) return {
		lane: "boolean",
		value: row.valueBool
	};
	if (row.valueDate !== null) return {
		lane: "dateTime",
		value: row.valueDate.toISOString()
	};
	if (row.refType !== null && row.refId !== null) return {
		lane: "ref",
		value: canonicalJson({
			entityType: row.refType,
			entityId: row.refId,
			meta: row.refMeta
		})
	};
	throw new TypeError(`flat field value ${row.id} does not contain exactly one legacy lane`);
}
function isLegacyMultiple(field) {
	if (!field) return false;
	return (field.type === "select" || field.type === "media" || field.type === "relationship") && field.multiple === true;
}
function valueJsonForRows(rows) {
	return canonicalJson(rows.map((row) => {
		const lane = oneLane(row);
		return {
			legacyId: row.id,
			ordinal: row.ordinal,
			lane: lane.lane,
			value: lane.value
		};
	}));
}
async function projectNode(rows, siblingOrdinal, field) {
	const first = rows[0];
	if (!first) throw new TypeError("cannot project an empty field-value group");
	const sorted = [...rows].sort((left, right) => left.ordinal - right.ordinal || left.id.localeCompare(right.id));
	const legacySourceIds = Object.freeze(sorted.map((row) => row.id));
	const legacySourceHash = await canonicalFieldsMigrationHash(sorted.map(plainFlatRow));
	const path = fieldPath(first.fieldKey);
	const base = {
		nodeId: await deterministicUuid([
			FIELDS_RECURSIVE_EAV_MIGRATION_ID,
			first.entityType,
			first.entityId,
			first.groupId,
			path
		].join("\0")),
		entityType: first.entityType,
		entityId: first.entityId,
		groupKey: first.groupId,
		definitionRevision: 1,
		fieldKey: first.fieldKey,
		path,
		parentNodeId: null,
		rowId: null,
		layoutKey: null,
		nodeKind: "leaf",
		ordinal: siblingOrdinal,
		isNull: false,
		valueText: null,
		valueNumber: null,
		valueBoolean: null,
		valueDateTime: null,
		valueRef: null,
		valueJson: null,
		legacySourceIds,
		legacySourceHash
	};
	if (sorted.length > 1 || isLegacyMultiple(field)) return Object.freeze({
		...base,
		valueJson: valueJsonForRows(sorted)
	});
	const lane = oneLane(sorted[0]);
	switch (lane.lane) {
		case "text": return Object.freeze({
			...base,
			valueText: lane.value
		});
		case "number": {
			const valueNumber = Number(lane.value);
			if (!Number.isFinite(valueNumber)) throw new TypeError(`flat numeric field value ${sorted[0].id} is not finite`);
			return Object.freeze({
				...base,
				valueNumber
			});
		}
		case "boolean": return Object.freeze({
			...base,
			valueBoolean: lane.value
		});
		case "dateTime": return Object.freeze({
			...base,
			valueDateTime: lane.value
		});
		case "ref": return Object.freeze({
			...base,
			valueRef: lane.value
		});
	}
}
function assertCompleteLegacyGroups(groups, values) {
	const groupFields = new Map(groups.map((group) => [group.key, new Set(group.fields.map((field) => field.key))]));
	for (const value of values) {
		const fields = groupFields.get(value.groupId);
		if (!fields) throw new TypeError(`flat field value ${value.id} references missing group ${value.groupId}`);
		if (!fields.has(value.fieldKey)) throw new TypeError(`flat field value ${value.id} references missing historical field ${value.groupId}.${value.fieldKey}`);
	}
}
async function planFieldsRecursiveEavMigration(values, groups) {
	assertCompleteLegacyGroups(groups, values);
	const source = await snapshotFlatFieldsCorpus(values);
	const definitions = Object.freeze(await Promise.all([...groups].sort((left, right) => left.key.localeCompare(right.key)).map((group) => materializeLegacyFieldDefinitionVersion(group, "db"))));
	const fields = legacyFieldMap(groups);
	const fieldOrder = /* @__PURE__ */ new Map();
	for (const group of groups) group.fields.forEach((field, index) => fieldOrder.set(`${group.key}\u0000${field.key}`, index));
	const grouped = /* @__PURE__ */ new Map();
	for (const value of values) {
		const key = [
			value.entityType,
			value.entityId,
			value.groupId,
			value.fieldKey
		].join("\0");
		const bucket = grouped.get(key) ?? [];
		bucket.push(value);
		grouped.set(key, bucket);
	}
	const buckets = [...grouped.values()].sort((left, right) => {
		const a = left[0];
		const b = right[0];
		return a.entityType.localeCompare(b.entityType) || a.entityId.localeCompare(b.entityId) || a.groupId.localeCompare(b.groupId) || fieldOrder.get(`${a.groupId}\u0000${a.fieldKey}`) - fieldOrder.get(`${b.groupId}\u0000${b.fieldKey}`) || a.fieldKey.localeCompare(b.fieldKey);
	});
	const nodes = [];
	for (const bucket of buckets) {
		const first = bucket[0];
		const siblingOrdinal = fieldOrder.get(`${first.groupId}\u0000${first.fieldKey}`);
		nodes.push(await projectNode(bucket, siblingOrdinal, fields.get(`${first.groupId}\u0000${first.fieldKey}`)));
	}
	const definitionRefs = Object.freeze(definitions.map((definition) => Object.freeze({
		groupKey: definition.groupKey,
		revision: definition.revision
	})));
	const target = Object.freeze({
		count: nodes.length,
		hash: await canonicalFieldsMigrationHash(nodes),
		lastKey: nodes.at(-1)?.nodeId ?? null
	});
	return Object.freeze({
		migrationId: FIELDS_RECURSIVE_EAV_MIGRATION_ID,
		source,
		target,
		definitions,
		definitionRefs,
		nodes: Object.freeze(nodes)
	});
}
function postgresDefinitionTables() {
	return [
		`CREATE TABLE IF NOT EXISTS field_group_definitions (
      key text PRIMARY KEY, origin text NOT NULL, version integer NOT NULL DEFAULT 1 CHECK (version > 0),
      active boolean NOT NULL DEFAULT true, current_revision integer NOT NULL DEFAULT 1 CHECK (current_revision > 0),
      canonical_hash text NOT NULL, definition jsonb NOT NULL, shadowed_db_version integer, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS field_definition_versions (
      group_key text NOT NULL, revision integer NOT NULL CHECK (revision > 0), canonical_hash text NOT NULL,
      definition jsonb NOT NULL, origin text NOT NULL, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), PRIMARY KEY (group_key, revision)
    )`,
		`CREATE TABLE IF NOT EXISTS field_options_definitions (
      key text PRIMARY KEY, origin text NOT NULL, version integer NOT NULL DEFAULT 1 CHECK (version > 0),
      active boolean NOT NULL DEFAULT true, current_revision integer NOT NULL DEFAULT 1 CHECK (current_revision > 0),
      canonical_hash text NOT NULL, definition jsonb NOT NULL, shadowed_db_version integer, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS field_options_definition_versions (
      options_key text NOT NULL, revision integer NOT NULL CHECK (revision > 0), canonical_hash text NOT NULL,
      definition jsonb NOT NULL, origin text NOT NULL, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), PRIMARY KEY (options_key, revision)
    )`,
		`CREATE TABLE IF NOT EXISTS field_block_definitions (
      key text PRIMARY KEY, origin text NOT NULL, version integer NOT NULL DEFAULT 1 CHECK (version > 0),
      active boolean NOT NULL DEFAULT true, current_revision integer NOT NULL DEFAULT 1 CHECK (current_revision > 0),
      canonical_hash text NOT NULL, definition jsonb NOT NULL, shadowed_db_version integer, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS field_block_definition_versions (
      block_key text NOT NULL, revision integer NOT NULL CHECK (revision > 0), canonical_hash text NOT NULL,
      definition jsonb NOT NULL, origin text NOT NULL, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), PRIMARY KEY (block_key, revision)
    )`
	];
}
function d1DefinitionTables() {
	const current = (table) => `CREATE TABLE IF NOT EXISTS ${table} (
    key TEXT PRIMARY KEY, origin TEXT NOT NULL, version INTEGER NOT NULL DEFAULT 1 CHECK (version > 0),
    active INTEGER NOT NULL DEFAULT 1 CHECK (active IN (0,1)), current_revision INTEGER NOT NULL DEFAULT 1 CHECK (current_revision > 0),
    canonical_hash TEXT NOT NULL, definition TEXT NOT NULL, shadowed_db_version INTEGER, host_session_id TEXT,
    created_at TEXT NOT NULL, updated_at TEXT NOT NULL
  )`;
	const version = (table, key) => `CREATE TABLE IF NOT EXISTS ${table} (
    ${key} TEXT NOT NULL, revision INTEGER NOT NULL CHECK (revision > 0), canonical_hash TEXT NOT NULL,
    definition TEXT NOT NULL, origin TEXT NOT NULL, host_session_id TEXT, created_at TEXT NOT NULL,
    PRIMARY KEY (${key}, revision)
  )`;
	return [
		current("field_group_definitions"),
		version("field_definition_versions", "group_key"),
		current("field_options_definitions"),
		version("field_options_definition_versions", "options_key"),
		current("field_block_definitions"),
		version("field_block_definition_versions", "block_key")
	];
}
function postgresForwardSql() {
	return Object.freeze([
		...postgresDefinitionTables(),
		`CREATE TABLE IF NOT EXISTS field_value_nodes (
      node_id uuid PRIMARY KEY, entity_type text NOT NULL, entity_id text NOT NULL, group_key text NOT NULL,
      definition_revision integer NOT NULL CHECK (definition_revision > 0), field_key text NOT NULL, path text NOT NULL,
      parent_node_id uuid REFERENCES field_value_nodes(node_id) ON DELETE CASCADE, row_id text, layout_key text,
      node_kind text NOT NULL CHECK (node_kind IN ('group','repeaterRow','flexibleRow','leaf')),
      ordinal integer NOT NULL CHECK (ordinal >= 0), is_null boolean NOT NULL DEFAULT false,
      value_text text, value_number numeric, value_boolean boolean, value_date_time text, value_ref text, value_json text,
      legacy_source_ids jsonb, legacy_source_hash text, host_session_id text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW(),
      CONSTRAINT field_value_nodes_row_shape CHECK (
        (node_kind IN ('repeaterRow','flexibleRow') AND row_id IS NOT NULL)
        OR (node_kind NOT IN ('repeaterRow','flexibleRow') AND row_id IS NULL)
      ),
      CONSTRAINT field_value_nodes_layout_shape CHECK (
        (node_kind = 'flexibleRow' AND layout_key IS NOT NULL)
        OR (node_kind <> 'flexibleRow' AND layout_key IS NULL)
      ),
      CONSTRAINT field_value_nodes_lane_shape CHECK (
        CASE
          WHEN node_kind <> 'leaf' THEN is_null = false AND value_text IS NULL AND value_number IS NULL
            AND value_boolean IS NULL AND value_date_time IS NULL AND value_ref IS NULL AND value_json IS NULL
          WHEN is_null = true THEN value_text IS NULL AND value_number IS NULL AND value_boolean IS NULL
            AND value_date_time IS NULL AND value_ref IS NULL AND value_json IS NULL
          ELSE (CASE WHEN value_text IS NOT NULL THEN 1 ELSE 0 END
              + CASE WHEN value_number IS NOT NULL THEN 1 ELSE 0 END
              + CASE WHEN value_boolean IS NOT NULL THEN 1 ELSE 0 END
              + CASE WHEN value_date_time IS NOT NULL THEN 1 ELSE 0 END
              + CASE WHEN value_ref IS NOT NULL THEN 1 ELSE 0 END
              + CASE WHEN value_json IS NOT NULL THEN 1 ELSE 0 END) = 1
        END
      )
    )`,
		`CREATE UNIQUE INDEX IF NOT EXISTS field_value_nodes_entity_group_path_uq
      ON field_value_nodes (entity_type, entity_id, group_key, path)`,
		`CREATE UNIQUE INDEX IF NOT EXISTS field_value_nodes_sibling_ordinal_uq
      ON field_value_nodes (entity_type, entity_id, group_key, COALESCE(parent_node_id, '00000000-0000-0000-0000-000000000000'::uuid), ordinal)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_entity_idx ON field_value_nodes (entity_type, entity_id, group_key)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_definition_idx ON field_value_nodes (group_key, definition_revision)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_text_idx ON field_value_nodes (entity_type, field_key, value_text)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_number_idx ON field_value_nodes (entity_type, field_key, value_number)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_ref_idx ON field_value_nodes (entity_type, field_key, value_ref)`,
		`CREATE TABLE IF NOT EXISTS fields_import_staging (
      host_session_id text NOT NULL, section text NOT NULL, ordinal integer NOT NULL CHECK (ordinal >= 0),
      canonical_hash text NOT NULL, payload jsonb NOT NULL, created_at timestamptz(3) NOT NULL DEFAULT NOW(),
      PRIMARY KEY (host_session_id, section, ordinal)
    )`,
		`CREATE TABLE IF NOT EXISTS fields_import_journal (
      import_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), host_session_id text NOT NULL UNIQUE,
      manifest_hash text NOT NULL, plan_hash text NOT NULL, state text NOT NULL, version integer NOT NULL DEFAULT 0 CHECK (version >= 0),
      next_section text, next_offset integer, high_water_mark text, payload jsonb,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS fields_migration_checkpoints (
      migration_id text NOT NULL, adapter text NOT NULL, phase text NOT NULL, batch_ordinal integer NOT NULL DEFAULT 0,
      version integer NOT NULL DEFAULT 0, last_key text, source_count integer NOT NULL, target_count integer,
      source_hash text NOT NULL, target_hash text, high_water_mark text,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW(),
      PRIMARY KEY (migration_id, adapter, phase, batch_ordinal)
    )`,
		`CREATE TABLE IF NOT EXISTS fields_migration_write_journal (
      seq bigserial PRIMARY KEY, migration_id text NOT NULL, operation text NOT NULL, value_id text NOT NULL,
      before_value jsonb, after_value jsonb, created_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE OR REPLACE FUNCTION fields_recursive_eav_journal_fn() RETURNS trigger AS $$
      BEGIN
        INSERT INTO fields_migration_write_journal (migration_id, operation, value_id, before_value, after_value)
        VALUES (
          '${FIELDS_RECURSIVE_EAV_MIGRATION_ID}', lower(TG_OP),
          CASE WHEN TG_OP = 'DELETE' THEN OLD.id::text ELSE NEW.id::text END,
          CASE WHEN TG_OP = 'INSERT' THEN NULL ELSE to_jsonb(OLD) END,
          CASE WHEN TG_OP = 'DELETE' THEN NULL ELSE to_jsonb(NEW) END
        );
        RETURN NULL;
      END;
    $$ LANGUAGE plpgsql`,
		`DROP TRIGGER IF EXISTS fields_recursive_eav_write_trigger ON field_values`,
		`CREATE TRIGGER fields_recursive_eav_write_trigger AFTER INSERT OR UPDATE OR DELETE ON field_values
      FOR EACH ROW EXECUTE FUNCTION fields_recursive_eav_journal_fn()`
	]);
}
function d1JsonRow(prefix) {
	return `json_object(
    'id', ${prefix}.id, 'entity_type', ${prefix}.entity_type, 'entity_id', ${prefix}.entity_id,
    'group_id', ${prefix}.group_id, 'field_key', ${prefix}.field_key, 'ordinal', ${prefix}.ordinal,
    'value_text', ${prefix}.value_text, 'value_num', ${prefix}.value_num, 'value_bool', ${prefix}.value_bool,
    'value_date', ${prefix}.value_date, 'ref_type', ${prefix}.ref_type, 'ref_id', ${prefix}.ref_id,
    'ref_meta', ${prefix}.ref_meta, 'created_at', ${prefix}.created_at, 'updated_at', ${prefix}.updated_at
  )`;
}
function d1ForwardSql() {
	const now = "strftime('%Y-%m-%dT%H:%M:%fZ','now')";
	return Object.freeze([
		...d1DefinitionTables(),
		`CREATE TABLE IF NOT EXISTS field_value_nodes (
      node_id TEXT PRIMARY KEY, entity_type TEXT NOT NULL, entity_id TEXT NOT NULL, group_key TEXT NOT NULL,
      definition_revision INTEGER NOT NULL CHECK (definition_revision > 0), field_key TEXT NOT NULL, path TEXT NOT NULL,
      parent_node_id TEXT REFERENCES field_value_nodes(node_id) ON DELETE CASCADE, row_id TEXT, layout_key TEXT,
      node_kind TEXT NOT NULL CHECK (node_kind IN ('group','repeaterRow','flexibleRow','leaf')),
      ordinal INTEGER NOT NULL CHECK (ordinal >= 0), is_null INTEGER NOT NULL DEFAULT 0 CHECK (is_null IN (0,1)),
      value_text TEXT, value_number TEXT, value_boolean INTEGER, value_date_time TEXT, value_ref TEXT, value_json TEXT,
      legacy_source_ids TEXT, legacy_source_hash TEXT, host_session_id TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL,
      CHECK ((node_kind IN ('repeaterRow','flexibleRow') AND row_id IS NOT NULL)
        OR (node_kind NOT IN ('repeaterRow','flexibleRow') AND row_id IS NULL)),
      CHECK ((node_kind = 'flexibleRow' AND layout_key IS NOT NULL) OR (node_kind <> 'flexibleRow' AND layout_key IS NULL)),
      CHECK (CASE
        WHEN node_kind <> 'leaf' THEN is_null = 0 AND value_text IS NULL AND value_number IS NULL
          AND value_boolean IS NULL AND value_date_time IS NULL AND value_ref IS NULL AND value_json IS NULL
        WHEN is_null = 1 THEN value_text IS NULL AND value_number IS NULL AND value_boolean IS NULL
          AND value_date_time IS NULL AND value_ref IS NULL AND value_json IS NULL
        ELSE (CASE WHEN value_text IS NOT NULL THEN 1 ELSE 0 END
          + CASE WHEN value_number IS NOT NULL THEN 1 ELSE 0 END
          + CASE WHEN value_boolean IS NOT NULL THEN 1 ELSE 0 END
          + CASE WHEN value_date_time IS NOT NULL THEN 1 ELSE 0 END
          + CASE WHEN value_ref IS NOT NULL THEN 1 ELSE 0 END
          + CASE WHEN value_json IS NOT NULL THEN 1 ELSE 0 END) = 1
      END)
    )`,
		`CREATE UNIQUE INDEX IF NOT EXISTS field_value_nodes_entity_group_path_uq
      ON field_value_nodes (entity_type, entity_id, group_key, path)`,
		`CREATE UNIQUE INDEX IF NOT EXISTS field_value_nodes_sibling_ordinal_uq
      ON field_value_nodes (entity_type, entity_id, group_key, COALESCE(parent_node_id, ''), ordinal)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_entity_idx ON field_value_nodes (entity_type, entity_id, group_key)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_definition_idx ON field_value_nodes (group_key, definition_revision)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_text_idx ON field_value_nodes (entity_type, field_key, value_text)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_number_idx ON field_value_nodes (entity_type, field_key, value_number)`,
		`CREATE INDEX IF NOT EXISTS field_value_nodes_ref_idx ON field_value_nodes (entity_type, field_key, value_ref)`,
		`CREATE TABLE IF NOT EXISTS fields_import_staging (
      host_session_id TEXT NOT NULL, section TEXT NOT NULL, ordinal INTEGER NOT NULL CHECK (ordinal >= 0),
      canonical_hash TEXT NOT NULL, payload TEXT NOT NULL, created_at TEXT NOT NULL,
      PRIMARY KEY (host_session_id, section, ordinal)
    )`,
		`CREATE TABLE IF NOT EXISTS fields_import_journal (
      import_id TEXT PRIMARY KEY, host_session_id TEXT NOT NULL UNIQUE, manifest_hash TEXT NOT NULL,
      plan_hash TEXT NOT NULL, state TEXT NOT NULL, version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
      next_section TEXT, next_offset INTEGER, high_water_mark TEXT, payload TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
    )`,
		`CREATE TABLE IF NOT EXISTS fields_migration_checkpoints (
      migration_id TEXT NOT NULL, adapter TEXT NOT NULL, phase TEXT NOT NULL, batch_ordinal INTEGER NOT NULL DEFAULT 0,
      version INTEGER NOT NULL DEFAULT 0, last_key TEXT, source_count INTEGER NOT NULL, target_count INTEGER,
      source_hash TEXT NOT NULL, target_hash TEXT, high_water_mark TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL,
      PRIMARY KEY (migration_id, adapter, phase, batch_ordinal)
    )`,
		`CREATE TABLE IF NOT EXISTS fields_migration_write_journal (
      seq INTEGER PRIMARY KEY AUTOINCREMENT, migration_id TEXT NOT NULL, operation TEXT NOT NULL, value_id TEXT NOT NULL,
      before_value TEXT, after_value TEXT, created_at TEXT NOT NULL DEFAULT (${now})
    )`,
		`DROP TRIGGER IF EXISTS fields_recursive_eav_write_insert`,
		`DROP TRIGGER IF EXISTS fields_recursive_eav_write_update`,
		`DROP TRIGGER IF EXISTS fields_recursive_eav_write_delete`,
		`CREATE TRIGGER fields_recursive_eav_write_insert AFTER INSERT ON field_values BEGIN
      INSERT INTO fields_migration_write_journal (migration_id, operation, value_id, before_value, after_value)
      VALUES ('${FIELDS_RECURSIVE_EAV_MIGRATION_ID}', 'insert', NEW.id, NULL, ${d1JsonRow("NEW")});
    END`,
		`CREATE TRIGGER fields_recursive_eav_write_update AFTER UPDATE ON field_values BEGIN
      INSERT INTO fields_migration_write_journal (migration_id, operation, value_id, before_value, after_value)
      VALUES ('${FIELDS_RECURSIVE_EAV_MIGRATION_ID}', 'update', NEW.id, ${d1JsonRow("OLD")}, ${d1JsonRow("NEW")});
    END`,
		`CREATE TRIGGER fields_recursive_eav_write_delete AFTER DELETE ON field_values BEGIN
      INSERT INTO fields_migration_write_journal (migration_id, operation, value_id, before_value, after_value)
      VALUES ('${FIELDS_RECURSIVE_EAV_MIGRATION_ID}', 'delete', OLD.id, ${d1JsonRow("OLD")}, NULL);
    END`
	]);
}
function fieldsRecursiveEavForwardMigrationSql(adapter) {
	return adapter === "postgres" ? postgresForwardSql() : d1ForwardSql();
}
function fieldsRecursiveEavReverseMigrationSql(adapter) {
	return Object.freeze([
		...adapter === "postgres" ? [`DROP TRIGGER IF EXISTS fields_recursive_eav_write_trigger ON field_values`, `DROP FUNCTION IF EXISTS fields_recursive_eav_journal_fn()`] : [
			`DROP TRIGGER IF EXISTS fields_recursive_eav_write_insert`,
			`DROP TRIGGER IF EXISTS fields_recursive_eav_write_update`,
			`DROP TRIGGER IF EXISTS fields_recursive_eav_write_delete`
		],
		`DROP TABLE IF EXISTS field_value_nodes`,
		`DROP TABLE IF EXISTS fields_import_staging`,
		`DROP TABLE IF EXISTS fields_import_journal`,
		`DROP TABLE IF EXISTS fields_migration_checkpoints`
	]);
}
/** Public migration metadata intentionally excludes transient adapter journal bytes. */
function fieldDefinitionRefsForPlan(plan) {
	return plan.definitionRefs;
}
/** Parses a migration JSON leaf without interpreting it as an arbitrary recursive field object. */
function parseLegacyMultipleValueJson(valueJson) {
	const parsed = JSON.parse(valueJson);
	if (!Array.isArray(parsed)) throw new TypeError("legacy multiple value JSON must be an array");
	return Object.freeze(parsed.map((item) => {
		if (typeof item !== "object" || item === null || Array.isArray(item)) throw new TypeError("legacy multiple value JSON contains an invalid item");
		const record = item;
		if (typeof record.legacyId !== "string" || typeof record.ordinal !== "number" || typeof record.lane !== "string" || ![
			"text",
			"number",
			"boolean",
			"dateTime",
			"ref"
		].includes(record.lane) || !(typeof record.value === "string" || typeof record.value === "boolean")) throw new TypeError("legacy multiple value JSON contains an invalid item");
		return Object.freeze({
			legacyId: record.legacyId,
			ordinal: record.ordinal,
			lane: record.lane,
			value: record.value
		});
	}));
}
//#endregion
//#region src/migrate.ts
/** Idempotent additive DDL for fields EAV tables (spec §4). */
const fieldsMigrationSql = () => `
CREATE TABLE IF NOT EXISTS field_values (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  entity_type text NOT NULL,
  entity_id   text NOT NULL,
  group_id    text NOT NULL,
  field_key   text NOT NULL,
  ordinal     integer NOT NULL DEFAULT 0,
  value_text  text,
  value_num   numeric,
  value_bool  boolean,
  value_date  timestamptz(3),
  ref_type    text,
  ref_id      text,
  ref_meta    jsonb,
  created_at  timestamptz(3) NOT NULL DEFAULT NOW(),
  updated_at  timestamptz(3) NOT NULL DEFAULT NOW(),
  CONSTRAINT field_values_one_lane CHECK (
    (CASE WHEN value_text IS NOT NULL THEN 1 ELSE 0 END
   + CASE WHEN value_num  IS NOT NULL THEN 1 ELSE 0 END
   + CASE WHEN value_bool IS NOT NULL THEN 1 ELSE 0 END
   + CASE WHEN value_date IS NOT NULL THEN 1 ELSE 0 END
   + CASE WHEN ref_id     IS NOT NULL THEN 1 ELSE 0 END) = 1
  )
);
CREATE UNIQUE INDEX IF NOT EXISTS field_values_entity_group_field_ord_uq
  ON field_values (entity_type, entity_id, group_id, field_key, ordinal);
CREATE INDEX IF NOT EXISTS field_values_entity_idx ON field_values (entity_type, entity_id);
CREATE INDEX IF NOT EXISTS field_values_facet_text_idx ON field_values (entity_type, field_key, value_text);
CREATE INDEX IF NOT EXISTS field_values_facet_num_idx ON field_values (entity_type, field_key, value_num);
CREATE INDEX IF NOT EXISTS field_values_facet_date_idx ON field_values (entity_type, field_key, value_date);
CREATE INDEX IF NOT EXISTS field_values_ref_idx ON field_values (entity_type, ref_type, ref_id);
CREATE TABLE IF NOT EXISTS field_groups (
  id          uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  entity_type text NOT NULL,
  sub_type    text,
  key         text NOT NULL,
  label       text NOT NULL,
  fields      jsonb NOT NULL,
  position    integer NOT NULL DEFAULT 0,
  created_at  timestamptz(3) NOT NULL DEFAULT NOW(),
  updated_at  timestamptz(3) NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS field_groups_entity_key_uq ON field_groups (entity_type, key);
`.trim();
//#endregion
export { fieldDefinitionRefsForPlan as a, fieldsRecursiveEavReverseMigrationSql as c, snapshotFlatFieldsCorpus as d, legacyFieldGroupToFinalDefinition as f, referencedFieldDefinitionVersions as h, escapeFieldPathSegment as i, parseLegacyMultipleValueJson as l, materializeLegacyFieldDefinitionVersion as m, FIELDS_RECURSIVE_EAV_MIGRATION_ID as n, fieldPath as o, legacyFieldToFinalDefinition as p, canonicalFieldsMigrationHash as r, fieldsRecursiveEavForwardMigrationSql as s, fieldsMigrationSql as t, planFieldsRecursiveEavMigration as u };
