import { Ct as ContentSchema, Et as FlatContentEntry, Jt as ContentStatus, Tt as ContentTransaction, Vt as ContentInput, en as ContentVisibility, sn as Sanitize, t as Actor, zt as ContentEntry } from "./authz-CFBezbW-.js";
import { SQL, SQLWrapper } from "drizzle-orm";
import { Querier, TransactionIdentity } from "@platform-modules/db";
//#region src/store.d.ts
type EntityRef = {
  id: string;
  slug: string;
  type: string;
};
type ContentAdapterKind = "d1" | "postgres";
/**
 * The final read seam used while the corpus is still in its flat table. Both
 * adapters expose the callback transaction's normalized `execute()` result;
 * no dialect-specific query builder or registry is allowed through this seam.
 */
interface ContentFlatCorpusReader {
  readonly adapter: ContentAdapterKind;
  execute<Row extends Record<string, unknown> = Record<string, unknown>>(query: SQLWrapper): Promise<readonly Row[]>;
}
type ContentStoreErrorCode = "invalid-flat-row" | "unsupported-adapter" | "transaction-capability";
/** Typed structural error for the final-store boundary. */
declare class ContentStoreContractError extends Error {
  readonly code: ContentStoreErrorCode;
  readonly detail: string;
  readonly field?: string | undefined;
  readonly name = "ContentStoreContractError";
  constructor(code: ContentStoreErrorCode, detail: string, field?: string | undefined);
}
declare function isContentStoreContractError(error: unknown): error is ContentStoreContractError;
/**
 * Reads the legacy flat corpus losslessly enough for cross-adapter comparison.
 * It validates only transport shape; arbitrary legacy type/status strings are
 * deliberately preserved until the registry-materialization migration.
 */
declare function readFlatContentEntries(reader: ContentFlatCorpusReader): Promise<readonly FlatContentEntry[]>;
/** Require the exact callback-minted identity before a composite caller acts. */
declare function assertContentTransactionIdentity(tx: ContentTransaction, expectedIdentity: TransactionIdentity): void;
type ListQuery = {
  type?: string;
  status?: ContentStatus;
  term?: string;
  includeDescendants?: boolean;
  limit?: number;
  offset?: number;
};
/**
 * Tenancy readiness seam (spec §4.4 / CLAUDE.md §5). NO-OP in the single-install public schema
 * (no scope column). The private SaaS supplies its own schema + a store variant that consumes
 * `scope`. Accepting it here keeps the public contract stable across that swap — no tenant_id leak.
 */
type StoreOpts = {
  scope?: string;
};
declare class ContentNotFoundError extends Error {
  readonly selector: string;
  readonly name = "ContentNotFoundError";
  constructor(selector: string);
}
/**
 * A duplicate (type, slug) hits content_entries_type_slug_uq. Surface it as a TYPED, contextful
 * boundary error (coding-standard §4) instead of leaking the raw Postgres error out of the seam.
 * DB-index-enforced + caught = race-safe (no pre-check TOCTOU).
 */
declare class ContentConflictError extends Error {
  readonly type: string;
  readonly slug: string;
  readonly name = "ContentConflictError";
  constructor(type: string, slug: string);
}
declare function list(db: Querier<ContentSchema>, query?: ListQuery, viewer?: Actor | null, _opts?: StoreOpts): Promise<ContentEntry[]>;
declare function getBySlug(db: Querier<ContentSchema>, type: string, slug: string, viewer?: Actor | null, _opts?: StoreOpts): Promise<ContentEntry | null>;
/**
 * Read a single entry by its stable primary-key id (peer of `getBySlug`; admin edit URLs key on id,
 * not the mutable slug). Applies the IDENTICAL viewer visibility predicate in SQL — an admin
 * (`canEditAny`) loads any status/visibility; a non-permitted viewer gets `null` with no
 * existence oracle (indistinguishable from absent). Read-authz floor enforced in-store, never delegated.
 */
