globalThis.process ??= {};
globalThis.process.env ??= {};
import { A as inArray, T as and, Tt as sql, n as d1AssertPreviousChanges } from "./d1_DTqC4o_t.mjs";
import { G as assertActiveContentTransaction, H as visibilityPredicate, J as contentEntries, q as authorizeContentAction } from "./crypto_CY2zBtG3.mjs";
//#region ../../packages/content/dist/index.js
function regconfigLiteral(config) {
	return sql.raw(`'${config.replace(/'/g, "''")}'`);
}
function createContentSearchProvider(opts) {
	const cfgLit = regconfigLiteral(opts?.textSearchConfig ?? "english");
	const types = opts?.types;
	return async (query, ctx, window) => {
		if (!query.trim()) return {
			hits: [],
			total: 0
		};
		const tsq = sql`to_tsquery(${cfgLit}, ${query})`;
		const match = sql`search_vector @@ ${tsq}`;
		const vis = visibilityPredicate(ctx.viewer);
		const conditions = [match];
		if (vis) conditions.unshift(vis);
		if (types && types.length > 0) conditions.push(inArray(contentEntries.type, types));
		const where = conditions.length === 1 ? conditions[0] : and(...conditions);
		const rows = normalizeExecuteRows(await ctx.db.execute(sql`
      SELECT
        id,
        title,
        ts_rank(search_vector, ${tsq}) AS rank,
        ts_headline(
          ${cfgLit},
          regexp_replace(body, '<[^>]*>', ' ', 'g'),
          ${tsq},
          'StartSel=«,StopSel=»,MaxWords=30,MinWords=15,ShortWord=3'
        ) AS snippet_html,
        count(*) OVER()::int AS total
      FROM content_entries
      WHERE ${where}
      ORDER BY rank DESC, published_at DESC NULLS LAST
      LIMIT ${window.limit} OFFSET ${window.offset}
    `));
		const total = rows[0]?.total ?? 0;
		return {
			hits: rows.map((row) => ({
				entityType: "content",
				id: row.id,
				rank: row.rank,
				title: row.title,
				snippetHtml: row.snippet_html
			})),
			total
		};
	};
}
function normalizeExecuteRows(result) {
	if (Array.isArray(result)) return result;
	return result?.rows ?? [];
}
var CONTENT_MODEL_MIGRATION_ID = "content-model-v1";
var STANDARD_STATUSES = /* @__PURE__ */ new Set([
	"draft",
	"pending",
	"scheduled",
	"published",
	"trashed"
]);
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("canonical 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 canonical migration value: ${typeof value}`);
}
async function canonicalContentMigrationHash(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 plainEntry(entry) {
	return {
		id: entry.id,
		slug: entry.slug,
		type: entry.type,
		title: entry.title,
		body: entry.body,
		status: entry.status,
		visibility: entry.visibility,
		publishedAt: entry.publishedAt?.toISOString() ?? null,
		author: entry.author,
		createdAt: entry.createdAt.toISOString(),
		updatedAt: entry.updatedAt.toISOString()
	};
}
async function snapshotFlatContentCorpus(entries) {
	const sorted = [...entries].sort((left, right) => left.id.localeCompare(right.id));
	return Object.freeze({
		count: sorted.length,
		hash: await canonicalContentMigrationHash(sorted.map(plainEntry)),
		lastKey: sorted.at(-1)?.id ?? null
	});
}
function humanizeKey(key) {
	const label = key.replaceAll(/[-_]+/g, " ").trim();
	if (!label) return key;
	return label.replace(/\b\p{L}/gu, (letter) => letter.toUpperCase());
}
function legacyLabels(key) {
	const singular = humanizeKey(key);
	const plural = singular.endsWith("s") ? singular : `${singular}s`;
	return {
		name: plural,
		singularName: singular,
		menuName: plural,
		nameAdminBar: singular,
		addNew: "Add New",
		addNewItem: `Add New ${singular}`,
		editItem: `Edit ${singular}`,
		newItem: `New ${singular}`,
		viewItem: `View ${singular}`,
		viewItems: `View ${plural}`,
		searchItems: `Search ${plural}`,
		notFound: `No ${plural.toLowerCase()} found`,
		notFoundInTrash: `No ${plural.toLowerCase()} found in trash`,
		parentItemColon: `Parent ${singular}:`,
		allItems: `All ${plural}`,
		archives: `${singular} Archives`,
		attributes: `${singular} Attributes`,
		insertIntoItem: `Insert into ${singular.toLowerCase()}`,
		uploadedToThisItem: `Uploaded to this ${singular.toLowerCase()}`,
		featuredImage: "Featured image",
		setFeaturedImage: "Set featured image",
		removeFeaturedImage: "Remove featured image",
		useFeaturedImage: "Use as featured image",
		filterItemsList: `Filter ${plural.toLowerCase()} list`,
		filterByDate: `Filter ${plural.toLowerCase()} by date`,
		itemsListNavigation: `${plural} list navigation`,
		itemsList: `${plural} list`,
		itemPublished: `${singular} published`,
		itemPublishedPrivately: `${singular} published privately`,
		itemRevertedToDraft: `${singular} reverted to draft`,
		itemScheduled: `${singular} scheduled`,
		itemUpdated: `${singular} updated`,
		itemLink: `${singular} link`,
		itemLinkDescription: `A link to a ${singular.toLowerCase()}`
	};
}
function legacyCapabilities(key) {
	const prefix = `content.${key}`;
	return {
		manageType: `${prefix}.manageType`,
		migrateAll: `${prefix}.migrateAll`,
		manageTerms: `${prefix}.manageTerms`,
		create: `${prefix}.create`,
		read: `${prefix}.read`,
		readPrivate: `${prefix}.readPrivate`,
		readProtected: `${prefix}.readProtected`,
		editOwn: `${prefix}.editOwn`,
		editOthers: `${prefix}.editOthers`,
		editPrivate: `${prefix}.editPrivate`,
		editPublished: `${prefix}.editPublished`,
		publish: `${prefix}.publish`,
		deleteOwn: `${prefix}.deleteOwn`,
		deleteOthers: `${prefix}.deleteOthers`,
		deletePrivate: `${prefix}.deletePrivate`,
		deletePublished: `${prefix}.deletePublished`
	};
}
function legacyTypeDefinition(key, statusKeys, defaultTemplateKey) {
	return {
		key,
		labels: legacyLabels(key),
		public: true,
		hierarchical: false,
		excludeFromSearch: false,
		publiclyQueryable: true,
		showUi: true,
		showInMenu: true,
		showInNavMenus: true,
		showInAdminBar: true,
		capabilities: legacyCapabilities(key),
		supports: [
			"title",
			"editor",
			"author",
			"revisions"
		],
		taxonomies: [],
		hasArchive: false,
		rewrite: false,
		queryVariable: false,
		canExport: true,
		deleteWithAuthor: null,
		rest: false,
		defaultTemplateKey,
		statusKeys,
		active: true
	};
}
function legacyStatusDefinition(key) {
	const published = key === "published";
	const scheduled = key === "scheduled";
	return {
		key,
		label: humanizeKey(key),
		published,
		internal: key === "trashed",
		excludeFromSearch: !published,
		publiclyQueryable: published,
		showInAdminAll: true,
		showInAdminStatusFilter: true,
		dateLabel: published ? "published" : scheduled ? "scheduled" : key === "draft" || key === "pending" ? "lastModified" : "created",
		transitionInput: scheduled ? "scheduleAt" : published ? "publishedAt" : "none"
	};
}
async function materializeDefinitions(entries, defaultTemplateKey) {
	const statusKeys = [...new Set(entries.map((entry) => entry.status))].sort();
	const typeKeys = [...new Set(entries.map((entry) => entry.type))].sort();
	const allStatusKeys = [.../* @__PURE__ */ new Set([...STANDARD_STATUSES, ...statusKeys])].sort();
	const definitions = [];
	for (const key of typeKeys) {
		const definition = legacyTypeDefinition(key, allStatusKeys, defaultTemplateKey);
		definitions.push({
			kind: "type",
			key,
			origin: "db",
			revision: 1,
			canonicalHash: await canonicalContentMigrationHash(definition),
			definition
		});
	}
	for (const key of allStatusKeys) {
		const definition = legacyStatusDefinition(key);
		definitions.push({
			kind: "status",
			key,
			origin: STANDARD_STATUSES.has(key) ? "code" : "db",
			revision: 1,
			canonicalHash: await canonicalContentMigrationHash(definition),
			definition
		});
	}
	return Object.freeze(definitions.sort((left, right) => left.kind.localeCompare(right.kind) || left.key.localeCompare(right.key)));
}
async function planContentModelMigration(entries, options) {
	const defaultTemplateKey = options.defaultTemplateKey.trim();
	if (!defaultTemplateKey || defaultTemplateKey.length > 128) throw new TypeError("content migration defaultTemplateKey must be a bounded non-empty key");
	const source = await snapshotFlatContentCorpus(entries);
	const definitions = await materializeDefinitions(entries, defaultTemplateKey);
	const entriesById = [...entries].sort((left, right) => left.id.localeCompare(right.id));
	const projected = Object.freeze(entriesById.map((entry) => Object.freeze({
		...entry,
		parentId: null,
		menuOrder: 0,
		templateKey: null,
		excerpt: "",
		featuredMedia: null,
		commentStatus: "open",
		pingStatus: "open",
		sticky: false,
		format: null,
		deletedAt: null,
		lastEditedBy: entry.author,
		typeDefinitionRevision: 1,
		statusDefinitionRevision: 1
	})));
	const target = Object.freeze({
		count: projected.length,
		hash: await canonicalContentMigrationHash(projected.map((entry) => ({
			...plainEntry(entry),
			parentId: entry.parentId,
			menuOrder: entry.menuOrder,
			templateKey: entry.templateKey,
			excerpt: entry.excerpt,
			featuredMedia: entry.featuredMedia,
			commentStatus: entry.commentStatus,
			pingStatus: entry.pingStatus,
			sticky: entry.sticky,
			format: entry.format,
			deletedAt: entry.deletedAt,
			lastEditedBy: entry.lastEditedBy,
			typeDefinitionRevision: entry.typeDefinitionRevision,
			statusDefinitionRevision: entry.statusDefinitionRevision
		}))),
		lastKey: projected.at(-1)?.id ?? null
	});
	return Object.freeze({
		migrationId: CONTENT_MODEL_MIGRATION_ID,
		source,
		target,
		definitions,
		entries: projected
	});
}
var PG_DEFINITION_TABLE = (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 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()
)`;
var D1_DEFINITION_TABLE = (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
)`;
function postgresForwardSql() {
	return Object.freeze([
		PG_DEFINITION_TABLE("content_type_definitions"),
		PG_DEFINITION_TABLE("content_status_definitions"),
		`CREATE TABLE IF NOT EXISTS content_definition_versions (
      definition_kind text NOT NULL,
      definition_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 (definition_kind, definition_key, revision)
    )`,
		`CREATE TABLE IF NOT EXISTS content_password_credentials (
      entry_id uuid PRIMARY KEY REFERENCES content_entries(id) ON DELETE CASCADE,
      credential_version text NOT NULL,
      credential text NOT NULL,
      created_at timestamptz(3) NOT NULL DEFAULT NOW(),
      updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS content_lifecycle_journal (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(), operation_id text NOT NULL UNIQUE, kind text NOT NULL,
      entry_id uuid, definition_kind text, definition_key text, definition_revision integer, state text NOT NULL,
      payload jsonb, created_at timestamptz(3) NOT NULL DEFAULT NOW(), updated_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`CREATE TABLE IF NOT EXISTS content_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 content_tombstones (
      id uuid PRIMARY KEY DEFAULT gen_random_uuid(), entry_id uuid NOT NULL, operation_id text NOT NULL,
      type_key text NOT NULL, type_definition_revision integer NOT NULL, status_key text NOT NULL,
      status_definition_revision integer NOT NULL, snapshot jsonb NOT NULL,
      deleted_at timestamptz(3) NOT NULL DEFAULT NOW(), UNIQUE(operation_id, entry_id)
    )`,
		`CREATE TABLE IF NOT EXISTS content_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 content_migration_write_journal (
      seq bigserial PRIMARY KEY, migration_id text NOT NULL, operation text NOT NULL, entry_id text NOT NULL,
      before_value jsonb, after_value jsonb, created_at timestamptz(3) NOT NULL DEFAULT NOW()
    )`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS parent_id uuid`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS menu_order integer NOT NULL DEFAULT 0`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS template_key text`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS excerpt text NOT NULL DEFAULT ''`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS featured_media jsonb`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS comment_status text NOT NULL DEFAULT 'open' CHECK (comment_status IN ('open','closed'))`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS ping_status text NOT NULL DEFAULT 'open' CHECK (ping_status IN ('open','closed'))`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS sticky boolean NOT NULL DEFAULT false`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS format text`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS deleted_at timestamptz(3)`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS last_edited_by text`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS type_definition_revision integer NOT NULL DEFAULT 1`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS status_definition_revision integer NOT NULL DEFAULT 1`,
		`ALTER TABLE content_entries ADD COLUMN IF NOT EXISTS host_session_id text`,
		`UPDATE content_entries SET last_edited_by = author WHERE last_edited_by IS NULL`,
		`ALTER TABLE content_entries ALTER COLUMN last_edited_by SET NOT NULL`,
		`CREATE INDEX IF NOT EXISTS content_entries_parent_order_idx ON content_entries (type, parent_id, menu_order, id)`,
		`CREATE INDEX IF NOT EXISTS content_entries_deleted_idx ON content_entries (deleted_at)`,
		`CREATE INDEX IF NOT EXISTS content_entries_type_definition_idx ON content_entries (type, type_definition_revision)`,
		`CREATE INDEX IF NOT EXISTS content_entries_status_definition_idx ON content_entries (status, status_definition_revision)`,
		`CREATE OR REPLACE FUNCTION content_model_migration_journal_fn() RETURNS trigger AS $$
      BEGIN
        INSERT INTO content_migration_write_journal (migration_id, operation, entry_id, before_value, after_value)
        VALUES (
          '${CONTENT_MODEL_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 content_model_migration_write_trigger ON content_entries`,
		`CREATE TRIGGER content_model_migration_write_trigger AFTER INSERT OR UPDATE OR DELETE ON content_entries
      FOR EACH ROW EXECUTE FUNCTION content_model_migration_journal_fn()`
	]);
}
function d1JsonRow(prefix) {
	return `json_object(
    'id', ${prefix}.id, 'slug', ${prefix}.slug, 'type', ${prefix}.type, 'title', ${prefix}.title,
    'body', ${prefix}.body, 'status', ${prefix}.status, 'visibility', ${prefix}.visibility,
    'published_at', ${prefix}.published_at, 'author', ${prefix}.author,
    'created_at', ${prefix}.created_at, 'updated_at', ${prefix}.updated_at
  )`;
}
function d1ForwardSql() {
	return Object.freeze([
		D1_DEFINITION_TABLE("content_type_definitions"),
		D1_DEFINITION_TABLE("content_status_definitions"),
		`CREATE TABLE IF NOT EXISTS content_definition_versions (
      definition_kind TEXT NOT NULL, definition_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 (definition_kind, definition_key, revision)
    )`,
		`CREATE TABLE IF NOT EXISTS content_password_credentials (
      entry_id TEXT PRIMARY KEY REFERENCES content_entries(id) ON DELETE CASCADE,
      credential_version TEXT NOT NULL, credential TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
    )`,
		`CREATE TABLE IF NOT EXISTS content_lifecycle_journal (
      id TEXT PRIMARY KEY, operation_id TEXT NOT NULL UNIQUE, kind TEXT NOT NULL, entry_id TEXT,
      definition_kind TEXT, definition_key TEXT, definition_revision INTEGER, state TEXT NOT NULL,
      payload TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL
    )`,
		`CREATE TABLE IF NOT EXISTS content_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 content_tombstones (
      id TEXT PRIMARY KEY, entry_id TEXT NOT NULL, operation_id TEXT NOT NULL, type_key TEXT NOT NULL,
      type_definition_revision INTEGER NOT NULL, status_key TEXT NOT NULL, status_definition_revision INTEGER NOT NULL,
      snapshot TEXT NOT NULL, deleted_at TEXT NOT NULL, UNIQUE(operation_id, entry_id)
    )`,
		`CREATE TABLE IF NOT EXISTS content_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 content_migration_write_journal (
      seq INTEGER PRIMARY KEY AUTOINCREMENT, migration_id TEXT NOT NULL, operation TEXT NOT NULL, entry_id TEXT NOT NULL,
      before_value TEXT, after_value TEXT, created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
    )`,
		`ALTER TABLE content_entries ADD COLUMN parent_id TEXT`,
		`ALTER TABLE content_entries ADD COLUMN menu_order INTEGER NOT NULL DEFAULT 0`,
		`ALTER TABLE content_entries ADD COLUMN template_key TEXT`,
		`ALTER TABLE content_entries ADD COLUMN excerpt TEXT NOT NULL DEFAULT ''`,
		`ALTER TABLE content_entries ADD COLUMN featured_media TEXT`,
		`ALTER TABLE content_entries ADD COLUMN comment_status TEXT NOT NULL DEFAULT 'open' CHECK (comment_status IN ('open','closed'))`,
		`ALTER TABLE content_entries ADD COLUMN ping_status TEXT NOT NULL DEFAULT 'open' CHECK (ping_status IN ('open','closed'))`,
		`ALTER TABLE content_entries ADD COLUMN sticky INTEGER NOT NULL DEFAULT 0 CHECK (sticky IN (0,1))`,
		`ALTER TABLE content_entries ADD COLUMN format TEXT`,
		`ALTER TABLE content_entries ADD COLUMN deleted_at TEXT`,
		`ALTER TABLE content_entries ADD COLUMN last_edited_by TEXT`,
		`ALTER TABLE content_entries ADD COLUMN type_definition_revision INTEGER NOT NULL DEFAULT 1`,
		`ALTER TABLE content_entries ADD COLUMN status_definition_revision INTEGER NOT NULL DEFAULT 1`,
		`ALTER TABLE content_entries ADD COLUMN host_session_id TEXT`,
		`UPDATE content_entries SET last_edited_by = author WHERE last_edited_by IS NULL`,
		`CREATE INDEX IF NOT EXISTS content_entries_parent_order_idx ON content_entries (type, parent_id, menu_order, id)`,
		`CREATE INDEX IF NOT EXISTS content_entries_deleted_idx ON content_entries (deleted_at)`,
		`CREATE INDEX IF NOT EXISTS content_entries_type_definition_idx ON content_entries (type, type_definition_revision)`,
		`CREATE INDEX IF NOT EXISTS content_entries_status_definition_idx ON content_entries (status, status_definition_revision)`,
		`DROP TRIGGER IF EXISTS content_model_migration_write_insert`,
		`DROP TRIGGER IF EXISTS content_model_migration_write_update`,
		`DROP TRIGGER IF EXISTS content_model_migration_write_delete`,
		`CREATE TRIGGER content_model_migration_write_insert AFTER INSERT ON content_entries BEGIN
      INSERT INTO content_migration_write_journal (migration_id, operation, entry_id, before_value, after_value)
      VALUES ('${CONTENT_MODEL_MIGRATION_ID}', 'insert', NEW.id, NULL, ${d1JsonRow("NEW")});
    END`,
		`CREATE TRIGGER content_model_migration_write_update AFTER UPDATE ON content_entries BEGIN
      INSERT INTO content_migration_write_journal (migration_id, operation, entry_id, before_value, after_value)
      VALUES ('${CONTENT_MODEL_MIGRATION_ID}', 'update', NEW.id, ${d1JsonRow("OLD")}, ${d1JsonRow("NEW")});
    END`,
		`CREATE TRIGGER content_model_migration_write_delete AFTER DELETE ON content_entries BEGIN
      INSERT INTO content_migration_write_journal (migration_id, operation, entry_id, before_value, after_value)
      VALUES ('${CONTENT_MODEL_MIGRATION_ID}', 'delete', OLD.id, ${d1JsonRow("OLD")}, NULL);
    END`
	]);
}
function contentModelForwardMigrationSql(adapter) {
	return adapter === "postgres" ? postgresForwardSql() : d1ForwardSql();
}
var ContentDefinitionError = class extends Error {
	code;
	detail;
	field;
	name = "ContentDefinitionError";
	constructor(code, detail, field) {
		super(`content definition ${code}: ${detail}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
var TYPE_KEY$1 = /^[a-z][a-z0-9_-]{0,63}$/;
var CAPABILITY_KEYS = [
	"manageType",
	"migrateAll",
	"manageTerms",
	"create",
	"read",
	"readPrivate",
	"readProtected",
	"editOwn",
	"editOthers",
	"editPrivate",
	"editPublished",
	"publish",
	"deleteOwn",
	"deleteOthers",
	"deletePrivate",
	"deletePublished"
];
var LABEL_KEYS = [
	"name",
	"singularName",
	"menuName",
	"nameAdminBar",
	"addNew",
	"addNewItem",
	"editItem",
	"newItem",
	"viewItem",
	"viewItems",
	"searchItems",
	"notFound",
	"notFoundInTrash",
	"parentItemColon",
	"allItems",
	"archives",
	"attributes",
	"insertIntoItem",
	"uploadedToThisItem",
	"featuredImage",
	"setFeaturedImage",
	"removeFeaturedImage",
	"useFeaturedImage",
	"filterItemsList",
	"filterByDate",
	"itemsListNavigation",
	"itemsList",
	"itemPublished",
	"itemPublishedPrivately",
	"itemRevertedToDraft",
	"itemScheduled",
	"itemUpdated",
	"itemLink",
	"itemLinkDescription"
];
var FEATURE_SET = /* @__PURE__ */ new Set([
	"title",
	"editor",
	"blocks",
	"author",
	"featuredImage",
	"excerpt",
	"comments",
	"revisions",
	"pageAttributes",
	"postFormats",
	"customFields",
	"trackbacks"
]);
function invalid$1(detail, field) {
	throw new ContentDefinitionError("invalid-definition", detail, field);
}
function bounded$2(value, field, max = 256) {
	if (typeof value !== "string") invalid$1("must be a string", field);
	const normalized = value.trim();
	if (normalized.length === 0 || normalized.length > max) invalid$1(`must contain 1..${max} characters`, field);
	return normalized;
}
function finitePosition(value, field) {
	if (value === void 0) return void 0;
	if (typeof value !== "number" || !Number.isSafeInteger(value)) invalid$1("must be a safe integer", field);
	return value;
}
function uniqueSorted(values, field) {
	const normalized = values.map((value, index) => bounded$2(value, `${field}[${index}]`, 128));
	return Object.freeze([...new Set(normalized)].sort());
}
function normalizeTemplateValue(value, path, depth = 0) {
	if (depth > 32) invalid$1("template nesting exceeds 32 levels", path);
	if (value === null || typeof value === "string" || typeof value === "boolean") return value;
	if (typeof value === "number") {
		if (!Number.isFinite(value)) invalid$1("template numbers must be finite", path);
		return value;
	}
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => normalizeTemplateValue(item, `${path}[${index}]`, depth + 1)));
	if (typeof value === "object") {
		const out = {};
		for (const key of Object.keys(value).sort()) out[key] = normalizeTemplateValue(value[key], `${path}.${key}`, depth + 1);
		return Object.freeze(out);
	}
	invalid$1("unsupported template value", path);
}
function normalizeTemplateBlock(block, path, depth = 0) {
	if (depth > 32) invalid$1("template nesting exceeds 32 levels", path);
	const type = bounded$2(block.type, `${path}.type`, 128);
	const attributes = block.attributes ? Object.freeze(Object.fromEntries(Object.keys(block.attributes).sort().map((key) => [key, normalizeTemplateValue(block.attributes[key], `${path}.attributes.${key}`)]))) : void 0;
	const children = block.children ? Object.freeze(block.children.map((child, index) => normalizeTemplateBlock(child, `${path}.children[${index}]`, depth + 1))) : void 0;
	return Object.freeze({
		type,
		...attributes ? { attributes } : {},
		...children ? { children } : {}
	});
}
function normalizeContentTypeDefinition(definition) {
	if (!TYPE_KEY$1.test(definition.key)) invalid$1("must be a stable lowercase machine key", "key");
	const labels = Object.fromEntries(LABEL_KEYS.map((key) => [key, bounded$2(definition.labels?.[key], `labels.${key}`, 256)]));
	const capabilities = Object.fromEntries(CAPABILITY_KEYS.map((key) => [key, bounded$2(definition.capabilities?.[key], `capabilities.${key}`, 128)]));
	if (!Array.isArray(definition.supports)) invalid$1("must be an array", "supports");
	for (const [index, feature] of definition.supports.entries()) if (!FEATURE_SET.has(feature)) invalid$1(`unknown feature ${String(feature)}`, `supports[${index}]`);
	const supports = Object.freeze([...new Set(definition.supports)].sort());
	const taxonomies = uniqueSorted(definition.taxonomies ?? [], "taxonomies");
	const statusKeys = definition.statusKeys === void 0 ? void 0 : uniqueSorted(definition.statusKeys, "statusKeys");
	const defaultTemplateKey = bounded$2(definition.defaultTemplateKey, "defaultTemplateKey", 128);
	if (definition.hasArchive !== false && !definition.publiclyQueryable) invalid$1("archive requires publiclyQueryable", "hasArchive");
	if (definition.rewrite !== false && !definition.publiclyQueryable) invalid$1("rewrite requires publiclyQueryable", "rewrite");
	if (definition.template !== void 0 && !supports.includes("blocks")) invalid$1("template requires blocks support", "template");
	if (!definition.hierarchical && supports.includes("pageAttributes")) {}
	if (definition.rest !== false) {
		if (definition.rest.revisions && !supports.includes("revisions")) invalid$1("REST revisions require revisions support", "rest.revisions");
		if (definition.rest.autosaves && (!supports.includes("revisions") || !supports.includes("editor"))) invalid$1("REST autosaves require revisions and editor support", "rest.autosaves");
	}
	const rewrite = definition.rewrite === false ? false : Object.freeze({
		slug: bounded$2(definition.rewrite.slug, "rewrite.slug", 128),
		...definition.rewrite.withFront === void 0 ? {} : { withFront: Boolean(definition.rewrite.withFront) },
		...definition.rewrite.feeds === void 0 ? {} : { feeds: Boolean(definition.rewrite.feeds) },
		...definition.rewrite.pages === void 0 ? {} : { pages: Boolean(definition.rewrite.pages) }
	});
	const rest = definition.rest === false ? false : Object.freeze({
		base: bounded$2(definition.rest.base, "rest.base", 128),
		namespace: bounded$2(definition.rest.namespace, "rest.namespace", 128),
		revisions: Boolean(definition.rest.revisions),
		autosaves: Boolean(definition.rest.autosaves)
	});
	const template = definition.template === void 0 ? void 0 : Object.freeze(definition.template.map((block, index) => normalizeTemplateBlock(block, `template[${index}]`)));
	return Object.freeze({
		key: definition.key,
		labels: Object.freeze(labels),
		...definition.description === void 0 ? {} : { description: bounded$2(definition.description, "description", 4096) },
		public: Boolean(definition.public),
		hierarchical: Boolean(definition.hierarchical),
		excludeFromSearch: Boolean(definition.excludeFromSearch),
		publiclyQueryable: Boolean(definition.publiclyQueryable),
		showUi: Boolean(definition.showUi),
		showInMenu: typeof definition.showInMenu === "string" ? bounded$2(definition.showInMenu, "showInMenu", 128) : Boolean(definition.showInMenu),
		showInNavMenus: Boolean(definition.showInNavMenus),
		showInAdminBar: Boolean(definition.showInAdminBar),
		...finitePosition(definition.menuPosition, "menuPosition") === void 0 ? {} : { menuPosition: definition.menuPosition },
		...definition.menuIcon === void 0 ? {} : { menuIcon: bounded$2(definition.menuIcon, "menuIcon", 256) },
		capabilities: Object.freeze(capabilities),
		supports,
		taxonomies,
		hasArchive: typeof definition.hasArchive === "string" ? bounded$2(definition.hasArchive, "hasArchive", 128) : Boolean(definition.hasArchive),
		rewrite,
		queryVariable: typeof definition.queryVariable === "string" ? bounded$2(definition.queryVariable, "queryVariable", 128) : false,
		canExport: Boolean(definition.canExport),
		deleteWithAuthor: definition.deleteWithAuthor === null ? null : Boolean(definition.deleteWithAuthor),
		rest,
		defaultTemplateKey,
		...template ? { template } : {},
		...definition.templateLock === void 0 ? {} : { templateLock: definition.templateLock },
		...statusKeys ? { statusKeys } : {},
		active: Boolean(definition.active),
		...finitePosition(definition.position, "position") === void 0 ? {} : { position: definition.position }
	});
}
function defineContentType(definition) {
	return Object.freeze({
		...normalizeContentTypeDefinition(definition),
		origin: "code"
	});
}
function parseDefinition(value) {
	return normalizeContentTypeDefinition(typeof value === "string" ? JSON.parse(value) : value);
}
function bool$4(value) {
	return value === true || value === 1 || value === "1";
}
async function definitionRows(db, kind, key) {
	const table = kind === "type" ? "content_type_definitions" : "content_status_definitions";
	const where = key === void 0 ? sql.raw("") : sql` WHERE key = ${key}`;
	return db.execute(sql`SELECT key, origin, version, current_revision AS "currentRevision", canonical_hash AS "canonicalHash", definition, active, shadowed_db_version AS "shadowedDbVersion" FROM ${sql.raw(table)}${where}`);
}
async function resolveContentTypes(db, opts = {}) {
	const rows = await definitionRows(db, "type");
	const code = new Map((opts.codeTypes ?? []).map((definition) => [definition.key, defineContentType(definition)]));
	const dbRows = new Map(rows.map((row) => [row.key, row]));
	const resolved = [];
	for (const definition of code.values()) {
		const collision = dbRows.get(definition.key);
		const canonicalHash = await canonicalContentMigrationHash(definition);
		resolved.push(Object.freeze({
			...definition,
			version: collision?.origin === "code" ? Number(collision.version) : 1,
			revision: collision?.origin === "code" ? Number(collision.currentRevision) : 1,
			canonicalHash,
			...collision && collision.origin !== "code" ? { shadowedDbVersion: Number(collision.version) } : {}
		}));
	}
	for (const row of rows) {
		if (code.has(row.key)) continue;
		const definition = parseDefinition(row.definition);
		resolved.push(Object.freeze({
			...definition,
			active: bool$4(row.active),
			origin: row.origin === "code" ? "code" : "db",
			version: Number(row.version),
			revision: Number(row.currentRevision),
			canonicalHash: row.canonicalHash,
			...row.shadowedDbVersion === null ? {} : { shadowedDbVersion: Number(row.shadowedDbVersion) }
		}));
	}
	return resolved.sort((left, right) => (left.position ?? 0) - (right.position ?? 0) || left.labels.name.localeCompare(right.labels.name) || left.key.localeCompare(right.key));
}
async function resolveContentType(db, key, opts = {}) {
	const found = (await resolveContentTypes(db, opts)).find((definition) => definition.key === key);
	if (!found) throw new ContentDefinitionError("definition-not-found", "content type is not registered");
	return found;
}
function principalScope$2(principal) {
	return `${principal.tenantId ?? ""}:${principal.id}`;
}
async function readDefinitionReceipt(db, operationId) {
	const raw = (await db.execute(sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id = ${operationId}`))[0]?.payload;
	if (raw === void 0) return void 0;
	const payload = typeof raw === "string" ? JSON.parse(raw) : raw;
	if (!payload || typeof payload.requestHash !== "string" || typeof payload.principalScope !== "string") throw new ContentDefinitionError("invalid-receipt", "operation receipt is malformed");
	return payload;
}
async function writeDefinitionReceipt(db, input) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	await db.execute(sql`INSERT INTO content_lifecycle_journal (id, operation_id, kind, state, payload, created_at, updated_at)
    VALUES (${crypto.randomUUID()}, ${input.operationId}, ${input.kind}, 'committed', ${JSON.stringify(input.payload)}, ${now}, ${now})`);
}
async function writeDefinitionVersion(db, input) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	await db.execute(sql`INSERT INTO content_definition_versions (definition_kind, definition_key, revision, canonical_hash, definition, origin, created_at)
    VALUES (${input.kind}, ${input.key}, ${input.revision}, ${input.canonicalHash}, ${JSON.stringify(input.definition)}, ${input.origin}, ${now})`);
}
async function createContentType(db, principal, input, authorization, effects, opts = {}) {
	const normalized = normalizeContentTypeDefinition({
		...input.definition,
		active: true
	});
	const { policyVersion } = await authorization.assert(db, principal, "createType", normalized.key);
	if ((opts.codeTypes ?? []).some((definition) => definition.key === normalized.key)) throw new ContentDefinitionError("definition-conflict", "database definition cannot shadow a code-owned key", "key");
	const requestHash = await canonicalContentMigrationHash({
		definition: normalized,
		operationId: input.operationId
	});
	const scope = principalScope$2(principal);
	const replay = await readDefinitionReceipt(db, input.operationId);
	if (replay) {
		if (replay.requestHash !== requestHash || replay.principalScope !== scope) throw new ContentDefinitionError("operation-conflict", "operation id was already used for different bytes or scope");
		return Object.freeze(replay.result);
	}
	if ((await definitionRows(db, "type", normalized.key)).length !== 0) throw new ContentDefinitionError("definition-conflict", "content type key already exists", "key");
	const canonicalHash = await canonicalContentMigrationHash(normalized);
	const now = (/* @__PURE__ */ new Date()).toISOString();
	await db.execute(sql`INSERT INTO content_type_definitions (key, origin, version, active, current_revision, canonical_hash, definition, created_at, updated_at)
    VALUES (${normalized.key}, 'db', 1, ${true}, 1, ${canonicalHash}, ${JSON.stringify(normalized)}, ${now}, ${now})`);
	await writeDefinitionVersion(db, {
		kind: "type",
		key: normalized.key,
		revision: 1,
		canonicalHash,
		definition: normalized,
		origin: "db"
	});
	const result = Object.freeze({
		...normalized,
		origin: "db",
		version: 1,
		revision: 1,
		canonicalHash
	});
	await writeDefinitionReceipt(db, {
		operationId: input.operationId,
		kind: "definition:create:type",
		payload: {
			requestHash,
			principalScope: scope,
			result
		}
	});
	const event = {
		id: crypto.randomUUID(),
		version: 1,
		kind: "dbDefinitionCreated",
		operationId: input.operationId,
		principalId: principal.id,
		definitionKind: "type",
		definitionKey: normalized.key,
		definitionHash: canonicalHash,
		revision: 1,
		authorizationPolicyVersion: policyVersion
	};
	await effects.audit.record(db, event);
	await effects.outbox.enqueue(db, event);
	return result;
}
Object.freeze({
	definitionRows,
	parseDefinition,
	bool: bool$4
});
var STATUS_KEY = /^[a-z][a-z0-9_-]{0,63}$/;
var DATE_LABELS = /* @__PURE__ */ new Set([
	"published",
	"scheduled",
	"lastModified",
	"created"
]);
var TRANSITION_INPUTS = /* @__PURE__ */ new Set([
	"none",
	"scheduleAt",
	"publishedAt"
]);
function invalid(detail, field) {
	throw new ContentDefinitionError("invalid-definition", detail, field);
}
function bounded$1(value, field, max = 256) {
	if (typeof value !== "string") invalid("must be a string", field);
	const normalized = value.trim();
	if (normalized.length === 0 || normalized.length > max) invalid(`must contain 1..${max} characters`, field);
	return normalized;
}
function normalizeContentStatusDefinition(definition) {
	if (!STATUS_KEY.test(definition.key)) invalid("must be a stable lowercase machine key", "key");
	if (!DATE_LABELS.has(definition.dateLabel)) invalid("unknown date label", "dateLabel");
	if (!TRANSITION_INPUTS.has(definition.transitionInput)) invalid("unknown transition input", "transitionInput");
	if (definition.transitionInput === "scheduleAt" && definition.key !== "scheduled") invalid("scheduleAt is reserved for the scheduled status", "transitionInput");
	if (definition.transitionInput === "publishedAt" && !definition.published) invalid("publishedAt requires a published status", "transitionInput");
	if (definition.dateLabel === "scheduled" && definition.transitionInput !== "scheduleAt") invalid("scheduled date label requires scheduleAt input", "dateLabel");
	if (definition.position !== void 0 && (!Number.isSafeInteger(definition.position) || !Number.isFinite(definition.position))) invalid("must be a safe integer", "position");
	return Object.freeze({
		key: definition.key,
		label: bounded$1(definition.label, "label"),
		published: Boolean(definition.published),
		internal: Boolean(definition.internal),
		excludeFromSearch: Boolean(definition.excludeFromSearch),
		publiclyQueryable: Boolean(definition.publiclyQueryable),
		showInAdminAll: Boolean(definition.showInAdminAll),
		showInAdminStatusFilter: Boolean(definition.showInAdminStatusFilter),
		dateLabel: definition.dateLabel,
		transitionInput: definition.transitionInput,
		...definition.position === void 0 ? {} : { position: definition.position }
	});
}
function defineContentStatus(definition) {
	return Object.freeze({
		...normalizeContentStatusDefinition(definition),
		origin: "code"
	});
}
function bool$3(value) {
	return value === true || value === 1 || value === "1";
}
function parseStatus$1(value) {
	return normalizeContentStatusDefinition(typeof value === "string" ? JSON.parse(value) : value);
}
async function statusRows(db, key) {
	const where = key === void 0 ? sql.raw("") : sql` WHERE key = ${key}`;
	return db.execute(sql`SELECT key, origin, version, current_revision AS "currentRevision", canonical_hash AS "canonicalHash", definition, active, shadowed_db_version AS "shadowedDbVersion" FROM content_status_definitions${where}`);
}
async function resolveContentStatuses(db, opts = {}) {
	const rows = await statusRows(db);
	const code = new Map((opts.codeStatuses ?? []).map((definition) => [definition.key, defineContentStatus(definition)]));
	const dbRows = new Map(rows.map((row) => [row.key, row]));
	const resolved = [];
	for (const definition of code.values()) {
		const collision = dbRows.get(definition.key);
		resolved.push(Object.freeze({
			...definition,
			active: true,
			version: collision?.origin === "code" ? Number(collision.version) : 1,
			revision: collision?.origin === "code" ? Number(collision.currentRevision) : 1,
			canonicalHash: await canonicalContentMigrationHash(definition),
			...collision && collision.origin !== "code" ? { shadowedDbVersion: Number(collision.version) } : {}
		}));
	}
	for (const row of rows) {
		if (code.has(row.key)) continue;
		const definition = parseStatus$1(row.definition);
		resolved.push(Object.freeze({
			...definition,
			active: bool$3(row.active),
			origin: row.origin === "code" ? "code" : "db",
			version: Number(row.version),
			revision: Number(row.currentRevision),
			canonicalHash: row.canonicalHash,
			...row.shadowedDbVersion === null ? {} : { shadowedDbVersion: Number(row.shadowedDbVersion) }
		}));
	}
	return resolved.sort((left, right) => (left.position ?? 0) - (right.position ?? 0) || left.label.localeCompare(right.label) || left.key.localeCompare(right.key));
}
async function resolveContentStatus(db, key, opts = {}) {
	const status = (await resolveContentStatuses(db, opts)).find((item) => item.key === key);
	if (!status) throw new ContentDefinitionError("definition-not-found", "content status is not registered");
	return status;
}
async function createContentStatus(db, principal, input, authorization, effects, opts = {}) {
	const normalized = normalizeContentStatusDefinition(input.definition);
	const { policyVersion } = await authorization.assert(db, principal, "createStatus", normalized.key);
	if ((opts.codeStatuses ?? []).some((definition) => definition.key === normalized.key)) throw new ContentDefinitionError("definition-conflict", "database status cannot shadow a code-owned key", "key");
	const requestHash = await canonicalContentMigrationHash({
		definition: normalized,
		operationId: input.operationId
	});
	const scope = principalScope$2(principal);
	const replay = await readDefinitionReceipt(db, input.operationId);
	if (replay) {
		if (replay.requestHash !== requestHash || replay.principalScope !== scope) throw new ContentDefinitionError("operation-conflict", "operation id was already used for different bytes or scope");
		return Object.freeze(replay.result);
	}
	if ((await statusRows(db, normalized.key)).length !== 0) throw new ContentDefinitionError("definition-conflict", "content status key already exists", "key");
	const canonicalHash = await canonicalContentMigrationHash(normalized);
	const now = (/* @__PURE__ */ new Date()).toISOString();
	await db.execute(sql`INSERT INTO content_status_definitions (key, origin, version, active, current_revision, canonical_hash, definition, created_at, updated_at)
    VALUES (${normalized.key}, 'db', 1, ${true}, 1, ${canonicalHash}, ${JSON.stringify(normalized)}, ${now}, ${now})`);
	await writeDefinitionVersion(db, {
		kind: "status",
		key: normalized.key,
		revision: 1,
		canonicalHash,
		definition: normalized,
		origin: "db"
	});
	const result = Object.freeze({
		...normalized,
		origin: "db",
		version: 1,
		revision: 1,
		active: true,
		canonicalHash
	});
	await writeDefinitionReceipt(db, {
		operationId: input.operationId,
		kind: "definition:create:status",
		payload: {
			requestHash,
			principalScope: scope,
			result
		}
	});
	const event = {
		id: crypto.randomUUID(),
		version: 1,
		kind: "dbDefinitionCreated",
		operationId: input.operationId,
		principalId: principal.id,
		definitionKind: "status",
		definitionKey: normalized.key,
		definitionHash: canonicalHash,
		revision: 1,
		authorizationPolicyVersion: policyVersion
	};
	await effects.audit.record(db, event);
	await effects.outbox.enqueue(db, event);
	return result;
}
Object.freeze({
	statusRows,
	parseStatus: parseStatus$1,
	bool: bool$3
});
function asSchemaValue(value) {
	return JSON.parse(JSON.stringify(value));
}
function parsePayload(value) {
	return typeof value === "string" ? JSON.parse(value) : value;
}
function countValue(value) {
	if (typeof value === "number") return value;
	if (typeof value === "bigint") return Number(value);
	if (typeof value === "string" && /^\d+$/.test(value)) return Number(value);
	throw new ContentDefinitionError("invalid-receipt", "adapter returned a non-numeric count");
}
async function typeCorpus(db, key) {
	return db.execute(sql`SELECT id, status, parent_id AS "parentId", menu_order AS "menuOrder",
    template_key AS "templateKey", excerpt, featured_media AS "featuredMedia", comment_status AS "commentStatus",
    ping_status AS "pingStatus", sticky, format, deleted_at AS "deletedAt", updated_at AS "updatedAt"
    FROM content_entries WHERE type = ${key} ORDER BY id`);
}
async function statusCorpus(db, key) {
	return db.execute(sql`SELECT id, type, updated_at AS "updatedAt" FROM content_entries WHERE status = ${key} ORDER BY id`);
}
async function corpusEvidence(rows) {
	const hash = await canonicalContentMigrationHash(rows.map((row) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, value instanceof Date ? value.toISOString() : value]))));
	return {
		version: `sha256:${hash}`,
		hash
	};
}
function removed(before, after) {
	const next = new Set(after ?? []);
	return (before ?? []).filter((item) => !next.has(item));
}
function validateStrategies(strategies) {
	if (strategies.length === 0) throw new ContentDefinitionError("strategy-conflict", "at least one strategy is required");
	if (strategies.some((strategy) => strategy.kind === "reject") && strategies.length !== 1) throw new ContentDefinitionError("strategy-conflict", "reject must be the sole strategy");
	const singular = /* @__PURE__ */ new Set();
	for (const strategy of strategies) {
		const category = strategy.kind === "mapStatus" ? "status" : strategy.kind === "flattenHierarchy" ? "hierarchy" : strategy.kind === "reassignType" || strategy.kind === "deactivate" ? "lifecycle" : void 0;
		if (category && singular.has(category)) throw new ContentDefinitionError("strategy-conflict", `multiple ${category} strategies are not allowed`);
		if (category) singular.add(category);
	}
}
function typeImpactCounts(current, next, rows) {
	const counts = { entries: rows.length };
	const incompatibilities = [];
	for (const status of removed(current.statusKeys, next.statusKeys)) {
		const count = rows.filter((row) => row.status === status).length;
		counts[`status:${status}`] = count;
		if (count > 0) incompatibilities.push(`status:${status}`);
	}
	if (current.hierarchical && !next.hierarchical) {
		const count = rows.filter((row) => row.parentId !== null).length;
		counts.hierarchy = count;
		if (count > 0) incompatibilities.push("hierarchy");
	}
	for (const feature of removed(current.supports, next.supports)) {
		let count = 0;
		if (feature === "excerpt") count = rows.filter((row) => row.excerpt.length > 0).length;
		else if (feature === "featuredImage") count = rows.filter((row) => row.featuredMedia !== null).length;
		else if (feature === "pageAttributes") count = rows.filter((row) => row.parentId !== null || Number(row.menuOrder) !== 0 || row.templateKey !== null).length;
		else if (feature === "postFormats") count = rows.filter((row) => row.format !== null).length;
		else count = rows.length;
		counts[`feature:${feature}`] = count;
		if (count > 0) incompatibilities.push(`feature:${feature}`);
	}
	if ((current.publiclyQueryable && !next.publiclyQueryable || current.rest !== false && next.rest === false || current.hasArchive !== false && next.hasArchive === false || current.rewrite !== false && next.rewrite === false) && rows.length > 0) {
		counts.routing = rows.length;
		incompatibilities.push("routing");
	}
	return {
		counts,
		incompatibilities
	};
}
async function storeImpact(db, plan) {
	const token = await canonicalContentMigrationHash(plan);
	const operationId = `impact:${token}`;
	if ((await db.execute(sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id = ${operationId}`)).length === 0) {
		const now = (/* @__PURE__ */ new Date()).toISOString();
		await db.execute(sql`INSERT INTO content_lifecycle_journal (id, operation_id, kind, definition_kind, definition_key, definition_revision, state, payload, created_at, updated_at)
      VALUES (${crypto.randomUUID()}, ${operationId}, 'definition-impact', ${plan.definitionKind}, ${plan.key}, ${plan.expectedVersion}, 'prepared', ${JSON.stringify(plan)}, ${now}, ${now})`);
	}
	return token;
}
async function readImpact(db, token) {
	const rows = await db.execute(sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id = ${`impact:${token}`} AND kind = 'definition-impact'`);
	if (!rows[0]) throw new ContentDefinitionError("stale-impact", "impact token is unknown or expired");
	const plan = parsePayload(rows[0].payload);
	if (await canonicalContentMigrationHash(plan) !== token) throw new ContentDefinitionError("stale-impact", "impact token bytes do not match stored plan");
	return plan;
}
function strategyHash(strategies) {
	return canonicalContentMigrationHash(strategies);
}
async function previewContentTypeChange(db, principal, input, authorization, opts = {}) {
	validateStrategies(input.strategies);
	const { policyVersion } = await authorization.assert(db, principal, "changeType", input.key);
	const current = await resolveContentType(db, input.key, opts);
	if (current.origin === "code") throw new ContentDefinitionError("code-definition-owned", "code definitions can only change through reconciliation");
	if (current.version !== input.expectedVersion) throw new ContentDefinitionError("stale-definition", "expected version does not match current definition");
	const next = normalizeContentTypeDefinition({
		...current,
		...input.patch ?? {},
		key: current.key,
		active: input.deactivate || input.delete ? false : current.active
	});
	const rows = await typeCorpus(db, input.key);
	const evidence = await corpusEvidence(rows);
	const impact = typeImpactCounts(current, next, rows);
	if ((input.deactivate || input.delete) && rows.length > 0) impact.incompatibilities.push(input.delete ? "delete-with-entries" : "deactivate-with-entries");
	const plan = {
		definitionKind: "type",
		key: input.key,
		expectedVersion: input.expectedVersion,
		policyVersion,
		corpusVersion: evidence.version,
		corpusHash: evidence.hash,
		affectedCounts: Object.freeze({ ...impact.counts }),
		incompatibilities: Object.freeze([...new Set(impact.incompatibilities)].sort()),
		request: asSchemaValue({
			patch: input.patch ?? null,
			deactivate: Boolean(input.deactivate),
			delete: Boolean(input.delete),
			strategies: input.strategies
		}),
		strategyHash: await strategyHash(input.strategies)
	};
	const token = await storeImpact(db, plan);
	return Object.freeze({
		token,
		definitionKey: input.key,
		expectedVersion: input.expectedVersion,
		authorizationPolicyVersion: policyVersion,
		corpusVersion: evidence.version,
		corpusHash: evidence.hash,
		affectedCounts: plan.affectedCounts,
		incompatibilities: plan.incompatibilities
	});
}
function requestRecord(plan) {
	return plan.request;
}
async function verifyBackups(db, plan, strategies, destructive) {
	const purges = strategies.filter((strategy) => strategy.kind === "purgeFeatureData");
	if (purges.length === 0) return Object.freeze([]);
	if (!destructive) throw new ContentDefinitionError("backup-required", "purge requires destructive backup dependencies");
	const ids = [];
	for (const purge of purges) {
		const expectedCounts = Object.fromEntries(purge.features.map((feature) => [`feature:${feature}`, plan.affectedCounts[`feature:${feature}`] ?? 0]));
		const scopeHash = await canonicalContentMigrationHash({
			definitionKey: plan.key,
			features: [...purge.features].sort(),
			policyVersion: plan.policyVersion,
			corpusVersion: plan.corpusVersion,
			corpusHash: plan.corpusHash
		});
		const manifest = await destructive.backups.verify(db, purge.backupId, scopeHash, plan.corpusVersion, plan.corpusHash, expectedCounts);
		if (!manifest.immutable || manifest.id !== purge.backupId || manifest.scopeHash !== scopeHash || manifest.corpusHash !== plan.corpusHash) throw new ContentDefinitionError("backup-mismatch", "backup manifest does not match the bound destructive scope");
		ids.push(manifest.id);
	}
	return Object.freeze(ids.sort());
}
async function applyTypeStrategies(db, key, strategies, opts) {
	for (const strategy of strategies) {
		if (strategy.kind === "reject" || strategy.kind === "deactivate" || strategy.kind === "retainDormantFeatureData") continue;
		if (strategy.kind === "mapStatus") for (const [from, to] of Object.entries(strategy.mappings).sort(([a], [b]) => a.localeCompare(b))) {
			const target = await resolveContentStatus(db, to, { codeStatuses: opts.codeStatuses });
			if (!target.active) throw new ContentDefinitionError("strategy-conflict", `target status ${to} is inactive`);
			await db.execute(sql`UPDATE content_entries SET status = ${to}, status_definition_revision = ${target.revision} WHERE type = ${key} AND status = ${from}`);
		}
		else if (strategy.kind === "flattenHierarchy") await db.execute(sql`UPDATE content_entries SET parent_id = NULL WHERE type = ${key} AND parent_id IS NOT NULL`);
		else if (strategy.kind === "detachTaxonomies") for (const taxonomy of [...new Set(strategy.taxonomyKeys)].sort()) await db.execute(sql`DELETE FROM content_entry_terms WHERE entry_id IN (SELECT id FROM content_entries WHERE type = ${key}) AND term_id IN (SELECT id FROM content_terms WHERE taxonomy = ${taxonomy})`);
		else if (strategy.kind === "purgeFeatureData") {
			for (const feature of strategy.features) if (feature === "excerpt") await db.execute(sql`UPDATE content_entries SET excerpt = '' WHERE type = ${key}`);
			else if (feature === "featuredImage") await db.execute(sql`UPDATE content_entries SET featured_media = NULL WHERE type = ${key}`);
			else if (feature === "pageAttributes") await db.execute(sql`UPDATE content_entries SET parent_id = NULL, menu_order = 0, template_key = NULL WHERE type = ${key}`);
			else if (feature === "postFormats") await db.execute(sql`UPDATE content_entries SET format = NULL WHERE type = ${key}`);
		} else if (strategy.kind === "reassignType") {
			const target = await resolveContentType(db, strategy.targetTypeKey, { codeTypes: opts.codeTypes });
			if (!target.active) throw new ContentDefinitionError("strategy-conflict", "target type is inactive");
			await db.execute(sql`UPDATE content_entries SET type = ${target.key}, type_definition_revision = ${target.revision} WHERE type = ${key}`);
		}
	}
}
async function applyContentTypeChange(db, principal, input, authorization, effects, opts = {}) {
	validateStrategies(input.strategies);
	await authorization.assert(db, principal, "changeType");
	const plan = await readImpact(db, input.impactToken);
	if (plan.definitionKind !== "type") throw new ContentDefinitionError("stale-impact", "impact token belongs to another definition kind");
	const { policyVersion } = await authorization.assert(db, principal, "changeType", plan.key);
	if (policyVersion !== plan.policyVersion) throw new ContentDefinitionError("authorization-drift", "authorization policy changed after preview");
	if (await strategyHash(input.strategies) !== plan.strategyHash) throw new ContentDefinitionError("stale-impact", "strategies differ from preview");
	const scope = principalScope$2(principal);
	const requestHash = await canonicalContentMigrationHash({
		impactToken: input.impactToken,
		strategies: input.strategies
	});
	const replay = await readDefinitionReceipt(db, input.operationId);
	if (replay) {
		if (replay.requestHash !== requestHash || replay.principalScope !== scope) throw new ContentDefinitionError("operation-conflict", "operation id was already used for different bytes or scope");
		return replay.result === null ? null : Object.freeze(replay.result);
	}
	const current = await resolveContentType(db, plan.key, { codeTypes: opts.codeTypes });
	if (current.origin === "code") throw new ContentDefinitionError("code-definition-owned", "code definition became effective after preview");
	if (current.version !== plan.expectedVersion) throw new ContentDefinitionError("stale-impact", "definition version changed after preview");
	const evidence = await corpusEvidence(await typeCorpus(db, plan.key));
	if (evidence.hash !== plan.corpusHash || evidence.version !== plan.corpusVersion) throw new ContentDefinitionError("stale-impact", "affected corpus changed after preview");
	const request = requestRecord(plan);
	const backups = await verifyBackups(db, plan, input.strategies, opts.destructive);
	if (input.strategies[0]?.kind === "reject" && plan.incompatibilities.length > 0) throw new ContentDefinitionError("strategy-conflict", "reject strategy cannot apply an incompatible change");
	await applyTypeStrategies(db, plan.key, input.strategies, opts);
	const remainingCount = countValue((await db.execute(sql`SELECT COUNT(*) AS count FROM content_entries WHERE type = ${plan.key}`))[0]?.count ?? 0);
	if (request.delete && remainingCount > 0) throw new ContentDefinitionError("strategy-conflict", "delete requires zero references or complete reassignment");
	const next = normalizeContentTypeDefinition({
		...current,
		...request.patch ?? {},
		key: current.key,
		active: request.deactivate || request.delete ? false : current.active
	});
	const version = current.version + 1;
	const revision = current.revision + 1;
	const canonicalHash = await canonicalContentMigrationHash(next);
	await writeDefinitionVersion(db, {
		kind: "type",
		key: current.key,
		revision,
		canonicalHash,
		definition: next,
		origin: "db"
	});
	let result;
	if (request.delete) {
		await db.execute(sql`DELETE FROM content_type_definitions WHERE key = ${current.key} AND version = ${current.version}`);
		result = null;
	} else {
		const now = (/* @__PURE__ */ new Date()).toISOString();
		await db.execute(sql`UPDATE content_type_definitions SET version = ${version}, current_revision = ${revision}, active = ${next.active}, canonical_hash = ${canonicalHash}, definition = ${JSON.stringify(next)}, updated_at = ${now} WHERE key = ${current.key} AND version = ${current.version}`);
		result = Object.freeze({
			...next,
			origin: "db",
			version,
			revision,
			canonicalHash
		});
	}
	await writeDefinitionReceipt(db, {
		operationId: input.operationId,
		kind: "definition:change:type",
		payload: {
			requestHash,
			principalScope: scope,
			result
		}
	});
	const event = {
		id: crypto.randomUUID(),
		version: 1,
		kind: "dbDefinitionChanged",
		operationId: input.operationId,
		principalId: principal.id,
		definitionKind: "type",
		definitionKey: current.key,
		action: request.delete ? "delete" : request.deactivate ? "deactivate" : "update",
		strategyHash: plan.strategyHash,
		impactToken: input.impactToken,
		authorizationPolicyVersion: policyVersion,
		corpusVersion: plan.corpusVersion,
		corpusHash: plan.corpusHash,
		affectedCounts: plan.affectedCounts,
		backupIds: backups
	};
	await effects.audit.record(db, event);
	await effects.outbox.enqueue(db, event);
	return result;
}
async function previewContentStatusChange(db, principal, input, authorization, opts = {}) {
	const { policyVersion } = await authorization.assert(db, principal, "changeStatus", input.key);
	const current = await resolveContentStatus(db, input.key, opts);
	if (current.origin === "code") throw new ContentDefinitionError("code-definition-owned", "code statuses can only change through reconciliation");
	if (current.version !== input.expectedVersion) throw new ContentDefinitionError("stale-definition", "expected version does not match current status");
	normalizeContentStatusDefinition({
		...current,
		...input.patch ?? {},
		key: current.key
	});
	const rows = await statusCorpus(db, input.key);
	const evidence = await corpusEvidence(rows);
	const counts = Object.freeze({ entries: rows.length });
	const incompatibilities = Object.freeze(rows.length > 0 && (input.delete || input.deactivate || input.patch !== void 0) ? ["status-in-use"] : []);
	const token = await storeImpact(db, {
		definitionKind: "status",
		key: input.key,
		expectedVersion: input.expectedVersion,
		policyVersion,
		corpusVersion: evidence.version,
		corpusHash: evidence.hash,
		affectedCounts: counts,
		incompatibilities,
		request: asSchemaValue({
			patch: input.patch ?? null,
			deactivate: Boolean(input.deactivate),
			delete: Boolean(input.delete),
			strategy: input.strategy
		}),
		strategyHash: await strategyHash(input.strategy)
	});
	return Object.freeze({
		token,
		definitionKey: input.key,
		expectedVersion: input.expectedVersion,
		authorizationPolicyVersion: policyVersion,
		corpusVersion: evidence.version,
		corpusHash: evidence.hash,
		affectedCounts: counts,
		incompatibilities
	});
}
async function applyContentStatusChange(db, principal, input, authorization, effects, opts = {}) {
	await authorization.assert(db, principal, "changeStatus");
	const plan = await readImpact(db, input.impactToken);
	if (plan.definitionKind !== "status") throw new ContentDefinitionError("stale-impact", "impact token belongs to another definition kind");
	const { policyVersion } = await authorization.assert(db, principal, "changeStatus", plan.key);
	if (policyVersion !== plan.policyVersion) throw new ContentDefinitionError("authorization-drift", "authorization policy changed after preview");
	if (await strategyHash(input.strategy) !== plan.strategyHash) throw new ContentDefinitionError("stale-impact", "strategy differs from preview");
	const scope = principalScope$2(principal);
	const requestHash = await canonicalContentMigrationHash({
		impactToken: input.impactToken,
		strategy: input.strategy
	});
	const replay = await readDefinitionReceipt(db, input.operationId);
	if (replay) {
		if (replay.requestHash !== requestHash || replay.principalScope !== scope) throw new ContentDefinitionError("operation-conflict", "operation id was already used for different bytes or scope");
		return replay.result === null ? null : Object.freeze(replay.result);
	}
	const current = await resolveContentStatus(db, plan.key, opts);
	if (current.origin === "code") throw new ContentDefinitionError("code-definition-owned", "code status became effective after preview");
	if (current.version !== plan.expectedVersion) throw new ContentDefinitionError("stale-impact", "status version changed after preview");
	const rows = await statusCorpus(db, plan.key);
	if ((await corpusEvidence(rows)).hash !== plan.corpusHash) throw new ContentDefinitionError("stale-impact", "status corpus changed after preview");
	const request = plan.request;
	if (rows.length > 0) {
		if (input.strategy.kind === "reject") throw new ContentDefinitionError("strategy-conflict", "status is still referenced");
		const target = await resolveContentStatus(db, input.strategy.targetStatusKey, opts);
		if (!target.active || target.key === current.key) throw new ContentDefinitionError("strategy-conflict", "status mapping target must be another active status");
		await db.execute(sql`UPDATE content_entries SET status = ${target.key}, status_definition_revision = ${target.revision} WHERE status = ${current.key}`);
	}
	const next = normalizeContentStatusDefinition({
		...current,
		...request.patch ?? {},
		key: current.key
	});
	const version = current.version + 1;
	const revision = current.revision + 1;
	const canonicalHash = await canonicalContentMigrationHash(next);
	await writeDefinitionVersion(db, {
		kind: "status",
		key: current.key,
		revision,
		canonicalHash,
		definition: next,
		origin: "db"
	});
	let result;
	if (request.delete) {
		await db.execute(sql`DELETE FROM content_status_definitions WHERE key = ${current.key} AND version = ${current.version}`);
		result = null;
	} else {
		const active = request.deactivate ? false : current.active;
		const persisted = {
			...next,
			active
		};
		const now = (/* @__PURE__ */ new Date()).toISOString();
		await db.execute(sql`UPDATE content_status_definitions SET version = ${version}, current_revision = ${revision}, active = ${active}, canonical_hash = ${canonicalHash}, definition = ${JSON.stringify(next)}, updated_at = ${now} WHERE key = ${current.key} AND version = ${current.version}`);
		result = Object.freeze({
			...persisted,
			origin: "db",
			version,
			revision,
			canonicalHash
		});
	}
	await writeDefinitionReceipt(db, {
		operationId: input.operationId,
		kind: "definition:change:status",
		payload: {
			requestHash,
			principalScope: scope,
			result
		}
	});
	const event = {
		id: crypto.randomUUID(),
		version: 1,
		kind: "dbDefinitionChanged",
		operationId: input.operationId,
		principalId: principal.id,
		definitionKind: "status",
		definitionKey: current.key,
		action: request.delete ? "delete" : request.deactivate ? "deactivate" : "update",
		strategyHash: plan.strategyHash,
		impactToken: input.impactToken,
		authorizationPolicyVersion: policyVersion,
		corpusVersion: plan.corpusVersion,
		corpusHash: plan.corpusHash,
		affectedCounts: plan.affectedCounts,
		backupIds: []
	};
	await effects.audit.record(db, event);
	await effects.outbox.enqueue(db, event);
	return result;
}
function own(record, key) {
	return Object.prototype.hasOwnProperty.call(record, key);
}
function parseBackupPayload(value) {
	if (typeof value !== "object" || value === null || Array.isArray(value)) throw new ContentDefinitionError("backup-mismatch", "backup payload must be an object");
	const record = value;
	if (record.version !== 1) throw new ContentDefinitionError("backup-mismatch", "backup payload version must be 1");
	for (const section of [
		"entries",
		"typeDefinitions",
		"statusDefinitions"
	]) if (record[section] !== void 0 && !Array.isArray(record[section])) throw new ContentDefinitionError("backup-mismatch", `${section} must be an array`);
	const payload = record;
	const entryIds = /* @__PURE__ */ new Set();
	for (const entry of payload.entries ?? []) {
		if (typeof entry !== "object" || entry === null || typeof entry.id !== "string" || entry.id.length === 0) throw new ContentDefinitionError("backup-mismatch", "backup entry snapshots require a non-empty id");
		if (entryIds.has(entry.id)) throw new ContentDefinitionError("backup-mismatch", `duplicate backup entry ${entry.id}`);
		entryIds.add(entry.id);
		if (own(entry, "excerpt") && typeof entry.excerpt !== "string") throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} excerpt must be a string`);
		if (own(entry, "parentId") && entry.parentId !== null && typeof entry.parentId !== "string") throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} parentId must be string|null`);
		if (own(entry, "menuOrder") && !Number.isSafeInteger(entry.menuOrder)) throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} menuOrder must be a safe integer`);
		if (own(entry, "templateKey") && entry.templateKey !== null && typeof entry.templateKey !== "string") throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} templateKey must be string|null`);
		if (own(entry, "format") && entry.format !== null && typeof entry.format !== "string") throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} format must be string|null`);
		if (![
			"excerpt",
			"featuredMedia",
			"parentId",
			"menuOrder",
			"templateKey",
			"format"
		].some((key) => own(entry, key))) throw new ContentDefinitionError("backup-mismatch", `entry ${entry.id} snapshot contains no restorable fields`);
	}
	const typeKeys = /* @__PURE__ */ new Set();
	for (const item of payload.typeDefinitions ?? []) {
		if (typeof item !== "object" || item === null || typeof item.key !== "string") throw new ContentDefinitionError("backup-mismatch", "type definition snapshot is malformed");
		if (typeKeys.has(item.key)) throw new ContentDefinitionError("backup-mismatch", `duplicate type definition ${item.key}`);
		typeKeys.add(item.key);
		if (normalizeContentTypeDefinition(item.definition).key !== item.key) throw new ContentDefinitionError("backup-mismatch", `type definition key mismatch for ${item.key}`);
	}
	const statusKeys = /* @__PURE__ */ new Set();
	for (const item of payload.statusDefinitions ?? []) {
		if (typeof item !== "object" || item === null || typeof item.key !== "string" || typeof item.active !== "boolean") throw new ContentDefinitionError("backup-mismatch", "status definition snapshot is malformed");
		if (statusKeys.has(item.key)) throw new ContentDefinitionError("backup-mismatch", `duplicate status definition ${item.key}`);
		statusKeys.add(item.key);
		if (normalizeContentStatusDefinition(item.definition).key !== item.key) throw new ContentDefinitionError("backup-mismatch", `status definition key mismatch for ${item.key}`);
	}
	return Object.freeze({
		version: 1,
		...payload.entries ? { entries: Object.freeze([...payload.entries]) } : {},
		...payload.typeDefinitions ? { typeDefinitions: Object.freeze([...payload.typeDefinitions]) } : {},
		...payload.statusDefinitions ? { statusDefinitions: Object.freeze([...payload.statusDefinitions]) } : {}
	});
}
function normalizeJsonColumn(value) {
	if (value === null) return null;
	if (typeof value === "string") try {
		return JSON.parse(value);
	} catch {
		return value;
	}
	return value;
}
async function contentBackupDestinationState(db, payload) {
	const entries = [];
	for (const entry of [...payload.entries ?? []].sort((a, b) => a.id.localeCompare(b.id))) {
		const rows = await db.execute(sql`SELECT id, excerpt, featured_media AS "featuredMedia", parent_id AS "parentId", menu_order AS "menuOrder", template_key AS "templateKey", format FROM content_entries WHERE id = ${entry.id}`);
		const row = rows[0];
		if (!row || rows.length !== 1) throw new ContentDefinitionError("backup-mismatch", `restore destination entry ${entry.id} is missing`);
		const state = { id: entry.id };
		if (own(entry, "excerpt")) state.excerpt = String(row.excerpt);
		if (own(entry, "featuredMedia")) state.featuredMedia = normalizeJsonColumn(row.featuredMedia);
		if (own(entry, "parentId")) state.parentId = row.parentId === null ? null : String(row.parentId);
		if (own(entry, "menuOrder")) state.menuOrder = Number(row.menuOrder);
		if (own(entry, "templateKey")) state.templateKey = row.templateKey === null ? null : String(row.templateKey);
		if (own(entry, "format")) state.format = row.format === null ? null : String(row.format);
		entries.push(state);
	}
	const types = [];
	for (const item of [...payload.typeDefinitions ?? []].sort((a, b) => a.key.localeCompare(b.key))) {
		const current = await resolveContentType(db, item.key);
		const refs = await db.execute(sql`SELECT id, type_definition_revision AS revision FROM content_entries WHERE type = ${item.key} ORDER BY id`);
		types.push({
			key: item.key,
			origin: current.origin,
			version: current.version,
			revision: current.revision,
			active: current.active,
			canonicalHash: current.canonicalHash,
			references: refs.map((row) => ({
				id: row.id,
				revision: Number(row.revision)
			}))
		});
	}
	const statuses = [];
	for (const item of [...payload.statusDefinitions ?? []].sort((a, b) => a.key.localeCompare(b.key))) {
		const current = await resolveContentStatus(db, item.key);
		const refs = await db.execute(sql`SELECT id, status_definition_revision AS revision FROM content_entries WHERE status = ${item.key} ORDER BY id`);
		statuses.push({
			key: item.key,
			origin: current.origin,
			version: current.version,
			revision: current.revision,
			active: current.active,
			canonicalHash: current.canonicalHash,
			references: refs.map((row) => ({
				id: row.id,
				revision: Number(row.revision)
			}))
		});
	}
	return {
		version: 1,
		entries,
		typeDefinitions: types,
		statusDefinitions: statuses
	};
}
async function contentBackupDestinationHash(db, payload) {
	return canonicalContentMigrationHash(await contentBackupDestinationState(db, payload));
}
function manifestsMatch(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;
}
async function restoreContentBackup(db, principal, input, authorization, effects, deps) {
	const { policyVersion } = await authorization.assert(db, principal, "restoreBackup");
	const scope = principalScope$2(principal);
	const requestHash = await canonicalContentMigrationHash({
		manifestId: input.manifest.id,
		destinationCorpusHash: input.destinationCorpusHash
	});
	const replay = await readDefinitionReceipt(db, input.operationId);
	if (replay) {
		if (replay.requestHash !== requestHash || replay.principalScope !== scope) throw new ContentDefinitionError("operation-conflict", "restore operation id was reused with different identity");
		return Object.freeze(replay.result);
	}
	if (!input.manifest.immutable) throw new ContentDefinitionError("backup-mismatch", "restore requires an immutable backup");
	const verified = await deps.backups.verify(db, input.manifest.id, input.manifest.scopeHash, input.manifest.corpusVersion, input.manifest.corpusHash, input.manifest.itemCounts);
	if (!manifestsMatch(verified, input.manifest) || await canonicalContentMigrationHash(verified.itemCounts) !== await canonicalContentMigrationHash(input.manifest.itemCounts)) throw new ContentDefinitionError("backup-mismatch", "restore manifest verification changed identity");
	const snapshot = await deps.backups.read(db, verified);
	if (!manifestsMatch(snapshot.manifest, verified) || await canonicalContentMigrationHash(snapshot.manifest.itemCounts) !== await canonicalContentMigrationHash(verified.itemCounts)) throw new ContentDefinitionError("backup-mismatch", "backup store returned a different snapshot identity");
	const payload = parseBackupPayload(snapshot.payload);
	const affectedTypeKeys = new Set((payload.typeDefinitions ?? []).map((item) => item.key));
	for (const entry of payload.entries ?? []) {
		const rows = await db.execute(sql`SELECT type FROM content_entries WHERE id = ${entry.id}`);
		if (rows.length !== 1) throw new ContentDefinitionError("backup-mismatch", `restore destination entry ${entry.id} is missing`);
		affectedTypeKeys.add(rows[0].type);
	}
	for (const item of payload.statusDefinitions ?? []) {
		const rows = await db.execute(sql`SELECT DISTINCT type FROM content_entries WHERE status = ${item.key} ORDER BY type`);
		for (const row of rows) affectedTypeKeys.add(row.type);
	}
	for (const key of [...affectedTypeKeys].sort()) if ((await authorization.assert(db, principal, "restoreBackup", key)).policyVersion !== policyVersion) throw new ContentDefinitionError("authorization-drift", "authorization policy changed while authorizing restore scope");
	if (await contentBackupDestinationHash(db, payload) !== input.destinationCorpusHash) throw new ContentDefinitionError("stale-impact", "restore destination corpus changed");
	const typeCurrents = /* @__PURE__ */ new Map();
	for (const item of payload.typeDefinitions ?? []) {
		const current = await resolveContentType(db, item.key);
		if (current.origin !== "db") throw new ContentDefinitionError("code-definition-owned", `cannot restore deploy-owned type ${item.key}`);
		typeCurrents.set(item.key, current);
	}
	const statusCurrents = /* @__PURE__ */ new Map();
	for (const item of payload.statusDefinitions ?? []) {
		const current = await resolveContentStatus(db, item.key);
		if (current.origin !== "db") throw new ContentDefinitionError("code-definition-owned", `cannot restore deploy-owned status ${item.key}`);
		statusCurrents.set(item.key, current);
	}
	const restoredCounts = {};
	const now = (/* @__PURE__ */ new Date()).toISOString();
	for (const entry of payload.entries ?? []) {
		const assignments = [];
		if (own(entry, "excerpt")) assignments.push(sql`excerpt = ${entry.excerpt}`);
		if (own(entry, "featuredMedia")) assignments.push(sql`featured_media = ${entry.featuredMedia === null ? null : JSON.stringify(entry.featuredMedia)}`);
		if (own(entry, "parentId")) assignments.push(sql`parent_id = ${entry.parentId ?? null}`);
		if (own(entry, "menuOrder")) assignments.push(sql`menu_order = ${entry.menuOrder}`);
		if (own(entry, "templateKey")) assignments.push(sql`template_key = ${entry.templateKey ?? null}`);
		if (own(entry, "format")) assignments.push(sql`format = ${entry.format ?? null}`);
		if ((await db.execute(sql`UPDATE content_entries SET ${sql.join(assignments, sql`, `)}, updated_at = ${now} WHERE id = ${entry.id} RETURNING id`)).length !== 1) throw new ContentDefinitionError("stale-impact", `restore destination entry ${entry.id} changed or disappeared`);
	}
	if ((payload.entries ?? []).length > 0) restoredCounts.entries = payload.entries.length;
	for (const item of payload.typeDefinitions ?? []) {
		const current = typeCurrents.get(item.key);
		const next = normalizeContentTypeDefinition(item.definition);
		const revision = current.revision + 1;
		const version = current.version + 1;
		const hash = await canonicalContentMigrationHash(next);
		await writeDefinitionVersion(db, {
			kind: "type",
			key: item.key,
			revision,
			canonicalHash: hash,
			definition: next,
			origin: "db"
		});
		if ((await db.execute(sql`UPDATE content_type_definitions SET version = ${version}, current_revision = ${revision}, active = ${next.active}, canonical_hash = ${hash}, definition = ${JSON.stringify(next)}, updated_at = ${now} WHERE key = ${item.key} AND version = ${current.version} RETURNING key`)).length !== 1) throw new ContentDefinitionError("stale-impact", `type definition ${item.key} changed during restore`);
		await db.execute(sql`UPDATE content_entries SET type_definition_revision = ${revision} WHERE type = ${item.key}`);
	}
	if ((payload.typeDefinitions ?? []).length > 0) restoredCounts.typeDefinitions = payload.typeDefinitions.length;
	for (const item of payload.statusDefinitions ?? []) {
		const current = statusCurrents.get(item.key);
		const next = normalizeContentStatusDefinition(item.definition);
		const revision = current.revision + 1;
		const version = current.version + 1;
		const hash = await canonicalContentMigrationHash(next);
		await writeDefinitionVersion(db, {
			kind: "status",
			key: item.key,
			revision,
			canonicalHash: hash,
			definition: next,
			origin: "db"
		});
		if ((await db.execute(sql`UPDATE content_status_definitions SET version = ${version}, current_revision = ${revision}, active = ${item.active}, canonical_hash = ${hash}, definition = ${JSON.stringify(next)}, updated_at = ${now} WHERE key = ${item.key} AND version = ${current.version} RETURNING key`)).length !== 1) throw new ContentDefinitionError("stale-impact", `status definition ${item.key} changed during restore`);
		await db.execute(sql`UPDATE content_entries SET status_definition_revision = ${revision} WHERE status = ${item.key}`);
	}
	if ((payload.statusDefinitions ?? []).length > 0) restoredCounts.statusDefinitions = payload.statusDefinitions.length;
	const result = Object.freeze({
		operationId: input.operationId,
		manifestId: verified.id,
		destinationCorpusHash: input.destinationCorpusHash,
		restoredCounts: Object.freeze(restoredCounts)
	});
	await writeDefinitionReceipt(db, {
		operationId: input.operationId,
		kind: "definition:restore",
		payload: {
			requestHash,
			principalScope: scope,
			result
		}
	});
	const event = {
		id: crypto.randomUUID(),
		version: 1,
		kind: "backupRestored",
		operationId: input.operationId,
		principalId: principal.id,
		manifestId: verified.id,
		destinationCorpusHash: input.destinationCorpusHash,
		restoredCounts: result.restoredCounts,
		authorizationPolicyVersion: policyVersion
	};
	await effects.audit.record(db, event);
	await effects.outbox.enqueue(db, event);
	return result;
}
var ContentHierarchyError = class extends Error {
	code;
	detail;
	name = "ContentHierarchyError";
	constructor(code, detail) {
		super(`content hierarchy ${code}: ${detail}`);
		this.code = code;
		this.detail = detail;
	}
};
async function row(tx, id) {
	return (await tx.execute(sql`SELECT id, type, status, visibility, author,
    parent_id AS "parentId", updated_at AS "updatedAt", deleted_at AS "deletedAt",
    type_definition_revision AS "typeDefinitionRevision", status_definition_revision AS "statusDefinitionRevision"
    FROM content_entries WHERE id = ${id}`))[0];
}
async function validateContentParent(tx, input) {
	assertActiveContentTransaction(tx);
	if (input.parentId === null) return;
	if (!input.type.hierarchical) throw new ContentHierarchyError("invalid-parent", "flat content types cannot have parents");
	const parent = await row(tx, input.parentId);
	if (!parent || parent.deletedAt !== null || parent.type !== input.type.key) throw new ContentHierarchyError("invalid-parent", "parent is unavailable or belongs to another type");
	const seen = /* @__PURE__ */ new Set();
	let current = parent;
	for (let depth = 0; current; depth++) {
		if (depth > 1e3) throw new ContentHierarchyError("cycle", "hierarchy exceeds the maximum supported depth");
		if (input.entryId && current.id === input.entryId) throw new ContentHierarchyError("cycle", "parent would create a cycle");
		if (seen.has(current.id)) throw new ContentHierarchyError("cycle", "existing hierarchy contains a cycle");
		seen.add(current.id);
		if (current.parentId === null) break;
		current = await row(tx, current.parentId);
		if (!current) throw new ContentHierarchyError("invalid-parent", "ancestor chain is incomplete");
		if (current.type !== input.type.key || current.deletedAt !== null) throw new ContentHierarchyError("invalid-parent", "ancestor chain leaves the active type hierarchy");
	}
}
var ContentLifecycleError = class extends Error {
	code;
	detail;
	field;
	name = "ContentLifecycleError";
	constructor(code, detail, field) {
		super(`content lifecycle ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
