import type { PageSection, PostHeaderConfig, PostTemplate, SectionSettings } from './types.js';
/** Generate a unique section id (UUID when available, monotonic fallback). */
export declare function generateSectionId(): string;
/** Create a fresh section of the given type, seeded with registry defaults. */
export declare function createSection(type: string): PageSection;
/** Insert a section at `index` (defaults to the end). Returns a new array. */
export declare function addSection(sections: PageSection[], section: PageSection, index?: number): PageSection[];
export declare function removeSection(sections: PageSection[], id: string): PageSection[];
/** Duplicate a section (new id, "(Copy)" suffix), inserted right after the original. */
export declare function duplicateSection(sections: PageSection[], id: string): PageSection[];
export declare function toggleSectionVisibility(sections: PageSection[], id: string): PageSection[];
/** Explicitly set a section's visibility (used by the API toggle endpoint). */
export declare function setSectionVisibility(sections: PageSection[], id: string, visible: boolean): PageSection[];
/** Move the section with `id` to a new index (clamped). Returns a new array. */
export declare function moveSection(sections: PageSection[], id: string, toIndex: number): PageSection[];
/** Reorder to an explicit id order (used by drag-and-drop drop handlers). */
export declare function reorderSections(sections: PageSection[], orderedIds: string[]): PageSection[];
export declare function updateSectionContent(sections: PageSection[], id: string, patch: Record<string, unknown>): PageSection[];
export declare function updateSectionSettings(sections: PageSection[], id: string, patch: Partial<SectionSettings>): PageSection[];
export declare function updateSectionMeta(sections: PageSection[], id: string, patch: {
    name?: string;
    internalLabel?: string;
}): PageSection[];
/** How {@link coerceSections} handles an entry with an unregistered type. */
export type UnknownSectionStrategy = 'drop' | 'preserve' | 'error';
/** A section whose `sectionType` has no registered definition. */
export interface UnknownSectionRef {
    sectionType: string;
    /** original index in the input array */
    index: number;
}
/**
 * Thrown by {@link coerceSections} / {@link coerceSectionsWithReport} when
 * `onUnknown: 'error'` and the input contains unregistered section types.
 * Use it to block a publish/import rather than silently dropping content.
 */
export declare class UnknownSectionTypeError extends Error {
    readonly sectionTypes: string[];
    constructor(sectionTypes: string[]);
}
export interface CoerceSectionsOptions {
    /**
     * What to do with an entry whose `sectionType` has no registered definition
     * (neither a built-in nor a config-declared custom type):
     *  - `'drop'` (default): omit it. In development a single `console.warn`
     *    summarizes what was dropped so a forgotten `sections.types` registration
     *    is visible instead of silent.
     *  - `'preserve'`: keep it verbatim (content/settings/position intact),
     *    flagged `unmanaged: true`, so externally-managed sections (seed/code-
     *    owned, e.g. `opal-hero`) round-trip through read/save without data loss.
     *  - `'error'`: throw {@link UnknownSectionTypeError}. Use at a publish/import
     *    boundary to block rather than drop.
     */
    onUnknown?: UnknownSectionStrategy;
    /**
     * @deprecated Use `onUnknown: 'preserve'`. When `true` (and `onUnknown` is
     * unset) unknown entries are preserved as `unmanaged`.
     */
    preserveUnknown?: boolean;
    /**
     * Invoked once per dropped section (only in `'drop'` mode). Provide it to
     * record observability/telemetry; supplying it suppresses the default dev
     * `console.warn` since the caller is handling the signal.
     */
    onDrop?: (ref: UnknownSectionRef) => void;
}
export interface CoerceSectionsReport {
    /** the normalized, kept sections (managed + any preserved unmanaged) */
    sections: PageSection[];
    /** entries that were dropped because their type is unknown (`'drop'` mode) */
    dropped: UnknownSectionRef[];
    /** entries kept verbatim as `unmanaged` (`'preserve'` mode) */
    preserved: UnknownSectionRef[];
}
/**
 * Normalize arbitrary JSON into a clean `PageSection[]` and report what
 * happened to entries with an unknown `sectionType`. See
 * {@link CoerceSectionsOptions} for the unknown-type strategy.
 *
 * Used when reading `data.sections` from the DB and when accepting an AI/agent
 * payload that may be partially shaped.
 */
export declare function coerceSectionsWithReport(raw: unknown, opts?: CoerceSectionsOptions): CoerceSectionsReport;
/**
 * Normalize arbitrary JSON into a clean `PageSection[]`.
 *
 * Thin wrapper over {@link coerceSectionsWithReport} that returns just the
 * sections. Backfills missing ids/names and coerces visibility; unknown types
 * are dropped by default (with a dev warning) — pass `{ onUnknown: 'preserve' }`
 * at a persistence boundary to keep them as `unmanaged`, or `{ onUnknown:
 * 'error' }` to block.
 */
export declare function coerceSections(raw: unknown, opts?: CoerceSectionsOptions): PageSection[];
/**
 * Build a fully-formed section from a (possibly partial) AI/agent payload:
 * start from the registry defaults for `type`, then shallow-merge the
 * provided `content` / `settings` and apply an optional display name.
 * The returned section always has a fresh id + valid shape.
 */
export declare function buildSection(type: string, input?: {
    name?: string;
    internalLabel?: string;
    visible?: boolean;
    content?: Record<string, unknown>;
    settings?: Partial<SectionSettings>;
}): PageSection;
/**
 * Estimate reading time in whole minutes from a body of text. HTML tags are
 * stripped first (post bodies are stored as sanitized HTML) and the word
 * count is divided by an average adult reading speed of 200 wpm. Always
 * returns at least 1 so the header never shows "0 min read".
 *
 * Shared by the admin post header preview and the public site header so both
 * surfaces show the same figure.
 */
export declare function computeReadingTime(text: string | null | undefined): number;
/** Sensible default header layout for a brand-new post type template. */
export declare function defaultPostHeader(): PostHeaderConfig;
/**
 * Normalize arbitrary JSON into a clean {@link PostHeaderConfig}, falling
 * back to {@link defaultPostHeader} for any missing/invalid keys. Used when
 * reading a `post-templates` document or accepting an agent payload.
 */
export declare function coercePostHeader(raw: unknown): PostHeaderConfig;
/**
 * Build a default template for a post type: a centered header plus an
 * article body and a related-posts block — a usable starting point an
 * author or AI agent can then alter.
 */
export declare function createPostTemplate(postType: string): PostTemplate;
/** Normalize a raw `post-templates` document's data into a {@link PostTemplate}. */
export declare function coercePostTemplate(postType: string, raw: unknown): PostTemplate;
//# sourceMappingURL=helpers.d.ts.map