declare function getById(db: Querier<ContentSchema>, id: string, viewer?: Actor | null, _opts?: StoreOpts): Promise<ContentEntry | null>;
/**
 * Fail-closed guard for the host-injected sanitizer (mirrors comments). A missing/non-function
 * `sanitize` throws BEFORE any DB access — a forgotten sanitizer never silently stores raw HTML.
 */
declare function assertSanitize(sanitize: unknown, verb: string): asserts sanitize is Sanitize;
/**
 * Create or update a content entry. The HTML `body` is sanitized on store (XSS hard floor):
 * `sanitize` is REQUIRED and applied to `body` on both the insert and update paths; the SANITIZED
 * value is persisted (no raw HTML retained). `title` is plain text and is NOT sanitized — the host
 * render-escapes it. The sanitizer ENGINE is host-owned (an allowlist sanitizer appropriate to the
 * host runtime — the adopter picks one that actually strips on their runtime); this module owns the
 * contract + enforcement, never the engine.
 */
declare function put(db: Querier<ContentSchema>, raw: ContentInput, actor: Actor, sanitize: unknown, _opts?: StoreOpts): Promise<ContentEntry>;
declare function setVisibility(db: Querier<ContentSchema>, id: string, visibility: ContentVisibility, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
declare function publish(db: Querier<ContentSchema>, id: string, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
declare function schedule(db: Querier<ContentSchema>, id: string, at: Date, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
/** System cron runner — promotes due scheduled entries to published. No actor; authz gated at schedule() time. */
declare function promoteScheduled(db: Querier<ContentSchema>, now?: Date): Promise<EntityRef[]>;
declare function unpublish(db: Querier<ContentSchema>, id: string, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
/**
 * Take-offline floor (U1b): trashing a live (published|scheduled) entry is a publication-status transition —
 * also requires `canPublish`. Non-live (draft|trashed) → `canModify` only.
 */
declare function trash(db: Querier<ContentSchema>, id: string, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
/**
 * Restores a TRASHED entry to draft (the inverse of `trash`). Prior status is intentionally not
 * persisted (no column) — restored content re-enters review and must be re-published by the admin.
 *
 * Scoped to `status='trashed'` ONLY: on a non-trashed entry this is a no-op that returns the entry's
 * ref unchanged. This keeps restore from being a publish-state bypass — `restore` must NOT be a path
 * for a `canModify`-but-not-`canPublish` actor to move a LIVE (published/scheduled) entry to draft
 * (that liveness transition is gated by `unpublish`/`assertCanPublish`). Idempotent: a second restore
 * sees `draft`, matches no row, and no-ops.
 */
declare function restore(db: Querier<ContentSchema>, id: string, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
/**
 * Take-offline floor (U1b): removing a live (published|scheduled) entry is a publication-status transition —
 * also requires `canPublish`. Non-live (draft|trashed) → `canModify` only.
 */
declare function remove(db: Querier<ContentSchema>, id: string, actor: Actor, _opts?: StoreOpts): Promise<EntityRef>;
/** Idempotent base DDL for content_entries — v0.0.1 shape only (visibility/search are separate migrations). */
declare const contentEntriesBaseMigrationSql: (table?: string) => string;
/** Additive, idempotent-guarded DDL for adopters migrating existing content_entries tables (spec §7). */
declare const contentVisibilityMigrationSql: (table?: string) => string;
//#endregion
export { restore as C, unpublish as D, trash as E, remove as S, setVisibility as T, list as _, ContentStoreContractError as a, put as b, ListQuery as c, assertSanitize as d, contentEntriesBaseMigrationSql as f, isContentStoreContractError as g, getBySlug as h, ContentNotFoundError as i, StoreOpts as l, getById as m, ContentConflictError as n, ContentStoreErrorCode as o, contentVisibilityMigrationSql as p, ContentFlatCorpusReader as r, EntityRef as s, ContentAdapterKind as t, assertContentTransactionIdentity as u, promoteScheduled as v, schedule as w, readFlatContentEntries as x, publish as y };