function principalScope$1(principal) {
	return `${principal.tenantId ?? ""}:${principal.id}`;
}
function bool$2(value) {
	return value === true || value === 1 || value === "1" || value === "true";
}
function asDate(value, field) {
	const parsed = value instanceof Date ? new Date(value.getTime()) : new Date(value);
	if (Number.isNaN(parsed.getTime())) throw new ContentLifecycleError("integrity", "stored timestamp is invalid", field);
	return parsed;
}
function parseJson$1(value) {
	if (value === null) return null;
	if (typeof value === "string") try {
		return JSON.parse(value);
	} catch {
		return value;
	}
	return value;
}
function plainObject(value) {
	if (typeof value !== "object" || value === null || Array.isArray(value)) throw new ContentLifecycleError("integrity", "stored object is malformed");
	return value;
}
function nonEmptyString(value, field, max) {
	if (typeof value !== "string") throw new ContentLifecycleError("validation", "must be a string", field);
	const normalized = value.trim();
	if (!normalized || normalized.length > max) throw new ContentLifecycleError("validation", `must contain 1..${max} characters`, field);
	return normalized;
}
function nullableString$1(value, field, max) {
	if (value === null) return null;
	return nonEmptyString(value, field, max);
}
function exactDate(value, field) {
	if (!(value instanceof Date) || Number.isNaN(value.getTime())) throw new ContentLifecycleError("validation", "must be a valid Date", field);
	return new Date(value.getTime());
}
function uniqueStrings(value, field, max = 1e4) {
	if (!Array.isArray(value) || value.length > max) throw new ContentLifecycleError("validation", `must be an array with at most ${max} items`, field);
	const out = [];
	const seen = /* @__PURE__ */ new Set();
	for (const item of value) {
		const string = nonEmptyString(item, field, 256);
		if (!seen.has(string)) {
			seen.add(string);
			out.push(string);
		}
	}
	return out;
}
function entryBase(row, terms) {
	const media = parseJson$1(row.featuredMedia);
	return Object.freeze({
		id: row.id,
		slug: row.slug,
		type: row.type,
		title: row.title,
		body: row.body,
		status: row.status,
		visibility: row.visibility,
		publishedAt: row.publishedAt === null ? null : asDate(row.publishedAt, "publishedAt"),
		author: row.author,
		terms: Object.freeze([...terms]),
		createdAt: asDate(row.createdAt, "createdAt"),
		updatedAt: asDate(row.updatedAt, "updatedAt"),
		parentId: row.parentId,
		menuOrder: Number(row.menuOrder),
		templateKey: row.templateKey,
		excerpt: row.excerpt,
		featuredMedia: media === null ? null : plainObject(media),
		commentStatus: row.commentStatus,
		pingStatus: row.pingStatus,
		passwordProtected: bool$2(row.passwordProtected),
		sticky: bool$2(row.sticky),
		format: row.format,
		deletedAt: row.deletedAt === null ? null : asDate(row.deletedAt, "deletedAt"),
		lastEditedBy: row.lastEditedBy,
		typeDefinitionRevision: Number(row.typeDefinitionRevision),
		statusDefinitionRevision: Number(row.statusDefinitionRevision)
	});
}
var ENTRY_SELECT$1 = sql.raw(`id, slug, type, title, body, status, visibility,
  published_at AS "publishedAt", author, created_at AS "createdAt", updated_at AS "updatedAt",
  parent_id AS "parentId", menu_order AS "menuOrder", template_key AS "templateKey", excerpt,
  featured_media AS "featuredMedia", comment_status AS "commentStatus", ping_status AS "pingStatus",
  sticky, format, deleted_at AS "deletedAt", last_edited_by AS "lastEditedBy",
  type_definition_revision AS "typeDefinitionRevision", status_definition_revision AS "statusDefinitionRevision",
  EXISTS (SELECT 1 FROM content_password_credentials c WHERE c.entry_id = content_entries.id) AS "passwordProtected"`);
async function termsForEntry(tx, entryId) {
	return (await tx.execute(sql`
    SELECT t.id, t.taxonomy, t.slug, t.name, t.parent_id AS "parentId", t.depth
    FROM content_entry_terms et INNER JOIN content_terms t ON t.id = et.term_id
    WHERE et.entry_id = ${entryId} ORDER BY t.depth, t.name, t.id`)).map((row) => Object.freeze({
		id: row.id,
		taxonomy: row.taxonomy,
		slug: row.slug,
		name: row.name,
		parentId: row.parentId,
		depth: Number(row.depth)
	}));
}
async function readEntry(tx, id) {
	const rows = await tx.execute(sql`SELECT ${ENTRY_SELECT$1} FROM content_entries WHERE id = ${id}`);
	if (!rows[0]) return void 0;
	return entryBase(rows[0], await termsForEntry(tx, id));
}
async function requireEntry(tx, id) {
	const entry = await readEntry(tx, id);
	if (!entry) throw new ContentLifecycleError("access-denied", "content is unavailable");
	return entry;
}
function schemaValue$2(value) {
	return JSON.parse(JSON.stringify(value));
}
async function requestHash(value) {
	return canonicalContentMigrationHash(schemaValue$2(value));
}
async function readReceipt$1(tx, operationId) {
	const rows = await tx.execute(sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id = ${operationId}`);
	if (!rows[0]) return void 0;
	const receipt = typeof rows[0].payload === "string" ? JSON.parse(rows[0].payload) : rows[0].payload;
	if (!receipt || typeof receipt.requestHash !== "string" || typeof receipt.principalScope !== "string" || receipt.result === void 0) throw new ContentLifecycleError("integrity", "operation receipt is malformed");
	return receipt;
}
async function writeReceipt(tx, input) {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const payload = {
		requestHash: input.requestHash,
		principalScope: principalScope$1(input.principal),
		result: schemaValue$2(input.result)
	};
	await tx.execute(sql`INSERT INTO content_lifecycle_journal (id, operation_id, kind, entry_id, state, payload, created_at, updated_at)
    VALUES (${crypto.randomUUID()}, ${input.operationId}, ${input.kind}, ${input.entryId ?? null}, 'committed', ${JSON.stringify(payload)}, ${now}, ${now})`);
}
async function replayEntry(tx, receipt, expectedHash, principal) {
	if (receipt.requestHash !== expectedHash || receipt.principalScope !== principalScope$1(principal)) throw new ContentLifecycleError("operation-conflict", "operation id was already used for different input or principal");
	const result = plainObject(receipt.result);
	if (typeof result.id !== "string") return void 0;
	return readEntry(tx, result.id);
}
async function eventId(operationId, kind, entryId) {
	return canonicalContentMigrationHash({
		operationId,
		kind,
		entryId
	});
}
async function enqueue(tx, outbox, operationId, kind, entryId, occurredAt) {
	await outbox.enqueue(tx, {
		id: await eventId(operationId, kind, entryId),
		version: 1,
		operationId,
		kind,
		entryId,
		occurredAt
	});
}
function mutationContext(operationId, principal, type, before, proposed) {
	return Object.freeze({
		operationId,
		principal,
		type,
		before: before ? Object.freeze(before) : null,
		proposed: proposed ? Object.freeze(proposed) : null
	});
}
async function runValidateHooks(hooks, ctx) {
	await hooks?.beforeValidate?.(ctx);
	await hooks?.afterValidate?.(ctx);
}
async function runBeforeCommit(hooks, ctx) {
	await hooks?.beforeCommit?.(ctx);
}
function assertFeature(type, feature, field) {
	if (!type.supports.includes(feature)) throw new ContentLifecycleError("validation", `${field} is not supported by content type ${type.key}`, field);
}
function assertVisibility(value) {
	if (value !== "public" && value !== "private" && value !== "members") throw new ContentLifecycleError("validation", "must be public, private, or members", "visibility");
	return value;
}
function assertMediaRef(value) {
	if (value === null) return null;
	if (typeof value !== "object" || value === null || Array.isArray(value)) throw new ContentLifecycleError("validation", "must be an opaque media reference", "featuredMedia");
	const ref = value;
	const id = nonEmptyString(ref.id, "featuredMedia.id", 256);
	if (Object.keys(ref).some((key) => key !== "id" && key !== "kind")) throw new ContentLifecycleError("validation", "contains unsupported media reference keys", "featuredMedia");
	const kind = ref.kind === void 0 ? void 0 : nonEmptyString(ref.kind, "featuredMedia.kind", 128);
	return Object.freeze({
		id,
		...kind ? { kind } : {}
	});
}
async function validateTerms(tx, type, termIds) {
	if (termIds.length === 0) return;
	const rows = await tx.execute(sql`SELECT id, taxonomy FROM content_terms WHERE id IN (${sql.join(termIds.map((id) => sql`${id}`), sql`, `)})`);
	if (rows.length !== termIds.length) throw new ContentLifecycleError("validation", "one or more terms are unavailable", "termIds");
	const found = new Set(rows.map((row) => row.id));
	if (termIds.some((id) => !found.has(id))) throw new ContentLifecycleError("validation", "one or more terms are unavailable", "termIds");
	for (const row of rows) if (!type.taxonomies.includes(row.taxonomy)) throw new ContentLifecycleError("validation", `taxonomy ${row.taxonomy} is not assigned to content type ${type.key}`, "termIds");
}
async function replaceTerms(tx, entryId, termIds) {
	await tx.execute(sql`DELETE FROM content_entry_terms WHERE entry_id = ${entryId}`);
	for (const termId of termIds) await tx.execute(sql`INSERT INTO content_entry_terms (entry_id, term_id) VALUES (${entryId}, ${termId})`);
}
async function resolveExactTypeStatus(tx, entry) {
	try {
		const [type, status] = await Promise.all([resolveContentType(tx, entry.type), resolveContentStatus(tx, entry.status)]);
		if (entry.typeDefinitionRevision !== type.revision || entry.statusDefinitionRevision !== status.revision) throw new ContentLifecycleError("integrity", "entry references stale definition revisions");
		return {
			type,
			status
		};
	} catch (error) {
		if (error instanceof ContentLifecycleError) throw error;
		throw new ContentLifecycleError("integrity", "entry definition metadata is unavailable");
	}
}
function sanitizeHtml(sanitize, value, field) {
	if (typeof sanitize !== "function") throw new ContentLifecycleError("capability-unavailable", "HTML sanitizer is required", field);
	if (typeof value !== "string") throw new ContentLifecycleError("validation", "must be a string", field);
	const safe = sanitize(value);
	if (typeof safe !== "string") throw new ContentLifecycleError("integrity", "sanitizer must return a string", field);
	return safe;
}
function validateTemplate(type, key, templates) {
	if (key === void 0) return void 0;
	assertFeature(type, "pageAttributes", "templateKey");
	if (key === null) return null;
	const normalized = nonEmptyString(key, "templateKey", 256);
	const descriptor = templates.resolve(type.key, normalized);
	if (!descriptor || !descriptor.typeKeys.includes(type.key)) throw new ContentLifecycleError("validation", "template is unavailable for this content type", "templateKey");
	return normalized;
}
async function validateParent(tx, type, entryId, parentId) {
	if (parentId === void 0) return void 0;
	if (parentId !== null) nonEmptyString(parentId, "parentId", 256);
	if (!type.hierarchical && parentId !== null) throw new ContentLifecycleError("validation", "flat content types cannot have parents", "parentId");
	await validateContentParent(tx, {
		...entryId ? { entryId } : {},
		type,
		parentId
	});
	return parentId;
}
function normalizeMenuOrder(type, value) {
	if (value === void 0) return void 0;
	assertFeature(type, "pageAttributes", "menuOrder");
	if (typeof value !== "number" || !Number.isSafeInteger(value) || value < -2147483648 || value > 2147483647) throw new ContentLifecycleError("validation", "must be a 32-bit integer", "menuOrder");
	return value;
}
function normalizeCommentStatus(type, value) {
	if (value === void 0) return void 0;
	assertFeature(type, "comments", "commentStatus");
	if (value !== "open" && value !== "closed") throw new ContentLifecycleError("validation", "must be open or closed", "commentStatus");
	return value;
}
function normalizePingStatus(type, value) {
	if (value === void 0) return void 0;
	assertFeature(type, "trackbacks", "pingStatus");
	if (value !== "open" && value !== "closed") throw new ContentLifecycleError("validation", "must be open or closed", "pingStatus");
	return value;
}
function isUniqueViolation$1(error) {
	let current = error;
	while (current) {
		const code = current.code;
		const message = current instanceof Error ? current.message : String(current);
		if (code === "23505" || /content_entries_type_slug_uq|duplicate key|unique constraint/i.test(message)) return true;
		current = current instanceof Error ? current.cause : void 0;
	}
	return false;
}
async function termRefsByIds(tx, termIds) {
	if (termIds.length === 0) return [];
	return (await tx.execute(sql`
    SELECT id, taxonomy, slug, name, parent_id AS "parentId", depth FROM content_terms
    WHERE id IN (${sql.join(termIds.map((id) => sql`${id}`), sql`, `)}) ORDER BY depth, name, id`)).map((row) => Object.freeze({
		id: row.id,
		taxonomy: row.taxonomy,
		slug: row.slug,
		name: row.name,
		parentId: row.parentId,
		depth: Number(row.depth)
	}));
}
function revisionSnapshot(entry) {
	return schemaValue$2({
		id: entry.id,
		slug: entry.slug,
		type: entry.type,
		title: entry.title,
		body: entry.body,
		status: entry.status,
		visibility: entry.visibility,
		publishedAt: entry.publishedAt?.toISOString() ?? null,
		author: entry.author,
		termIds: entry.terms.map((term) => term.id),
		parentId: entry.parentId,
		menuOrder: entry.menuOrder,
		templateKey: entry.templateKey,
		excerpt: entry.excerpt,
		featuredMedia: entry.featuredMedia,
		commentStatus: entry.commentStatus,
		pingStatus: entry.pingStatus,
		passwordProtected: entry.passwordProtected,
		sticky: entry.sticky,
		format: entry.format,
		deletedAt: entry.deletedAt?.toISOString() ?? null,
		lastEditedBy: entry.lastEditedBy,
		typeDefinitionRevision: entry.typeDefinitionRevision,
		statusDefinitionRevision: entry.statusDefinitionRevision,
		createdAt: entry.createdAt.toISOString(),
		updatedAt: entry.updatedAt.toISOString()
	});
}
async function snapshotRevision(tx, entry, editor) {
	const id = crypto.randomUUID();
	await tx.execute(sql`INSERT INTO content_revisions
    (id, entry_id, title, body, slug, type, term_ids, snapshot, editor, created_at)
    VALUES (${id}, ${entry.id}, ${entry.title}, ${entry.body}, ${entry.slug}, ${entry.type},
      ${JSON.stringify(entry.terms.map((term) => term.id))}, ${JSON.stringify(revisionSnapshot(entry))}, ${editor}, ${(/* @__PURE__ */ new Date()).toISOString()})`);
	return id;
}
async function normalizeWrite(tx, type, raw, deps, principal, mode, entryId) {
	if (typeof raw !== "object" || raw === null || Array.isArray(raw)) throw new ContentLifecycleError("validation", "input must be an object");
	const candidate = raw;
	const allowed = /* @__PURE__ */ new Set([
		"slug",
		"type",
		"title",
		"body",
		"excerpt",
		"visibility",
		"author",
		"termIds",
		"parentId",
		"menuOrder",
		"templateKey",
		"featuredMedia",
		"commentStatus",
		"pingStatus",
		"sticky",
		"format"
	]);
	for (const key of Object.keys(candidate)) if (!allowed.has(key)) throw new ContentLifecycleError("validation", "field is owned by another lifecycle operation", key);
	if (mode === "update" && Object.prototype.hasOwnProperty.call(candidate, "type")) throw new ContentLifecycleError("validation", "content type reassignment requires definition migration machinery", "type");
	if (mode === "update" && Object.keys(candidate).length === 0) throw new ContentLifecycleError("validation", "empty update patches are not allowed");
	const out = {};
	if (mode === "create" || Object.prototype.hasOwnProperty.call(candidate, "slug")) out.slug = nonEmptyString(candidate.slug, "slug", 200);
	if (mode === "create" || Object.prototype.hasOwnProperty.call(candidate, "title")) {
		if (type.supports.includes("title")) out.title = nonEmptyString(candidate.title, "title", 300);
		else {
			if (candidate.title !== "") throw new ContentLifecycleError("validation", "title is not supported by this content type", "title");
			out.title = "";
		}
	}
	if (mode === "create" || Object.prototype.hasOwnProperty.call(candidate, "body")) {
		if (type.supports.includes("editor") || type.supports.includes("blocks")) out.body = sanitizeHtml(deps.sanitize, candidate.body, "body");
		else {
			if (candidate.body !== "") throw new ContentLifecycleError("validation", "body is not supported by this content type", "body");
			out.body = "";
		}
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "excerpt")) {
		assertFeature(type, "excerpt", "excerpt");
		if (typeof candidate.excerpt !== "string" || candidate.excerpt.length > 1e5) throw new ContentLifecycleError("validation", "must be a string up to 100000 characters", "excerpt");
		out.excerpt = candidate.excerpt;
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "visibility")) out.visibility = assertVisibility(candidate.visibility);
	if (Object.prototype.hasOwnProperty.call(candidate, "author")) {
		assertFeature(type, "author", "author");
		const target = nonEmptyString(candidate.author, "author", 256);
		if (!deps.authors) throw new ContentLifecycleError("capability-unavailable", "author authority adapter is required", "author");
		await deps.authors.assertAssign(principal, target);
		out.author = target;
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "termIds")) {
		const termIds = uniqueStrings(candidate.termIds, "termIds");
		authorizeContentAction({
			principal,
			type,
			operation: "manageTerms"
		});
		await validateTerms(tx, type, termIds);
		out.termIds = termIds;
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "parentId")) out.parentId = await validateParent(tx, type, entryId, candidate.parentId);
	if (Object.prototype.hasOwnProperty.call(candidate, "menuOrder")) out.menuOrder = normalizeMenuOrder(type, candidate.menuOrder);
	if (Object.prototype.hasOwnProperty.call(candidate, "templateKey")) out.templateKey = validateTemplate(type, candidate.templateKey, deps.templates);
	if (Object.prototype.hasOwnProperty.call(candidate, "featuredMedia")) {
		assertFeature(type, "featuredImage", "featuredMedia");
		const ref = assertMediaRef(candidate.featuredMedia);
		if (ref !== null) {
			if (!deps.capabilities?.validateMediaRef) throw new ContentLifecycleError("capability-unavailable", "media validation adapter is required", "featuredMedia");
			await deps.capabilities.validateMediaRef(ref, principal);
		}
		out.featuredMedia = ref;
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "commentStatus")) out.commentStatus = normalizeCommentStatus(type, candidate.commentStatus);
	if (Object.prototype.hasOwnProperty.call(candidate, "pingStatus")) out.pingStatus = normalizePingStatus(type, candidate.pingStatus);
	if (Object.prototype.hasOwnProperty.call(candidate, "sticky")) {
		if (typeof candidate.sticky !== "boolean") throw new ContentLifecycleError("validation", "must be a boolean", "sticky");
		out.sticky = candidate.sticky;
	}
	if (Object.prototype.hasOwnProperty.call(candidate, "format")) {
		assertFeature(type, "postFormats", "format");
		out.format = nullableString$1(candidate.format, "format", 128);
	}
	return out;
}
async function updateContentEntry(tx, id, input, principal, deps) {
	assertActiveContentTransaction(tx);
	const operationId = nonEmptyString(input.operationId, "operationId", 256);
	const expectedUpdatedAt = exactDate(input.expectedUpdatedAt, "expectedUpdatedAt");
	const before = await requireEntry(tx, id);
	const { type, status } = await resolveExactTypeStatus(tx, before);
	authorizeContentAction({
		principal,
		type,
		status,
		operation: "edit",
		entry: before
	});
	const normalized = await normalizeWrite(tx, type, input.patch, deps, principal, "update", id);
	if (normalized.author !== void 0 && normalized.author !== before.author) {
		if (!deps.authors) throw new ContentLifecycleError("capability-unavailable", "author authority adapter is required", "author");
		await deps.authors.assertTransfer(principal, before.author, normalized.author);
	}
	const hash = await requestHash({
		id,
		expectedUpdatedAt: expectedUpdatedAt.toISOString(),
		patch: normalized
	});
	const replay = await readReceipt$1(tx, operationId);
	if (replay) {
		const entry = await replayEntry(tx, replay, hash, principal);
		if (!entry) throw new ContentLifecycleError("operation-conflict", "recorded update result is no longer available");
		return entry;
	}
	if (before.updatedAt.getTime() !== expectedUpdatedAt.getTime()) throw new ContentLifecycleError("stale-version", "content changed after caller read it");
	const now = /* @__PURE__ */ new Date();
	const termIds = normalized.termIds ?? before.terms.map((term) => term.id);
	const proposed = Object.freeze({
		...before,
		...normalized.slug === void 0 ? {} : { slug: normalized.slug },
		...normalized.title === void 0 ? {} : { title: normalized.title },
		...normalized.body === void 0 ? {} : { body: normalized.body },
		...normalized.excerpt === void 0 ? {} : { excerpt: normalized.excerpt },
		...normalized.visibility === void 0 ? {} : { visibility: normalized.visibility },
		...normalized.author === void 0 ? {} : { author: normalized.author },
		terms: normalized.termIds === void 0 ? before.terms : await termRefsByIds(tx, normalized.termIds),
		...normalized.parentId === void 0 ? {} : { parentId: normalized.parentId },
		...normalized.menuOrder === void 0 ? {} : { menuOrder: normalized.menuOrder },
		...normalized.templateKey === void 0 ? {} : { templateKey: normalized.templateKey },
		...normalized.featuredMedia === void 0 ? {} : { featuredMedia: normalized.featuredMedia },
		...normalized.commentStatus === void 0 ? {} : { commentStatus: normalized.commentStatus },
		...normalized.pingStatus === void 0 ? {} : { pingStatus: normalized.pingStatus },
		...normalized.sticky === void 0 ? {} : { sticky: normalized.sticky },
		...normalized.format === void 0 ? {} : { format: normalized.format },
		updatedAt: now,
		lastEditedBy: principal.id
	});
	const ctx = mutationContext(operationId, principal, type, before, proposed);
	await runValidateHooks(deps.hooks, ctx);
	await runBeforeCommit(deps.hooks, ctx);
	if (type.supports.includes("revisions")) await snapshotRevision(tx, before, principal.id);
	try {
		if ((await tx.execute(sql`UPDATE content_entries SET
      slug = ${proposed.slug}, title = ${proposed.title}, body = ${proposed.body}, visibility = ${proposed.visibility},
      author = ${proposed.author}, parent_id = ${proposed.parentId}, menu_order = ${proposed.menuOrder}, template_key = ${proposed.templateKey},
      excerpt = ${proposed.excerpt}, featured_media = ${proposed.featuredMedia === null ? null : JSON.stringify(proposed.featuredMedia)},
      comment_status = ${proposed.commentStatus}, ping_status = ${proposed.pingStatus}, sticky = ${proposed.sticky}, format = ${proposed.format},
      last_edited_by = ${principal.id}, updated_at = ${now.toISOString()}
      WHERE id = ${id} AND updated_at = ${expectedUpdatedAt.toISOString()} RETURNING id`)).length !== 1) throw new ContentLifecycleError("stale-version", "content changed during update");
	} catch (error) {
		if (isUniqueViolation$1(error)) throw new ContentLifecycleError("conflict", "slug already exists for this content type", "slug");
		throw error;
	}
	if (normalized.termIds !== void 0) await replaceTerms(tx, id, termIds);
	await writeReceipt(tx, {
		operationId,
		kind: "content:update",
		entryId: id,
		requestHash: hash,
		principal,
		result: { id }
	});
	await enqueue(tx, deps.outbox, operationId, "written", id, now);
	return await readEntry(tx, id);
}
function resolvedFrom(values, key, field) {
	const found = values.find((item) => item.key === key);
	if (!found) throw new ContentLifecycleError("validation", `${field} is unavailable`, field);
	return found;
}
function checkMappedCapability(principal, type, key) {
	const capability = type.capabilities[key];
	if (!principal.capabilities.has(capability)) throw new ContentLifecycleError("access-denied", "content is unavailable");
}
function transitionRule(rules, from, to) {
	const rule = rules.find((candidate) => candidate.to === to && (candidate.from === from || candidate.from === "*"));
	if (!rule) throw new ContentLifecycleError("validation", "status transition is not allowed", "to");
	return rule;
}
async function transitionContent(tx, id, input, principal, deps) {
	assertActiveContentTransaction(tx);
	const operationId = nonEmptyString(input.operationId, "operationId", 256);
	const to = nonEmptyString(input.to, "to", 128);
	const expectedUpdatedAt = exactDate(input.expectedUpdatedAt, "expectedUpdatedAt");
	const before = await requireEntry(tx, id);
	const type = resolvedFrom(deps.types, before.type, "type");
	const currentStatus = resolvedFrom(deps.statuses, before.status, "status");
	if (before.typeDefinitionRevision !== type.revision || before.statusDefinitionRevision !== currentStatus.revision) throw new ContentLifecycleError("integrity", "entry definition revisions do not match supplied registries");
	authorizeContentAction({
		principal,
		type,
		status: currentStatus,
		operation: "edit",
		entry: before
	});
	const target = resolvedFrom(deps.statuses, to, "to");
	if (!target.active || type.statusKeys !== void 0 && !type.statusKeys.includes(target.key)) throw new ContentLifecycleError("validation", "target status is not active for this content type", "to");
	const rule = transitionRule(deps.rules, before.status, target.key);
	checkMappedCapability(principal, type, rule.capability);
	if (target.published) authorizeContentAction({
		principal,
		type,
		status: currentStatus,
		operation: "publish",
		entry: before
	});
	const scheduleAt = input.scheduleAt === void 0 ? void 0 : exactDate(input.scheduleAt, "scheduleAt");
	const publishedAtInput = input.publishedAt === void 0 ? void 0 : exactDate(input.publishedAt, "publishedAt");
	if (scheduleAt && publishedAtInput) throw new ContentLifecycleError("validation", "scheduleAt and publishedAt are mutually exclusive");
	const now = /* @__PURE__ */ new Date();
	let publicationDate = null;
	if (target.transitionInput === "scheduleAt") {
		if (!scheduleAt || scheduleAt.getTime() <= now.getTime()) throw new ContentLifecycleError("validation", "scheduled transition requires a future scheduleAt", "scheduleAt");
		publicationDate = scheduleAt;
	} else if (scheduleAt) throw new ContentLifecycleError("validation", "scheduleAt is not accepted by the target status", "scheduleAt");
	if (target.transitionInput === "publishedAt") publicationDate = publishedAtInput ?? now;
	else if (publishedAtInput) throw new ContentLifecycleError("validation", "publishedAt is not accepted by the target status", "publishedAt");
	if (rule.requiresScheduleAt && !scheduleAt) throw new ContentLifecycleError("validation", "transition requires scheduleAt", "scheduleAt");
	if (before.status === target.key && !(target.published && publishedAtInput)) throw new ContentLifecycleError("validation", "same-status transition is not a lifecycle change", "to");
	const hash = await requestHash({
		id,
		to,
		scheduleAt: scheduleAt?.toISOString(),
		publishedAt: publishedAtInput?.toISOString(),
		expectedUpdatedAt: expectedUpdatedAt.toISOString()
	});
	const replay = await readReceipt$1(tx, operationId);
	if (replay) {
		const entry = await replayEntry(tx, replay, hash, principal);
		if (!entry) throw new ContentLifecycleError("operation-conflict", "recorded transition result is no longer available");
		return entry;
	}
	if (before.updatedAt.getTime() !== expectedUpdatedAt.getTime()) throw new ContentLifecycleError("stale-version", "content changed after caller read it");
	const ctx = mutationContext(operationId, principal, type, before, Object.freeze({
		...before,
		status: target.key,
		statusDefinitionRevision: target.revision,
		publishedAt: publicationDate,
		updatedAt: now,
		lastEditedBy: principal.id
	}));
	await runValidateHooks(deps.hooks, ctx);
	await runBeforeCommit(deps.hooks, ctx);
	if (type.supports.includes("revisions")) await snapshotRevision(tx, before, principal.id);
	if ((await tx.execute(sql`UPDATE content_entries SET status = ${target.key}, status_definition_revision = ${target.revision},
    published_at = ${publicationDate?.toISOString() ?? null}, updated_at = ${now.toISOString()}, last_edited_by = ${principal.id}
    WHERE id = ${id} AND updated_at = ${expectedUpdatedAt.toISOString()} RETURNING id`)).length !== 1) throw new ContentLifecycleError("stale-version", "content changed during transition");
	await writeReceipt(tx, {
		operationId,
		kind: "content:transition",
		entryId: id,
		requestHash: hash,
		principal,
		result: { id }
	});
	await enqueue(tx, deps.outbox, operationId, "transitioned", id, now);
	return await readEntry(tx, id);
}
function revisionFromRow(row) {
	const termIdsValue = parseJson$1(row.termIds);
	const snapshotValue = parseJson$1(row.snapshot);
	return Object.freeze({
		id: String(row.id),
		entryId: String(row.entryId),
		seq: Number(row.seq),
		title: String(row.title),
		body: String(row.body),
		slug: String(row.slug),
		type: String(row.type),
		termIds: Array.isArray(termIdsValue) ? termIdsValue.map(String) : [],
		...snapshotValue && typeof snapshotValue === "object" && !Array.isArray(snapshotValue) ? { snapshot: snapshotValue } : {},
		editor: String(row.editor),
		createdAt: asDate(row.createdAt, "createdAt")
	});
}
async function getContentRevision(tx, entryId, revisionId, principal) {
	assertActiveContentTransaction(tx);
	const entry = await requireEntry(tx, entryId);
	const { type, status } = await resolveExactTypeStatus(tx, entry);
	authorizeContentAction({
		principal,
		type,
		status,
		operation: "edit",
		entry
	});
	const rows = await tx.execute(sql`SELECT id, entry_id AS "entryId", seq, title, body, slug, type, term_ids AS "termIds", snapshot, editor, created_at AS "createdAt"
    FROM content_revisions WHERE id = ${revisionId} AND entry_id = ${entryId}`);
	if (!rows[0]) throw new ContentLifecycleError("access-denied", "revision is unavailable");
	return revisionFromRow(rows[0]);
}
async function restoreContentRevision(tx, entryId, revisionId, input, principal, deps) {
	const revision = await getContentRevision(tx, entryId, revisionId, principal);
	if (!revision.snapshot) throw new ContentLifecycleError("integrity", "revision predates full snapshot support");
	const snapshot = revision.snapshot;
	return updateContentEntry(tx, entryId, {
		patch: {
			slug: String(snapshot.slug),
			title: String(snapshot.title),
			body: String(snapshot.body),
			excerpt: String(snapshot.excerpt ?? ""),
			visibility: snapshot.visibility,
			author: String(snapshot.author),
			termIds: Array.isArray(snapshot.termIds) ? snapshot.termIds.map(String) : [],
			parentId: snapshot.parentId === null ? null : String(snapshot.parentId),
			menuOrder: Number(snapshot.menuOrder ?? 0),
			templateKey: snapshot.templateKey === null ? null : String(snapshot.templateKey),
			featuredMedia: snapshot.featuredMedia === null ? null : snapshot.featuredMedia,
			commentStatus: snapshot.commentStatus,
			pingStatus: snapshot.pingStatus,
			sticky: Boolean(snapshot.sticky),
			format: snapshot.format === null ? null : String(snapshot.format)
		},
		expectedUpdatedAt: input.expectedUpdatedAt,
		operationId: input.operationId
	}, principal, deps);
}
sql.raw(`id, slug, type, title, body, status, visibility,
  published_at AS "publishedAt", author, created_at AS "createdAt", updated_at AS "updatedAt",
  parent_id AS "parentId", menu_order AS "menuOrder", template_key AS "templateKey", excerpt,
  featured_media AS "featuredMedia", comment_status AS "commentStatus", ping_status AS "pingStatus",
  sticky, format, deleted_at AS "deletedAt", last_edited_by AS "lastEditedBy",
  type_definition_revision AS "typeDefinitionRevision", status_definition_revision AS "statusDefinitionRevision",
  EXISTS (SELECT 1 FROM content_password_credentials c WHERE c.entry_id = content_entries.id) AS "passwordProtected"`);
var MAX_ROUTE_SEGMENTS = 128;
var MAX_PAGE = 1e6;
var SEGMENT_RE = /^[^/?#]+$/;
var ContentRouteError = class extends Error {
	code;
	detail;
	field;
	name = "ContentRouteError";
	constructor(code, detail, field) {
		super(`content route ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
function cleanSlug(value, field) {
	if (typeof value !== "string") throw new ContentRouteError("invalid-route", "route slug must be a string", field);
	const stripped = value.replace(/^\/+|\/+$/g, "");
	if (!stripped) throw new ContentRouteError("invalid-route", "route slug must not be empty", field);
	let segments;
	try {
		segments = stripped.split("/").map((segment) => decodeURIComponent(segment));
	} catch {
		throw new ContentRouteError("invalid-route", "route slug contains malformed percent encoding", field);
	}
	if (segments.length > MAX_ROUTE_SEGMENTS || segments.some((segment) => !segment || !SEGMENT_RE.test(segment) || segment === "." || segment === "..")) throw new ContentRouteError("invalid-route", "route slug contains an invalid segment", field);
	return Object.freeze(segments);
}
function pathname(segments) {
	return `/${segments.map((s) => encodeURIComponent(s)).join("/")}`;
}
function normalizedPathname(url) {
	return url.pathname.replace(/\/{2,}/g, "/").replace(/\/$/, "") || "/";
}
function decodePath(url) {
	try {
		return normalizedPathname(url).split("/").filter(Boolean).map(decodeURIComponent);
	} catch {
		return [];
	}
}
function startsWith(value, prefix) {
	return prefix.every((segment, index) => value[index] === segment);
}
function routeRecord(type) {
	const singleBase = type.rewrite === false ? null : cleanSlug(type.rewrite.slug, `${type.key}.rewrite.slug`);
	let archiveBase = null;
	if (type.hasArchive === true) {
		if (!singleBase) throw new ContentRouteError("invalid-route", "hasArchive=true requires rewrite routing", `${type.key}.hasArchive`);
		archiveBase = singleBase;
	} else if (typeof type.hasArchive === "string") archiveBase = cleanSlug(type.hasArchive, `${type.key}.hasArchive`);
	const queryVariable = type.queryVariable === false ? null : type.queryVariable;
	if (queryVariable !== null && !/^[a-z][a-z0-9_-]{0,63}$/.test(queryVariable)) throw new ContentRouteError("invalid-route", "query variable must be a stable machine key", `${type.key}.queryVariable`);
	return {
		type,
		singleBase,
		archiveBase,
		queryVariable,
		feeds: type.rewrite !== false && type.rewrite.feeds === true,
		pages: type.rewrite !== false && type.rewrite.pages === true
	};
}
function assertConflicts(records) {
	const singleRoots = /* @__PURE__ */ new Map(), archives = /* @__PURE__ */ new Map(), queries = /* @__PURE__ */ new Map();
	const staticRoutes = /* @__PURE__ */ new Map();
	const claimStatic = (path, typeKey, kind) => {
		const previous = staticRoutes.get(path);
		if (previous && previous.typeKey !== typeKey) throw new ContentRouteError("route-conflict", `${kind} route ${path} for ${typeKey} conflicts with ${previous.kind} route for ${previous.typeKey}`);
		staticRoutes.set(path, {
			typeKey,
			kind
		});
	};
	for (const record of records) {
		if (record.singleBase) {
			const key = pathname(record.singleBase);
			const previous = singleRoots.get(key);
			if (previous && previous !== record.type.key) throw new ContentRouteError("route-conflict", `single route ${key} is shared by ${previous} and ${record.type.key}`);
			singleRoots.set(key, record.type.key);
		}
		if (record.archiveBase) {
			const key = pathname(record.archiveBase);
			const previous = archives.get(key);
			if (previous && previous !== record.type.key) throw new ContentRouteError("route-conflict", `archive route ${key} is shared by ${previous} and ${record.type.key}`);
			archives.set(key, record.type.key);
			claimStatic(key, record.type.key, "archive");
			if (record.feeds) claimStatic(pathname([...record.archiveBase, "feed"]), record.type.key, "feed");
		}
		if (record.queryVariable) {
			const previous = queries.get(record.queryVariable);
			if (previous && previous !== record.type.key) throw new ContentRouteError("route-conflict", `query variable ${record.queryVariable} is shared by ${previous} and ${record.type.key}`);
			queries.set(record.queryVariable, record.type.key);
		}
	}
	for (const [path, typeKey] of archives) {
		const other = singleRoots.get(path);
		if (other && other !== typeKey) throw new ContentRouteError("route-conflict", `archive ${path} for ${typeKey} conflicts with single route for ${other}`);
	}
}
function bySpecificBase(field) {
	return (left, right) => {
		const a = left[field], b = right[field];
		return b.length - a.length || pathname(a).localeCompare(pathname(b)) || left.type.key.localeCompare(right.type.key);
	};
}
function pageNumber(segment) {
	if (segment === void 0 || !/^[1-9][0-9]*$/.test(segment)) return null;
	const value = Number(segment);
	return Number.isSafeInteger(value) && value >= 1 && value <= MAX_PAGE ? value : null;
}
function compileContentRoutes(types) {
	const keys = /* @__PURE__ */ new Set(), records = types.filter((type) => type.publiclyQueryable).map((type) => {
		if (keys.has(type.key)) throw new ContentRouteError("route-conflict", `duplicate resolved type ${type.key}`);
		keys.add(type.key);
		return routeRecord(type);
	});
	assertConflicts(records);
	const byKey = new Map(records.map((record) => [record.type.key, record]));
	const queryRecords = [...records].filter((record) => record.queryVariable).sort((a, b) => a.type.key.localeCompare(b.type.key));
	const archiveRecords = [...records].filter((record) => record.archiveBase).sort(bySpecificBase("archiveBase"));
	const singleRecords = [...records].filter((record) => record.singleBase).sort(bySpecificBase("singleBase"));
	const compiled = {
		records: byKey,
		match(url) {
			for (const record of queryRecords) {
				if (!record.queryVariable) continue;
				const raw = url.searchParams.get(record.queryVariable);
				if (raw !== null && normalizedPathname(url) === "/") {
					let pathSegments;
					try {
						pathSegments = raw.split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
					} catch {
						continue;
					}
					if (pathSegments.length > 0 && pathSegments.length <= MAX_ROUTE_SEGMENTS && pathSegments.every((segment) => SEGMENT_RE.test(segment))) return Object.freeze({
						kind: "single",
						typeKey: record.type.key,
						pathSegments: Object.freeze(pathSegments)
					});
				}
			}
			const segments = decodePath(url);
			let blockedSingleBaseLength = -1;
			for (const record of archiveRecords) {
				if (!startsWith(segments, record.archiveBase)) continue;
				const rest = segments.slice(record.archiveBase.length);
				if (rest.length === 0) return Object.freeze({
					kind: "archive",
					typeKey: record.type.key,
					page: 1
				});
				if (rest[0] === "page" && record.pages) {
					if (rest.length === 2) {
						const page = pageNumber(rest[1]);
						if (page !== null) return Object.freeze({
							kind: "archive",
							typeKey: record.type.key,
							page
						});
					}
					blockedSingleBaseLength = Math.max(blockedSingleBaseLength, record.archiveBase.length);
					continue;
				}
				if (rest[0] === "feed" && record.feeds) {
					if (rest.length === 1) return Object.freeze({
						kind: "feed",
						typeKey: record.type.key,
						page: 1
					});
					if (record.pages && rest.length === 3 && rest[1] === "page") {
						const page = pageNumber(rest[2]);
						if (page !== null) return Object.freeze({
							kind: "feed",
							typeKey: record.type.key,
							page
						});
					}
					blockedSingleBaseLength = Math.max(blockedSingleBaseLength, record.archiveBase.length);
				}
			}
			for (const record of singleRecords) {
				if (record.singleBase.length <= blockedSingleBaseLength || !startsWith(segments, record.singleBase)) continue;
				const pathSegments = segments.slice(record.singleBase.length);
				if (pathSegments.length === 0 || pathSegments.length > MAX_ROUTE_SEGMENTS) continue;
				if (!record.type.hierarchical && pathSegments.length !== 1) continue;
				return Object.freeze({
					kind: "single",
					typeKey: record.type.key,
					pathSegments: Object.freeze(pathSegments)
				});
			}
			return null;
		},
		canonical(typeKey, entryPath) {
			const record = byKey.get(typeKey);
			if (!record) throw new ContentRouteError("unknown-type", `unknown routable type ${typeKey}`);
			if (entryPath !== void 0) {
				if (entryPath.length === 0 || entryPath.length > MAX_ROUTE_SEGMENTS || entryPath.some((segment) => typeof segment !== "string" || !SEGMENT_RE.test(segment) || !segment)) throw new ContentRouteError("invalid-route", "entry path is invalid", "entryPath");
				if (!record.type.hierarchical && entryPath.length !== 1) throw new ContentRouteError("invalid-route", "flat types require exactly one entry path segment", "entryPath");
				if (record.singleBase) return { pathname: pathname([...record.singleBase, ...entryPath]) };
				if (record.queryVariable) return {
					pathname: "/",
					search: `?${encodeURIComponent(record.queryVariable)}=${encodeURIComponent(entryPath.join("/"))}`
				};
				throw new ContentRouteError("invalid-route", `type ${typeKey} has no single route`);
			}
			if (!record.archiveBase) throw new ContentRouteError("invalid-route", `type ${typeKey} has no archive route`);
			return { pathname: pathname(record.archiveBase) };
		},
		pathFor(match) {
			const record = byKey.get(match.typeKey);
			if (!record) throw new ContentRouteError("unknown-type", `unknown routable type ${match.typeKey}`);
			if (match.kind === "single") return compiled.canonical(match.typeKey, match.pathSegments);
			if (!record.archiveBase) throw new ContentRouteError("invalid-route", `type ${match.typeKey} has no archive route`);
			const base = [...record.archiveBase];
			if (match.kind === "feed") base.push("feed");
			if (match.page > 1) base.push("page", String(match.page));
			return { pathname: pathname(base) };
		}
	};
	return Object.freeze(compiled);
}
async function resolveContentRoute(compiled, lookup, url, principal, passwordProof) {
	const match = compiled.match(url);
	if (!match) return { kind: "notFound" };
	const expected = compiled.pathFor(match);
	const actualPath = normalizedPathname(url);
	if (match.kind !== "single") {
		if (actualPath !== expected.pathname) return {
			kind: "redirect",
			status: 308,
			location: expected.pathname
		};
		return Object.freeze({
			kind: match.kind,
			match
		});
	}
	const content = await lookup.resolve(match.typeKey, match.pathSegments, principal, passwordProof);
	if (!content) return { kind: "notFound" };
	const entryId = content.entry.id;
	const canonicalPath = await lookup.canonicalPath(entryId, principal);
	if (!canonicalPath) return { kind: "notFound" };
	const canonical = compiled.canonical(match.typeKey, canonicalPath);
	const queryCanonical = canonical.search ?? "";
	if (actualPath !== canonical.pathname || queryCanonical && url.search !== queryCanonical) return {
		kind: "redirect",
		status: 308,
		location: `${canonical.pathname}${queryCanonical}`
	};
	return Object.freeze({
		kind: "single",
		match,
		content
	});
}
function templateDescriptor(registry, type, key) {
	const descriptor = registry.resolve(type.key, key);
	if (!descriptor) throw new ContentRouteError("template-resolution", `template ${key} is missing for type ${type.key}`, "templateKey");
	if (descriptor.active === false) throw new ContentRouteError("template-resolution", `template ${key} is inactive`, "templateKey");
	if (!descriptor.typeKeys.includes(type.key)) throw new ContentRouteError("template-resolution", `template ${key} is not assigned to type ${type.key}`, "templateKey");
	return descriptor;
}
function resolveContentTemplate(registry, type, match, entry) {
	if (match.typeKey !== type.key) throw new ContentRouteError("template-resolution", "route type does not match resolved type", "typeKey");
	if (entry && entry.type !== type.key) throw new ContentRouteError("template-resolution", "entry type does not match resolved route type", "entry.type");
	if (entry && entry.typeDefinitionRevision !== type.revision) throw new ContentRouteError("template-resolution", "entry references a stale type definition", "entry.typeDefinitionRevision");
	const key = match.kind === "single" && entry?.templateKey ? entry.templateKey : type.defaultTemplateKey;
	templateDescriptor(registry, type, key);
	const lockedBlocks = type.templateLock && type.template ? type.template : void 0;
	return Object.freeze({
		templateKey: key,
		...lockedBlocks ? { lockedBlocks } : {}
	});
}
var ContentHeadlessError = class extends Error {
	code;
	detail;
	field;
	name = "ContentHeadlessError";
	constructor(code, detail, field) {
		super(`content headless ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
var ERRORS = Object.freeze([
	"validation",
	"authorization",
	"notFound",
	"conflict",
	"capability",
	"integrity"
]);
function schemaValue$1(value, path = "schema") {
	if (value === null || typeof value === "string" || typeof value === "boolean") return value;
	if (typeof value === "number") {
		if (!Number.isFinite(value)) throw new ContentHeadlessError("invalid-schema-source", "contains a non-finite number", path);
		return value;
	}
	if (value instanceof Date) return value.toISOString();
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => schemaValue$1(item, `${path}.${index}`)));
	if (typeof value === "object") {
		const out = {};
		for (const key of Object.keys(value).sort()) {
			const child = value[key];
			if (child !== void 0) out[key] = schemaValue$1(child, `${path}.${key}`);
		}
		return Object.freeze(out);
	}
	throw new ContentHeadlessError("invalid-schema-source", "contains a non-serializable value", path);
}
function uniqueByKey(values, field) {
	const map = /* @__PURE__ */ new Map();
	for (const value of values) {
		if (!value || typeof value.key !== "string" || !value.key) throw new ContentHeadlessError("invalid-schema-source", "contains an invalid key", field);
		if (map.has(value.key)) throw new ContentHeadlessError("invalid-schema-source", `duplicate key ${value.key}`, field);
		map.set(value.key, value);
	}
	return map;
}
function jsonSchema(type, properties, required = []) {
	return Object.freeze({
		type,
		...properties ? { properties: Object.freeze(properties) } : {},
		...required.length ? { required: Object.freeze([...required]) } : {}
	});
}
var STRING = jsonSchema("string");
var NUMBER = jsonSchema("number");
jsonSchema("boolean");
var DATE = Object.freeze({
	type: "string",
	format: "date-time"
});
var UUID = Object.freeze({
	type: "string",
	format: "uuid"
});
var ENTRY = Object.freeze({ $ref: "ContentEntry" });
var REVISION = Object.freeze({ $ref: "ContentRevision" });
var AUTOSAVE = Object.freeze({ $ref: "ContentAutosave" });
function operationSchemas(key) {
	switch (key) {
		case "list": return {
			input: Object.freeze({ $ref: "ContentListQuery" }),
			output: Object.freeze({ $ref: "ContentPage" })
		};
		case "count": return {
			input: Object.freeze({ $ref: "ContentListQuery" }),
			output: NUMBER
		};
		case "get": return {
			input: jsonSchema("object", {
				id: UUID,
				passwordProof: STRING
			}, ["id"]),
			output: Object.freeze({ $ref: "ProtectedContentRead" })
		};
		case "create": return {
			input: Object.freeze({ $ref: "ContentWriteInputWithOperationId" }),
			output: ENTRY
		};
		case "update": return {
			input: jsonSchema("object", {
				id: UUID,
				patch: Object.freeze({ $ref: "ContentUpdatePatch" }),
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"patch",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: ENTRY
		};
		case "transition": return {
			input: jsonSchema("object", {
				id: UUID,
				to: STRING,
				scheduleAt: DATE,
				publishedAt: DATE,
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"to",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: ENTRY
		};
		case "trash":
		case "restore": return {
			input: jsonSchema("object", {
				id: UUID,
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: ENTRY
		};
		case "delete": return {
			input: jsonSchema("object", {
				id: UUID,
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: Object.freeze({ $ref: "EntityRef" })
		};
		case "listRevisions": return {
			input: jsonSchema("object", {
				id: UUID,
				before: NUMBER,
				limit: NUMBER
			}, ["id"]),
			output: Object.freeze({ $ref: "ContentRevisionPage" })
		};
		case "getRevision": return {
			input: jsonSchema("object", {
				id: UUID,
				revisionId: UUID
			}, ["id", "revisionId"]),
			output: REVISION
		};
		case "restoreRevision": return {
			input: jsonSchema("object", {
				id: UUID,
				revisionId: UUID,
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"revisionId",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: ENTRY
		};
		case "createAutosave": return {
			input: jsonSchema("object", {
				id: UUID,
				snapshot: Object.freeze({ $ref: "ContentUpdatePatch" }),
				parentRevisionId: UUID,
				operationId: STRING
			}, [
				"id",
				"snapshot",
				"parentRevisionId",
				"operationId"
			]),
			output: AUTOSAVE
		};
		case "getAutosave": return {
			input: jsonSchema("object", {
				id: UUID,
				autosaveId: UUID
			}, ["id", "autosaveId"]),
			output: AUTOSAVE
		};
		case "restoreAutosave": return {
			input: jsonSchema("object", {
				id: UUID,
				autosaveId: UUID,
				expectedUpdatedAt: DATE,
				operationId: STRING
			}, [
				"id",
				"autosaveId",
				"expectedUpdatedAt",
				"operationId"
			]),
			output: ENTRY
		};
	}
}
function enabledKeys(type) {
	if (type.rest === false) return [];
	const keys = [
		"list",
		"count",
		"get",
		...type.active ? ["create"] : [],
		"update",
		"transition",
		"trash",
		"restore",
		"delete"
	];
	if (type.rest.revisions && type.supports.includes("revisions")) keys.push("listRevisions", "getRevision", "restoreRevision");
	if (type.rest.autosaves && type.rest.revisions && type.supports.includes("revisions")) keys.push("createAutosave", "getAutosave", "restoreAutosave");
	return keys;
}
function capabilityLabel(type, key) {
	switch (key) {
		case "list":
		case "count":
		case "get": return type.capabilities.read;
		case "create": return type.capabilities.create;
		case "delete": return `${type.capabilities.deleteOwn}|${type.capabilities.deleteOthers}`;
		case "transition": return `${type.capabilities.editOwn}|${type.capabilities.editOthers};published:${type.capabilities.publish}`;
		default: return `${type.capabilities.editOwn}|${type.capabilities.editOthers}`;
	}
}
function typeSchema(type, fields) {
	return schemaValue$1({
		key: type.key,
		version: type.version,
		revision: type.revision,
		canonicalHash: type.canonicalHash,
		active: type.active,
		labels: type.labels,
		description: type.description,
		public: type.public,
		hierarchical: type.hierarchical,
		excludeFromSearch: type.excludeFromSearch,
		publiclyQueryable: type.publiclyQueryable,
		supports: type.supports,
		taxonomies: type.taxonomies,
		capabilities: type.capabilities,
		rest: type.rest,
		statusKeys: type.statusKeys,
		defaultTemplateKey: type.defaultTemplateKey,
		template: type.template,
		templateLock: type.templateLock,
		...fields === void 0 ? {} : { fields }
	});
}
function statusSchema(status) {
	return schemaValue$1({
		key: status.key,
		version: status.version,
		revision: status.revision,
		canonicalHash: status.canonicalHash,
		active: status.active,
		label: status.label,
		published: status.published,
		internal: status.internal,
		excludeFromSearch: status.excludeFromSearch,
		publiclyQueryable: status.publiclyQueryable,
		showInAdminAll: status.showInAdminAll,
		showInAdminStatusFilter: status.showInAdminStatusFilter,
		dateLabel: status.dateLabel,
		transitionInput: status.transitionInput
	});
}
async function generateContentSchema(sources) {
	const types = uniqueByKey(sources.types, "types"), statuses = uniqueByKey(sources.statuses, "statuses"), taxonomies = uniqueByKey(sources.taxonomies, "taxonomies");
	for (const taxonomy of taxonomies.values()) if (typeof taxonomy.version !== "string" || !taxonomy.version) throw new ContentHeadlessError("invalid-schema-source", `taxonomy ${taxonomy.key} has no version`, "taxonomies");
	const serializedTypes = [];
	const operations = [];
	for (const type of [...types.values()].sort((a, b) => a.key.localeCompare(b.key))) {
		if (type.rest !== false) {
			for (const statusKey of type.statusKeys ?? []) if (!statuses.has(statusKey)) throw new ContentHeadlessError("invalid-schema-source", `type ${type.key} references missing status ${statusKey}`, "types");
			for (const taxonomyKey of type.taxonomies) if (!taxonomies.has(taxonomyKey)) throw new ContentHeadlessError("invalid-schema-source", `type ${type.key} references missing taxonomy schema ${taxonomyKey}`, "taxonomies");
			if (type.supports.includes("customFields") && !sources.fields) throw new ContentHeadlessError("invalid-schema-source", `type ${type.key} exposes custom fields without a fields schema adapter`, "fields");
		}
		let fields;
		if (sources.fields && type.rest !== false) fields = schemaValue$1(await sources.fields.schemaForType(type.key), `fields.${type.key}`);
		serializedTypes.push(typeSchema(type, fields));
		for (const key of enabledKeys(type)) {
			const schemas = operationSchemas(key);
			operations.push(Object.freeze({
				typeKey: type.key,
				key,
				capability: capabilityLabel(type, key),
				input: schemas.input,
				output: schemas.output,
				errors: ERRORS
			}));
		}
	}
	const serializedStatuses = [...statuses.values()].sort((a, b) => a.key.localeCompare(b.key)).map(statusSchema);
	const serializedTaxonomies = [...taxonomies.values()].sort((a, b) => a.key.localeCompare(b.key)).map((taxonomy) => Object.freeze({
		key: taxonomy.key,
		version: taxonomy.version,
		schema: schemaValue$1(taxonomy.schema, `taxonomies.${taxonomy.key}`)
	}));
	const version = await canonicalContentMigrationHash(schemaValue$1({
		types: serializedTypes,
		statuses: serializedStatuses,
		taxonomies: serializedTaxonomies,
		operations
	}));
	return Object.freeze({
		version,
		types: Object.freeze(serializedTypes),
		statuses: Object.freeze(serializedStatuses),
		taxonomies: Object.freeze(serializedTaxonomies),
		operations: Object.freeze(operations)
	});
}
[
	"slug",
	"type",
	"title",
	"body",
	"excerpt",
	"visibility",
	"author",
	"termIds",
	"parentId",
	"menuOrder",
	"templateKey",
	"featuredMedia",
	"commentStatus",
	"pingStatus",
	"sticky",
	"format"
].filter((key) => key !== "type");
/** Maximum bind parameters in one native D1 import statement. */
var CONTENT_IMPORT_D1_BIND_BUDGET = 100;
var ContentImportError = class extends Error {
	code;
	detail;
	field;
	name = "ContentImportError";
	constructor(code, detail, field) {
		super(`content import ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
var fail$1 = (code, detail, field) => {
	throw new ContentImportError(code, detail, field);
};
function required(value, code, detail) {
	if (value === void 0) fail$1(code, detail);
	return value;
}
var ALL_BRANCHES = Object.freeze([
	"manageType",
	"migrateAll",
	"manageTerms",
	"create",
	"read",
	"readPrivate",
	"readProtected",
	"editOwn",
	"editOthers",
	"editPrivate",
	"editPublished",
	"publish",
	"deleteOwn",
	"deleteOthers",
	"deletePrivate",
	"deletePublished"
]);
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
var KEY_RE = /^[a-z][a-z0-9_-]*$/;
var FORBIDDEN_IMPORT_KEY = /password|credential/i;
function boundedString(value, field, max = 4096) {
	if (typeof value !== "string") fail$1("validation", "must be a string", field);
	const normalized = value.trim();
	if (!normalized || normalized.length > max) fail$1("validation", `must contain 1..${max} characters`, field);
	return normalized;
}
function plain(value, field) {
	if (typeof value !== "object" || value === null || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype) fail$1("validation", "must be a plain object", field);
	return value;
}
function array(value, field, max) {
	if (!Array.isArray(value) || value.length > max) fail$1("limit", `must be an array with at most ${max} items`, field);
	return value;
}
function positive$1(value, field) {
	if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) fail$1("validation", "must be a positive safe integer", field);
	return value;
}
function nonnegative(value, field) {
	if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) fail$1("validation", "must be a non-negative safe integer", field);
	return value;
}
function iso$1(value, field) {
	const raw = boundedString(value, field, 128), date = new Date(raw);
	if (Number.isNaN(date.getTime())) fail$1("validation", "must be an ISO timestamp", field);
	return date.toISOString();
}
function uuid(value, field) {
	const raw = boundedString(value, field, 128);
	if (!UUID_RE.test(raw)) fail$1("validation", "must be a UUID", field);
	return raw;
}
function key(value, field) {
	const raw = boundedString(value, field, 128);
	if (!KEY_RE.test(raw)) fail$1("validation", "must be a normalized key", field);
	return raw;
}
function schemaValue(value, field = "value", depth = 0) {
	if (depth > 32) fail$1("limit", "exceeds maximum nested depth", field);
	if (value === null || typeof value === "string" || typeof value === "boolean") return value;
	if (value instanceof Date) return value.toISOString();
	if (typeof value === "bigint") return value.toString();
	if (typeof value === "number") {
		if (!Number.isFinite(value)) fail$1("validation", "contains non-finite number", field);
		return value;
	}
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => schemaValue(item, `${field}.${index}`, depth + 1)));
	if (typeof value === "object") {
		if (Object.getPrototypeOf(value) !== Object.prototype) fail$1("validation", "contains a non-plain object", field);
		const out = {};
		for (const [name, child] of Object.entries(value)) {
			if (FORBIDDEN_IMPORT_KEY.test(name)) fail$1("validation", "password/credential material is forbidden", `${field}.${name}`);
			if (child !== void 0) out[name] = schemaValue(child, `${field}.${name}`, depth + 1);
		}
		return Object.freeze(out);
	}
	return fail$1("validation", "contains unsupported value", field);
}
function stableScope(scope) {
	const tenantKey = boundedString(scope.tenantKey, "scope.tenantKey", 256), typeKeys = [...new Set(scope.typeKeys.map((item, index) => key(item, `scope.typeKeys.${index}`)))].sort();
	if (typeKeys.length === 0 || typeKeys.length > 500) fail$1("validation", "scope must contain 1..500 type keys", "scope.typeKeys");
	return Object.freeze({
		tenantKey,
		typeKeys: Object.freeze(typeKeys)
	});
}
function assertD1Scope(scope) {
	const normalized = stableScope(scope);
	if (normalized.typeKeys.length > CONTENT_IMPORT_D1_BIND_BUDGET) fail$1("limit", `native D1 import scope requires ${normalized.typeKeys.length} bind parameters; maximum is ${CONTENT_IMPORT_D1_BIND_BUDGET}`, "scope.typeKeys");
	return normalized;
}
function sameScope(a, b) {
	return a.tenantKey === b.tenantKey && a.typeKeys.length === b.typeKeys.length && a.typeKeys.every((value, index) => value === b.typeKeys[index]);
}
function stableAuthority(input) {
	const map = /* @__PURE__ */ new Map();
	for (const row of input) {
		const typeKey = key(row.typeKey, "requiredAuthority.typeKey"), set = map.get(typeKey) ?? /* @__PURE__ */ new Set();
		for (const branch of row.branches) {
			if (!ALL_BRANCHES.includes(branch)) fail$1("validation", "unknown capability branch", "requiredAuthority.branches");
			set.add(branch);
		}
		map.set(typeKey, set);
	}
	return Object.freeze([...map].sort(([a], [b]) => a.localeCompare(b)).map(([typeKey, branches]) => Object.freeze({
		typeKey,
		branches: Object.freeze(ALL_BRANCHES.filter((branch) => branches.has(branch)))
	})));
}
function sameAuthority(a, b) {
	return JSON.stringify(stableAuthority(a)) === JSON.stringify(stableAuthority(b));
}
function principalScope(principal) {
	return `${principal.tenantId ?? ""}:${principal.id}`;
}
function isUniqueViolation(error) {
	let current = error;
	while (current) {
		const code = current.code, message = current instanceof Error ? current.message : String(current);
		if (code === "23505" || /unique constraint|duplicate key|content_lifecycle_journal_operation_uq/i.test(message)) return true;
		current = current instanceof Error ? current.cause : void 0;
	}
	return false;
}
function rowJson(value) {
	const parsed = typeof value === "string" ? JSON.parse(value) : value;
	if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) fail$1("integrity", "stored journal payload is malformed");
	return parsed;
}
function rowsOf$1(result) {
	if (Array.isArray(result)) return result;
	const rows = result?.rows;
	if (Array.isArray(rows)) return rows;
	return fail$1("integrity", "database adapter returned invalid rows");
}
async function execRows(tx, query) {
	return rowsOf$1(await tx.execute(query));
}
async function execRowsByD1BindChunks(tx, values, query) {
	const rows = [];
	for (let offset = 0; offset < values.length; offset += CONTENT_IMPORT_D1_BIND_BUDGET) rows.push(...await execRows(tx, query(values.slice(offset, offset + CONTENT_IMPORT_D1_BIND_BUDGET))));
	return rows;
}
function nullableString(value, field, max = 4096) {
	return value === null ? null : boundedString(value, field, max);
}
function parseDefinitionVersions(value, field, keyValue, normalize) {
	const versions = array(value, field, 1e3).map((raw, index) => {
		const item = plain(raw, `${field}.${index}`), definition = normalize(item.definition), origin = item.origin;
		if (origin !== "code" && origin !== "db" && origin !== "import") fail$1("validation", "invalid origin", `${field}.${index}.origin`);
		if (definition.key !== keyValue) fail$1("validation", "definition version key mismatch", `${field}.${index}.definition.key`);
		return Object.freeze({
			revision: positive$1(item.revision, `${field}.${index}.revision`),
			canonicalHash: boundedString(item.canonicalHash, `${field}.${index}.canonicalHash`, 128),
			definition,
			origin,
			createdAt: iso$1(item.createdAt, `${field}.${index}.createdAt`)
		});
	});
	duplicates(versions, (item) => String(item.revision), field);
	return Object.freeze(versions.sort((a, b) => a.revision - b.revision));
}
function parseType(raw, index) {
	const item = plain(raw, `types.${index}`), definition = normalizeContentTypeDefinition(item.definition), itemKey = key(item.key, `types.${index}.key`);
	if (definition.key !== itemKey) fail$1("validation", "definition key mismatch", `types.${index}.definition.key`);
	const origin = item.origin;
	if (origin !== "code" && origin !== "db" && origin !== "import") fail$1("validation", "invalid origin", `types.${index}.origin`);
	const versions = parseDefinitionVersions(item.versions, `types.${index}.versions`, itemKey, normalizeContentTypeDefinition);
	const active = Boolean(item.active);
	if (active !== definition.active) fail$1("validation", "type active state differs from normalized definition", `types.${index}.active`);
	return Object.freeze({
		key: itemKey,
		origin,
		version: positive$1(item.version, `types.${index}.version`),
		revision: positive$1(item.revision, `types.${index}.revision`),
		active,
		canonicalHash: boundedString(item.canonicalHash, `types.${index}.canonicalHash`, 128),
		definition,
		versions
	});
}
function parseStatus(raw, index) {
	const item = plain(raw, `statuses.${index}`), definition = normalizeContentStatusDefinition(item.definition), itemKey = key(item.key, `statuses.${index}.key`);
	if (definition.key !== itemKey) fail$1("validation", "definition key mismatch", `statuses.${index}.definition.key`);
	const origin = item.origin;
	if (origin !== "code" && origin !== "db" && origin !== "import") fail$1("validation", "invalid origin", `statuses.${index}.origin`);
	const versions = parseDefinitionVersions(item.versions, `statuses.${index}.versions`, itemKey, normalizeContentStatusDefinition);
	if (typeof item.active !== "boolean") fail$1("validation", "status active must be boolean", `statuses.${index}.active`);
	return Object.freeze({
		key: itemKey,
		origin,
		version: positive$1(item.version, `statuses.${index}.version`),
		revision: positive$1(item.revision, `statuses.${index}.revision`),
		active: item.active,
		canonicalHash: boundedString(item.canonicalHash, `statuses.${index}.canonicalHash`, 128),
		definition,
		versions
	});
}
function parseTaxonomy(raw, index) {
	const item = plain(raw, `taxonomies.${index}`);
	return Object.freeze({
		key: key(item.key, `taxonomies.${index}.key`),
		version: boundedString(item.version, `taxonomies.${index}.version`, 128)
	});
}
function parseTerm(raw, index) {
	const item = plain(raw, `terms.${index}`);
	return Object.freeze({
		id: uuid(item.id, `terms.${index}.id`),
		taxonomy: key(item.taxonomy, `terms.${index}.taxonomy`),
		slug: boundedString(item.slug, `terms.${index}.slug`, 256),
		name: boundedString(item.name, `terms.${index}.name`, 512),
		parentId: item.parentId === null ? null : uuid(item.parentId, `terms.${index}.parentId`),
		depth: nonnegative(item.depth, `terms.${index}.depth`),
		createdAt: iso$1(item.createdAt, `terms.${index}.createdAt`)
	});
}
function parseEntry(raw, index) {
	const item = plain(raw, `entries.${index}`), visibility = item.visibility, commentStatus = item.commentStatus, pingStatus = item.pingStatus;
	if (visibility !== "public" && visibility !== "private" && visibility !== "members") fail$1("validation", "invalid visibility", `entries.${index}.visibility`);
	if (commentStatus !== "open" && commentStatus !== "closed") fail$1("validation", "invalid comment status", `entries.${index}.commentStatus`);
	if (pingStatus !== "open" && pingStatus !== "closed") fail$1("validation", "invalid ping status", `entries.${index}.pingStatus`);
	if (typeof item.sticky !== "boolean") fail$1("validation", "must be boolean", `entries.${index}.sticky`);
	const termIds = array(item.termIds, `entries.${index}.termIds`, 1e4).map((value, i) => uuid(value, `entries.${index}.termIds.${i}`));
	return Object.freeze({
		id: uuid(item.id, `entries.${index}.id`),
		slug: boundedString(item.slug, `entries.${index}.slug`, 256),
		type: key(item.type, `entries.${index}.type`),
		title: typeof item.title === "string" && item.title.length <= 300 ? item.title : fail$1("validation", "invalid title", `entries.${index}.title`),
		body: typeof item.body === "string" && item.body.length <= 2e6 ? item.body : fail$1("validation", "invalid body", `entries.${index}.body`),
		status: key(item.status, `entries.${index}.status`),
		visibility,
		publishedAt: item.publishedAt === null ? null : iso$1(item.publishedAt, `entries.${index}.publishedAt`),
		author: boundedString(item.author, `entries.${index}.author`, 512),
		createdAt: iso$1(item.createdAt, `entries.${index}.createdAt`),
		updatedAt: iso$1(item.updatedAt, `entries.${index}.updatedAt`),
		parentId: item.parentId === null ? null : uuid(item.parentId, `entries.${index}.parentId`),
		menuOrder: nonnegative(item.menuOrder, `entries.${index}.menuOrder`),
		templateKey: nullableString(item.templateKey, `entries.${index}.templateKey`, 256),
		excerpt: typeof item.excerpt === "string" && item.excerpt.length <= 1e5 ? item.excerpt : fail$1("validation", "invalid excerpt", `entries.${index}.excerpt`),
		featuredMedia: item.featuredMedia === null ? null : schemaValue(item.featuredMedia, `entries.${index}.featuredMedia`),
		commentStatus,
		pingStatus,
		sticky: item.sticky,
		format: nullableString(item.format, `entries.${index}.format`, 128),
		deletedAt: item.deletedAt === null ? null : iso$1(item.deletedAt, `entries.${index}.deletedAt`),
		lastEditedBy: boundedString(item.lastEditedBy, `entries.${index}.lastEditedBy`, 512),
		typeDefinitionRevision: positive$1(item.typeDefinitionRevision, `entries.${index}.typeDefinitionRevision`),
		statusDefinitionRevision: positive$1(item.statusDefinitionRevision, `entries.${index}.statusDefinitionRevision`),
		termIds: Object.freeze(termIds)
	});
}
function parseRevision(raw, index) {
	const item = plain(raw, `revisions.${index}`), termIds = array(item.termIds, `revisions.${index}.termIds`, 1e4).map((value, i) => uuid(value, `revisions.${index}.termIds.${i}`));
	return Object.freeze({
		id: uuid(item.id, `revisions.${index}.id`),
		entryId: uuid(item.entryId, `revisions.${index}.entryId`),
		seq: positive$1(item.seq, `revisions.${index}.seq`),
		title: typeof item.title === "string" ? item.title : fail$1("validation", "invalid title", `revisions.${index}.title`),
		body: typeof item.body === "string" ? item.body : fail$1("validation", "invalid body", `revisions.${index}.body`),
		slug: boundedString(item.slug, `revisions.${index}.slug`, 256),
		type: key(item.type, `revisions.${index}.type`),
		termIds: Object.freeze(termIds),
		...item.snapshot === void 0 ? {} : { snapshot: schemaValue(item.snapshot, `revisions.${index}.snapshot`) },
		editor: boundedString(item.editor, `revisions.${index}.editor`, 512),
		createdAt: iso$1(item.createdAt, `revisions.${index}.createdAt`)
	});
}
function duplicates(items, id, field) {
	const seen = /* @__PURE__ */ new Set();
	for (const item of items) {
		const value = id(item);
		if (seen.has(value)) fail$1("validation", "contains duplicate identity", field);
		seen.add(value);
	}
}
function assertTermGraph(terms) {
	const byId = new Map(terms.map((item) => [item.id, item]));
	for (const item of terms) {
		if (item.parentId === null) {
			if (item.depth !== 0) fail$1("validation", "root term depth must be zero", `term:${item.id}`);
			continue;
		}
		const parent = byId.get(item.parentId);
		if (!parent) throw new ContentImportError("validation", "term references missing parent", `term:${item.id}`);
		if (parent.taxonomy !== item.taxonomy) fail$1("validation", "term parent must share taxonomy", `term:${item.id}`);
		if (item.depth !== parent.depth + 1) fail$1("validation", "term depth does not match parent", `term:${item.id}`);
		const seen = /* @__PURE__ */ new Set([item.id]);
		let cursor = parent;
		while (cursor) {
			if (seen.has(cursor.id)) fail$1("validation", "term hierarchy contains a cycle", `term:${item.id}`);
			seen.add(cursor.id);
			cursor = cursor.parentId === null ? void 0 : byId.get(cursor.parentId);
		}
	}
}
function assertEntryGraph(entries) {
	const byId = new Map(entries.map((item) => [item.id, item]));
	for (const item of entries) {
		if (item.parentId === null) continue;
		const parent = byId.get(item.parentId);
		if (!parent) throw new ContentImportError("validation", "entry references missing parent", `entry:${item.id}`);
		if (parent.type !== item.type) fail$1("validation", "entry parent must share content type", `entry:${item.id}`);
		const seen = /* @__PURE__ */ new Set([item.id]);
		let cursor = parent;
		while (cursor) {
			if (seen.has(cursor.id)) fail$1("validation", "entry hierarchy contains a cycle", `entry:${item.id}`);
			seen.add(cursor.id);
			cursor = cursor.parentId === null ? void 0 : byId.get(cursor.parentId);
		}
	}
}
function assertLimits(limits) {
	for (const [name, value] of Object.entries(limits)) if (!Number.isSafeInteger(value) || value < 1) fail$1("validation", "must be a positive safe integer", `limits.${name}`);
	if (limits.batchSize > 1e3) fail$1("validation", "batchSize must be <= 1000", "limits.batchSize");
}
async function parseBundle(input, limits) {
	assertLimits(limits);
	if (input.byteLength > limits.maxBytes) fail$1("limit", "input exceeds maxBytes", "input");
	let decoded;
	try {
		decoded = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(input));
	} catch {
		fail$1("validation", "input is not valid UTF-8 JSON", "input");
	}
	const root = plain(decoded, "bundle");
	schemaValue(root, "bundle");
	for (const name of Object.keys(root)) if (![
		"version",
		"generatedAt",
		"types",
		"statuses",
		"taxonomies",
		"terms",
		"entries",
		"revisions"
	].includes(name)) fail$1("validation", "unsupported bundle property", name);
	if (root.version !== 1) fail$1("validation", "unsupported bundle version", "version");
	const generatedAt = iso$1(root.generatedAt, "generatedAt");
	const types = array(root.types, "types", limits.maxDefinitions).map(parseType), statuses = array(root.statuses, "statuses", limits.maxDefinitions).map(parseStatus), taxonomies = array(root.taxonomies, "taxonomies", limits.maxDefinitions).map(parseTaxonomy);
	if (types.length + statuses.length + taxonomies.length > limits.maxDefinitions) fail$1("limit", "definitions exceed maxDefinitions", "definitions");
	const terms = array(root.terms, "terms", Math.max(limits.maxEntries * 10, limits.maxDefinitions)).map(parseTerm), entries = array(root.entries, "entries", limits.maxEntries).map(parseEntry), revisions = array(root.revisions, "revisions", limits.maxRevisions).map(parseRevision);
	for (const item of types) {
		if (await canonicalContentMigrationHash(item.definition) !== item.canonicalHash) fail$1("validation", "type canonicalHash does not match normalized definition", `type:${item.key}`);
		for (const version of item.versions) if (await canonicalContentMigrationHash(version.definition) !== version.canonicalHash) fail$1("validation", "type version hash does not match normalized definition", `type:${item.key}@${version.revision}`);
		const current = item.versions.find((version) => version.revision === item.revision);
		if (!current || current.canonicalHash !== item.canonicalHash) fail$1("validation", "current type revision is absent or mismatched", `type:${item.key}`);
	}
	for (const item of statuses) {
		if (await canonicalContentMigrationHash(item.definition) !== item.canonicalHash) fail$1("validation", "status canonicalHash does not match normalized definition", `status:${item.key}`);
		for (const version of item.versions) if (await canonicalContentMigrationHash(version.definition) !== version.canonicalHash) fail$1("validation", "status version hash does not match normalized definition", `status:${item.key}@${version.revision}`);
		const current = item.versions.find((version) => version.revision === item.revision);
		if (!current || current.canonicalHash !== item.canonicalHash) fail$1("validation", "current status revision is absent or mismatched", `status:${item.key}`);
	}
	duplicates(types, (item) => item.key, "types");
	duplicates(statuses, (item) => item.key, "statuses");
	duplicates(taxonomies, (item) => item.key, "taxonomies");
	duplicates(terms, (item) => item.id, "terms");
	duplicates(entries, (item) => item.id, "entries");
	duplicates(revisions, (item) => item.id, "revisions");
	assertTermGraph(terms);
	assertEntryGraph(entries);
	const taxonomyKeys = new Set(taxonomies.map((item) => item.key)), termIds = new Set(terms.map((item) => item.id)), termById = new Map(terms.map((item) => [item.id, item])), entryIds = new Set(entries.map((item) => item.id)), typeKeys = new Set(types.map((item) => item.key)), statusKeys = new Set(statuses.map((item) => item.key));
	for (const type of types) for (const definition of [type.definition, ...type.versions.map((version) => version.definition)]) {
		for (const statusKey of definition.statusKeys ?? []) if (!statusKeys.has(statusKey)) fail$1("validation", "type definition references missing status", `type:${type.key}`);
		for (const taxonomy of definition.taxonomies) if (!taxonomyKeys.has(taxonomy)) fail$1("validation", "type definition references missing taxonomy", `type:${type.key}`);
	}
	for (const term of terms) {
		if (!taxonomyKeys.has(term.taxonomy)) fail$1("validation", "term references missing taxonomy", `term:${term.id}`);
		if (term.parentId !== null && !termIds.has(term.parentId)) fail$1("validation", "term references missing parent", `term:${term.id}`);
	}
	for (const entry of entries) {
		const type = types.find((item) => item.key === entry.type), status = statuses.find((item) => item.key === entry.status);
		if (!type || !typeKeys.has(entry.type)) throw new ContentImportError("validation", "entry references missing type", `entry:${entry.id}`);
		if (!status || !statusKeys.has(entry.status)) throw new ContentImportError("validation", "entry references missing status", `entry:${entry.id}`);
		const typeVersion = type.versions.find((version) => version.revision === entry.typeDefinitionRevision), statusVersion = status.versions.find((version) => version.revision === entry.statusDefinitionRevision);
		if (!typeVersion) throw new ContentImportError("validation", "entry type revision is absent from bundle", `entry:${entry.id}`);
		if (!statusVersion) throw new ContentImportError("validation", "entry status revision is absent from bundle", `entry:${entry.id}`);
		if (typeVersion.definition.statusKeys !== void 0 && !typeVersion.definition.statusKeys.includes(entry.status)) fail$1("validation", "entry status is not allowed by bundled type", `entry:${entry.id}`);
		if (entry.parentId !== null && !entryIds.has(entry.parentId)) fail$1("validation", "entry references missing parent", `entry:${entry.id}`);
		for (const id of entry.termIds) {
			const term = termById.get(id);
			if (!term) fail$1("validation", "entry references missing term", `entry:${entry.id}`);
			if (!typeVersion.definition.taxonomies.includes(term.taxonomy)) fail$1("validation", "entry term taxonomy is not allowed by pinned type definition", `entry:${entry.id}`);
		}
	}
	for (const revision of revisions) {
		const entry = entries.find((item) => item.id === revision.entryId);
		if (!entry || !entryIds.has(revision.entryId)) throw new ContentImportError("validation", "revision references missing entry", `revision:${revision.id}`);
		if (revision.type !== entry.type) fail$1("validation", "revision type does not match entry", `revision:${revision.id}`);
		for (const id of revision.termIds) if (!termIds.has(id)) fail$1("validation", "revision references missing term", `revision:${revision.id}`);
	}
	const bundle = Object.freeze({
		version: 1,
		generatedAt,
		types: Object.freeze(types.map((item) => schemaValue(item))),
		statuses: Object.freeze(statuses.map((item) => schemaValue(item))),
		taxonomies: Object.freeze(taxonomies.map((item) => schemaValue(item))),
		terms: Object.freeze(terms.map((item) => schemaValue(item))),
		entries: Object.freeze(entries.map((item) => schemaValue(item))),
		revisions: Object.freeze(revisions.map((item) => schemaValue(item)))
	});
	return Object.freeze({
		bundle,
		types: Object.freeze(types),
		statuses: Object.freeze(statuses),
		taxonomies: Object.freeze(taxonomies),
		terms: Object.freeze(terms),
		entries: Object.freeze(entries),
		revisions: Object.freeze(revisions),
		manifestHash: await canonicalContentMigrationHash(bundle)
	});
}
async function parseContentImport(input, limits) {
	return (await parseBundle(input, limits)).bundle;
}
function sessionFromRow(row) {
	const stored = plain(rowJson(row.payload).session, "journal.session"), staging = plain(stored.staging, "journal.session.staging");
	return Object.freeze({
		...stored,
		id: String(row.importId),
		planHash: String(row.planHash),
		manifestHash: String(row.manifestHash),
		state: row.state,
		journalVersion: String(row.version),
		nextSection: row.nextSection,
		nextOffset: Number(row.nextOffset ?? 0),
		...row.highWaterMark === null ? {} : { publishedCorpusVersion: String(row.highWaterMark) },
		staging: Object.freeze({
			...staging,
			hostSessionId: String(row.hostSessionId)
		})
	});
}
async function readJournalRow(tx, sessionId) {
	return (await execRows(tx, sql`SELECT import_id AS "importId",host_session_id AS "hostSessionId",manifest_hash AS "manifestHash",plan_hash AS "planHash",state,version,next_section AS "nextSection",next_offset AS "nextOffset",high_water_mark AS "highWaterMark",payload FROM content_import_journal WHERE import_id=${sessionId}`))[0];
}
async function readReceiptEvidence(tx, operationId) {
	const row = (await execRows(tx, sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id=${operationId} AND kind LIKE 'content:import:%' AND state='committed' LIMIT 1`))[0];
	if (!row) return;
	const value = rowJson(row.payload);
	if (typeof value.kind !== "string" || typeof value.commandHash !== "string" || typeof value.principalScope !== "string" || typeof value.session !== "object") fail$1("integrity", "committed import receipt payload is malformed");
	return Object.freeze({
		receipt: value,
		payloadBytes: typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload)
	});
}
async function readReceipt(tx, operationId) {
	return (await readReceiptEvidence(tx, operationId))?.receipt;
}
function prepareExactReplayGuard(db, operationId, kind, evidence, row, session) {
	const journalPayloadBytes = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload), section = session.nextSection === null ? sql`journal.next_section IS NULL` : sql`journal.next_section=${session.nextSection}`;
	return db.prepare(sql`SELECT CASE WHEN EXISTS (SELECT 1 FROM content_lifecycle_journal AS receipt JOIN content_import_journal AS journal ON journal.import_id=${session.id} WHERE receipt.operation_id=${operationId} AND receipt.kind=${`content:import:${kind}`} AND receipt.state='committed' AND receipt.payload=${evidence.payloadBytes} AND journal.payload=${journalPayloadBytes} AND journal.host_session_id=${session.staging.hostSessionId} AND journal.plan_hash=${session.planHash} AND journal.manifest_hash=${session.manifestHash} AND journal.state=${session.state} AND journal.version=${Number(session.journalVersion)} AND ${section} AND journal.next_offset=${session.nextOffset} AND journal.high_water_mark IS ${session.publishedCorpusVersion ?? null}) THEN 1 ELSE json_extract('not-json','$') END AS ok`);
}
async function insertPendingReceipt(tx, operationId, kind, hash, scope) {
	const now = (/* @__PURE__ */ new Date()).toISOString(), payload = schemaValue({
		kind,
		commandHash: hash,
		principalScope: scope
	});
	await tx.execute(sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${crypto.randomUUID()},${operationId},${`content:import:${kind}`},'pending',${JSON.stringify(payload)},${now},${now})`);
}
async function commitReceipt(tx, operationId, kind, hash, scope, session) {
	const payload = schemaValue({
		kind,
		commandHash: hash,
		principalScope: scope,
		session
	});
	if ((await execRows(tx, sql`UPDATE content_lifecycle_journal SET state='committed',payload=${JSON.stringify(payload)},updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE operation_id=${operationId} AND state='pending' RETURNING id`)).length !== 1) fail$1("integrity", "import command claim disappeared");
}
function createDbContentImportJournal() {
	return Object.freeze({
		async claimStart(tx, principal, authorizationInput, authorization, operationId, canonicalStartHash) {
			assertActiveContentTransaction(tx);
			boundedString(operationId, "operationId", 256);
			const auth = await authorization.assert(tx, principal, "start", authorizationInput);
			if (authorizationInput.expectedPolicyVersion !== void 0 && auth.policyVersion !== authorizationInput.expectedPolicyVersion) fail$1("authorization", "import scope is unavailable");
			const receipt = await readReceipt(tx, operationId);
			if (receipt) {
				if (receipt.kind !== "start" || receipt.commandHash !== canonicalStartHash || receipt.principalScope !== principalScope(principal)) return { kind: "conflict" };
				return {
					kind: "replay",
					session: receipt.session
				};
			}
			try {
				await insertPendingReceipt(tx, operationId, "start", canonicalStartHash, principalScope(principal));
				return { kind: "new" };
			} catch (error) {
				if (isUniqueViolation(error)) return { kind: "conflict" };
				throw error;
			}
		},
		async create(plan, staging, principal, operationId, tx) {
			assertActiveContentTransaction(tx);
			if (staging.visibility !== "hiddenUntilPublish") fail$1("validation", "unsupported staging visibility", "staging.visibility");
			const id = uuid(staging.hostSessionId, "staging.hostSessionId"), session = Object.freeze({
				id,
				planHash: plan.planHash,
				manifestHash: plan.manifestHash,
				state: "validated",
				staging: Object.freeze(staging),
				scope: plan.scope,
				conflictPolicy: plan.conflictPolicy,
				requiredAuthority: plan.requiredAuthority,
				authorizationPolicyVersion: plan.authorizationPolicyVersion,
				destinationCorpusVersion: plan.destinationCorpusVersion,
				mappings: plan.mappings,
				appliedBatches: 0,
				journalVersion: "0",
				nextSection: "type",
				nextOffset: 0
			}), payload = {
				session,
				batches: Object.freeze([])
			}, now = (/* @__PURE__ */ new Date()).toISOString();
			try {
				await tx.execute(sql`INSERT INTO content_import_journal (import_id,host_session_id,manifest_hash,plan_hash,state,version,next_section,next_offset,payload,created_at,updated_at) VALUES (${id},${staging.hostSessionId},${plan.manifestHash},${plan.planHash},'validated',0,'type',0,${JSON.stringify(schemaValue(payload))},${now},${now})`);
			} catch (error) {
				if (isUniqueViolation(error)) fail$1("conflict", "staging session already exists");
				throw error;
			}
			const pending = (await execRows(tx, sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id=${operationId} AND state='pending'`))[0];
			if (!pending) fail$1("integrity", "start claim disappeared");
			const raw = rowJson(pending.payload);
			await commitReceipt(tx, operationId, "start", boundedString(raw.commandHash, "receipt.commandHash", 128), boundedString(raw.principalScope, "receipt.principalScope", 1024), session);
			return session;
		},
		async claimCommand(tx, sessionId, principal, kind, command, canonicalCommandHash, authorization) {
			assertActiveContentTransaction(tx);
			boundedString(sessionId, "sessionId", 128);
			boundedString(command.operationId, "operationId", 256);
			const authInput = {
				scope: stableScope(command.scope),
				requiredAuthority: stableAuthority(command.requiredAuthority),
				expectedPolicyVersion: command.expectedAuthorizationPolicyVersion
			};
			if ((await authorization.assert(tx, principal, kind, authInput)).policyVersion !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
			const receipt = await readReceipt(tx, command.operationId);
			if (receipt) {
				if (receipt.kind !== kind || receipt.commandHash !== canonicalCommandHash || receipt.principalScope !== principalScope(principal)) return { kind: "conflict" };
				return {
					kind: "replay",
					session: receipt.session
				};
			}
			const expectedVersion = Number(command.expectedJournalVersion);
			if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0) fail$1("validation", "expectedJournalVersion is invalid", "expectedJournalVersion");
			const sectionPredicate = command.expectedSection === null ? sql`next_section IS NULL` : sql`next_section=${command.expectedSection}`;
			const row = (await execRows(tx, sql`UPDATE content_import_journal SET version=version+1,updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE import_id=${sessionId} AND plan_hash=${command.expectedPlanHash} AND manifest_hash=${command.expectedManifestHash} AND version=${expectedVersion} AND ${sectionPredicate} AND next_offset=${command.expectedOffset} RETURNING import_id AS "importId",host_session_id AS "hostSessionId",manifest_hash AS "manifestHash",plan_hash AS "planHash",state,version,next_section AS "nextSection",next_offset AS "nextOffset",high_water_mark AS "highWaterMark",payload`))[0];
			if (!row) {
				if (!await readJournalRow(tx, sessionId)) fail$1("authorization", "import session is unavailable");
				fail$1("stale-journal", "journal coordinate changed");
			}
			const session = sessionFromRow(row);
			if (!sameScope(session.scope, authInput.scope) || !sameAuthority(session.requiredAuthority, authInput.requiredAuthority) || session.authorizationPolicyVersion !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import session is unavailable");
			try {
				await insertPendingReceipt(tx, command.operationId, kind, canonicalCommandHash, principalScope(principal));
			} catch (error) {
				if (isUniqueViolation(error)) return { kind: "conflict" };
				throw error;
			}
			return {
				kind: "new",
				session
			};
		},
		async get(tx, sessionId, _principal) {
			assertActiveContentTransaction(tx);
			const row = await readJournalRow(tx, sessionId);
			if (!row) fail$1("authorization", "import session is unavailable");
			return sessionFromRow(row);
		},
		async recordBatch(sessionId, batch, beforeImage, tx) {
			assertActiveContentTransaction(tx);
			if (!Number.isSafeInteger(batch) || batch < 0) fail$1("validation", "batch must be non-negative", "batch");
			const row = await readJournalRow(tx, sessionId);
			if (!row) fail$1("authorization", "import session is unavailable");
			const payload = rowJson(row.payload), batches = Array.isArray(payload.batches) ? payload.batches : [];
			if (batches.some((item) => item.batch === batch)) fail$1("integrity", "duplicate import batch");
			const next = schemaValue({
				...payload,
				batches: [...batches, {
					batch,
					beforeImage
				}]
			});
			await tx.execute(sql`UPDATE content_import_journal SET payload=${JSON.stringify(next)},updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE import_id=${sessionId}`);
		},
		async readBatchesReverse(tx, sessionId, expectedPlanHash, expectedManifestHash) {
			assertActiveContentTransaction(tx);
			const row = await readJournalRow(tx, sessionId);
			if (!row || row.planHash !== expectedPlanHash || row.manifestHash !== expectedManifestHash) fail$1("authorization", "import session is unavailable");
			const payload = rowJson(row.payload);
			const sorted = [...Array.isArray(payload.batches) ? payload.batches : []].sort((a, b) => b.batch - a.batch);
			for (let i = 0; i < sorted.length; i++) if (sorted[i].batch !== sorted.length - 1 - i) fail$1("integrity", "import batch ledger is not contiguous");
			return Object.freeze(sorted.map((item) => Object.freeze(item)));
		},
		async transition(sessionId, from, to, tx) {
			assertActiveContentTransaction(tx);
			if ((await execRows(tx, sql`UPDATE content_import_journal SET state=${to},updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE import_id=${sessionId} AND state=${from} RETURNING import_id AS "importId"`)).length !== 1) fail$1("stale-journal", "import state changed");
		},
		async completeCommand(tx, sessionId, kind, command, canonicalCommandHash, result) {
			assertActiveContentTransaction(tx);
			const row = await readJournalRow(tx, sessionId);
			if (!row) fail$1("authorization", "import session is unavailable");
			const next = schemaValue({
				...rowJson(row.payload),
				session: result
			}), highWaterMark = result.publishedCorpusVersion ?? row.highWaterMark;
			if ((await execRows(tx, sql`UPDATE content_import_journal SET state=${result.state},next_section=${result.nextSection},next_offset=${result.nextOffset},high_water_mark=${highWaterMark},payload=${JSON.stringify(next)},updated_at=${(/* @__PURE__ */ new Date()).toISOString()} WHERE import_id=${sessionId} AND version=${Number(result.journalVersion)} RETURNING import_id AS "importId"`)).length !== 1) fail$1("stale-journal", "journal claim was lost");
			const pending = (await execRows(tx, sql`SELECT payload FROM content_lifecycle_journal WHERE operation_id=${command.operationId} AND state='pending'`))[0];
			if (!pending) fail$1("integrity", "command claim disappeared");
			const receipt = rowJson(pending.payload);
			if (receipt.commandHash !== canonicalCommandHash) fail$1("integrity", "command claim hash changed");
			await commitReceipt(tx, command.operationId, kind, canonicalCommandHash, boundedString(receipt.principalScope, "receipt.principalScope", 1024), result);
		}
	});
}
function bundleLimits(bundle) {
	const bytes = new TextEncoder().encode(JSON.stringify(bundle)).byteLength;
	return Object.freeze({
		maxBytes: Math.max(bytes, 1),
		maxDefinitions: Math.max(bundle.types.length + bundle.statuses.length + bundle.taxonomies.length, 1),
		maxEntries: Math.max(bundle.entries.length, bundle.terms.length, 1),
		maxRevisions: Math.max(bundle.revisions.length, 1),
		batchSize: 100
	});
}
function mappingFor(parsed) {
	const out = {};
	for (const item of parsed.types) out[`type:${item.key}`] = item.key;
	for (const item of parsed.statuses) out[`status:${item.key}`] = item.key;
	for (const item of parsed.taxonomies) out[`taxonomy:${item.key}`] = item.key;
	for (const item of parsed.terms) out[`term:${item.id}`] = item.id;
	for (const item of parsed.entries) out[`entry:${item.id}`] = item.id;
	for (const item of parsed.revisions) out[`revision:${item.id}`] = item.id;
	return out;
}
function definitionRevisionMappingKey(kind, keyValue, sourceRevision) {
	return `${kind}:${keyValue}@${sourceRevision}`;
}
function mappedDefinitionRevision(mappings, kind, keyValue, sourceRevision) {
	const raw = mappings[definitionRevisionMappingKey(kind, keyValue, sourceRevision)], revision = Number(raw);
	if (!Number.isSafeInteger(revision) || revision < 1) fail$1("stale-plan", `missing ${kind} definition revision mapping for ${keyValue}@${sourceRevision}`);
	return revision;
}
function conservativeAuthority(scope) {
	return Object.freeze(scope.typeKeys.map((typeKey) => Object.freeze({
		typeKey,
		branches: ALL_BRANCHES
	})));
}
function conflict(code, message, fieldPath) {
	return Object.freeze({
		code,
		category: "conflict",
		message,
		...fieldPath ? { fieldPath } : {}
	});
}
function addBranch(branches, typeKey, ...items) {
	const set = branches.get(typeKey);
	if (!set) fail$1("authorization", "import scope is unavailable");
	for (const item of items) set.add(item);
}
async function assertImportAuthorized(tx, authorization, principal, action, input) {
	try {
		const result = await authorization.assert(tx, principal, action, input);
		if (!result || typeof result.policyVersion !== "string" || !result.policyVersion) fail$1("authorization", "import scope is unavailable");
		return result.policyVersion;
	} catch (error) {
		if (error instanceof ContentImportError) throw error;
		return fail$1("authorization", "import scope is unavailable");
	}
}
function sqlList$1(values) {
	return sql.join(values.map((value) => sql`${value}`), sql`, `);
}
function corpusJson(value, field) {
	if (typeof value !== "string") return schemaValue(value, field);
	try {
		return schemaValue(JSON.parse(value), field);
	} catch {
		return fail$1("integrity", `${field} contains invalid JSON`);
	}
}
function corpusDate(value, field) {
	const date = value instanceof Date ? value : new Date(String(value));
	if (Number.isNaN(date.getTime())) return fail$1("integrity", `${field} contains an invalid timestamp`);
	return date.toISOString();
}
function corpusNullableDate(value, field) {
	return value === null || value === void 0 ? null : corpusDate(value, field);
}
function corpusNullableString(value) {
	return value === null || value === void 0 ? null : String(value);
}
function corpusInteger(value, field) {
	const number = Number(value);
	if (!Number.isSafeInteger(number)) return fail$1("integrity", `${field} contains an invalid integer`);
	return number;
}
function canonicalDefinitionRow(row) {
	return schemaValue({
		key: String(row.key),
		origin: String(row.origin),
		version: corpusInteger(row.version, "definition.version"),
		active: boolValue(row.active),
		currentRevision: corpusInteger(row.currentRevision, "definition.currentRevision"),
		canonicalHash: String(row.canonicalHash),
		definition: corpusJson(row.definition, "definition.definition"),
		shadowedDbVersion: row.shadowedDbVersion === null || row.shadowedDbVersion === void 0 ? null : corpusInteger(row.shadowedDbVersion, "definition.shadowedDbVersion")
	});
}
function canonicalDefinitionVersionRow(row) {
	return schemaValue({
		kind: String(row.kind),
		key: String(row.key),
		revision: corpusInteger(row.revision, "definitionVersion.revision"),
		canonicalHash: String(row.canonicalHash),
		definition: corpusJson(row.definition, "definitionVersion.definition"),
		origin: String(row.origin),
		createdAt: corpusDate(row.createdAt, "definitionVersion.createdAt")
	});
}
function canonicalEntryRow(row) {
	return schemaValue({
		id: String(row.id),
		slug: String(row.slug),
		type: String(row.type),
		title: String(row.title),
		body: String(row.body),
		status: String(row.status),
		visibility: String(row.visibility),
		publishedAt: corpusNullableDate(row.publishedAt, "entry.publishedAt"),
		author: String(row.author),
		createdAt: corpusDate(row.createdAt, "entry.createdAt"),
		updatedAt: corpusDate(row.updatedAt, "entry.updatedAt"),
		parentId: corpusNullableString(row.parentId),
		menuOrder: corpusInteger(row.menuOrder, "entry.menuOrder"),
		templateKey: corpusNullableString(row.templateKey),
		excerpt: String(row.excerpt),
		featuredMedia: row.featuredMedia === null || row.featuredMedia === void 0 ? null : corpusJson(row.featuredMedia, "entry.featuredMedia"),
		commentStatus: String(row.commentStatus),
		pingStatus: String(row.pingStatus),
		sticky: boolValue(row.sticky),
		format: corpusNullableString(row.format),
		deletedAt: corpusNullableDate(row.deletedAt, "entry.deletedAt"),
		lastEditedBy: String(row.lastEditedBy),
		typeDefinitionRevision: corpusInteger(row.typeDefinitionRevision, "entry.typeDefinitionRevision"),
		statusDefinitionRevision: corpusInteger(row.statusDefinitionRevision, "entry.statusDefinitionRevision"),
		hostSessionId: corpusNullableString(row.hostSessionId)
	});
}
function canonicalAssignmentRow(row) {
	return schemaValue({
		entryId: String(row.entryId),
		termId: String(row.termId)
	});
}
function canonicalTermRow(row) {
	return schemaValue({
		id: String(row.id),
		taxonomy: String(row.taxonomy),
		slug: String(row.slug),
		name: String(row.name),
		parentId: corpusNullableString(row.parentId),
		depth: corpusInteger(row.depth, "term.depth"),
		createdAt: corpusDate(row.createdAt, "term.createdAt"),
		hostSessionId: corpusNullableString(row.hostSessionId)
	});
}
function canonicalRevisionRow(row) {
	return schemaValue({
		id: String(row.id),
		entryId: String(row.entryId),
		title: String(row.title),
		body: String(row.body),
		slug: String(row.slug),
		type: String(row.type),
		termIds: corpusJson(row.termIds, "revision.termIds"),
		snapshot: row.snapshot === null || row.snapshot === void 0 ? null : corpusJson(row.snapshot, "revision.snapshot"),
		editor: String(row.editor),
		createdAt: corpusDate(row.createdAt, "revision.createdAt"),
		hostSessionId: corpusNullableString(row.hostSessionId)
	});
}
async function readDestinationCorpus(tx, scope, extraTaxonomyKeys = []) {
	const mappedTypeKeys = scope.typeKeys;
	const typeRows = [...await execRowsByD1BindChunks(tx, mappedTypeKeys, (chunk) => sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM content_type_definitions WHERE key IN (${sqlList$1(chunk)}) ORDER BY key`)].sort((a, b) => String(a.key).localeCompare(String(b.key)));
	const types = Object.freeze(typeRows.map(canonicalDefinitionRow));
	const statusRows = await execRows(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM content_status_definitions ORDER BY key`);
	const statuses = Object.freeze(statusRows.map(canonicalDefinitionRow));
	const statusKeys = statusRows.map((row) => String(row.key));
	const taxonomyKeys = [.../* @__PURE__ */ new Set([...extraTaxonomyKeys, ...typeRows.flatMap((row) => {
		try {
			return normalizeContentTypeDefinition(typeof row.definition === "string" ? JSON.parse(row.definition) : row.definition).taxonomies;
		} catch {
			return [];
		}
	})])].sort();
	const definitionKeys = [...mappedTypeKeys.map((key) => `type:${key}`), ...statusKeys.map((key) => `status:${key}`)];
	const versionRows = definitionKeys.length ? [...await execRowsByD1BindChunks(tx, definitionKeys, (chunk) => sql`SELECT definition_kind AS kind,definition_key AS key,revision,canonical_hash AS "canonicalHash",definition,origin,created_at AS "createdAt" FROM content_definition_versions WHERE (definition_kind||':'||definition_key) IN (${sqlList$1(chunk)}) ORDER BY definition_kind,definition_key,revision`)].sort((a, b) => `${a.kind}:${a.key}:${String(a.revision).padStart(20, "0")}`.localeCompare(`${b.kind}:${b.key}:${String(b.revision).padStart(20, "0")}`)) : [];
	const versions = Object.freeze(versionRows.map(canonicalDefinitionVersionRow));
	const entryRows = [...await execRowsByD1BindChunks(tx, mappedTypeKeys, (chunk) => sql`SELECT id,slug,type,title,body,status,visibility,published_at AS "publishedAt",author,created_at AS "createdAt",updated_at AS "updatedAt",parent_id AS "parentId",menu_order AS "menuOrder",template_key AS "templateKey",excerpt,featured_media AS "featuredMedia",comment_status AS "commentStatus",ping_status AS "pingStatus",sticky,format,deleted_at AS "deletedAt",last_edited_by AS "lastEditedBy",type_definition_revision AS "typeDefinitionRevision",status_definition_revision AS "statusDefinitionRevision",host_session_id AS "hostSessionId" FROM content_entries WHERE type IN (${sqlList$1(chunk)}) ORDER BY id`)].sort((a, b) => String(a.id).localeCompare(String(b.id)));
	const entries = Object.freeze(entryRows.map(canonicalEntryRow));
	const entryIds = entryRows.map((row) => String(row.id));
	const assignmentRows = entryIds.length ? [...await execRowsByD1BindChunks(tx, entryIds, (chunk) => sql`SELECT entry_id AS "entryId",term_id AS "termId" FROM content_entry_terms WHERE entry_id IN (${sqlList$1(chunk)}) ORDER BY entry_id,term_id`)].sort((a, b) => `${a.entryId}:${a.termId}`.localeCompare(`${b.entryId}:${b.termId}`)) : [];
	const assignments = Object.freeze(assignmentRows.map(canonicalAssignmentRow));
	const termRows = taxonomyKeys.length ? [...await execRowsByD1BindChunks(tx, taxonomyKeys, (chunk) => sql`SELECT id,taxonomy,slug,name,parent_id AS "parentId",depth,created_at AS "createdAt",host_session_id AS "hostSessionId" FROM content_terms WHERE taxonomy IN (${sqlList$1(chunk)}) ORDER BY taxonomy,depth,id`)].sort((a, b) => String(a.taxonomy).localeCompare(String(b.taxonomy)) || Number(a.depth) - Number(b.depth) || String(a.id).localeCompare(String(b.id))) : [];
	const terms = Object.freeze(termRows.map(canonicalTermRow));
	const revisionRows = entryIds.length ? [...await execRowsByD1BindChunks(tx, entryIds, (chunk) => sql`SELECT id,entry_id AS "entryId",title,body,slug,type,term_ids AS "termIds",snapshot,editor,created_at AS "createdAt",host_session_id AS "hostSessionId" FROM content_revisions WHERE entry_id IN (${sqlList$1(chunk)}) ORDER BY entry_id,id`)].sort((a, b) => String(a.entryId).localeCompare(String(b.entryId)) || String(a.id).localeCompare(String(b.id))) : [];
	const revisions = Object.freeze(revisionRows.map(canonicalRevisionRow));
	return Object.freeze({
		scope,
		mappedTypeKeys: Object.freeze([...mappedTypeKeys]),
		statusKeys: Object.freeze(statusKeys),
		taxonomyKeys: Object.freeze(taxonomyKeys),
		types,
		statuses,
		versions,
		entries,
		assignments,
		terms,
		revisions
	});
}
async function hashDestinationCorpus(snapshot) {
	return canonicalContentMigrationHash(snapshot);
}
async function destinationCorpusVersion(tx, scope) {
	return hashDestinationCorpus(await readDestinationCorpus(tx, scope));
}
function mappedTypeDefinition(item, mappings) {
	const keyValue = mappings[`type:${item.key}`] ?? item.key, statusKeys = item.definition.statusKeys?.map((key) => mappings[`status:${key}`] ?? key), taxonomies = item.definition.taxonomies.map((key) => mappings[`taxonomy:${key}`] ?? key);
	return normalizeContentTypeDefinition({
		...item.definition,
		key: keyValue,
		statusKeys,
		taxonomies
	});
}
function mappedStatusDefinition(item, mappings) {
	return normalizeContentStatusDefinition({
		...item.definition,
		key: mappings[`status:${item.key}`] ?? item.key
	});
}
function authorityForImportedEntry(entry, status, principal, mode) {
	const branches = [];
	if (mode === "create") {
		branches.push("create", entry.author === principal.id ? "deleteOwn" : "deleteOthers");
		if (entry.visibility === "private") branches.push("deletePrivate");
		if (status.definition.published) branches.push("deletePublished");
	} else {
		branches.push(entry.author === principal.id ? "editOwn" : "editOthers");
		if (entry.visibility === "private") branches.push("editPrivate");
		if (status.definition.published) branches.push("editPublished");
	}
	if (status.definition.published) branches.push("publish");
	if (entry.termIds.length) branches.push("manageTerms");
	return branches;
}
function authorityForExistingEntry(entry, statusPublished, principal) {
	const branches = [entry.author === principal.id ? "editOwn" : "editOthers"];
	if (entry.visibility === "private") branches.push("editPrivate");
	if (statusPublished) branches.push("editPublished");
	return branches;
}
async function deterministicUuid(namespace, source, manifestHash) {
	const chars = (await canonicalContentMigrationHash({
		namespace,
		source,
		manifestHash
	})).slice(0, 32).split("");
	chars[12] = "5";
	chars[16] = (Number.parseInt(chars[16], 16) & 3 | 8).toString(16);
	const value = chars.join("");
	return `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`;
}
function planMaterial(plan) {
	return schemaValue(plan);
}
async function assertPlanHash(plan) {
	const { planHash, ...rest } = plan;
	if (await canonicalContentMigrationHash(planMaterial(rest)) !== planHash) fail$1("integrity", "import plan hash is invalid");
}
async function planContentImport(tx, authorization, principal, bundle, input) {
	const scope = stableScope(input.scope);
	if (input.conflictPolicy !== "reject" && input.conflictPolicy !== "preserve" && input.conflictPolicy !== "mappedReplacement") fail$1("validation", "invalid conflict policy", "conflictPolicy");
	const firstPolicy = await assertImportAuthorized(tx, authorization, principal, "plan", {
		scope,
		requiredAuthority: conservativeAuthority(scope)
	});
	const bytes = new TextEncoder().encode(JSON.stringify(bundle));
	const parsed = await parseBundle(bytes, bundleLimits(bundle));
	if (parsed.types.some((item) => !scope.typeKeys.includes(item.key)) || parsed.entries.some((item) => !scope.typeKeys.includes(item.type))) fail$1("authorization", "import scope is unavailable");
	const mappings = mappingFor(parsed);
	const conflicts = [];
	const branches = new Map(scope.typeKeys.map((typeKey) => [typeKey, /* @__PURE__ */ new Set()]));
	const typeKeys = parsed.types.map((item) => item.key), statusKeys = parsed.statuses.map((item) => item.key), taxonomyKeys = parsed.taxonomies.map((item) => item.key);
	const currentTypes = typeKeys.length ? await execRows(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition FROM content_type_definitions WHERE key IN (${sqlList$1(typeKeys)})`) : [];
	const currentStatuses = statusKeys.length ? await execRows(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition FROM content_status_definitions WHERE key IN (${sqlList$1(statusKeys)})`) : [];
	const definitionKeys = [...typeKeys.map((key) => `type:${key}`), ...statusKeys.map((key) => `status:${key}`)];
	const currentVersions = definitionKeys.length ? await execRows(tx, sql`SELECT definition_kind AS kind,definition_key AS key,revision,canonical_hash AS "canonicalHash" FROM content_definition_versions WHERE (definition_kind||':'||definition_key) IN (${sqlList$1(definitionKeys)})`) : [];
	const currentTypeByKey = new Map(currentTypes.map((row) => [row.key, row])), currentStatusByKey = new Map(currentStatuses.map((row) => [row.key, row]));
	for (const item of parsed.types) {
		const current = currentTypeByKey.get(item.key), destVersions = currentVersions.filter((row) => row.kind === "type" && row.key === item.key), maxRevision = Math.max(0, ...destVersions.map((row) => Number(row.revision)));
		let allocated = 0;
		addBranch(branches, item.key, "manageType");
		for (const version of item.versions) {
			const match = destVersions.find((row) => row.canonicalHash === version.canonicalHash);
			mappings[definitionRevisionMappingKey("type", item.key, version.revision)] = String(match ? Number(match.revision) : maxRevision + ++allocated);
		}
		if (current) {
			const differs = current.canonicalHash !== item.canonicalHash || boolValue(current.active) !== item.active;
			if (input.conflictPolicy === "reject") conflicts.push(conflict("type-conflict", `type ${item.key} already exists`, `type:${item.key}`));
			else if (input.conflictPolicy === "preserve" && differs) conflicts.push(conflict("type-definition-mismatch", `type ${item.key} differs from preserved destination`, `type:${item.key}`));
			else if (input.conflictPolicy === "mappedReplacement" && current.origin === "code" && differs && parsed.entries.some((entry) => entry.type === item.key)) conflicts.push(conflict("code-type-owned", `type ${item.key} is code-owned and cannot be replaced for imported entries`, `type:${item.key}`));
			else if (input.conflictPolicy === "mappedReplacement" && current.origin !== "code" && differs) addBranch(branches, item.key, "migrateAll");
		}
	}
	for (const item of parsed.statuses) {
		for (const typeKey of scope.typeKeys) addBranch(branches, typeKey, "manageType");
		const current = currentStatusByKey.get(item.key), destVersions = currentVersions.filter((row) => row.kind === "status" && row.key === item.key), maxRevision = Math.max(0, ...destVersions.map((row) => Number(row.revision)));
		let allocated = 0;
		for (const version of item.versions) {
			const match = destVersions.find((row) => row.canonicalHash === version.canonicalHash);
			mappings[definitionRevisionMappingKey("status", item.key, version.revision)] = String(match ? Number(match.revision) : maxRevision + ++allocated);
		}
		if (current) {
			const differs = current.canonicalHash !== item.canonicalHash || boolValue(current.active) !== item.active;
			if (input.conflictPolicy === "reject") conflicts.push(conflict("status-conflict", `status ${item.key} already exists`, `status:${item.key}`));
			else if (input.conflictPolicy === "preserve" && differs) conflicts.push(conflict("status-definition-mismatch", `status ${item.key} differs from preserved destination`, `status:${item.key}`));
			else if (input.conflictPolicy === "mappedReplacement" && current.origin === "code" && differs && parsed.entries.some((entry) => entry.status === item.key)) conflicts.push(conflict("code-status-owned", `status ${item.key} is code-owned and cannot be replaced for imported entries`, `status:${item.key}`));
			else if (input.conflictPolicy === "mappedReplacement" && current.origin !== "code" && differs) for (const typeKey of scope.typeKeys) addBranch(branches, typeKey, "migrateAll");
		}
	}
	const existingTerms = taxonomyKeys.length ? await execRows(tx, sql`SELECT id,taxonomy,slug,parent_id AS "parentId",depth FROM content_terms WHERE taxonomy IN (${sqlList$1(taxonomyKeys)}) ORDER BY depth,id`) : [];
	const termById = new Map(existingTerms.map((row) => [row.id, row]));
	const termByPath = new Map(existingTerms.map((row) => [`${row.taxonomy}:${row.parentId ?? ""}:${row.slug}`, row]));
	for (const item of [...parsed.terms].sort((a, b) => a.depth - b.depth || a.id.localeCompare(b.id))) {
		const mappedTax = mappings[`taxonomy:${item.taxonomy}`] ?? item.taxonomy;
		const mappedParent = item.parentId === null ? null : mappings[`term:${item.parentId}`] ?? item.parentId;
		const byId = termById.get(item.id), byPath = termByPath.get(`${mappedTax}:${mappedParent ?? ""}:${item.slug}`), existing = byId ?? byPath;
		if (byId && byPath && byId.id !== byPath.id) {
			conflicts.push(conflict("term-conflict-ambiguous", `term ${item.id} collides by both id and sibling slug`, `term:${item.id}`));
			continue;
		}
		if (existing) {
			if (input.conflictPolicy === "reject") conflicts.push(conflict("term-conflict", `term ${item.id} conflicts with destination term ${existing.id}`, `term:${item.id}`));
			else mappings[`term:${item.id}`] = existing.id;
		}
	}
	if (parsed.terms.length) {
		for (const type of parsed.types) if (type.definition.taxonomies.some((taxonomy) => taxonomyKeys.includes(taxonomy))) addBranch(branches, type.key, "manageTerms");
	}
	const existingEntries = typeKeys.length ? await execRows(tx, sql`SELECT id,type,slug,author,status,visibility FROM content_entries WHERE type IN (${sqlList$1(typeKeys)})`) : [];
	const entryById = new Map(existingEntries.map((row) => [row.id, row])), entryByPath = new Map(existingEntries.map((row) => [`${row.type}:${row.slug}`, row]));
	const statusPublished = /* @__PURE__ */ new Map();
	for (const row of currentStatuses) try {
		statusPublished.set(row.key, normalizeContentStatusDefinition(typeof row.definition === "string" ? JSON.parse(row.definition) : row.definition).published);
	} catch {
		fail$1("integrity", "destination status definition is malformed");
	}
	const entryConflictSources = /* @__PURE__ */ new Set();
	for (const item of parsed.entries) {
		const mappedType = mappings[`type:${item.type}`] ?? item.type, byId = entryById.get(item.id), byPath = entryByPath.get(`${mappedType}:${item.slug}`), existing = byId ?? byPath;
		if (byId && byPath && byId.id !== byPath.id) {
			conflicts.push(conflict("entry-conflict-ambiguous", `entry ${item.id} collides by both id and type/slug`, `entry:${item.id}`));
			continue;
		}
		const importedStatus = parsed.statuses.find((status) => status.key === item.status);
		if (existing) {
			entryConflictSources.add(item.id);
			if (input.conflictPolicy === "reject") conflicts.push(conflict("entry-conflict", `entry ${item.id} conflicts with destination entry ${existing.id}`, `entry:${item.id}`));
			else mappings[`entry:${item.id}`] = existing.id;
			if (input.conflictPolicy === "mappedReplacement") addBranch(branches, item.type, ...authorityForExistingEntry(existing, statusPublished.get(existing.status) === true, principal), ...authorityForImportedEntry(item, importedStatus, principal, "replace"));
		} else addBranch(branches, item.type, ...authorityForImportedEntry(item, importedStatus, principal, "create"));
	}
	const existingRevisions = parsed.revisions.length ? await execRowsByD1BindChunks(tx, parsed.revisions.map((item) => item.id), (chunk) => sql`SELECT id,entry_id AS "entryId" FROM content_revisions WHERE id IN (${sqlList$1(chunk)})`) : [];
	const revisionIds = new Set(existingRevisions.map((row) => row.id));
	for (const item of parsed.revisions) {
		if (revisionIds.has(item.id)) {
			if (input.conflictPolicy === "reject") conflicts.push(conflict("revision-conflict", `revision ${item.id} already exists`, `revision:${item.id}`));
			else if (input.conflictPolicy === "mappedReplacement") mappings[`revision:${item.id}`] = await deterministicUuid("revision", item.id, parsed.manifestHash);
		}
		if (input.conflictPolicy === "preserve" && entryConflictSources.has(item.entryId)) continue;
	}
	const frozenMappings = Object.freeze({ ...mappings });
	const destination = await destinationCorpusVersion(tx, scope);
	const requiredAuthority = stableAuthority([...branches].map(([typeKey, set]) => ({
		typeKey,
		branches: [...set]
	})));
	const policy = await assertImportAuthorized(tx, authorization, principal, "plan", {
		scope,
		requiredAuthority
	});
	if (policy !== firstPolicy) fail$1("authorization", "import scope is unavailable");
	const counts = Object.freeze({
		types: parsed.types.length,
		statuses: parsed.statuses.length,
		taxonomies: parsed.taxonomies.length,
		terms: parsed.terms.length,
		entries: parsed.entries.length,
		revisions: parsed.revisions.length
	});
	const rest = {
		manifestHash: parsed.manifestHash,
		destinationCorpusVersion: destination,
		authorizationPolicyVersion: policy,
		scope,
		conflictPolicy: input.conflictPolicy,
		requiredAuthority,
		counts,
		mappings: frozenMappings,
		conflicts: Object.freeze(conflicts),
		estimatedBytes: bytes.byteLength
	};
	return Object.freeze({
		planHash: await canonicalContentMigrationHash(planMaterial(rest)),
		...rest
	});
}
function authorizationInputFromPlan(plan) {
	return Object.freeze({
		scope: plan.scope,
		requiredAuthority: plan.requiredAuthority,
		expectedPolicyVersion: plan.authorizationPolicyVersion
	});
}
function authorizationInputFromCommand(command) {
	return Object.freeze({
		scope: stableScope(command.scope),
		requiredAuthority: stableAuthority(command.requiredAuthority),
		expectedPolicyVersion: command.expectedAuthorizationPolicyVersion
	});
}
async function canonicalCommandHash(kind, sessionId, principal, value) {
	return canonicalContentMigrationHash(schemaValue({
		kind,
		sessionId,
		principalScope: principalScope(principal),
		value
	}));
}
async function parsedBundleObject(bundle) {
	return parseBundle(new TextEncoder().encode(JSON.stringify(bundle)), bundleLimits(bundle));
}
async function revalidatePlan(tx, authorization, principal, bundle, expected) {
	await assertPlanHash(expected);
	const current = await planContentImport(tx, authorization, principal, bundle, {
		scope: expected.scope,
		conflictPolicy: expected.conflictPolicy
	});
	if (current.planHash !== expected.planHash || current.destinationCorpusVersion !== expected.destinationCorpusVersion || current.manifestHash !== expected.manifestHash) fail$1("stale-plan", "destination corpus or plan evidence changed");
}
async function startContentImport(tx, journal, authorization, principal, bundle, input) {
	assertActiveContentTransaction(tx);
	await assertPlanHash(input.plan);
	const operationId = boundedString(input.operationId, "operationId", 256), parsed = await parsedBundleObject(bundle);
	if (parsed.manifestHash !== input.plan.manifestHash) fail$1("stale-plan", "bundle manifest differs from plan");
	if (input.plan.conflicts.length > 0) fail$1("conflict", "import plan contains unresolved conflicts");
	const authInput = authorizationInputFromPlan(input.plan), policy = await assertImportAuthorized(tx, authorization, principal, "start", authInput);
	if (policy !== input.plan.authorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const currentCorpus = await destinationCorpusVersion(tx, input.plan.scope), startHash = await canonicalCommandHash("start", null, principal, {
		manifestHash: parsed.manifestHash,
		plan: input.plan,
		staging: input.staging,
		authorizationInput: authInput,
		currentPolicyVersion: policy,
		destinationCorpusVersion: currentCorpus
	});
	const claim = await journal.claimStart(tx, principal, authInput, authorization, operationId, startHash);
	if (claim.kind === "conflict") fail$1("conflict", "operation id was already used for another import start");
	if (claim.kind === "replay") return claim.session;
	if (currentCorpus !== input.plan.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after planning");
	await revalidatePlan(tx, authorization, principal, bundle, input.plan);
	return journal.create(input.plan, input.staging, principal, operationId, tx);
}
/** Prepare a content-import start for one host-owned atomic D1 batch. */
async function prepareStartContentImportD1(db, authorization, principal, bundle, input) {
	assertD1Scope(input.plan.scope);
	await assertPlanHash(input.plan);
	const operationId = boundedString(input.operationId, "operationId", 256);
	const parsed = await parsedBundleObject(bundle);
	if (parsed.manifestHash !== input.plan.manifestHash) fail$1("stale-plan", "bundle manifest differs from plan");
	if (input.plan.conflicts.length > 0) fail$1("conflict", "import plan contains unresolved conflicts");
	if (input.staging.visibility !== "hiddenUntilPublish") fail$1("validation", "unsupported staging visibility", "staging.visibility");
	const id = uuid(input.staging.hostSessionId, "staging.hostSessionId");
	const authInput = authorizationInputFromPlan(input.plan);
	const policy = await assertImportAuthorized(db, authorization, principal, "start", authInput);
	if (policy !== input.plan.authorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const destinationSnapshot = await readDestinationCorpus(db, input.plan.scope);
	const currentCorpus = await hashDestinationCorpus(destinationSnapshot);
	if (currentCorpus !== input.plan.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after planning");
	const startHash = await canonicalCommandHash("start", null, principal, {
		manifestHash: parsed.manifestHash,
		plan: input.plan,
		staging: input.staging,
		authorizationInput: authInput,
		currentPolicyVersion: policy,
		destinationCorpusVersion: currentCorpus
	});
	const receiptEvidence = await readReceiptEvidence(db, operationId), receipt = receiptEvidence?.receipt;
	if (receipt && receiptEvidence) {
		if (receipt.kind !== "start" || receipt.commandHash !== startHash || receipt.principalScope !== principalScope(principal) || receipt.session.id !== id) fail$1("conflict", "operation id was already used for another import start");
		const persisted = required(await readJournalRow(db, id), "integrity", "committed start receipt has no import journal");
		const session = sessionFromRow(persisted);
		if (JSON.stringify(session) !== JSON.stringify(receipt.session)) fail$1("integrity", "committed start receipt and import journal differ");
		const guard = prepareExactReplayGuard(db, operationId, "start", receiptEvidence, persisted, session);
		return Object.freeze({
			items: Object.freeze([guard]),
			result: session
		});
	}
	assertD1CorpusCountGuardBindBudget(destinationSnapshot);
	assertD1StatementBudget("start", exactCorpusGuardCount(destinationSnapshot) + 6);
	const session = Object.freeze({
		id,
		planHash: input.plan.planHash,
		manifestHash: input.plan.manifestHash,
		state: "validated",
		staging: Object.freeze({
			...input.staging,
			hostSessionId: id
		}),
		scope: input.plan.scope,
		conflictPolicy: input.plan.conflictPolicy,
		requiredAuthority: input.plan.requiredAuthority,
		authorizationPolicyVersion: input.plan.authorizationPolicyVersion,
		destinationCorpusVersion: input.plan.destinationCorpusVersion,
		mappings: input.plan.mappings,
		appliedBatches: 0,
		journalVersion: "0",
		nextSection: "type",
		nextOffset: 0
	});
	const now = (/* @__PURE__ */ new Date()).toISOString(), receiptId = crypto.randomUUID(), scope = principalScope(principal);
	const pendingPayload = JSON.stringify(schemaValue({
		kind: "start",
		commandHash: startHash,
		principalScope: scope
	}));
	const journalPayload = JSON.stringify(schemaValue({
		session,
		batches: [],
		plan: input.plan,
		staging: input.staging,
		authorizationInput: authInput,
		destinationCorpusVersion: currentCorpus,
		preflightDestinationCorpusSnapshot: destinationSnapshot
	}));
	const committedPayload = JSON.stringify(schemaValue({
		kind: "start",
		commandHash: startHash,
		principalScope: scope,
		session
	}));
	const claim = db.prepare(sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${receiptId},${operationId},'content:import:start','pending',${pendingPayload},${now},${now})`);
	const claimGuard = db.prepare(d1AssertPreviousChanges(1));
	const create = db.prepare(sql`INSERT INTO content_import_journal (import_id,host_session_id,manifest_hash,plan_hash,state,version,next_section,next_offset,payload,created_at,updated_at) VALUES (${id},${id},${input.plan.manifestHash},${input.plan.planHash},'validated',0,'type',0,${journalPayload},${now},${now})`);
	const createGuard = db.prepare(d1AssertPreviousChanges(1));
	const complete = db.prepare(sql`UPDATE content_lifecycle_journal SET state='committed',payload=${committedPayload},updated_at=${now} WHERE operation_id=${operationId} AND kind='content:import:start' AND state='pending' AND payload=${pendingPayload}`);
	const completeGuard = db.prepare(d1AssertPreviousChanges(1));
	return Object.freeze({
		items: Object.freeze([
			...d1ExactCorpusGuards(db, destinationSnapshot),
			claim,
			claimGuard,
			create,
			createGuard,
			complete,
			completeGuard
		]),
		result: session
	});
}
/** Prepare a read-only staged-state guard for one host-owned atomic D1 batch. */
async function prepareStagedContentImportGuardD1(db, authorization, principal, sessionIdInput, command) {
	assertD1Scope(command.scope);
	const sessionId = uuid(sessionIdInput, "sessionId");
	boundedString(command.operationId, "operationId", 256);
	boundedString(command.expectedPlanHash, "expectedPlanHash", 128);
	boundedString(command.expectedManifestHash, "expectedManifestHash", 128);
	const expectedVersion = Number(command.expectedJournalVersion);
	if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0) fail$1("validation", "expectedJournalVersion is invalid", "expectedJournalVersion");
	if (command.expectedSection !== null) fail$1("stale-journal", "staged import must have a terminal section coordinate");
	if (!Number.isSafeInteger(command.expectedOffset) || command.expectedOffset !== 0) fail$1("stale-journal", "staged import must have a terminal offset coordinate");
	const authInput = authorizationInputFromCommand(command);
	const policy = await assertImportAuthorized(db, authorization, principal, "resume", authInput);
	if (policy !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const row = required(await readJournalRow(db, sessionId), "authorization", "import session is unavailable");
	const payload = rowJson(row.payload), session = sessionFromRow(row), storedSession = payload.session, storedPlan = payload.plan;
	if (!sameScope(session.scope, authInput.scope) || !sameAuthority(session.requiredAuthority, authInput.requiredAuthority) || session.authorizationPolicyVersion !== policy) fail$1("authorization", "import session is unavailable");
	if (session.planHash !== command.expectedPlanHash || session.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "command plan evidence differs from session");
	if (session.journalVersion !== command.expectedJournalVersion || session.nextSection !== null || session.nextOffset !== 0) fail$1("stale-journal", "journal coordinate changed");
	if (session.state !== "staged") fail$1("stale-journal", "import is not staged");
	if (session.staging.visibility !== "hiddenUntilPublish" || session.staging.hostSessionId !== String(row.hostSessionId)) fail$1("integrity", "staging identity differs from journal");
	if (!storedPlan || typeof storedPlan !== "object") fail$1("integrity", "import journal has no retained plan evidence");
	const retainedPlan = storedPlan;
	await assertPlanHash(retainedPlan);
	if (retainedPlan.planHash !== session.planHash || retainedPlan.manifestHash !== session.manifestHash || !sameScope(retainedPlan.scope, session.scope) || !sameAuthority(retainedPlan.requiredAuthority, session.requiredAuthority) || retainedPlan.authorizationPolicyVersion !== session.authorizationPolicyVersion || retainedPlan.destinationCorpusVersion !== session.destinationCorpusVersion) fail$1("integrity", "retained plan evidence differs from session");
	if (JSON.stringify(schemaValue(storedSession, "journal.session")) !== JSON.stringify(schemaValue(session, "session"))) fail$1("integrity", "retained session evidence differs from journal");
	const batches = Array.isArray(payload.batches) ? payload.batches : [];
	if (batches.length !== session.appliedBatches || batches.some((item, index) => item.batch !== index)) fail$1("integrity", "import batch ledger is not contiguous");
	for (const item of batches) stagedBatchFromValue(item.beforeImage);
	const exactPayload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload);
	const guard = db.prepare(sql`SELECT CASE WHEN EXISTS (SELECT 1 FROM content_import_journal WHERE import_id=${sessionId} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash} AND state='staged' AND version=${expectedVersion} AND next_section IS NULL AND next_offset=0 AND payload=${exactPayload}) THEN 1 ELSE json_extract('not-json','$') END AS ok`);
	return Object.freeze({
		items: Object.freeze([guard]),
		result: session
	});
}
function sectionItems(parsed, section) {
	switch (section) {
		case "type": return parsed.types;
		case "status": return parsed.statuses;
		case "taxonomy": return parsed.taxonomies;
		case "term": return [...parsed.terms].sort((a, b) => a.depth - b.depth || a.id.localeCompare(b.id));
		case "entry": return sortEntriesParentFirst(parsed.entries);
		case "revision": return [...parsed.revisions].sort((a, b) => a.entryId.localeCompare(b.entryId) || a.seq - b.seq || a.id.localeCompare(b.id));
	}
}
function sortEntriesParentFirst(entries) {
	const byId = new Map(entries.map((item) => [item.id, item])), depthCache = /* @__PURE__ */ new Map();
	const depth = (item) => {
		const cached = depthCache.get(item.id);
		if (cached !== void 0) return cached;
		const result = item.parentId === null ? 0 : depth(byId.get(item.parentId)) + 1;
		depthCache.set(item.id, result);
		return result;
	};
	return Object.freeze([...entries].sort((a, b) => depth(a) - depth(b) || a.id.localeCompare(b.id)));
}
function nextCoordinate(parsed, current, offset, batchSize) {
	const order = [
		"type",
		"status",
		"taxonomy",
		"term",
		"entry",
		"revision"
	];
	if (offset < sectionItems(parsed, current).length) return {
		section: current,
		offset
	};
	let index = order.indexOf(current) + 1;
	while (index < order.length) {
		const section = order[index];
		if (sectionItems(parsed, section).length > 0) return {
			section,
			offset: 0
		};
		index++;
	}
	return {
		section: null,
		offset: 0
	};
}
async function currentDefinitionSnapshot(tx, kind, keyValue) {
	const currentRows = kind === "type" ? await execRows(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion",host_session_id AS "hostSessionId",created_at AS "createdAt",updated_at AS "updatedAt" FROM content_type_definitions WHERE key=${keyValue}`) : await execRows(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion",host_session_id AS "hostSessionId",created_at AS "createdAt",updated_at AS "updatedAt" FROM content_status_definitions WHERE key=${keyValue}`);
	const versions = await execRows(tx, sql`SELECT definition_kind AS kind,definition_key AS key,revision,canonical_hash AS "canonicalHash",definition,origin,host_session_id AS "hostSessionId",created_at AS "createdAt" FROM content_definition_versions WHERE definition_kind=${kind} AND definition_key=${keyValue} ORDER BY revision`);
	return {
		current: currentRows[0] ? schemaValue(currentRows[0]) : null,
		versions: Object.freeze(versions.map((row) => schemaValue(row)))
	};
}
async function mappedTypeItem(item, mappings) {
	const definition = mappedTypeDefinition(item, mappings), canonicalHash = await canonicalContentMigrationHash(definition), versions = [];
	for (const version of item.versions) {
		const mapped = normalizeContentTypeDefinition({
			...version.definition,
			key: mappings[`type:${item.key}`] ?? item.key,
			statusKeys: version.definition.statusKeys?.map((key) => mappings[`status:${key}`] ?? key),
			taxonomies: version.definition.taxonomies.map((key) => mappings[`taxonomy:${key}`] ?? key)
		}), revision = mappedDefinitionRevision(mappings, "type", item.key, version.revision);
		versions.push(schemaValue({
			revision,
			canonicalHash: await canonicalContentMigrationHash(mapped),
			definition: mapped,
			origin: "import",
			createdAt: version.createdAt
		}));
	}
	return schemaValue({
		key: mappings[`type:${item.key}`] ?? item.key,
		origin: "import",
		version: item.version,
		revision: mappedDefinitionRevision(mappings, "type", item.key, item.revision),
		active: item.active,
		canonicalHash,
		definition,
		versions
	});
}
async function mappedStatusItem(item, mappings) {
	const definition = mappedStatusDefinition(item, mappings), canonicalHash = await canonicalContentMigrationHash(definition), versions = [];
	for (const version of item.versions) {
		const mapped = normalizeContentStatusDefinition({
			...version.definition,
			key: mappings[`status:${item.key}`] ?? item.key
		}), revision = mappedDefinitionRevision(mappings, "status", item.key, version.revision);
		versions.push(schemaValue({
			revision,
			canonicalHash: await canonicalContentMigrationHash(mapped),
			definition: mapped,
			origin: "import",
			createdAt: version.createdAt
		}));
	}
	return schemaValue({
		key: mappings[`status:${item.key}`] ?? item.key,
		origin: "import",
		version: item.version,
		revision: mappedDefinitionRevision(mappings, "status", item.key, item.revision),
		active: item.active,
		canonicalHash,
		definition,
		versions
	});
}
async function stageMutation(tx, session, section, raw) {
	if (section === "type") {
		const item = raw, destKey = session.mappings[`type:${item.key}`] ?? item.key, before = await currentDefinitionSnapshot(tx, "type", destKey), current = before.current === null ? null : plain(before.current, "type.before.current"), mapped = plain(await mappedTypeItem(item, session.mappings), "type.after"), same = current !== null && String(current.canonicalHash) === String(mapped.canonicalHash) && boolValue(current.active) === boolValue(mapped.active), action = current === null ? "create" : session.conflictPolicy === "preserve" || same ? "preserve" : current.origin === "code" ? "shadow" : "replace", destinationVersion = current === null ? 1 : action === "preserve" ? Number(current.version) : Number(current.version) + 1;
		return schemaValue({
			kind: "type",
			action,
			destKey,
			after: {
				...mapped,
				version: destinationVersion
			},
			before
		});
	}
	if (section === "status") {
		const item = raw, destKey = session.mappings[`status:${item.key}`] ?? item.key, before = await currentDefinitionSnapshot(tx, "status", destKey), current = before.current === null ? null : plain(before.current, "status.before.current"), mapped = plain(await mappedStatusItem(item, session.mappings), "status.after"), same = current !== null && String(current.canonicalHash) === String(mapped.canonicalHash) && boolValue(current.active) === boolValue(mapped.active), action = current === null ? "create" : session.conflictPolicy === "preserve" || same ? "preserve" : current.origin === "code" ? "shadow" : "replace", destinationVersion = current === null ? 1 : action === "preserve" ? Number(current.version) : Number(current.version) + 1;
		return schemaValue({
			kind: "status",
			action,
			destKey,
			after: {
				...mapped,
				version: destinationVersion
			},
			before
		});
	}
	if (section === "taxonomy") {
		const item = raw;
		return schemaValue({
			kind: "taxonomy",
			action: "noop",
			source: item,
			destKey: session.mappings[`taxonomy:${item.key}`] ?? item.key
		});
	}
	if (section === "term") {
		const item = raw, destId = session.mappings[`term:${item.id}`] ?? item.id, destTaxonomy = session.mappings[`taxonomy:${item.taxonomy}`] ?? item.taxonomy, destParentId = item.parentId === null ? null : session.mappings[`term:${item.parentId}`] ?? item.parentId;
		const rows = await execRows(tx, sql`SELECT id,taxonomy,slug,name,parent_id AS "parentId",depth,created_at AS "createdAt",host_session_id AS "hostSessionId" FROM content_terms WHERE id=${destId}`), before = rows[0] ? schemaValue(rows[0]) : null;
		return schemaValue({
			kind: "term",
			action: before === null ? "create" : session.conflictPolicy === "preserve" ? "preserve" : "replace",
			destId,
			after: {
				id: destId,
				taxonomy: destTaxonomy,
				slug: item.slug,
				name: item.name,
				parentId: destParentId,
				depth: item.depth,
				createdAt: item.createdAt
			},
			before
		});
	}
	if (section === "entry") {
		const item = raw, destId = session.mappings[`entry:${item.id}`] ?? item.id, destType = session.mappings[`type:${item.type}`] ?? item.type, destStatus = session.mappings[`status:${item.status}`] ?? item.status, destParentId = item.parentId === null ? null : session.mappings[`entry:${item.parentId}`] ?? item.parentId, destTermIds = item.termIds.map((id) => session.mappings[`term:${id}`] ?? id);
		const rows = await execRows(tx, sql`SELECT id,slug,type,title,body,status,visibility,published_at AS "publishedAt",author,created_at AS "createdAt",updated_at AS "updatedAt",parent_id AS "parentId",menu_order AS "menuOrder",template_key AS "templateKey",excerpt,featured_media AS "featuredMedia",comment_status AS "commentStatus",ping_status AS "pingStatus",sticky,format,deleted_at AS "deletedAt",last_edited_by AS "lastEditedBy",type_definition_revision AS "typeDefinitionRevision",status_definition_revision AS "statusDefinitionRevision",host_session_id AS "hostSessionId" FROM content_entries WHERE id=${destId}`), before = rows[0] ? schemaValue(rows[0]) : null, beforeTerms = before === null ? [] : await execRows(tx, sql`SELECT term_id AS "termId" FROM content_entry_terms WHERE entry_id=${destId} ORDER BY term_id`);
		return schemaValue({
			kind: "entry",
			action: before === null ? "create" : session.conflictPolicy === "preserve" ? "preserve" : "replace",
			destId,
			after: {
				id: destId,
				slug: item.slug,
				type: destType,
				title: item.title,
				body: item.body,
				status: destStatus,
				visibility: item.visibility,
				publishedAt: item.publishedAt,
				author: item.author,
				createdAt: item.createdAt,
				updatedAt: item.updatedAt,
				parentId: destParentId,
				menuOrder: item.menuOrder,
				templateKey: item.templateKey,
				excerpt: item.excerpt,
				featuredMedia: item.featuredMedia,
				commentStatus: item.commentStatus,
				pingStatus: item.pingStatus,
				sticky: item.sticky,
				format: item.format,
				deletedAt: item.deletedAt,
				lastEditedBy: item.lastEditedBy,
				typeDefinitionRevision: mappedDefinitionRevision(session.mappings, "type", item.type, item.typeDefinitionRevision),
				statusDefinitionRevision: mappedDefinitionRevision(session.mappings, "status", item.status, item.statusDefinitionRevision),
				termIds: destTermIds
			},
			before,
			beforeTermIds: beforeTerms.map((row) => row.termId)
		});
	}
	const item = raw, destId = session.mappings[`revision:${item.id}`] ?? item.id, destEntryId = session.mappings[`entry:${item.entryId}`] ?? item.entryId, destTermIds = item.termIds.map((id) => session.mappings[`term:${id}`] ?? id);
	const entryExists = (await execRows(tx, sql`SELECT id FROM content_entries WHERE id=${destEntryId}`))[0] !== void 0;
	const rows = await execRows(tx, sql`SELECT id,entry_id AS "entryId",seq,title,body,slug,type,term_ids AS "termIds",snapshot,editor,created_at AS "createdAt",host_session_id AS "hostSessionId" FROM content_revisions WHERE id=${destId}`), before = rows[0] ? schemaValue(rows[0]) : null;
	return schemaValue({
		kind: "revision",
		action: session.conflictPolicy === "preserve" && entryExists ? "preserve" : before === null ? "create" : session.conflictPolicy === "preserve" ? "preserve" : "replace",
		destId,
		after: {
			id: destId,
			entryId: destEntryId,
			seq: item.seq,
			title: item.title,
			body: item.body,
			slug: item.slug,
			type: session.mappings[`type:${item.type}`] ?? item.type,
			termIds: destTermIds,
			...item.snapshot === void 0 ? {} : { snapshot: item.snapshot },
			editor: item.editor,
			createdAt: item.createdAt
		},
		before
	});
}
function stagedBatchFromValue(value) {
	const objectValue = plain(value, "stagedBatch"), rawSection = objectValue.section;
	if (rawSection !== "type" && rawSection !== "status" && rawSection !== "taxonomy" && rawSection !== "term" && rawSection !== "entry" && rawSection !== "revision") throw new ContentImportError("integrity", "staged batch section is invalid");
	const section = rawSection, offset = Number(objectValue.offset), rawMutations = objectValue.mutations;
	if (!Number.isSafeInteger(offset) || offset < 0) fail$1("integrity", "staged batch offset is invalid");
	if (!Array.isArray(rawMutations)) throw new ContentImportError("integrity", "staged batch mutations are invalid");
	return Object.freeze({
		section,
		offset,
		mutations: Object.freeze(rawMutations.map((item, index) => schemaValue(item, `stagedBatch.mutations.${index}`)))
	});
}
async function resumeContentImport(tx, journal, authorization, principal, bundle, sessionIdInput, command) {
	assertActiveContentTransaction(tx);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), parsed = await parsedBundleObject(bundle);
	if (parsed.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "bundle manifest differs from command");
	const commandHash = await canonicalCommandHash("resume", sessionId, principal, {
		command,
		bundleManifestHash: parsed.manifestHash
	}), claim = await journal.claimCommand(tx, sessionId, principal, "resume", command, commandHash, authorization);
	if (claim.kind === "conflict") throw new ContentImportError("conflict", "operation id was already used for another import command");
	if (claim.kind === "replay") return claim.session;
	const session = claim.session;
	if (!session) throw new ContentImportError("integrity", "resume claim did not return session");
	if (session.state !== "validated" && session.state !== "applying") fail$1("stale-journal", "import is not resumable");
	if (session.nextSection === null) throw new ContentImportError("stale-journal", "import is already staged");
	if (parsed.manifestHash !== session.manifestHash) fail$1("stale-plan", "bundle manifest differs from session");
	const currentPlan = await planContentImport(tx, authorization, principal, bundle, {
		scope: session.scope,
		conflictPolicy: session.conflictPolicy
	});
	if (currentPlan.planHash !== session.planHash || currentPlan.destinationCorpusVersion !== session.destinationCorpusVersion) fail$1("stale-plan", "destination corpus or plan evidence changed");
	if (await destinationCorpusVersion(tx, session.scope) !== session.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after planning");
	const section = session.nextSection, offset = session.nextOffset, batchSize = bundleLimits(bundle).batchSize, slice = sectionItems(parsed, section).slice(offset, offset + batchSize), mutations = [];
	for (const item of slice) mutations.push(await stageMutation(tx, session, section, item));
	const next = nextCoordinate(parsed, section, offset + slice.length, batchSize), result = Object.freeze({
		...session,
		state: next.section === null ? "staged" : "applying",
		appliedBatches: session.appliedBatches + 1,
		nextSection: next.section,
		nextOffset: next.offset
	});
	const batch = Object.freeze({
		section,
		offset,
		mutations: Object.freeze(mutations)
	});
	await journal.recordBatch(sessionId, session.appliedBatches, schemaValue(batch), tx);
	await journal.completeCommand(tx, sessionId, "resume", command, commandHash, result);
	return result;
}
/** Prepare one hidden content-import staging batch for a host-owned atomic D1 batch. */
async function prepareResumeContentImportD1(db, authorization, principal, bundle, sessionIdInput, command) {
	assertD1Scope(command.scope);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), operationId = boundedString(command.operationId, "operationId", 256), parsed = await parsedBundleObject(bundle);
	if (parsed.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "bundle manifest differs from command");
	const authInput = authorizationInputFromCommand(command), policy = await assertImportAuthorized(db, authorization, principal, "resume", authInput);
	if (policy !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const commandHash = await canonicalCommandHash("resume", sessionId, principal, {
		command,
		bundleManifestHash: parsed.manifestHash
	}), scope = principalScope(principal), receiptEvidence = await readReceiptEvidence(db, operationId), receipt = receiptEvidence?.receipt;
	if (receipt && receiptEvidence) {
		if (receipt.kind !== "resume" || receipt.commandHash !== commandHash || receipt.principalScope !== scope || receipt.session.id !== sessionId) fail$1("conflict", "operation id was already used for another import command");
		const persisted = required(await readJournalRow(db, sessionId), "integrity", "committed resume receipt has no import journal");
		const session = sessionFromRow(persisted);
		if (JSON.stringify(session) !== JSON.stringify(receipt.session)) fail$1("integrity", "committed resume receipt and import journal differ");
		const guard = prepareExactReplayGuard(db, operationId, "resume", receiptEvidence, persisted, session);
		return Object.freeze({
			items: Object.freeze([guard]),
			result: session
		});
	}
	const row = required(await readJournalRow(db, sessionId), "authorization", "import session is unavailable");
	const session = sessionFromRow(row), payload = rowJson(row.payload), storedPlan = payload.plan;
	if (!sameScope(session.scope, authInput.scope) || !sameAuthority(session.requiredAuthority, authInput.requiredAuthority) || session.authorizationPolicyVersion !== policy) fail$1("authorization", "import session is unavailable");
	if (session.planHash !== command.expectedPlanHash || session.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "command plan evidence differs from session");
	if (session.journalVersion !== command.expectedJournalVersion || session.nextSection !== command.expectedSection || session.nextOffset !== command.expectedOffset) fail$1("stale-journal", "journal coordinate changed");
	if (session.state !== "validated" && session.state !== "applying") fail$1("stale-journal", "import is not resumable");
	if (session.nextSection === null) fail$1("stale-journal", "import is already staged");
	if (!storedPlan || typeof storedPlan !== "object") fail$1("integrity", "import journal has no retained plan evidence");
	const retainedPlan = storedPlan;
	await assertPlanHash(retainedPlan);
	if (retainedPlan.planHash !== session.planHash || retainedPlan.manifestHash !== session.manifestHash || !sameScope(retainedPlan.scope, session.scope) || retainedPlan.authorizationPolicyVersion !== session.authorizationPolicyVersion || retainedPlan.destinationCorpusVersion !== session.destinationCorpusVersion) fail$1("integrity", "retained plan evidence differs from session");
	const batches = Array.isArray(payload.batches) ? payload.batches : [];
	if (batches.length !== session.appliedBatches || batches.some((item, index) => item.batch !== index)) fail$1("integrity", "import batch ledger is not contiguous");
	for (const item of batches) stagedBatchFromValue(item.beforeImage);
	const destinationSnapshot = await readDestinationCorpus(db, session.scope);
	if (await hashDestinationCorpus(destinationSnapshot) !== session.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after planning");
	const section = session.nextSection;
	if (section === null) throw new ContentImportError("stale-journal", "import is already staged");
	const offset = session.nextOffset, slice = sectionItems(parsed, section).slice(offset, offset + bundleLimits(bundle).batchSize), mutations = [];
	for (const item of slice) mutations.push(await stageMutation(db, session, section, item));
	const staged = Object.freeze({
		section,
		offset,
		mutations: Object.freeze(mutations)
	}), ordinal = session.appliedBatches, next = nextCoordinate(parsed, section, offset + slice.length, bundleLimits(bundle).batchSize);
	const result = Object.freeze({
		...session,
		state: next.section === null ? "staged" : "applying",
		appliedBatches: ordinal + 1,
		journalVersion: String(Number(session.journalVersion) + 1),
		nextSection: next.section,
		nextOffset: next.offset
	});
	const nextPayload = JSON.stringify(schemaValue({
		...payload,
		preflightDestinationCorpusSnapshot: destinationSnapshot,
		session: result,
		batches: [...batches, {
			batch: ordinal,
			beforeImage: schemaValue(staged)
		}]
	})), pendingPayload = JSON.stringify(schemaValue({
		kind: "resume",
		commandHash,
		principalScope: scope
	})), committedPayload = JSON.stringify(schemaValue({
		kind: "resume",
		commandHash,
		principalScope: scope,
		session: result
	})), now = (/* @__PURE__ */ new Date()).toISOString();
	const claim = db.prepare(sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${crypto.randomUUID()},${operationId},'content:import:resume','pending',${pendingPayload},${now},${now})`), claimGuard = db.prepare(d1AssertPreviousChanges(1));
	const sectionPredicate = session.nextSection === null ? sql`next_section IS NULL` : sql`next_section=${session.nextSection}`;
	const cas = db.prepare(sql`UPDATE content_import_journal SET state=${result.state},version=version+1,next_section=${result.nextSection},next_offset=${result.nextOffset},payload=${nextPayload},updated_at=${now} WHERE import_id=${sessionId} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash} AND state=${session.state} AND version=${Number(session.journalVersion)} AND ${sectionPredicate} AND next_offset=${session.nextOffset} AND payload=${JSON.stringify(schemaValue(payload))}`), casGuard = db.prepare(d1AssertPreviousChanges(1));
	const ledgerOperationId = `${sessionId}:batch:${ordinal}`, ledgerPayload = JSON.stringify(schemaValue({
		sessionId,
		planHash: session.planHash,
		manifestHash: session.manifestHash,
		batch: ordinal,
		staged
	}));
	const append = db.prepare(sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${crypto.randomUUID()},${ledgerOperationId},'content:import:batch','committed',${ledgerPayload},${now},${now})`), appendGuard = db.prepare(d1AssertPreviousChanges(1));
	const complete = db.prepare(sql`UPDATE content_lifecycle_journal SET state='committed',payload=${committedPayload},updated_at=${now} WHERE operation_id=${operationId} AND kind='content:import:resume' AND state='pending' AND payload=${pendingPayload}`), completeGuard = db.prepare(d1AssertPreviousChanges(1));
	assertD1StatementBudget("resume", exactCorpusGuardCount(destinationSnapshot) + 8);
	return Object.freeze({
		items: Object.freeze([
			...d1ExactCorpusGuards(db, destinationSnapshot),
			claim,
			claimGuard,
			cas,
			casGuard,
			append,
			appendGuard,
			complete,
			completeGuard
		]),
		result
	});
}
function parseMutation(value) {
	const record = plain(value, "mutation"), kind = record.kind, action = record.action;
	if (kind !== "type" && kind !== "status" && kind !== "taxonomy" && kind !== "term" && kind !== "entry" && kind !== "revision") throw new ContentImportError("integrity", "staged mutation kind is invalid");
	if (action !== "create" && action !== "replace" && action !== "preserve" && action !== "shadow" && action !== "noop") throw new ContentImportError("integrity", "staged mutation action is invalid");
	return {
		kind,
		action,
		record
	};
}
function mutationAfter(record) {
	return plain(record.after, "mutation.after");
}
function boolValue(value) {
	return value === true || value === 1 || value === "1";
}
function nullableJson(value) {
	return value === null || value === void 0 ? null : JSON.stringify(value);
}
async function applyDefinitionMutation(tx, session, mutation) {
	if (mutation.kind !== "type" && mutation.kind !== "status") return false;
	const after = mutationAfter(mutation.record), keyValue = boundedString(after.key, "definition.key", 128), revision = positive$1(Number(after.revision), "definition.revision"), version = positive$1(Number(after.version), "definition.version"), canonicalHash = boundedString(after.canonicalHash, "definition.canonicalHash", 128), definition = plain(after.definition, "definition.definition"), versions = array(after.versions, "definition.versions", 1e3), now = (/* @__PURE__ */ new Date()).toISOString();
	if (mutation.action === "preserve") return true;
	for (let index = 0; index < versions.length; index++) {
		const row = plain(versions[index], `definition.versions.${index}`), rowRevision = positive$1(Number(row.revision), `definition.versions.${index}.revision`), rowHash = boundedString(row.canonicalHash, `definition.versions.${index}.canonicalHash`, 128), rowDefinition = plain(row.definition, `definition.versions.${index}.definition`), createdAt = iso$1(row.createdAt, `definition.versions.${index}.createdAt`);
		await tx.execute(sql`INSERT INTO content_definition_versions (definition_kind,definition_key,revision,canonical_hash,definition,origin,host_session_id,created_at) VALUES (${mutation.kind},${keyValue},${rowRevision},${rowHash},${JSON.stringify(rowDefinition)},'import',${session.staging.hostSessionId},${createdAt}) ON CONFLICT (definition_kind,definition_key,revision) DO NOTHING`);
	}
	if (mutation.action === "shadow") {
		if (mutation.kind === "type") await tx.execute(sql`UPDATE content_type_definitions SET shadowed_db_version=${version},updated_at=${now} WHERE key=${keyValue} AND origin='code'`);
		else await tx.execute(sql`UPDATE content_status_definitions SET shadowed_db_version=${version},updated_at=${now} WHERE key=${keyValue} AND origin='code'`);
		return true;
	}
	const active = boolValue(after.active);
	if (mutation.kind === "type") await tx.execute(sql`INSERT INTO content_type_definitions (key,origin,version,active,current_revision,canonical_hash,definition,shadowed_db_version,host_session_id,created_at,updated_at) VALUES (${keyValue},'import',${version},${active},${revision},${canonicalHash},${JSON.stringify(definition)},NULL,${session.staging.hostSessionId},${now},${now}) ON CONFLICT (key) DO UPDATE SET origin='import',version=EXCLUDED.version,active=EXCLUDED.active,current_revision=EXCLUDED.current_revision,canonical_hash=EXCLUDED.canonical_hash,definition=EXCLUDED.definition,shadowed_db_version=NULL,host_session_id=EXCLUDED.host_session_id,updated_at=EXCLUDED.updated_at`);
	else await tx.execute(sql`INSERT INTO content_status_definitions (key,origin,version,active,current_revision,canonical_hash,definition,shadowed_db_version,host_session_id,created_at,updated_at) VALUES (${keyValue},'import',${version},${active},${revision},${canonicalHash},${JSON.stringify(definition)},NULL,${session.staging.hostSessionId},${now},${now}) ON CONFLICT (key) DO UPDATE SET origin='import',version=EXCLUDED.version,active=EXCLUDED.active,current_revision=EXCLUDED.current_revision,canonical_hash=EXCLUDED.canonical_hash,definition=EXCLUDED.definition,shadowed_db_version=NULL,host_session_id=EXCLUDED.host_session_id,updated_at=EXCLUDED.updated_at`);
	return true;
}
async function applyTermMutation(tx, session, mutation) {
	if (mutation.kind === "taxonomy") return true;
	if (mutation.kind !== "term") return false;
	if (mutation.action === "preserve") return true;
	const after = mutationAfter(mutation.record), id = uuid(after.id, "term.id"), taxonomy = key(after.taxonomy, "term.taxonomy"), slug = boundedString(after.slug, "term.slug", 256), name = boundedString(after.name, "term.name", 512), parentId = after.parentId === null ? null : uuid(after.parentId, "term.parentId"), depth = nonnegative(Number(after.depth), "term.depth"), createdAt = iso$1(after.createdAt, "term.createdAt");
	await tx.execute(sql`INSERT INTO content_terms (id,taxonomy,slug,name,parent_id,depth,created_at,host_session_id) VALUES (${id},${taxonomy},${slug},${name},${parentId},${depth},${createdAt},${session.staging.hostSessionId}) ON CONFLICT (id) DO UPDATE SET taxonomy=EXCLUDED.taxonomy,slug=EXCLUDED.slug,name=EXCLUDED.name,parent_id=EXCLUDED.parent_id,depth=EXCLUDED.depth,host_session_id=EXCLUDED.host_session_id`);
	return true;
}
async function applyEntryMutation(tx, session, mutation) {
	if (mutation.kind !== "entry") return false;
	if (mutation.action === "preserve") return true;
	const after = mutationAfter(mutation.record), id = uuid(after.id, "entry.id"), slug = boundedString(after.slug, "entry.slug", 256), type = key(after.type, "entry.type"), title = typeof after.title === "string" ? after.title : fail$1("integrity", "staged entry title is invalid"), body = typeof after.body === "string" ? after.body : fail$1("integrity", "staged entry body is invalid"), status = key(after.status, "entry.status"), visibility = after.visibility, author = boundedString(after.author, "entry.author", 512), createdAt = iso$1(after.createdAt, "entry.createdAt"), updatedAt = iso$1(after.updatedAt, "entry.updatedAt"), parentId = after.parentId === null ? null : uuid(after.parentId, "entry.parentId"), menuOrder = nonnegative(Number(after.menuOrder), "entry.menuOrder"), templateKey = after.templateKey === null ? null : boundedString(after.templateKey, "entry.templateKey", 256), excerpt = typeof after.excerpt === "string" ? after.excerpt : fail$1("integrity", "staged entry excerpt is invalid"), commentStatus = after.commentStatus, pingStatus = after.pingStatus, sticky = after.sticky, lastEditedBy = boundedString(after.lastEditedBy, "entry.lastEditedBy", 512), typeRevision = positive$1(Number(after.typeDefinitionRevision), "entry.typeDefinitionRevision"), statusRevision = positive$1(Number(after.statusDefinitionRevision), "entry.statusDefinitionRevision"), termIds = array(after.termIds, "entry.termIds", 1e4).map((value, index) => uuid(value, `entry.termIds.${index}`));
	if (visibility !== "public" && visibility !== "private" && visibility !== "members") fail$1("integrity", "staged entry visibility is invalid");
	if (commentStatus !== "open" && commentStatus !== "closed") fail$1("integrity", "staged entry comment status is invalid");
	if (pingStatus !== "open" && pingStatus !== "closed") fail$1("integrity", "staged entry ping status is invalid");
	if (typeof sticky !== "boolean") fail$1("integrity", "staged entry sticky value is invalid");
	const publishedAt = after.publishedAt === null ? null : iso$1(after.publishedAt, "entry.publishedAt"), deletedAt = after.deletedAt === null ? null : iso$1(after.deletedAt, "entry.deletedAt"), format = after.format === null ? null : boundedString(after.format, "entry.format", 128), featuredMedia = nullableJson(after.featuredMedia);
	await tx.execute(sql`INSERT INTO content_entries (id,slug,type,title,body,status,visibility,published_at,author,created_at,updated_at,parent_id,menu_order,template_key,excerpt,featured_media,comment_status,ping_status,sticky,format,deleted_at,last_edited_by,type_definition_revision,status_definition_revision,host_session_id) VALUES (${id},${slug},${type},${title},${body},${status},${visibility},${publishedAt},${author},${createdAt},${updatedAt},${parentId},${menuOrder},${templateKey},${excerpt},${featuredMedia},${commentStatus},${pingStatus},${sticky},${format},${deletedAt},${lastEditedBy},${typeRevision},${statusRevision},${session.staging.hostSessionId}) ON CONFLICT (id) DO UPDATE SET slug=EXCLUDED.slug,type=EXCLUDED.type,title=EXCLUDED.title,body=EXCLUDED.body,status=EXCLUDED.status,visibility=EXCLUDED.visibility,published_at=EXCLUDED.published_at,author=EXCLUDED.author,updated_at=EXCLUDED.updated_at,parent_id=EXCLUDED.parent_id,menu_order=EXCLUDED.menu_order,template_key=EXCLUDED.template_key,excerpt=EXCLUDED.excerpt,featured_media=EXCLUDED.featured_media,comment_status=EXCLUDED.comment_status,ping_status=EXCLUDED.ping_status,sticky=EXCLUDED.sticky,format=EXCLUDED.format,deleted_at=EXCLUDED.deleted_at,last_edited_by=EXCLUDED.last_edited_by,type_definition_revision=EXCLUDED.type_definition_revision,status_definition_revision=EXCLUDED.status_definition_revision,host_session_id=EXCLUDED.host_session_id`);
	await tx.execute(sql`DELETE FROM content_entry_terms WHERE entry_id=${id}`);
	for (const termId of termIds) await tx.execute(sql`INSERT INTO content_entry_terms (entry_id,term_id) VALUES (${id},${termId}) ON CONFLICT (entry_id,term_id) DO NOTHING`);
	return true;
}
async function applyRevisionMutation(tx, session, mutation) {
	if (mutation.kind !== "revision") return false;
	if (mutation.action === "preserve") return true;
	const after = mutationAfter(mutation.record), id = uuid(after.id, "revision.id"), entryId = uuid(after.entryId, "revision.entryId"), title = typeof after.title === "string" ? after.title : fail$1("integrity", "staged revision title is invalid"), body = typeof after.body === "string" ? after.body : fail$1("integrity", "staged revision body is invalid"), slug = boundedString(after.slug, "revision.slug", 256), type = key(after.type, "revision.type"), termIds = array(after.termIds, "revision.termIds", 1e4).map((value, index) => uuid(value, `revision.termIds.${index}`)), snapshot = after.snapshot === void 0 ? null : nullableJson(after.snapshot), editor = boundedString(after.editor, "revision.editor", 512), createdAt = iso$1(after.createdAt, "revision.createdAt");
	if ((await execRows(tx, sql`SELECT id FROM content_revisions WHERE id=${id}`))[0] !== void 0) await tx.execute(sql`UPDATE content_revisions SET entry_id=${entryId},title=${title},body=${body},slug=${slug},type=${type},term_ids=${JSON.stringify(termIds)},snapshot=${snapshot},editor=${editor},created_at=${createdAt},host_session_id=${session.staging.hostSessionId} WHERE id=${id}`);
	else await tx.execute(sql`INSERT INTO content_revisions (id,entry_id,title,body,slug,type,term_ids,snapshot,editor,created_at,host_session_id) VALUES (${id},${entryId},${title},${body},${slug},${type},${JSON.stringify(termIds)},${snapshot},${editor},${createdAt},${session.staging.hostSessionId})`);
	return true;
}
async function applyStagedMutation(tx, session, value) {
	const mutation = parseMutation(value);
	if (await applyDefinitionMutation(tx, session, mutation)) return;
	if (await applyTermMutation(tx, session, mutation)) return;
	if (await applyEntryMutation(tx, session, mutation)) return;
	if (await applyRevisionMutation(tx, session, mutation)) return;
	fail$1("integrity", "unknown staged mutation");
}
async function readValidatedLedger(tx, journal, session) {
	const reverse = await journal.readBatchesReverse(tx, session.id, session.planHash, session.manifestHash);
	if (reverse.length !== session.appliedBatches) fail$1("integrity", "import batch ledger count differs from session");
	const forward = [...reverse].reverse().map((item) => ({
		batch: item.batch,
		staged: stagedBatchFromValue(item.beforeImage)
	}));
	for (let i = 0; i < forward.length; i++) if (forward[i].batch !== i) fail$1("integrity", "import batch ledger sequence is invalid");
	let lastSection = -1, lastEnd = 0;
	for (const item of forward) {
		const sectionIndex = [
			"type",
			"status",
			"taxonomy",
			"term",
			"entry",
			"revision"
		].indexOf(item.staged.section);
		if (sectionIndex < lastSection) fail$1("integrity", "import batch section order is invalid");
		if (sectionIndex === lastSection && item.staged.offset !== lastEnd) fail$1("integrity", "import batch offset sequence is invalid");
		if (sectionIndex > lastSection) {
			lastSection = sectionIndex;
			lastEnd = 0;
			if (item.staged.offset !== 0) fail$1("integrity", "import section does not start at offset zero");
		}
		lastEnd = item.staged.offset + item.staged.mutations.length;
	}
	return Object.freeze(forward);
}
function replaceCorpusRow(rows, identity, id, next) {
	const result = rows.filter((row) => identity(plain(row, "corpus.row")) !== id);
	if (next !== null) result.push(next);
	return Object.freeze(result.sort((a, b) => identity(plain(a, "corpus.row")).localeCompare(identity(plain(b, "corpus.row")))));
}
function projectTermsToTaxonomies(terms, taxonomyKeys) {
	const visible = new Set(taxonomyKeys);
	return Object.freeze(terms.filter((value) => visible.has(String(plain(value, "corpus.term").taxonomy))));
}
function predictPostPublishSnapshot(snapshot, ledger, session) {
	let types = snapshot.types, statuses = snapshot.statuses, versions = snapshot.versions, terms = snapshot.terms, entries = snapshot.entries, assignments = snapshot.assignments, revisions = snapshot.revisions;
	for (const { staged } of ledger) for (const raw of staged.mutations) {
		const mutation = parseMutation(raw);
		if (mutation.action === "preserve" || mutation.action === "noop") continue;
		if (mutation.kind === "type" || mutation.kind === "status") {
			const after = mutationAfter(mutation.record), definitionKey = String(after.key), current = (mutation.kind === "type" ? types : statuses).find((row) => String(plain(row, "definition").key) === definitionKey), currentRecord = current ? plain(current, "definition") : null;
			for (const rawVersion of array(after.versions, "definition.versions", 1e3)) {
				const version = plain(rawVersion, "definition.version"), identity = `${mutation.kind}:${definitionKey}:${Number(version.revision)}`;
				if (!versions.some((row) => {
					const value = plain(row, "definitionVersion");
					return `${value.kind}:${value.key}:${Number(value.revision)}` === identity;
				})) versions = replaceCorpusRow(versions, (row) => `${row.kind}:${row.key}:${Number(row.revision)}`, identity, schemaValue({
					kind: mutation.kind,
					key: definitionKey,
					revision: Number(version.revision),
					canonicalHash: String(version.canonicalHash),
					definition: version.definition,
					origin: "import",
					createdAt: String(version.createdAt)
				}));
			}
			let next;
			if (mutation.action === "shadow") {
				if (currentRecord === null) fail$1("integrity", "shadow mutation has no destination definition");
				next = schemaValue({
					...currentRecord,
					shadowedDbVersion: Number(after.version)
				});
			} else next = schemaValue({
				key: definitionKey,
				origin: "import",
				version: Number(after.version),
				active: boolValue(after.active),
				currentRevision: Number(after.revision),
				canonicalHash: String(after.canonicalHash),
				definition: after.definition,
				shadowedDbVersion: null
			});
			if (mutation.kind === "type") types = replaceCorpusRow(types, (row) => String(row.key), definitionKey, next);
			else statuses = replaceCorpusRow(statuses, (row) => String(row.key), definitionKey, next);
			continue;
		}
		if (mutation.kind === "term") {
			const after = mutationAfter(mutation.record), id = String(after.id);
			terms = replaceCorpusRow(terms, (row) => String(row.id), id, schemaValue({
				...after,
				hostSessionId: session.staging.hostSessionId
			}));
			continue;
		}
		if (mutation.kind === "entry") {
			const after = mutationAfter(mutation.record), id = String(after.id), termIds = array(after.termIds, "entry.termIds", 1e4).map(String);
			entries = replaceCorpusRow(entries, (row) => String(row.id), id, schemaValue({
				...after,
				hostSessionId: session.staging.hostSessionId,
				termIds: void 0
			}));
			assignments = assignments.filter((row) => String(plain(row, "assignment").entryId) !== id);
			assignments = Object.freeze([...assignments, ...termIds.map((termId) => schemaValue({
				entryId: id,
				termId
			}))].sort((a, b) => {
				const left = plain(a, "assignment"), right = plain(b, "assignment");
				return `${left.entryId}:${left.termId}`.localeCompare(`${right.entryId}:${right.termId}`);
			}));
			continue;
		}
		if (mutation.kind === "revision") {
			const after = mutationAfter(mutation.record), id = String(after.id);
			revisions = replaceCorpusRow(revisions, (row) => String(row.id), id, schemaValue({
				id,
				entryId: after.entryId,
				title: after.title,
				body: after.body,
				slug: after.slug,
				type: after.type,
				termIds: after.termIds,
				snapshot: after.snapshot ?? null,
				editor: after.editor,
				createdAt: after.createdAt,
				hostSessionId: session.staging.hostSessionId
			}));
		}
	}
	const statusKeys = Object.freeze(statuses.map((row) => String(plain(row, "status").key)).sort()), taxonomyKeys = Object.freeze([...new Set(types.flatMap((row) => {
		try {
			return normalizeContentTypeDefinition(plain(row, "type").definition).taxonomies;
		} catch {
			return [];
		}
	}))].sort());
	terms = projectTermsToTaxonomies(terms, taxonomyKeys);
	return Object.freeze({
		...snapshot,
		statusKeys,
		taxonomyKeys,
		types,
		statuses,
		versions,
		terms,
		entries,
		assignments,
		revisions
	});
}
function d1Ledger(row, session) {
	const payload = rowJson(row.payload), batches = Array.isArray(payload.batches) ? payload.batches : [];
	if (batches.length !== session.appliedBatches) fail$1("integrity", "import batch ledger count differs from session");
	const ledger = batches.map((item, index) => {
		if (item.batch !== index) fail$1("integrity", "import batch ledger sequence is invalid");
		return {
			batch: item.batch,
			staged: stagedBatchFromValue(item.beforeImage)
		};
	});
	let section = -1, end = 0;
	for (const item of ledger) {
		const next = [
			"type",
			"status",
			"taxonomy",
			"term",
			"entry",
			"revision"
		].indexOf(item.staged.section);
		if (next < section || next === section && item.staged.offset !== end || next > section && item.staged.offset !== 0) fail$1("integrity", "import batch ledger is not contiguous");
		section = next;
		end = item.staged.offset + item.staged.mutations.length;
	}
	return Object.freeze(ledger);
}
async function readRetainedLedger(db, session) {
	const row = (await execRows(db, sql`SELECT import_id AS "importId",host_session_id AS "hostSessionId",manifest_hash AS "manifestHash",plan_hash AS "planHash",state,version,next_section AS "nextSection",next_offset AS "nextOffset",high_water_mark AS "highWaterMark",payload FROM content_import_journal WHERE import_id=${session.id} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash}`))[0];
	if (!row) fail$1("authorization", "import session is unavailable");
	const retained = sessionFromRow(row);
	if (retained.journalVersion !== session.journalVersion || retained.state !== session.state || retained.nextSection !== session.nextSection || retained.nextOffset !== session.nextOffset || retained.appliedBatches !== session.appliedBatches) fail$1("stale-journal", "journal coordinate changed");
	return d1Ledger(row, session);
}
/** Predict the exact semantic corpus hash produced by publishing a retained staged ledger. */
async function predictPublishedContentImportCorpus(db, session) {
	const ledger = await readRetainedLedger(db, session), extraTaxonomyKeys = ledger.flatMap(({ staged }) => staged.mutations.flatMap((raw) => {
		const mutation = parseMutation(raw);
		if (mutation.kind !== "type") return [];
		try {
			return normalizeContentTypeDefinition(mutationAfter(mutation.record).definition).taxonomies;
		} catch {
			return [];
		}
	}));
	return hashDestinationCorpus(predictPostPublishSnapshot(await readDestinationCorpus(db, session.scope, extraTaxonomyKeys), ledger, session));
}
function affectedCounts(ledger) {
	const counts = {};
	for (const { staged } of ledger) for (const raw of staged.mutations) {
		const mutation = parseMutation(raw);
		if (mutation.action === "preserve" || mutation.action === "noop") continue;
		counts[mutation.kind] = (counts[mutation.kind] ?? 0) + 1;
	}
	return Object.freeze(counts);
}
function lifecycleEvent(kind, operationId, session, principal, counts) {
	return Object.freeze({
		id: crypto.randomUUID(),
		version: 1,
		kind,
		operationId,
		sessionId: session.id,
		planHash: session.planHash,
		manifestHash: session.manifestHash,
		principalId: principal.id,
		scope: session.scope,
		authorizationPolicyVersion: session.authorizationPolicyVersion,
		affectedCounts: counts
	});
}
async function emitLifecycleEffects(tx, effects, event) {
	await effects.audit.record(tx, event);
	await effects.outbox.enqueue(tx, event);
}
function addChecked(items, db, query, expected = 1) {
	items.push(db.prepare(query), db.prepare(d1AssertPreviousChanges(expected)));
}
function assertD1StatementBudget(operation, count) {
	if (!Number.isSafeInteger(count) || count < 1 || count > 50) fail$1("limit", `${operation} contribution requires ${count} D1 statements; maximum is 50`, "d1Statements");
}
function exactCorpusGuardCount(snapshot) {
	return 1 + snapshot.types.length + snapshot.statuses.length + snapshot.versions.length + snapshot.terms.length + snapshot.entries.length + snapshot.assignments.length + snapshot.revisions.length;
}
function insertedDefinitionVersions(mutation) {
	const before = plain(mutation.record.before, "definition.before"), retained = new Set(array(before.versions, "definition.before.versions", 1e3).map((value) => Number(plain(value, "definition.before.version").revision)));
	return Object.freeze(array(mutationAfter(mutation.record).versions, "definition.versions", 1e3).filter((value) => !retained.has(Number(plain(value, "definition.version").revision))));
}
function publishMutationStatementCount(raw) {
	const mutation = parseMutation(raw);
	if (mutation.action === "preserve" || mutation.action === "noop") return 0;
	if (mutation.kind === "type" || mutation.kind === "status") return insertedDefinitionVersions(mutation).length + (mutation.action === "create" ? 1 : 2);
	if (mutation.kind === "term" || mutation.kind === "revision") return mutation.action === "create" ? 1 : 2;
	const after = mutationAfter(mutation.record);
	return (mutation.action === "create" ? 1 : 2) + 2 + array(after.termIds, "entry.termIds", 1e4).length;
}
function preparePublishMutation(items, db, session, raw, now, phase) {
	const mutation = parseMutation(raw);
	if (mutation.action === "preserve" || mutation.action === "noop") return;
	const after = mutationAfter(mutation.record), host = session.staging.hostSessionId;
	if (mutation.kind === "type" || mutation.kind === "status") {
		const definitionKey = key(after.key, "definition.key");
		if (phase === "versions") {
			for (const value of insertedDefinitionVersions(mutation)) {
				const version = plain(value, "definition.version");
				items.push(db.prepare(sql`INSERT INTO content_definition_versions (definition_kind,definition_key,revision,canonical_hash,definition,origin,host_session_id,created_at) VALUES (${mutation.kind},${definitionKey},${positive$1(Number(version.revision), "definition.version.revision")},${boundedString(version.canonicalHash, "definition.version.canonicalHash", 128)},${JSON.stringify(plain(version.definition, "definition.version.definition"))},'import',${host},${iso$1(version.createdAt, "definition.version.createdAt")})`));
			}
			return;
		}
		const version = positive$1(Number(after.version), "definition.version"), revision = positive$1(Number(after.revision), "definition.revision"), hash = boundedString(after.canonicalHash, "definition.canonicalHash", 128), definition = JSON.stringify(plain(after.definition, "definition.definition")), active = boolValue(after.active);
		if (mutation.action === "shadow") {
			addChecked(items, db, mutation.kind === "type" ? sql`UPDATE content_type_definitions SET shadowed_db_version=${version},updated_at=${now} WHERE key=${definitionKey} AND origin='code'` : sql`UPDATE content_status_definitions SET shadowed_db_version=${version},updated_at=${now} WHERE key=${definitionKey} AND origin='code'`);
			return;
		}
		if (mutation.action === "create") {
			items.push(db.prepare(mutation.kind === "type" ? sql`INSERT INTO content_type_definitions (key,origin,version,active,current_revision,canonical_hash,definition,shadowed_db_version,host_session_id,created_at,updated_at) VALUES (${definitionKey},'import',${version},${active},${revision},${hash},${definition},NULL,${host},${now},${now})` : sql`INSERT INTO content_status_definitions (key,origin,version,active,current_revision,canonical_hash,definition,shadowed_db_version,host_session_id,created_at,updated_at) VALUES (${definitionKey},'import',${version},${active},${revision},${hash},${definition},NULL,${host},${now},${now})`));
			return;
		}
		const before = plain(plain(mutation.record.before, "definition.before").current, "definition.before.current"), where = sql`key=${definitionKey} AND origin=${String(before.origin)} AND version=${Number(before.version)} AND current_revision=${Number(before.currentRevision)} AND canonical_hash=${String(before.canonicalHash)}`;
		addChecked(items, db, mutation.kind === "type" ? sql`UPDATE content_type_definitions SET origin='import',version=${version},active=${active},current_revision=${revision},canonical_hash=${hash},definition=${definition},shadowed_db_version=NULL,host_session_id=${host},updated_at=${now} WHERE ${where}` : sql`UPDATE content_status_definitions SET origin='import',version=${version},active=${active},current_revision=${revision},canonical_hash=${hash},definition=${definition},shadowed_db_version=NULL,host_session_id=${host},updated_at=${now} WHERE ${where}`);
		return;
	}
	if (phase === "versions") return;
	if (mutation.kind === "term") {
		const id = uuid(after.id, "term.id"), taxonomy = key(after.taxonomy, "term.taxonomy"), slug = boundedString(after.slug, "term.slug", 256), name = boundedString(after.name, "term.name", 512), parent = after.parentId === null ? null : uuid(after.parentId, "term.parentId"), depth = nonnegative(Number(after.depth), "term.depth"), created = iso$1(after.createdAt, "term.createdAt");
		if (mutation.action === "create") items.push(db.prepare(sql`INSERT INTO content_terms (id,taxonomy,slug,name,parent_id,depth,created_at,host_session_id) VALUES (${id},${taxonomy},${slug},${name},${parent},${depth},${created},${host})`));
		else addChecked(items, db, sql`UPDATE content_terms SET taxonomy=${taxonomy},slug=${slug},name=${name},parent_id=${parent},depth=${depth},host_session_id=${host} WHERE id=${id}`);
		return;
	}
	if (mutation.kind === "entry") {
		const id = uuid(after.id, "entry.id"), terms = array(after.termIds, "entry.termIds", 1e4).map((value, index) => uuid(value, `entry.termIds.${index}`)), values = sql`${id},${String(after.slug)},${String(after.type)},${String(after.title)},${String(after.body)},${String(after.status)},${String(after.visibility)},${after.publishedAt === null ? null : String(after.publishedAt)},${String(after.author)},${String(after.createdAt)},${String(after.updatedAt)},${after.parentId === null ? null : String(after.parentId)},${Number(after.menuOrder)},${after.templateKey === null ? null : String(after.templateKey)},${String(after.excerpt)},${nullableJson(after.featuredMedia)},${String(after.commentStatus)},${String(after.pingStatus)},${boolValue(after.sticky)},${after.format === null ? null : String(after.format)},${after.deletedAt === null ? null : String(after.deletedAt)},${String(after.lastEditedBy)},${Number(after.typeDefinitionRevision)},${Number(after.statusDefinitionRevision)},${host}`;
		if (mutation.action === "create") items.push(db.prepare(sql`INSERT INTO content_entries (id,slug,type,title,body,status,visibility,published_at,author,created_at,updated_at,parent_id,menu_order,template_key,excerpt,featured_media,comment_status,ping_status,sticky,format,deleted_at,last_edited_by,type_definition_revision,status_definition_revision,host_session_id) VALUES (${values})`));
		else addChecked(items, db, sql`UPDATE content_entries SET slug=${String(after.slug)},type=${String(after.type)},title=${String(after.title)},body=${String(after.body)},status=${String(after.status)},visibility=${String(after.visibility)},published_at=${after.publishedAt === null ? null : String(after.publishedAt)},author=${String(after.author)},updated_at=${String(after.updatedAt)},parent_id=${after.parentId === null ? null : String(after.parentId)},menu_order=${Number(after.menuOrder)},template_key=${after.templateKey === null ? null : String(after.templateKey)},excerpt=${String(after.excerpt)},featured_media=${nullableJson(after.featuredMedia)},comment_status=${String(after.commentStatus)},ping_status=${String(after.pingStatus)},sticky=${boolValue(after.sticky)},format=${after.format === null ? null : String(after.format)},deleted_at=${after.deletedAt === null ? null : String(after.deletedAt)},last_edited_by=${String(after.lastEditedBy)},type_definition_revision=${Number(after.typeDefinitionRevision)},status_definition_revision=${Number(after.statusDefinitionRevision)},host_session_id=${host} WHERE id=${id}`);
		addChecked(items, db, sql`DELETE FROM content_entry_terms WHERE entry_id=${id}`, array(mutation.record.beforeTermIds ?? [], "entry.beforeTermIds", 1e4).length);
		for (const term of terms) items.push(db.prepare(sql`INSERT INTO content_entry_terms (entry_id,term_id) VALUES (${id},${term})`));
		return;
	}
	const id = uuid(after.id, "revision.id"), entryId = uuid(after.entryId, "revision.entryId"), termIds = JSON.stringify(array(after.termIds, "revision.termIds", 1e4)), snapshot = after.snapshot === void 0 ? null : nullableJson(after.snapshot);
	if (mutation.action === "create") items.push(db.prepare(sql`INSERT INTO content_revisions (id,entry_id,title,body,slug,type,term_ids,snapshot,editor,created_at,host_session_id) VALUES (${id},${entryId},${String(after.title)},${String(after.body)},${String(after.slug)},${String(after.type)},${termIds},${snapshot},${String(after.editor)},${String(after.createdAt)},${host})`));
	else addChecked(items, db, sql`UPDATE content_revisions SET entry_id=${entryId},title=${String(after.title)},body=${String(after.body)},slug=${String(after.slug)},type=${String(after.type)},term_ids=${termIds},snapshot=${snapshot},editor=${String(after.editor)},created_at=${String(after.createdAt)},host_session_id=${host} WHERE id=${id}`);
}
async function preparePublishContentImportD1(db, authorization, principal, sessionIdInput, command) {
	assertD1Scope(command.scope);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), operationId = boundedString(command.operationId, "operationId", 256), authInput = authorizationInputFromCommand(command), policy = await assertImportAuthorized(db, authorization, principal, "publish", authInput);
	if (policy !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const commandHash = await canonicalCommandHash("publish", sessionId, principal, command), scope = principalScope(principal), receiptEvidence = await readReceiptEvidence(db, operationId), receipt = receiptEvidence?.receipt;
	if (receipt && receiptEvidence) {
		if (receipt.kind !== "publish" || receipt.commandHash !== commandHash || receipt.principalScope !== scope || receipt.session.id !== sessionId) fail$1("conflict", "operation id was already used for another import command");
		const persisted = required(await readJournalRow(db, sessionId), "integrity", "committed publish receipt has no import journal");
		const result = sessionFromRow(persisted);
		if (JSON.stringify(result) !== JSON.stringify(receipt.session)) fail$1("integrity", "committed publish receipt and import journal differ");
		const guard = prepareExactReplayGuard(db, operationId, "publish", receiptEvidence, persisted, result);
		return Object.freeze({
			items: Object.freeze([guard]),
			result
		});
	}
	const row = required(await readJournalRow(db, sessionId), "authorization", "import session is unavailable");
	const session = sessionFromRow(row);
	if (!sameScope(session.scope, authInput.scope) || !sameAuthority(session.requiredAuthority, authInput.requiredAuthority) || session.authorizationPolicyVersion !== policy) fail$1("authorization", "import session is unavailable");
	if (session.planHash !== command.expectedPlanHash || session.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "command plan evidence differs from session");
	if (session.journalVersion !== command.expectedJournalVersion || session.nextSection !== command.expectedSection || session.nextOffset !== command.expectedOffset || session.state !== "staged" || session.nextSection !== null || session.nextOffset !== 0) fail$1("stale-journal", "import is not staged for publication");
	if (await destinationCorpusVersion(db, session.scope) !== session.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after staging");
	const ledger = d1Ledger(row, session), counts = affectedCounts(ledger), extra = ledger.flatMap(({ staged }) => staged.mutations.flatMap((raw) => {
		const mutation = parseMutation(raw);
		return mutation.kind === "type" ? normalizeContentTypeDefinition(mutationAfter(mutation.record).definition).taxonomies : [];
	})), snapshot = await readDestinationCorpus(db, session.scope, extra), predictedSnapshot = predictPostPublishSnapshot(snapshot, ledger, session), predicted = await hashDestinationCorpus(predictedSnapshot), result = Object.freeze({
		...session,
		state: "published",
		publishedCorpusVersion: predicted,
		journalVersion: String(Number(session.journalVersion) + 1),
		nextSection: null,
		nextOffset: 0
	});
	const payload = rowJson(row.payload), storedPayload = JSON.stringify(schemaValue(payload)), nextPayload = JSON.stringify(schemaValue({
		...payload,
		session: result
	})), pendingPayload = JSON.stringify(schemaValue({
		kind: "publish",
		commandHash,
		principalScope: scope
	})), committedPayload = JSON.stringify(schemaValue({
		kind: "publish",
		commandHash,
		principalScope: scope,
		session: result
	})), now = (/* @__PURE__ */ new Date()).toISOString();
	const mutationStatements = ledger.reduce((count, { staged }) => count + staged.mutations.reduce((sum, mutation) => sum + publishMutationStatementCount(mutation), 0), 0);
	assertD1StatementBudget("publish", 7 + exactCorpusGuardCount(snapshot) + mutationStatements + exactCorpusGuardCount(predictedSnapshot));
	const items = [];
	addChecked(items, db, sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${crypto.randomUUID()},${operationId},'content:import:publish','pending',${pendingPayload},${now},${now})`);
	items.push(...d1ExactCorpusGuards(db, snapshot));
	items.push(db.prepare(sql`SELECT CASE WHEN EXISTS (SELECT 1 FROM content_import_journal WHERE import_id=${sessionId} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash} AND state='staged' AND version=${Number(session.journalVersion)} AND next_section IS NULL AND next_offset=0 AND payload=${storedPayload}) THEN 1 ELSE json_extract('not-json','$') END AS ok`));
	for (const phase of ["versions", "canonical"]) for (const { staged } of ledger) for (const mutation of staged.mutations) preparePublishMutation(items, db, session, mutation, now, phase);
	items.push(...d1ExactCorpusGuards(db, predictedSnapshot));
	addChecked(items, db, sql`UPDATE content_import_journal SET state='published',version=version+1,high_water_mark=${predicted},payload=${nextPayload},updated_at=${now} WHERE import_id=${sessionId} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash} AND state='staged' AND version=${Number(session.journalVersion)} AND next_section IS NULL AND next_offset=0 AND payload=${storedPayload}`);
	addChecked(items, db, sql`UPDATE content_lifecycle_journal SET state='committed',payload=${committedPayload},updated_at=${now} WHERE operation_id=${operationId} AND kind='content:import:publish' AND state='pending' AND payload=${pendingPayload}`);
	return Object.freeze({
		items: Object.freeze(items),
		result,
		affectedCounts: counts
	});
}
async function publishContentImport(tx, journal, authorization, effects, principal, sessionIdInput, command) {
	assertActiveContentTransaction(tx);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), commandHash = await canonicalCommandHash("publish", sessionId, principal, command), claim = await journal.claimCommand(tx, sessionId, principal, "publish", command, commandHash, authorization);
	if (claim.kind === "conflict") throw new ContentImportError("conflict", "operation id was already used for another import command");
	if (claim.kind === "replay") return claim.session;
	const session = claim.session;
	if (!session) throw new ContentImportError("integrity", "publish claim did not return session");
	if (session.state !== "staged" || session.nextSection !== null || session.nextOffset !== 0) fail$1("stale-journal", "import is not staged for publication");
	if (await destinationCorpusVersion(tx, session.scope) !== session.destinationCorpusVersion) fail$1("stale-plan", "destination corpus changed after staging");
	const ledger = await readValidatedLedger(tx, journal, session), counts = affectedCounts(ledger), predictedPublishedCorpus = await predictPublishedContentImportCorpus(tx, session);
	for (const { staged } of ledger) for (const mutation of staged.mutations) await applyStagedMutation(tx, session, mutation);
	const publishedCorpus = await destinationCorpusVersion(tx, session.scope);
	if (publishedCorpus !== predictedPublishedCorpus) fail$1("integrity", "predicted published corpus differs from committed publication");
	const result = Object.freeze({
		...session,
		state: "published",
		publishedCorpusVersion: publishedCorpus,
		nextSection: null,
		nextOffset: 0
	});
	await emitLifecycleEffects(tx, effects, lifecycleEvent("published", command.operationId, result, principal, counts));
	await journal.completeCommand(tx, session.id, "publish", command, commandHash, result);
	return result;
}
/** Prepare a staged content-import rollback for one host-owned atomic D1 batch. */
async function prepareRollbackContentImportD1(db, authorization, principal, sessionIdInput, command) {
	assertD1Scope(command.scope);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), operationId = boundedString(command.operationId, "operationId", 256), authInput = authorizationInputFromCommand(command);
	const policy = await assertImportAuthorized(db, authorization, principal, "rollback", authInput);
	if (policy !== command.expectedAuthorizationPolicyVersion) fail$1("authorization", "import scope is unavailable");
	const commandHash = await canonicalCommandHash("rollback", sessionId, principal, command), scope = principalScope(principal), receiptEvidence = await readReceiptEvidence(db, operationId), receipt = receiptEvidence?.receipt;
	if (receipt && receiptEvidence) {
		if (receipt.kind !== "rollback" || receipt.commandHash !== commandHash || receipt.principalScope !== scope || receipt.session.id !== sessionId) fail$1("conflict", "operation id was already used for another import command");
		const persisted = required(await readJournalRow(db, sessionId), "integrity", "committed rollback receipt has no import journal");
		const result = sessionFromRow(persisted);
		if (JSON.stringify(result) !== JSON.stringify(receipt.session)) fail$1("integrity", "committed rollback receipt and import journal differ");
		const guard = prepareExactReplayGuard(db, operationId, "rollback", receiptEvidence, persisted, result), ledgerGuard = db.prepare(sql`SELECT CASE WHEN NOT EXISTS (SELECT 1 FROM content_lifecycle_journal WHERE kind='content:import:batch' AND json_extract(payload,'$.sessionId')=${sessionId}) THEN 1 ELSE json_extract('not-json','$') END AS ok`);
		return Object.freeze({
			items: Object.freeze([guard, ledgerGuard]),
			result
		});
	}
	const row = required(await readJournalRow(db, sessionId), "authorization", "import session is unavailable");
	const session = sessionFromRow(row);
	if (!sameScope(session.scope, authInput.scope) || !sameAuthority(session.requiredAuthority, authInput.requiredAuthority) || session.authorizationPolicyVersion !== policy) fail$1("authorization", "import session is unavailable");
	if (session.planHash !== command.expectedPlanHash || session.manifestHash !== command.expectedManifestHash) fail$1("stale-plan", "command plan evidence differs from session");
	if (session.journalVersion !== command.expectedJournalVersion || session.nextSection !== command.expectedSection || session.nextOffset !== command.expectedOffset) fail$1("stale-journal", "journal coordinate changed");
	if (session.state !== "validated" && session.state !== "applying" && session.state !== "staged") fail$1("stale-journal", "published or terminal imports cannot use staged rollback");
	const ledger = d1Ledger(row, session), counts = affectedCounts(ledger), payload = rowJson(row.payload), storedPayload = JSON.stringify(schemaValue(payload)), result = Object.freeze({
		...session,
		state: "rolledBack",
		journalVersion: String(Number(session.journalVersion) + 1),
		nextSection: null,
		nextOffset: 0
	});
	const nextPayload = JSON.stringify(schemaValue({
		...payload,
		session: result,
		batches: []
	})), pendingPayload = JSON.stringify(schemaValue({
		kind: "rollback",
		commandHash,
		principalScope: scope
	})), committedPayload = JSON.stringify(schemaValue({
		kind: "rollback",
		commandHash,
		principalScope: scope,
		session: result
	})), now = (/* @__PURE__ */ new Date()).toISOString(), items = [];
	addChecked(items, db, sql`INSERT INTO content_lifecycle_journal (id,operation_id,kind,state,payload,created_at,updated_at) VALUES (${crypto.randomUUID()},${operationId},'content:import:rollback','pending',${pendingPayload},${now},${now})`);
	addChecked(items, db, sql`UPDATE content_import_journal SET state='rolledBack',version=version+1,next_section=NULL,next_offset=0,payload=${nextPayload},updated_at=${now} WHERE import_id=${sessionId} AND host_session_id=${session.staging.hostSessionId} AND plan_hash=${session.planHash} AND manifest_hash=${session.manifestHash} AND state=${session.state} AND version=${Number(session.journalVersion)} AND next_section ${session.nextSection === null ? sql`IS NULL` : sql`=${session.nextSection}`} AND next_offset=${session.nextOffset} AND payload=${storedPayload}`);
	addChecked(items, db, sql`DELETE FROM content_lifecycle_journal WHERE kind='content:import:batch' AND json_extract(payload,'$.sessionId')=${sessionId} AND json_extract(payload,'$.planHash')=${session.planHash} AND json_extract(payload,'$.manifestHash')=${session.manifestHash}`, ledger.length);
	addChecked(items, db, sql`UPDATE content_lifecycle_journal SET state='committed',payload=${committedPayload},updated_at=${now} WHERE operation_id=${operationId} AND kind='content:import:rollback' AND state='pending' AND payload=${pendingPayload}`);
	return Object.freeze({
		items: Object.freeze(items),
		result,
		affectedCounts: counts
	});
}
async function rollbackContentImport(tx, journal, authorization, effects, principal, sessionIdInput, command) {
	assertActiveContentTransaction(tx);
	const sessionId = boundedString(sessionIdInput, "sessionId", 128), commandHash = await canonicalCommandHash("rollback", sessionId, principal, command), claim = await journal.claimCommand(tx, sessionId, principal, "rollback", command, commandHash, authorization);
	if (claim.kind === "conflict") throw new ContentImportError("conflict", "operation id was already used for another import command");
	if (claim.kind === "replay") return claim.session;
	const session = claim.session;
	if (!session) throw new ContentImportError("integrity", "rollback claim did not return session");
	if (session.state !== "validated" && session.state !== "applying" && session.state !== "staged") fail$1("stale-journal", "published or terminal imports cannot use staged rollback");
	const ledger = await readValidatedLedger(tx, journal, session), counts = affectedCounts(ledger);
	for (const item of ledger) stagedBatchFromValue(schemaValue(item.staged));
	const result = Object.freeze({
		...session,
		state: "rolledBack",
		nextSection: null,
		nextOffset: 0
	});
	await emitLifecycleEffects(tx, effects, lifecycleEvent("rolledBack", command.operationId, result, principal, counts));
	await journal.completeCommand(tx, session.id, "rollback", command, commandHash, result);
	return result;
}
function d1CorpusCountGuardBindCount(snapshot) {
	const expectedCountBinds = 3 + (snapshot.mappedTypeKeys.length + snapshot.statusKeys.length > 0 ? 1 : 0) + (snapshot.taxonomyKeys.length > 0 ? 1 : 0) + (snapshot.entries.length > 0 ? 2 : 0);
	return snapshot.mappedTypeKeys.length * 3 + snapshot.statusKeys.length + snapshot.taxonomyKeys.length + snapshot.entries.length * 2 + expectedCountBinds;
}
function assertD1CorpusCountGuardBindBudget(snapshot) {
	const count = d1CorpusCountGuardBindCount(snapshot);
	if (count > CONTENT_IMPORT_D1_BIND_BUDGET) fail$1("limit", `exact D1 corpus count guard requires ${count} bind parameters; maximum is ${CONTENT_IMPORT_D1_BIND_BUDGET}`, "d1BindParameters");
}
function d1CorpusCountGuard(db, snapshot) {
	assertD1CorpusCountGuardBindBudget(snapshot);
	const checks = [
		sql`(SELECT COUNT(*) FROM content_type_definitions WHERE key IN (${sqlList$1(snapshot.mappedTypeKeys)}))=${snapshot.types.length}`,
		sql`(SELECT COUNT(*) FROM content_status_definitions)=${snapshot.statuses.length}`,
		sql`(SELECT COUNT(*) FROM content_entries WHERE type IN (${sqlList$1(snapshot.mappedTypeKeys)}))=${snapshot.entries.length}`
	];
	const definitionKeys = [...snapshot.mappedTypeKeys.map((value) => `type:${value}`), ...snapshot.statusKeys.map((value) => `status:${value}`)];
	if (definitionKeys.length) checks.push(sql`(SELECT COUNT(*) FROM content_definition_versions WHERE (definition_kind||':'||definition_key) IN (${sqlList$1(definitionKeys)}))=${snapshot.versions.length}`);
	if (snapshot.taxonomyKeys.length) checks.push(sql`(SELECT COUNT(*) FROM content_terms WHERE taxonomy IN (${sqlList$1(snapshot.taxonomyKeys)}))=${snapshot.terms.length}`);
	const entryIds = snapshot.entries.map((value) => String(plain(value, "corpus.entry").id));
	if (entryIds.length) checks.push(sql`(SELECT COUNT(*) FROM content_entry_terms WHERE entry_id IN (${sqlList$1(entryIds)}))=${snapshot.assignments.length}`, sql`(SELECT COUNT(*) FROM content_revisions WHERE entry_id IN (${sqlList$1(entryIds)}))=${snapshot.revisions.length}`);
	return db.prepare(sql`SELECT CASE WHEN ${sql.join(checks, sql` AND `)} THEN 1 ELSE json_extract('not-json','$') END AS ok`);
}
function d1ExactCorpusGuards(db, snapshot) {
	const items = [d1CorpusCountGuard(db, snapshot)], guard = (predicate) => {
		items.push(db.prepare(sql`SELECT CASE WHEN EXISTS (SELECT 1 WHERE ${predicate}) THEN 1 ELSE json_extract('not-json','$') END AS ok`));
	};
	for (const value of snapshot.types) {
		const row = plain(value, "corpus.type");
		guard(sql`EXISTS (SELECT 1 FROM content_type_definitions WHERE key=${String(row.key)} AND origin=${String(row.origin)} AND version=${Number(row.version)} AND active=${boolValue(row.active)} AND current_revision=${Number(row.currentRevision)} AND canonical_hash=${String(row.canonicalHash)} AND json(definition)=json(${JSON.stringify(row.definition)}) AND shadowed_db_version IS ${row.shadowedDbVersion === null ? null : Number(row.shadowedDbVersion)})`);
	}
	for (const value of snapshot.statuses) {
		const row = plain(value, "corpus.status");
		guard(sql`EXISTS (SELECT 1 FROM content_status_definitions WHERE key=${String(row.key)} AND origin=${String(row.origin)} AND version=${Number(row.version)} AND active=${boolValue(row.active)} AND current_revision=${Number(row.currentRevision)} AND canonical_hash=${String(row.canonicalHash)} AND json(definition)=json(${JSON.stringify(row.definition)}) AND shadowed_db_version IS ${row.shadowedDbVersion === null ? null : Number(row.shadowedDbVersion)})`);
	}
	for (const value of snapshot.versions) {
		const row = plain(value, "corpus.version");
		guard(sql`EXISTS (SELECT 1 FROM content_definition_versions WHERE definition_kind=${String(row.kind)} AND definition_key=${String(row.key)} AND revision=${Number(row.revision)} AND canonical_hash=${String(row.canonicalHash)} AND json(definition)=json(${JSON.stringify(row.definition)}) AND origin=${String(row.origin)} AND created_at=${String(row.createdAt)})`);
	}
	for (const value of snapshot.terms) {
		const row = plain(value, "corpus.term");
		guard(sql`EXISTS (SELECT 1 FROM content_terms WHERE id=${String(row.id)} AND taxonomy=${String(row.taxonomy)} AND slug=${String(row.slug)} AND name=${String(row.name)} AND parent_id IS ${row.parentId === null ? null : String(row.parentId)} AND depth=${Number(row.depth)} AND created_at=${String(row.createdAt)} AND host_session_id IS ${row.hostSessionId === null ? null : String(row.hostSessionId)})`);
	}
	for (const value of snapshot.entries) {
		const row = plain(value, "corpus.entry");
		guard(sql`EXISTS (SELECT 1 FROM content_entries WHERE id=${String(row.id)} AND slug=${String(row.slug)} AND type=${String(row.type)} AND title=${String(row.title)} AND body=${String(row.body)} AND status=${String(row.status)} AND visibility=${String(row.visibility)} AND published_at IS ${row.publishedAt === null ? null : String(row.publishedAt)} AND author=${String(row.author)} AND created_at=${String(row.createdAt)} AND updated_at=${String(row.updatedAt)} AND parent_id IS ${row.parentId === null ? null : String(row.parentId)} AND menu_order=${Number(row.menuOrder)} AND template_key IS ${row.templateKey === null ? null : String(row.templateKey)} AND excerpt=${String(row.excerpt)} AND featured_media IS ${row.featuredMedia === null ? null : JSON.stringify(row.featuredMedia)} AND comment_status=${String(row.commentStatus)} AND ping_status=${String(row.pingStatus)} AND sticky=${boolValue(row.sticky)} AND format IS ${row.format === null ? null : String(row.format)} AND deleted_at IS ${row.deletedAt === null ? null : String(row.deletedAt)} AND last_edited_by=${String(row.lastEditedBy)} AND type_definition_revision=${Number(row.typeDefinitionRevision)} AND status_definition_revision=${Number(row.statusDefinitionRevision)} AND host_session_id IS ${row.hostSessionId === null ? null : String(row.hostSessionId)})`);
	}
	for (const value of snapshot.assignments) {
		const row = plain(value, "corpus.assignment");
		guard(sql`EXISTS (SELECT 1 FROM content_entry_terms WHERE entry_id=${String(row.entryId)} AND term_id=${String(row.termId)})`);
	}
	for (const value of snapshot.revisions) {
		const row = plain(value, "corpus.revision");
		guard(sql`EXISTS (SELECT 1 FROM content_revisions WHERE id=${String(row.id)} AND entry_id=${String(row.entryId)} AND title=${String(row.title)} AND body=${String(row.body)} AND slug=${String(row.slug)} AND type=${String(row.type)} AND json(term_ids)=json(${JSON.stringify(row.termIds)}) AND ${row.snapshot === null ? sql`snapshot IS NULL` : sql`json(snapshot)=json(${JSON.stringify(row.snapshot)})`} AND editor=${String(row.editor)} AND created_at=${String(row.createdAt)} AND host_session_id IS ${row.hostSessionId === null ? null : String(row.hostSessionId)})`);
	}
	return Object.freeze(items);
}
var ContentExportError = class extends Error {
	code;
	detail;
	field;
	name = "ContentExportError";
	constructor(code, detail, field) {
		super(`content export ${code}: ${detail}${field ? ` (${field})` : ""}`);
		this.code = code;
		this.detail = detail;
		this.field = field;
	}
};
var fail = (code, detail, field) => {
	throw new ContentExportError(code, detail, field);
};
var TYPE_KEY = /^[a-z][a-z0-9_-]*$/;
function bounded(value, field, max) {
	if (typeof value !== "string") fail("validation", "must be a string", field);
	const normalized = value.trim();
	if (!normalized || normalized.length > max) fail("validation", `must contain 1..${max} characters`, field);
	return normalized;
}
function typeKey(value, field) {
	const normalized = bounded(value, field, 128);
	if (!TYPE_KEY.test(normalized)) fail("validation", "must be a normalized content type key", field);
	return normalized;
}
function positive(value, field) {
	const number = Number(value);
	if (!Number.isSafeInteger(number) || number < 1) fail("integrity", "must be a positive safe integer", field);
	return number;
}
function bool(value) {
	return value === true || value === 1 || value === "1";
}
function iso(value, field) {
	const date = value instanceof Date ? value : new Date(String(value));
	if (Number.isNaN(date.getTime())) fail("integrity", "must be a timestamp", field);
	return date.toISOString();
}
function parseJson(value, field) {
	if (typeof value !== "string") return value;
	try {
		return JSON.parse(value);
	} catch {
		fail("integrity", "contains invalid JSON", field);
	}
}
var FORBIDDEN = /(?:password|credential)/i;
function storage(value, field = "value", depth = 0) {
	if (depth > 32) fail("limit", "exceeds maximum nested depth", field);
	if (value === null || typeof value === "string" || typeof value === "boolean") return value;
	if (value instanceof Date) return value.toISOString();
	if (typeof value === "number") {
		if (!Number.isFinite(value)) fail("integrity", "contains non-finite number", field);
		return value;
	}
	if (Array.isArray(value)) return Object.freeze(value.map((item, index) => storage(item, `${field}.${index}`, depth + 1)));
	if (typeof value === "object") {
		const output = {};
		for (const [key, child] of Object.entries(value)) {
			if (FORBIDDEN.test(key)) fail("integrity", "contains forbidden password/credential material", `${field}.${key}`);
			if (child !== void 0) output[key] = storage(child, `${field}.${key}`, depth + 1);
		}
		return Object.freeze(output);
	}
	return fail("integrity", "contains unsupported value", field);
}
function rowsOf(value) {
	if (Array.isArray(value)) return value;
	const rows = value?.rows;
	if (Array.isArray(rows)) return rows;
	return fail("integrity", "database adapter returned invalid rows");
}
async function execute(tx, query) {
	return rowsOf(await tx.execute(query));
}
function sqlList(values) {
	return sql.join(values.map((value) => sql`${value}`), sql`, `);
}
function validateLimits(limits) {
	for (const [key, value] of Object.entries(limits)) if (!Number.isSafeInteger(value) || value < 1) fail("validation", "must be a positive safe integer", `limits.${key}`);
	if (limits.batchSize > 1e3) fail("validation", "batchSize must be <= 1000", "limits.batchSize");
}
function origin(value, field) {
	if (value === "code" || value === "db" || value === "import") return value;
	return fail("integrity", "invalid definition origin", field);
}
function resolvedType(row, version) {
	const definition = normalizeContentTypeDefinition(version ? parseJson(version.definition, "type.version.definition") : parseJson(row.definition, "type.definition"));
	return Object.freeze({
		...definition,
		active: bool(row.active),
		origin: (version ? origin(version.origin, "type.version.origin") : origin(row.origin, "type.origin")) === "code" ? "code" : "db",
		version: positive(row.version, "type.version"),
		revision: version ? positive(version.revision, "type.revision") : positive(row.currentRevision, "type.currentRevision"),
		canonicalHash: String(version?.canonicalHash ?? row.canonicalHash),
		...row.shadowedDbVersion === null ? {} : { shadowedDbVersion: positive(row.shadowedDbVersion, "type.shadowedDbVersion") }
	});
}
function resolvedStatus(row, version) {
	const definition = normalizeContentStatusDefinition(version ? parseJson(version.definition, "status.version.definition") : parseJson(row.definition, "status.definition"));
	return Object.freeze({
		...definition,
		active: bool(row.active),
		origin: (version ? origin(version.origin, "status.version.origin") : origin(row.origin, "status.origin")) === "code" ? "code" : "db",
		version: positive(row.version, "status.version"),
		revision: version ? positive(version.revision, "status.revision") : positive(row.currentRevision, "status.currentRevision"),
		canonicalHash: String(version?.canonicalHash ?? row.canonicalHash),
		...row.shadowedDbVersion === null ? {} : { shadowedDbVersion: positive(row.shadowedDbVersion, "status.shadowedDbVersion") }
	});
}
function definitionBundle(row, versions) {
	const currentDefinition = parseJson(row.definition, "definition.current"), items = [...versions].sort((a, b) => Number(a.revision) - Number(b.revision)).map((version) => storage({
		revision: positive(version.revision, "definition.version.revision"),
		canonicalHash: String(version.canonicalHash),
		definition: parseJson(version.definition, "definition.version.definition"),
		origin: origin(version.origin, "definition.version.origin"),
		createdAt: iso(version.createdAt, "definition.version.createdAt")
	}, "definition.version"));
	return storage({
		key: String(row.key),
		origin: origin(row.origin, "definition.origin"),
		version: positive(row.version, "definition.version"),
		revision: positive(row.currentRevision, "definition.currentRevision"),
		active: bool(row.active),
		canonicalHash: String(row.canonicalHash),
		definition: currentDefinition,
		versions: items
	}, "definition");
}
function stringArray(value, field) {
	const parsed = parseJson(value, field);
	if (!Array.isArray(parsed)) throw new ContentExportError("integrity", "must be an array", field);
	return Object.freeze(parsed.map((item, index) => bounded(item, `${field}.${index}`, 128)));
}
async function exportContent(tx, principal, input, deps) {
	assertActiveContentTransaction(tx);
	validateLimits(input.limits);
	if (typeof input.includeRevisions !== "boolean") fail("validation", "must be boolean", "includeRevisions");
	const requested = [...new Set(input.typeKeys.map((value, index) => typeKey(value, `typeKeys.${index}`)))].sort();
	if (requested.length === 0 || requested.length > input.limits.maxDefinitions) fail("limit", "typeKeys exceed export definition limit", "typeKeys");
	const typeRows = await execute(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM content_type_definitions WHERE key IN (${sqlList(requested)}) ORDER BY key`);
	if (typeRows.length !== requested.length) {
		const found = new Set(typeRows.map((row) => row.key));
		fail("not-found", `content type ${requested.find((key) => !found.has(key)) ?? "unknown"} is unavailable`, "typeKeys");
	}
	const currentTypes = new Map(typeRows.map((row) => [row.key, resolvedType(row)])), overridden = [];
	for (const key of requested) {
		const type = currentTypes.get(key);
		authorizeContentAction({
			principal,
			type,
			operation: "read"
		});
		if (type.canExport) continue;
		if (!input.overrideCanExport) fail("forbidden", `content type ${key} does not allow export`);
		authorizeContentAction({
			principal,
			type,
			operation: "manageType"
		});
		overridden.push(key);
	}
	let override;
	if (overridden.length) {
		const reason = bounded(input.overrideCanExport.reason, "overrideCanExport.reason", 512), operationId = bounded(input.overrideCanExport.operationId, "overrideCanExport.operationId", 256);
		override = Object.freeze({
			reason,
			operationId
		});
	}
	const entryRows = await execute(tx, sql`SELECT id,slug,type,title,body,status,visibility,published_at AS "publishedAt",author,created_at AS "createdAt",updated_at AS "updatedAt",parent_id AS "parentId",menu_order AS "menuOrder",template_key AS "templateKey",excerpt,featured_media AS "featuredMedia",comment_status AS "commentStatus",ping_status AS "pingStatus",sticky,format,deleted_at AS "deletedAt",last_edited_by AS "lastEditedBy",type_definition_revision AS "typeDefinitionRevision",status_definition_revision AS "statusDefinitionRevision",EXISTS (SELECT 1 FROM content_password_credentials c WHERE c.entry_id=content_entries.id) AS "passwordProtected" FROM content_entries WHERE type IN (${sqlList(requested)}) ORDER BY id`);
	if (entryRows.length > input.limits.maxEntries) fail("limit", "entries exceed export maxEntries");
	const typeVersionRows = await execute(tx, sql`SELECT definition_kind AS kind,definition_key AS key,revision,canonical_hash AS "canonicalHash",definition,origin,created_at AS "createdAt" FROM content_definition_versions WHERE definition_kind='type' AND definition_key IN (${sqlList(requested)}) ORDER BY definition_key,revision`);
	const typeVersionMap = new Map(typeVersionRows.map((row) => [`type:${row.key}:${Number(row.revision)}`, row]));
	for (const row of typeRows) if (!typeVersionMap.has(`type:${row.key}:${Number(row.currentRevision)}`)) fail("integrity", `current type ${row.key} has no immutable revision`);
	const referencedTypeDefinitions = [...typeRows.map((row) => normalizeContentTypeDefinition(parseJson(row.definition, "type.definition"))), ...typeVersionRows.map((row) => normalizeContentTypeDefinition(parseJson(row.definition, "type.version.definition")))];
	const explicitStatusKeys = referencedTypeDefinitions.flatMap((definition) => definition.statusKeys ?? []), statusKeys = [.../* @__PURE__ */ new Set([...explicitStatusKeys, ...entryRows.map((row) => row.status)])].sort();
	const taxonomyKeys = [...new Set(referencedTypeDefinitions.flatMap((definition) => definition.taxonomies))].sort();
	const statusRows = statusKeys.length ? await execute(tx, sql`SELECT key,origin,version,active,current_revision AS "currentRevision",canonical_hash AS "canonicalHash",definition,shadowed_db_version AS "shadowedDbVersion" FROM content_status_definitions WHERE key IN (${sqlList(statusKeys)}) ORDER BY key`) : [];
	if (statusRows.length !== statusKeys.length) fail("integrity", "selected corpus references an unavailable status");
	const currentStatuses = new Map(statusRows.map((row) => [row.key, row]));
	const statusVersionRows = statusKeys.length ? await execute(tx, sql`SELECT definition_kind AS kind,definition_key AS key,revision,canonical_hash AS "canonicalHash",definition,origin,created_at AS "createdAt" FROM content_definition_versions WHERE definition_kind='status' AND definition_key IN (${sqlList(statusKeys)}) ORDER BY definition_key,revision`) : [];
	const versionRows = Object.freeze([...typeVersionRows, ...statusVersionRows]), versionMap = new Map(versionRows.map((row) => [`${row.kind}:${row.key}:${Number(row.revision)}`, row]));
	for (const row of statusRows) if (!versionMap.has(`status:${row.key}:${Number(row.currentRevision)}`)) fail("integrity", `current status ${row.key} has no immutable revision`);
	for (const entry of entryRows) {
		const typeRow = typeRows.find((row) => row.key === entry.type), statusRow = currentStatuses.get(entry.status), typeVersion = versionMap.get(`type:${entry.type}:${Number(entry.typeDefinitionRevision)}`), statusVersion = versionMap.get(`status:${entry.status}:${Number(entry.statusDefinitionRevision)}`);
		if (!typeRow || !statusRow || !typeVersion || !statusVersion) throw new ContentExportError("integrity", `entry ${entry.id} has unresolved definition pins`);
		const type = resolvedType(typeRow, typeVersion), status = resolvedStatus(statusRow, statusVersion);
		authorizeContentAction({
			principal,
			type,
			operation: bool(entry.passwordProtected) ? "readProtected" : "read",
			entry: {
				id: entry.id,
				author: entry.author,
				status: entry.status,
				visibility: entry.visibility
			},
			status
		});
	}
	const entryIds = entryRows.map((row) => row.id), assignments = entryIds.length ? await execute(tx, sql`SELECT entry_id AS "entryId",term_id AS "termId" FROM content_entry_terms WHERE entry_id IN (${sqlList(entryIds)}) ORDER BY entry_id,term_id`) : [];
	const assignmentIds = [...new Set(assignments.map((row) => row.termId))];
	const termRows = taxonomyKeys.length ? await execute(tx, sql`SELECT id,taxonomy,slug,name,parent_id AS "parentId",depth,created_at AS "createdAt" FROM content_terms WHERE taxonomy IN (${sqlList(taxonomyKeys)}) ORDER BY taxonomy,depth,id`) : [];
	if (termRows.length > Math.max(input.limits.maxEntries * 10, input.limits.maxDefinitions)) fail("limit", "taxonomy terms exceed export limit");
	const termIds = new Set(termRows.map((row) => row.id));
	for (const id of assignmentIds) if (!termIds.has(id)) fail("integrity", `entry assignment references term ${id} outside selected type taxonomies`);
	const terms = Object.freeze(termRows.map((row) => storage({
		id: row.id,
		taxonomy: row.taxonomy,
		slug: row.slug,
		name: row.name,
		parentId: row.parentId,
		depth: Number(row.depth),
		createdAt: iso(row.createdAt, "term.createdAt")
	}, "term")));
	const taxonomies = Object.freeze(taxonomyKeys.map((key) => storage({
		key,
		version: "1"
	}, "taxonomy")));
	const assignmentMap = /* @__PURE__ */ new Map();
	for (const row of assignments) {
		const values = assignmentMap.get(row.entryId) ?? [];
		values.push(row.termId);
		assignmentMap.set(row.entryId, values);
	}
	const entries = Object.freeze(entryRows.map((row) => storage({
		id: row.id,
		slug: row.slug,
		type: row.type,
		title: row.title,
		body: row.body,
		status: row.status,
		visibility: row.visibility,
		publishedAt: row.publishedAt === null ? null : iso(row.publishedAt, "entry.publishedAt"),
		author: row.author,
		createdAt: iso(row.createdAt, "entry.createdAt"),
		updatedAt: iso(row.updatedAt, "entry.updatedAt"),
		parentId: row.parentId,
		menuOrder: Number(row.menuOrder),
		templateKey: row.templateKey,
		excerpt: row.excerpt,
		featuredMedia: row.featuredMedia === null ? null : storage(parseJson(row.featuredMedia, "entry.featuredMedia"), "entry.featuredMedia"),
		commentStatus: row.commentStatus,
		pingStatus: row.pingStatus,
		sticky: bool(row.sticky),
		format: row.format,
		deletedAt: row.deletedAt === null ? null : iso(row.deletedAt, "entry.deletedAt"),
		lastEditedBy: row.lastEditedBy,
		typeDefinitionRevision: Number(row.typeDefinitionRevision),
		statusDefinitionRevision: Number(row.statusDefinitionRevision),
		termIds: Object.freeze(assignmentMap.get(row.id) ?? [])
	}, "entry")));
	const revisions = [];
	if (input.includeRevisions && entryIds.length) {
		const rows = await execute(tx, sql`SELECT id,entry_id AS "entryId",seq,title,body,slug,type,term_ids AS "termIds",snapshot,editor,created_at AS "createdAt" FROM content_revisions WHERE entry_id IN (${sqlList(entryIds)}) ORDER BY entry_id,seq,id`);
		if (rows.length > input.limits.maxRevisions) fail("limit", "revisions exceed export maxRevisions");
		for (const row of rows) revisions.push(storage({
			id: row.id,
			entryId: row.entryId,
			seq: Number(row.seq),
			title: row.title,
			body: row.body,
			slug: row.slug,
			type: row.type,
			termIds: stringArray(row.termIds, "revision.termIds"),
			...row.snapshot === null ? {} : { snapshot: storage(parseJson(row.snapshot, "revision.snapshot"), "revision.snapshot") },
			editor: row.editor,
			createdAt: iso(row.createdAt, "revision.createdAt")
		}, "revision"));
	}
	const types = Object.freeze(typeRows.map((row) => definitionBundle(row, versionRows.filter((version) => version.kind === "type" && version.key === row.key))));
	const statuses = Object.freeze(statusRows.map((row) => definitionBundle(row, versionRows.filter((version) => version.kind === "status" && version.key === row.key))));
	if (types.length + statuses.length + taxonomies.length > input.limits.maxDefinitions) fail("limit", "export definitions exceed maxDefinitions");
	const bundle = Object.freeze({
		version: 1,
		generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
		types,
		statuses,
		taxonomies,
		terms,
		entries,
		revisions: Object.freeze(revisions)
	});
	if (new TextEncoder().encode(JSON.stringify(bundle)).byteLength > input.limits.maxBytes) fail("limit", "export bundle exceeds maxBytes");
	if (override) await deps.audit.recordOverride(tx, principal, Object.freeze(overridden.sort()), override);
	await canonicalContentMigrationHash(bundle);
	return bundle;
}
//#endregion
export { resolveContentTypes as A, prepareStartContentImportD1 as C, resolveContentRoute as D, publishContentImport as E, startContentImport as F, transitionContent as I, updateContentEntry as L, restoreContentRevision as M, resumeContentImport as N, resolveContentStatuses as O, rollbackContentImport as P, prepareStagedContentImportGuardD1 as S, previewContentTypeChange as T, planContentImport as _, contentBackupDestinationHash as a, prepareResumeContentImportD1 as b, createContentStatus as c, exportContent as d, generateContentSchema as f, parseContentImport as g, normalizeContentTypeDefinition as h, compileContentRoutes as i, restoreContentBackup as j, resolveContentTemplate as k, createContentType as l, normalizeContentStatusDefinition as m, applyContentTypeChange as n, contentModelForwardMigrationSql as o, getContentRevision as p, canonicalContentMigrationHash as r, createContentSearchProvider as s, applyContentStatusChange as t, createDbContentImportJournal as u, planContentModelMigration as v, previewContentStatusChange as w, prepareRollbackContentImportD1 as x, preparePublishContentImportD1 as y };
