import * as FileManager from './fileManager';

export { FileManager };

/**
 * **`@emailmaker/emailmaker`** — public typings for bundler plugin integration (`init`, `Options`, `Instance`).
 *
 * **`ExportedApi`**: repeating `export declare namespace ExportedApi` blocks merge. The effective
 * **`ExportedApi.Options`** and **`ExportedApi.Instance`** types come from merging every **`interface Options` /
 * `interface Instance`** declaration in those blocks below.
 */

export type MayBePromise<T> = T | Promise<T>;
export type PromiseWrap<T> = Promise<Awaited<T>>;
export type RecursivePartial<T> = {
  [K in keyof T]?: T[K] extends number | string | boolean | bigint ? T[K] : RecursivePartial<T[K]>;
};
export type AppListener<Value, Result = void> = (value: Value) => MayBePromise<Result>;
/** Subscribe helper used for `handle*` APIs: call with a listener → returns unsubscribe `() => void`. */
export type AppEvent<Listener extends AppListener<any, any>> = (
  listener: Listener,
  priority?: number,
  thisArg?: any,
) => () => void;

export type SaveEventPayload<T> = {
  /** source of the event */
  source?: string;
  /** previous value */
  prev?: T;
  /** changed fields */
  patch: Partial<T>;
  /** next value */
  value: T;
};

export type CreateEventPayload<T> = {
  /** source of the event */
  source?: string;
  /** next value */
  value: T;
};

export type RemoveEventPayload<T> = {
  /** source of the event */
  source?: string;
  /** removed value */
  value: T;
};

export type MergeTagGroup = { type?: 'group'; label: string; value: string; children?: MergeTag[] };

export type MergeTagItem = { label: string; value: string };
export type MergeTag = MergeTagGroup | MergeTagItem;

export type SaveListener<T> = AppListener<SaveEventPayload<T>, T | undefined | void>;
export type SaveEvent<T> = AppEvent<SaveListener<T>>;
export type RemoveListener<T> = AppListener<RemoveEventPayload<T>>;
export type RemoveEvent<T> = AppEvent<RemoveListener<T>>;
export type CreateListener<T> = AppListener<CreateEventPayload<T>, T | undefined | void>;
export type CreateEvent<T> = AppEvent<CreateListener<T>>;

/** Result of AMP-aware parsing (`parseAMP`): regular HTML preview vs AMP MIME document. */
export interface ParsedAMP {
  /** Original or normalized markup string (depending on caller). */
  code: string;
  /** Plain HTML usable outside strict AMP tooling. */
  html: string;
  /** AMP HTML document fragment/content for AMP-compliant mailers. */
  ampHtml: string;
}

/** Single border side (`width` / `style` / `color`). */
export interface CommonStylesBorderSide {
  width?: number | null;
  style?: string | null;
  color?: string | null;
}

/** Border preset used by buttons, cards, etc. */
export interface CommonStylesBorder {
  all?: CommonStylesBorderSide | null;
  top?: CommonStylesBorderSide | null;
  right?: CommonStylesBorderSide | null;
  bottom?: CommonStylesBorderSide | null;
  left?: CommonStylesBorderSide | null;
}

export interface CommonStylesBorderRadius {
  all?: number | null;
  topLeft?: number | null;
  topRight?: number | null;
  bottomRight?: number | null;
  bottomLeft?: number | null;
}

export interface CommonStylesPadding {
  all?: number | null;
  top?: number | null;
  right?: number | null;
  bottom?: number | null;
  left?: number | null;
}

export interface CommonStylesText {
  fontFamily?: string[];
  fontSize?: number;
  fontSizeDim?: string;
  lineHeight?: number;
  lineHeightDim?: string;
  color?: string;
  contrastColor?: string;
  textAlign?: string;
  paddingBottom?: number;
  paddingBottomDim?: string;
}

export interface CommonStylesHeading extends CommonStylesText {
  paddingTop?: number;
  paddingTopDim?: string;
  letterSpacing?: number;
  letterSpacingDim?: string;
  bold?: boolean;
  italic?: boolean;
}

export interface CommonStylesLink {
  color?: string;
  contrastColor?: string;
  underline?: boolean;
}

export interface CommonStylesButton {
  fontFamily?: string[];
  fontSize?: number;
  fontSizeDim?: string;
  letterSpacing?: number;
  letterSpacingDim?: string;
  color?: string;
  contrastColor?: string;
  bold?: boolean;
  italic?: boolean;
  backgroundColor?: string;
  contrastBackgroundColor?: string;
  marginTop?: number;
  marginTopDim?: string;
  marginBottom?: number;
  marginBottomDim?: string;
  border?: CommonStylesBorder;
  borderRadius?: CommonStylesBorderRadius;
  textAlign?: string;
  padding?: CommonStylesPadding;
}

export interface CommonStylesBlock {
  backgroundColor?: string;
  contrastBackgroundColor?: string;
  padding?: CommonStylesPadding;
}

export interface CommonStylesCard {
  contrastBackgroundColor?: string;
  contrastTextColor?: string;
  baseBackgroundColor?: string;
  baseTextColor?: string;
  border?: CommonStylesBorder;
  borderRadius?: CommonStylesBorderRadius;
}

/**
 * Content appearance preset (`common_styles` / `init({ commonStyles })`).
 * Runtime accepts partial trees; they are deep-merged with {@link COMMON_STYLES}.
 */
export interface CommonStyles {
  text?: CommonStylesText;
  headings?: CommonStylesHeading;
  links?: CommonStylesLink;
  buttons?: CommonStylesButton;
  block?: CommonStylesBlock;
  cards?: CommonStylesCard;
}

export type Notify = {
  type?: 'success' | 'info' | 'error' | 'warning';
  message: string | HTMLElement;
  description?: string | HTMLElement;
  btn?: string | HTMLElement;
  onClose?: () => void;
  duration?: number | null;
  icon?: string | HTMLElement;
  placement?: 'top' | 'topLeft' | 'topRight' | 'bottom' | 'bottomLeft' | 'bottomRight';
  style?: any;
  className?: string;
  onClick?: () => void;
  closeIcon?: boolean | string | HTMLElement;
  props?: any;
  role?: 'alert' | 'status';
};

export type EmailDesc = { id?: string; title?: string; code?: string; subject?: string; preheader?: string };

export type BlockDesc = { id?: string; title?: string; code?: string };

export interface ISelection {
  selectionStartLineNumber: number;
  selectionStartColumn: number;
  positionLineNumber: number;
  positionColumn: number;
}
export interface ISingleModelEditStackData {
  afterCursorState: ISelection[];
  afterVersionId: number;
  beforeCursorState: ISelection[];
  beforeVersionId: number;
  changes: { oldPosition: number; oldText: string; newPosition: number; newText: string }[];
}

export interface IFrameErrorInfo {
  future: ISingleModelEditStackData[];
  past: ISingleModelEditStackData[];
  errorResolved: boolean;
  message: string;
  text: string;
  stack: string;
  userId: string;
  entityId: string;
  entityType: 'email' | 'block';
  sentryEventId: string;
}
export declare namespace Notify {
  type FM_Notifications<Notifications extends Record<string, any>> = {
    [Key in keyof Notifications as `FM_${Key & string}`]: Notifications[Key];
  };

  /**
   * Payload types for FM_* notification events.
   * Mirror of FileManager.Notify payloads so types are meaningful without resolving @emailmaker/filemanager.
   */
  namespace FM {
    export interface FileManageErrorInfo {
      message?: string;
      code?: string;
      status?: number;
      raw?: unknown;
      stack?: string;
    }
    export interface ItemContextPayload {
      itemIds?: string[];
      itemNames?: string[];
      folderId?: string | null;
      folderName?: string | null;
    }
    export interface SingleItemPayload {
      itemId?: string;
      itemName?: string;
      folderId?: string | null;
      folderName?: string | null;
    }
    export type UploadEventSource = 'upload' | 'uploadByUrl' | 'pixie' | 'iconStock' | 'imageStock' | 'gif';
    export interface OperationErrorDetail {
      itemId?: string;
      itemName?: string;
      error: FileManageErrorInfo;
    }
    export interface OperationErrorPayload extends ItemContextPayload {
      failCount: number;
      totalCount: number;
      errors?: OperationErrorDetail[];
      isTrashMove?: boolean;
      eventSource?: UploadEventSource;
    }
    export interface OperationSuccessPayload extends ItemContextPayload {
      successCount: number;
      totalCount: number;
      eventSource?: UploadEventSource;
    }
    export interface FolderOperationPayload extends ItemContextPayload {
      folderId?: string | null;
      folderName?: string;
      reason?: string;
      is_force_create?: boolean;
    }
    export interface RenameErrorPayload extends SingleItemPayload {
      error: FileManageErrorInfo;
    }
    export interface FileUploadPayload extends SingleItemPayload {
      uploadId?: string;
      eventSource?: UploadEventSource;
    }
    export interface FileUploadErrorPayload extends FileUploadPayload {
      error?: FileManageErrorInfo;
    }
    export interface UnsupportedFileTypePayload extends FileUploadErrorPayload {
      fileType: string;
    }
    export interface FileUrlValidationErrorPayload {
      url?: string | null;
      error: FileManageErrorInfo;
    }
    export interface ImageFilePayload extends SingleItemPayload {
      thumbnail?: string | null;
    }
    export interface UrlUploadPayload {
      url?: string | null;
      folderId?: string | null;
      folderName?: string | null;
      eventSource?: UploadEventSource;
    }
    export interface UrlUploadErrorPayload extends UrlUploadPayload {
      error: FileManageErrorInfo;
    }
    export interface FetchFilesErrorPayload {
      params?: { folderId?: string; search?: string; page?: number; limit?: number; sortBy?: string; sortOrder?: string; itemType?: string };
    }
    export interface AIImageGenerationBasePayload {
      request: string;
      taskId?: string | null;
    }
    export interface AIImageGenerationStartedPayload extends AIImageGenerationBasePayload {
      response?: unknown;
    }
    export interface AIImageGenerationSuccessPayload extends AIImageGenerationBasePayload {
      images: string[];
    }
    export interface AIImageGenerationFailedPayload extends AIImageGenerationBasePayload {
      response?: unknown;
      error?: FileManageErrorInfo;
    }
  }

  //
  // ─────────────────────────────────────────────────────────────
  //  Base event types
  // ─────────────────────────────────────────────────────────────
  //

  /**
   * Generic base type for an event entry.
   * Used internally to generate unions from the map interfaces.
   */
  type EventBase<TId extends string, TData> = {
    id: TId;
    data: TData;
    innerException?: unknown;
  };

  /**
   * Default empty message.
   * Required for backward compatibility with legacy handlers
   * that may emit events without an id.
   */
  interface EmptyMessage {
    id?: '';
    data?: any;
    innerException?: unknown;
  }

  /**
   * Error map defines all possible error event identifiers
   * and their associated payload types.
   *
   * This interface is augmentable — new keys can be added
   * from other modules using `declare namespace Notify { interface ErrorMap { ... } }`.
   */
  interface ErrorMap {
    EMAIL_CREATING_ERROR: EmailDesc;
    EMAIL_EDITING_ERROR: EmailDesc;
    FOLDER_CREATE_ERROR: string;
    EMAIL_CLONING_ERROR: EmailDesc;
    TAG_CREATING_ERROR: string;
    EMAIL_ACCESS_TO_LOCKED_ERROR: EmailDesc;
    EMAIL_TOO_MANY_TAGS_ERROR: EmailDesc;
    BLOCK_GET_ERROR: {};
    BLOCK_ACCESS_TO_LOCKED_ERROR: BlockDesc;
    BLOCK_TOO_MANY_TAGS_ERROR: BlockDesc;
    BLOCK_CLONING_ERROR: BlockDesc;
    AI_IMAGE_SEND_ERROR: any;
    AI_IMAGE_GET_ERROR: any;
    IMAGE_UPLOAD_WRONG_FORMAT: File;
    IMAGE_UPLOAD_ERROR: File;
    BLOCK_CREATING_ERROR: BlockDesc;
    BLOCK_EDITING_ERROR: BlockDesc;
    EMAIL_AUTOSAVE_ERROR: ExportedApi.EmailRevision;
    EMAIL_INIT_EVENT_ERROR: EmailDesc;
    SAVE_BUTTON_CLICK_EVENT_ERROR: EmailDesc;
    NEXT_BUTTON_CLICK_EVENT_ERROR: EmailDesc;
    BLOCK_REMOVING_ERROR: BlockDesc;
    IFRAME_ERROR: IFrameErrorInfo;
    GET_LOCALE_ERROR: any;
    GET_LOCALES_ERROR: any;
  }

  /**
   * FM_* error ids from FileManager (mapped when resolved).
   * Fallback list below ensures NotifyEvent.id includes FM_* when @emailmaker/filemanager is not resolved (e.g. on CI/Uni).
   */
  type FMErrorMap = FM_Notifications<FileManager.Notify.ErrorMap>;

  /** Payloads use Notify.FM.* types; mirrors FileManager.Notify when package is not resolved. */
  interface FMErrorMapFallback {
    FM_FILE_DELETE_ERROR: FM.OperationErrorPayload;
    FM_FILE_MOVE_ERROR: FM.OperationErrorPayload;
    FM_FILE_COPY_ERROR: FM.OperationErrorPayload;
    FM_FILES_DELETE_ERROR: FM.OperationErrorPayload;
    FM_FOLDER_DELETE_ERROR: FM.OperationErrorPayload;
    FM_FILES_UPLOAD_BATCH_FAILED: FM.OperationErrorPayload;
    FM_FILES_MOVE_ERROR: FM.OperationErrorPayload;
    FM_FILES_COPY_ERROR: FM.OperationErrorPayload;
    FM_FILE_DOWNLOAD_FAILED: FM.ImageFilePayload;
    FM_IMAGE_DOWNLOAD_FAILED: FM.ImageFilePayload;
    FM_IMAGE_SAVE_FAILED: FM.ImageFilePayload;
    FM_EDITOR_INIT_FAILED: undefined;
    FM_AI_RESPONSE_INVALID: unknown;
    FM_AI_IMAGE_GENERATION_FAILED: FM.AIImageGenerationFailedPayload;
    FM_AI_IMAGE_GENERATION_LIMIT_EXCEEDED: undefined;
    FM_FILES_FETCH_FAILED: FM.FetchFilesErrorPayload;
    FM_FILE_RENAME_DISABLED_BY_CONFIG: FM.SingleItemPayload;
    FM_FILE_RENAME_FAILED: FM.RenameErrorPayload;
    FM_FOLDER_RENAME_DISABLED_BY_CONFIG: FM.SingleItemPayload;
    FM_FOLDER_RENAME_FAILED: FM.RenameErrorPayload;
    FM_ITEM_RENAME_FAILED: FM.RenameErrorPayload;
    FM_FILE_UPLOAD_ITEM_FAILED: FM.FileUploadErrorPayload;
    FM_FILES_UPLOAD_URL_VALIDATION_FAILED: FM.UrlUploadPayload;
    FM_FILES_UPLOAD_URL_NOT_SUPPORTED: FM.UrlUploadPayload;
    FM_FILES_UPLOAD_BY_URL_FAILED: FM.UrlUploadErrorPayload;
    FM_FILES_UPLOAD_PROVIDER_NOT_CONFIGURED: FM.FolderOperationPayload;
    FM_FILES_MOVE_DIRECTORY_NOT_SELECTED: undefined;
    FM_FILES_COPY_DIRECTORY_NOT_SELECTED: undefined;
    FM_FOLDERS_FETCH_FAILED: FM.FolderOperationPayload;
    FM_FOLDER_ALREADY_EXISTS: FM.FolderOperationPayload;
    FM_FOLDER_ALREADY_EXISTS_COPY: FM.FolderOperationPayload;
    FM_FOLDER_ALREADY_EXISTS_MOVE: FM.FolderOperationPayload;
    FM_FOLDER_CREATE_PROVIDER_NOT_CONFIGURED: FM.FolderOperationPayload;
    FM_FOLDER_CREATE_FAILED: FM.FolderOperationPayload;
    FM_FOLDER_CHILDREN_COUNT_FAILED: FM.FolderOperationPayload;
    FM_FOLDER_CHILDREN_FETCH_FAILED: FM.FolderOperationPayload;
    FM_FILE_URL_VALIDATION_FAILED: FM.FileUrlValidationErrorPayload;
    FM_TRASH_CLEAR_FAILED: FM.OperationErrorPayload;
    FM_TRASH_CLEAR_ERROR: undefined;
  }

  /** FM_* keys from Fallback so they are always in NotifyEvent.id (CI/Uni); when FileManager resolves, FMErrorMap augments payload types via declaration merging in consuming code. */
  interface ErrorMap extends FMErrorMapFallback {}

  /**
   * Union of all possible error event types.
   * Includes both the mapped error IDs and the empty message variant.
   */
  type Error =
    | EmptyMessage
    | {
      [K in keyof ErrorMap]: EventBase<K, ErrorMap[K]>;
    }[keyof ErrorMap];

  /** Full error event with the discriminating `type` field. */
  type ErrorEvent = { type: 'error' } & Error;

  interface SuccessMap {
    EMAIL_TITLE_UPDATED_FROM_AI: string;
    EMAIL_PREHEADER_UPDATED_FROM_AI: string;
    TEXT_COPIED_TO_CLIPBOARD: string;
    EMAIL_SAVING_SUCCESS: EmailDesc;
    AI_IMAGE_SEND_SUCCESS: any;
    IMAGE_UPLOAD_SUCCESS: File;
    BLOCK_CREATING_SUCCESS: BlockDesc;
    BLOCK_EDITING_SUCCESS: BlockDesc;
    EMAIL_AUTOSAVE_SUCCESS: ExportedApi.EmailRevision;
    BLOCK_CLONING_SUCCESS: BlockDesc;
    BLOCK_REMOVING_SUCCESS: BlockDesc;
  }

  type FMSuccessMap = FM_Notifications<FileManager.Notify.SuccessMap>;

  /**
   * Fallback: FM_* success ids when @emailmaker/filemanager is not resolved at build time.
   */
  interface FMSuccessMapFallback {
    FM_FILE_DELETE_SUCCESS: FM.OperationSuccessPayload;
    FM_FILE_MOVE_SUCCESS: FM.OperationSuccessPayload;
    FM_FILE_COPY_SUCCESS: FM.OperationSuccessPayload;
    FM_FILES_DELETE_SUCCESS: FM.OperationSuccessPayload;
    FM_FILES_MOVE_SUCCESS: FM.OperationSuccessPayload;
    FM_FILES_COPY_SUCCESS: FM.OperationSuccessPayload;
    FM_FOLDER_DELETE_SUCCESS: FM.OperationSuccessPayload;
    FM_FILES_UPLOAD_BATCH_SUCCESS: FM.OperationSuccessPayload;
    FM_AI_IMAGE_GENERATION_STARTED: FM.AIImageGenerationStartedPayload;
    FM_AI_IMAGE_GENERERATION_SUCCESS: FM.AIImageGenerationSuccessPayload;
    FM_IMAGE_UPDATE_SUCCESS: FM.ImageFilePayload;
    FM_FILE_RENAME_SUCCESS: FM.SingleItemPayload;
    FM_FOLDER_RENAME_SUCCESS: FM.SingleItemPayload;
    FM_FOLDER_CREATE_SUCCESS: FM.FolderOperationPayload;
    FM_FILE_UPLOAD_ITEM_SUCCESS: FM.FileUploadPayload;
    FM_TRASH_CLEARED_SUCCESS: undefined;
    FM_FOLDER_NOT_FOUND_NAVIGATE: undefined;
  }

  interface SuccessMap extends FMSuccessMapFallback {}

  type Success =
    | EmptyMessage
    | {
      [K in keyof SuccessMap]: EventBase<K, SuccessMap[K]>;
    }[keyof SuccessMap];

  type SuccessEvent = { type: 'success' } & Success;

  interface WarningMap {
    COPY_NOT_SAVED_BLOCK: ExportedApi.Block;
    EMAIL_TITLE_UPDATED: string;
  }

  type FMWarningMap = FM_Notifications<FileManager.Notify.WarningMap>;

  /**
   * Fallback: FM_* warning ids when @emailmaker/filemanager is not resolved at build time.
   */
  interface FMWarningMapFallback {
    FM_FILES_UPLOAD_UNSUPPORTED_TYPE: FM.UnsupportedFileTypePayload;
    FM_FOLDER_OPERATION_VALIDATION_FAILED: FM.FolderOperationPayload;
    FM_TRASH_CLEARED_PARTIAL: FM.OperationErrorPayload;
  }

  interface WarningMap extends FMWarningMapFallback {}

  type Warning =
    | EmptyMessage
    | {
      [K in keyof WarningMap]: EventBase<K, WarningMap[K]>;
    }[keyof WarningMap];

  type WarningEvent = { type: 'warning' } & Warning;

  /**
   * Info events map — currently empty.
   * Can be freely extended from other modules.
   */
  interface InfoMap {
    // Example for future extension:
    // USER_LOGGED_IN: { userId: string; timestamp: number };
  }

  type FMInfoMap = FM_Notifications<FileManager.Notify.InfoMap>;

  interface InfoMap extends FMInfoMap { }

  type Info =
    | EmptyMessage
    | {
      [K in keyof InfoMap]: EventBase<K, InfoMap[K]>;
    }[keyof InfoMap];

  type InfoEvent = { type: 'info' } & Info;
}

export type NotifyEvent = Notify.SuccessEvent | Notify.ErrorEvent | Notify.WarningEvent | Notify.InfoEvent;

export declare namespace ExportedApi {
  interface Block {
    meta?: Record<string, unknown>;
    /**
     * Date of publication of the record (according to the time zone of the site).
     * @format date-time
     */
    date?: string | null;
    /**
     * Date of publication of the record, GMT.
     * @format date-time
     */
    date_gmt?: string | null;

    /** The unique identifier of the record. */
    id?: string;
    /**
     * The URL of the record.
     * @format uri
     */

    modified?: string;
    /**
     * The date the record was last modified (in GMT format).
     * @format date-time
     */
    modified_gmt?: string;
    /** The name of the entry. */
    title?: string;
    /** ID of the author of the entry. */
    author?: string;
    /** An excerpt of the recording. */
    excerpt?: string;

    subject?: string;
    description?: string;
    code?: string;
    project?: string | number;
    related_email?: string;
    type?: string;
    /** Глобальный блок (ACF): при сохранении в HTML добавляется em-block-id */
    global_block?: boolean;
  }
}
export declare namespace ExportedApi {
  interface BlockRevision {
    /** ID of the editorial board author. */
    author?: string | number;
    /**
     * The date of publication of the record, according to the time zone of the site.
     * @format date-time
     */
    date?: string;
    /**
     * The time of publication of the editorial office, GMT.
     * @format date-time
     */
    date_gmt?: string;
    /** The global unique identifier of the record. */
    guid?: {
      /** GUID to write in the form in which it exists in the database. */
      raw?: string;
      /** The GUID for the record, converted for display. */
      rendered?: string;
    };
    /** Unique identifier of the editorial office. */
    id?: string;
    /**
     * The date of the last revision, according to the time zone of the site.
     * @format date-time
     */
    modified?: string;
    /**
     * Date of the last revision, GMT.
     * @format date-time
     */
    modified_gmt?: string;
    /** ID of the editorial parent. */
    parent?: string;
    /** The alphanumeric identifier of the record is unique for its type. */
    slug?: string;
    /** The name of the entry. */
    title?: string;
    /** An excerpt of the recording. */
    excerpt?: string;
    /**
     * Link to preview the recording.
     * @format uri
     */
    preview_link?: string;

    code?: string;
  }
}
export declare namespace ExportedApi {
  enum CodeErrorSeverity {
    Hint = 1,
    Info = 2,
    Warning = 4,
    Error = 8,
  }

  enum CodeErrorTag {
    Unnecessary = 1,
    Deprecated = 2,
  }

  /** Single validation/diagnostic marker for embedded HTML/email code (line/column spans). */
  interface CodeError {
    severity: CodeErrorSeverity;
    message: string;
    source?: string;
    startLineNumber: number;
    startColumn: number;
    endLineNumber: number;
    endColumn: number;
    startOffset: number;
    endOffset: number;
    tags?: CodeErrorTag[];
  }
}

export declare namespace ExportedApi {
  interface Comment {
    /** Unique identifier for the comment. */
    id?: string;
    /** User object ID, if the author is a user. */
    author?: string;
    /**
     * The email address of the author of the comment.
     * @format email
     */
    author_email?: string;
    /**
     * The IP address of the comment author.
     * @format ip
     */
    author_ip?: string;
    /** The display name of the comment author. */
    author_name?: string;
    /**
     * URL for the author of the comment.
     * @format uri
     */
    author_url?: string;
    /** Value of the User-Agent of the comment author. */
    author_user_agent?: string;
    /** The content of the comment. */
    content?: string;
    /**
     * Date of publication of the comment (according to the time zone of the site).
     * @format date-time
     */
    date?: string;
    /**
     * The time of publication of the comment, GMT.
     * @format date-time
     */
    date_gmt?: string;
    /**
     * ID of the associated record object.
     * @default 0
     */
    post?: string;
    /** Comment status. */
    status?: string;
    /** Comment type. */
    type?: string;
    /** URL of the comment author's avatar image. */
    author_avatar_urls?: {
      /**
       * URL avatars with an image size of 24 pixels.
       * @format uri
       */
      '24'?: string;
      /**
       * URL avatars with an image size of 48 pixels.
       * @format uri
       */
      '48'?: string;
      /**
       * URL avatars with an image size of 96 pixels.
       * @format uri
       */
      '96'?: string;
    };
    /** Meta fields. */
    meta?: object;
    target_id?: string;

    parent?: string;
  }
}
export declare namespace ExportedApi {
  /** Monaco (code editor) options passed through the email editor chrome. */
  type EditorOptions = {
    fontSize?: number;
    fontFamily?: string;
    tabSize?: number;
    wordWrap?: boolean;
    minimap?: boolean;
    insertSpaces?: boolean;
  };
}
export declare namespace ExportedApi {
  interface Email {
    meta?: Record<string, unknown>;
    /**
     * Date of publication of the record, GMT.
     * @format date-time
     */
    date_gmt?: string | null;
    /** Unique identifier of the record. */
    id?: string;
    /** The name of the letter. */
    title?: string;
    /** Preheader of the letter. */
    preheader?: string;
    /** ID of the author of the entry. */
    author?: string;
    lock?: boolean;
    subject?: string;
    description?: string;
    code?: string;
    project?: string | number;
    // email tag names
    tags?: string[];
    utm_parameters?: {
      utm_source?: string;
      utm_medium?: string;
      utm_campaign?: string;
      utm_term?: string;
      utm_content?: string;
    };
    parent_email?: string;
    common_styles?: string;
  }

  interface CompiledEmail extends Email {
    readonly compiled: { html: string; ampHtml: string; text: string };
  }
}
export declare namespace ExportedApi {
  interface EmailRevision {
    /** ID of the editorial board author. */
    author?: string;
    /**
     * The date of publication of the record, according to the time zone of the site.
     * @format date-time
     */
    date?: string;
    /**
     * The time of publication of the editorial office, GMT.
     * @format date-time
     */
    date_gmt?: string;
    /** Unique identifier of the editorial office. */
    id?: string;
    /**
     * The date of the last revision, according to the time zone of the site.
     * @format date-time
     */
    modified?: string;
    /**
     * Date of the last revision, GMT.
     * @format date-time
     */
    modified_gmt?: string;
    /** ID of the editorial parent. */
    parent?: string;
    /** The name of the entry. */
    title?: string;
    /** An excerpt of the recording. */
    excerpt?: string;

    code?: string;

    preheader?: string;

    subject?: string;

    common_styles?: string;
  }

  interface CompiledEmailRevision extends EmailRevision {
    readonly compiled: { html: string; ampHtml: string };
  }
}
export declare namespace ExportedApi {
  /** Opaque palette/typography blob for a theme id; keep **`any`** until a public theme schema is exported. */
  export type ThemeConfig = any;
}
export declare namespace ExportedApi {
  export type CodeModeDirection = 'none' | 'left' | 'right' | 'bottom';
  export type Locale = 'en_US' | 'ru_RU';
  export type ConfigMods = 'pro' | 'editor' | 'simple' | 'freeUserBlocks';

  /** Declared merge-tag delimiters (**`syntax`**) and hierarchical items for picker UI. */
  export interface MergeTagsInfo {
    syntax: string[];
    items: MergeTag[];
  }

  type LimitName = 'AiImgCount' | 'AiChatCount' | 'AiGeneratorCount' | 'OptimizationCount';

  type LocaleListener = AppListener<string, string>;
  type LimitListener = AppListener<{ name: LimitName; count: number }>;
  type TraslatePayload = { input: string; locale?: string };
  type TraslateListener = AppListener<TraslatePayload, string>;

  /** Named alternate configs (e.g. per-mode overrides) passed into `config.advancedConfigs`. */
  interface AdvancedConfigs {
    [key: string]: Config;
  }

  /** Usage counters returned to the host for quota / billing UI (**`handleLimitUsage`**). */
  interface Counters {
    /** Optimization analyzer runs consumed in the current billing period. */
    optimization_counter: number;
    /** AI chat / completion requests consumed. */
    ai_counter: number;
    /** AI image generations consumed. */
    ai_img_counter: number;
    /** Long-form AI generator completions consumed. */
    ai_generator_limit: number;
  }

  /** Quota ceilings paired with **`counters`** for limit messaging. */
  interface Limits {
    /** Max optimization runs per period (`undefined`/`0` = unlimited). */
    optimization_limit: number;
    /** AI chat / completion cap per period. */
    ai_limit: number;
    /** AI image generations cap per period. */
    ai_img_limit: number;
    /** AI long-form generator cap per period. */
    ai_generator_limit: number;
  }

  /**
   * Full editor chrome: themes, toolbox visibility, export actions, palette blocks, and image-center behavior.
   * Pass via **`init({ config })`**; after **`init`**, use **`instance.setConfig`** / **`updateConfig`** (**`Partial<Config>`**).
   */
  interface Config {
    /** Application mode */
    mode?: ConfigMods;

    /** Counters and limits */
    counters?: Counters;
    limits?: Limits;
    /** billing page url */
    billingPageUrl?: string;

    /** External URL opened for “image info” / metadata tooling (toolbar integration). */
    imageInfoToolUrl?: string;
    /** Injected stylesheet bundle key or URL resolving to editor-scope CSS for the iframe. */
    styles: string;
    /** Registered theme preset id consumed by **`themes`**. */
    theme: string;
    /** Registered theme presets (colors, densities) keyed by id; **`theme`** selects the active one. */
    themes: { [P in string]: ThemeConfig };
    /** showing the back arrow */
    headerArrowBackVisible: boolean;
    /** display of the Subject field */
    headerTitleVisible: boolean;
    /** showing the Preheader field */
    headerPreheaderVisible: boolean;
    /** showing breadcrumbs in an iframe */
    pathEnabled: boolean;
    /** showing copy-paste of a block in an iframe */
    copyPasteEnabled: boolean;
    /** showing the Version History button */
    historyEnabled: boolean;
    /** showing the Code-mode button */
    codeEnabled: boolean;
    /** showing the Code-mode button in the mode when there is a desktop/mobile switch */
    codeSideEnabled: boolean;
    /** showing the Preview button */
    previewIconEnabled: boolean;
    /** Preview link */
    previewModeEnabled: boolean;
    /** showing the Test button in the mailers */
    livePreviewEnabled: boolean;
    /** showing the Send Test button */
    sendTestEnabled: boolean;
    /** showing the Share button */
    sharePreviewEnabled: boolean;
    /** displaying the message menu */
    emailDropdownMenuEnabled: boolean;
    /** showing the Clone item in the message menu */
    emailDropdownMenuClone: boolean;
    /** showing the Import item in the emails menu */
    emailDropdownMenuImport: boolean;
    /** showing the Import item in the emails menu like button */
    emailDropdownMenuImportButton: boolean;
    /** showing the Block item in the message menu */
    emailDropdownMenuLock: boolean;
    /** showing the Delete item in the message menu */
    emailDropdownMenuRemove: boolean;
    /** showing the Export button */
    emailExportEnabled: boolean;
    /** showing a secondary button */
    nextButtonEnabled: boolean;
    /** text of the secondary button */
    nextButtonText: string;
    /** showing the main button */
    saveButtonEnabled: boolean;
    /** text of the main button */
    saveButtonText: string;
    /** Primary / command row of actions (extended toolbar cluster). */
    commandButtonsEnabled?: boolean;
    /** displaying the email ID */
    emailIdShow: boolean;
    /** side panel view */
    sidePanelFloating: boolean;
    /** mode switching bar */
    desktopMobileSwitchRule: boolean;
    /** mode switching panel */
    desktopMobileSwitchPanel: boolean;
    /** showing the block save button */
    saveBlockEnabled: boolean;
    /** «Global block» switch in Save block modal; default false in bundled configs — set true in plugin/init to enable */
    globalBlockCheckboxEnabled: boolean;
    /** showing the image change button */
    editImageControlEnabled: boolean;
    /** ability to collapse the sidebar */
    toggleSidePanel: boolean;

    /** Sidebar location */
    menuDirection: string;

    /** default setting of the opening tab (""/"common"/"empty") */
    defaultBuildPanel: string;

    /** Comments panel / thread in sidebar. */
    commentsEnabled: boolean;
    /** Optimization checklist / recommendations in sidebar. */
    optimizeEnabled: boolean;
    /** Global settings panel in sidebar. */
    settingsEnabled: boolean;
    /** UTM parameters section in sidebar. */
    UTMEnabled: boolean;
    /** Subject line field in sidebar. */
    subjectEnabled: boolean;
    /** Preheader field in sidebar. */
    preheaderEnabled: boolean;
    /** Description / meta description field in sidebar. */
    descriptionEnabled: boolean;
    /** Tags field in sidebar. */
    tagsEnabled: boolean;
    /** showing the mobile properties switch */
    switchDesktopMobilePropsEnabled: boolean;
    /** showing transition buttons to other elements */
    stepToOtherElementEnabled: boolean;
    /** showing the delete element button */
    deleteButtonEnabled: boolean;
    /** showing the Title field in the form of an image */
    formFieldImageTitleEnabled: boolean;
    /** showing border change fields */
    formFieldBorderEnabled: boolean;
    /** showing the rounding change fields */
    formFieldBorderRadiusEnabled: boolean;
    /** showing shadow change fields */
    formFieldBoxShadowEnabled: boolean;
    /** showing buttons to change the visibility of an element */
    formFieldVisibilityEnabled: boolean;
    /** showing the export to picture switch */
    formFieldExportAsPictureEnabled: boolean;

    /** showing the button to insert an image into the button text */
    formButtonFieldInsertImageEnabled: boolean;
    /** showing vertical alignment buttons */
    formButtonFieldVerticalAlignEnabled: boolean;
    /** showing text alignment buttons */
    formButtonFieldTextAlignEnabled: boolean;
    /** showing background image fields */
    formButtonFieldBackgroundImageEnabled: boolean;
    /** showing internal margins */
    formButtonFieldPaddingsEnabled: boolean;
    /** showing replacer button */
    formButtonFieldReplacerEnabled: boolean;

    /** showing vertical alignment buttons */
    formCellFieldVerticalAlignEnabled: boolean;
    /** showing background image fields */
    formCellFieldBackgroundImageEnabled: boolean;
    /** showing internal margins */
    formCellFieldPaddingsEnabled: boolean;
    /** showing sizes */
    formCellFieldSizeEnabled: boolean;
    /** showing the button to insert an image into the button text */
    formLinkFieldInsertImageEnabled: boolean;
    /** showing background image fields */
    formTableFieldBackgroundImageEnabled: boolean;
    /** showing background image fields */
    formDivFieldBackgroundImageEnabled: boolean;
    /** showing background image fields */
    formEmailFieldBackgroundImageEnabled: boolean;
    /** showing vertical alignment buttons */
    formImageFieldVerticalAlignEnabled: boolean;
    /** showing replacer button */
    formImageFieldReplacerEnabled: boolean;
    /** showing height field */
    formImageFieldHeightEnabled: boolean;
    /** showing typograf button */
    formTextFieldTypografEnabled: boolean;
    /** showing replacer button */
    formTextFieldReplacerEnabled: boolean;

    /** Enables revision / version history service (autosave revisions UI). */
    revisionService: boolean;

    /** Image block — show in palette. */
    elementImageEnabled: boolean;
    /** Text block — show in palette. */
    elementTextEnabled: boolean;
    /** Heading block — show in palette. */
    elementHeaderEnabled: boolean;
    /** Button block — show in palette. */
    elementButtonEnabled: boolean;
    /** Bullet list — show in palette. */
    elementListULEnabled: boolean;
    /** Numbered list — show in palette. */
    elementListOLEnabled: boolean;
    /** Divider block — show in palette. */
    elementDividerEnabled: boolean;
    /** Spacer block — show in palette. */
    elementSpacerEnabled: boolean;
    /** Social icons block — show in palette. */
    elementSocialEnabled: boolean;
    /** Table block — show in palette. */
    elementTableEnabled: boolean;
    /** Countdown/timer block — show in palette. */
    elementCountdownEnabled: boolean;
    /** Video block — show in palette. */
    elementVideoEnabled: boolean;
    /** AI image block — show in palette. */
    elementAIimageEnabled: boolean;
    /** AI text block — show in palette. */
    elementAItextEnabled: boolean;
    /** Carousel block — show in palette. */
    elementCarouselEnabled: boolean;
    /** Form block — show in palette. */
    elementFormEnabled: boolean;
    /** Accordion block — show in palette. */
    elementAccordionEnabled: boolean;

    /** If `true`, Image Center uses file-manager style UI; if `false`, simpler inline image flow. */
    imageCenterFileManagerView: boolean;

    /** Local “upload from computer” entry in Image Center. */
    imageCenterLocalUploadEnabled: boolean;

    /** Stock photo tab in Image Center / file manager. */
    imageCenterStockEnabled: boolean;
    /** GIF / animated stock tab in Image Center. */
    imageCenterGifEnabled: boolean;
    /** Icon stock (e.g. Streamline) tab; `false` hides like other optional stock tabs. */
    imageCenterIconStockEnabled: boolean;
    /** Built-in image crop / edit step in Image Center. */
    imageCenterEditorEnabled: boolean;
    /** Max upload size for compression path (bytes; typical default ~5 MiB in product). */
    compressMaxSize: number;
    /** Longest edge cap when resizing images for compression (pixels). */
    compressMaxWidthOrHeight: number;

    /** Monaco options for HTML/code editing surface. */
    editor: EditorOptions;

    /** UI locale (`en_US` / `ru_RU`). */
    locale: Locale;

    /** Placement of the code-mode panel relative to the canvas (`none` hides code split). */
    codeModeDirection: CodeModeDirection;

    /** When `true`, suppresses analytics/telemetry payloads to EmailMaker services (privacy / air-gapped). */
    preventSendDataToEM?: boolean;

    /** Merge-tag syntax and tree for the merge-tag picker. */
    mergeTags?: MergeTagsInfo;

    /** Toolbar / sidebar button that opens merge-tag picker (independent from **`mergeTags`** data presence). */
    mergeTagsShow?: boolean;

    /** Preset addresses for “send test email” quick-pick (UI convenience). */
    testEmails?: string[];

    /** Sidebar UI switch for alternate/simple configuration layout (persisted runtime key **`configSwither`**). */
    configSwither?: boolean;
    /** Idle delay (ms) before autosave drafts / revisions fire; `undefined`/`0` may disable interval autosave. */
    autosaveTimeout?: number;
    /** Per-plugin or per-mode overlays (see **`AdvancedConfigs`**). */
    advancedConfigs?: AdvancedConfigs;
    /** Forces code-only tooling on narrow/mobile breakpoints (minimal visual toolbar). */
    onlyCodeModeInMobile?: boolean;

    /** Enables GTM/event hooks for outbound integration (product-specific). */
    pushToGTM?: boolean;
    /** Top application header strip (brand, breadcrumbs host). */
    headerShow?: boolean;
    /** Public “web version” / hosted preview link tooling. */
    webversionEnabled?: boolean;
    /** Shared / global stylesheet editor for reused block styles across email. */
    commonStylesEnabled?: boolean;
    /** Responsive breakpoints / fluid layout controls inside the preview. */
    emailResponsiveControlEnabled?: boolean;
    /** show export to text */
    exportTextEnabled?: boolean;
    /** show export to HTML */
    exportHtmlEnabled?: boolean;
    /** show export to ZIP */
    exportZipEnabled?: boolean;
    /** show export to buffer */
    exportClipboardEnabled?: boolean;
    /** show export to webhook */
    exportWebHookEnabled?: boolean;
    /** show export to Outlook */
    exportOutlookEnabled?: boolean;
    /** show export to PDF */
    exportPdfEnabled?: boolean;
    /** show export to PNG */
    exportPngEnabled?: boolean;
    /** Sidebar “AI assistant” entry (persisted runtime key **`aiAssistentEnabled`**). */
    aiAssistentEnabled?: boolean;
    /** link check display */
    optimizeLinksEnabled?: boolean;
    /** picture check display */
    optimizeImagesEnabled?: boolean;
    /** SpamAssassin check display */
    optimizeSpamAssassinEnabled?: boolean;
    /** code check display */
    optimizeCheckCodeEnabled?: boolean;
    /** Exposes explicit “template” metadata vs one-off campaign fields. */
    isTemplateEnabled?: boolean;
    /** block menu display */
    blocksSectionsShow?: boolean;
    /** empty blocks display */
    blocksEmptyEnabled?: boolean;
    /** display of saved blocks */
    blocksSavedEnabled?: boolean;
    /** common blocks display */
    blocksCommonEnabled?: boolean;
    /** template blocks display */
    blocksTemplateEnabled?: boolean;
    /** block search display */
    blocksSearchEnabled?: boolean;
    /** showing the panel for adding a block in the visual editor */
    blocksAddPanelEnabled?: boolean;
    /** Read-only templates: forbid structure edits beyond allowed regions. */
    lockEditor?: boolean;
    /** Disables editing of preheader / title chrome when integrated with locking flows. */
    lockPreheaderAndTitle?: boolean;
    /** Collapses or hides the main side navigation strip. */
    disableSideMenu?: boolean;
    /** Showing a drop-down card with a path to the picture */
    imagePathDropdownEnabled?: boolean;

    /** Showing change visibility buttons in amp emails */
    formFieldAmpVisibilityEnabled?: boolean;
    /** Disable double click on next button  */
    disableDoubleClickNextButton?: boolean;
    /** manually change state of next button  */
    activeNextButton?: boolean;
    /** icons stroke width  */
    iconStrokeWidth: number;
    /** custom icons as SVG strings */
    icons?: Record<string, string>;
  }

  export interface User {
    id?: string | number;
    /** User's display name */
    name?: string;
    /** The user's email address. @format email */
    email?: string;
  }

  namespace AppConfigMixin {
    interface Options {
      config?: Partial<Config>;
      advancedConfigs?: AdvancedConfigs;
      project?: string | number;
      user?: User;
      handleReadLocale?: LocaleListener;
      handleLimitUsage?: LimitListener;
      handleTranslate?: TraslateListener;
      /**
       * Default content styles for previews and block insertion when the email has no `common_styles` of its own.
       * If omitted, the build's COMMON_STYLES preset is used (TS constants).
       * To clear an override stored in the plugin store: `reset({ ..., commonStyles: undefined })` or `updateConfig({ commonStyles: undefined })`.
       * Partial objects are deep-merged at runtime with {@link COMMON_STYLES}. Saved email `common_styles` from the server override these defaults when present.
       */
      commonStyles?: RecursivePartial<CommonStyles>;
    }

    interface Instance {
      setConfig(config: Partial<Config> & { commonStyles?: RecursivePartial<CommonStyles> }): Promise<void>;
      getConfig(): Partial<Config>;
      updateConfig(config: Partial<Config> & { commonStyles?: RecursivePartial<CommonStyles> }): Promise<void>;
      handleReadLocale: AppEvent<LocaleListener>;
      handleLimitUsage?: AppEvent<LimitListener>;
      handleTranslate: AppEvent<TraslateListener>;
    }
  }
  interface Options extends AppConfigMixin.Options { }

  interface Instance extends AppConfigMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace AppInitMixin {
    interface Options {
      /** base url of the app server */
      baseUrl?: string;
    }

    interface Instance { }
  }
  interface Options extends AppInitMixin.Options { }

  interface Instance extends AppInitMixin.Instance { }
}

export declare namespace ExportedApi {
  export type JWTAuthOptions = { email: string; password: string; remember?: boolean };

  type JWTOptions = {
    /** JWT authorization credentials */
    jwtAuth?: JWTAuthOptions;
  };
  namespace JWTMixin {
    interface Options extends JWTOptions { }

    interface Instance { }
  }
  interface Options extends JWTMixin.Options { }

  interface Instance extends JWTMixin.Instance { }
}
export declare namespace ExportedApi {
  type OAuthCallback = (user?: User, project?: string | number, prevToken?: string) => MayBePromise<string>;

  type OAuthOptions = {
    /**
     * Get token callback
     */
    getAuthToken?: OAuthCallback;
  };
  namespace OAuthMixin {
    interface Options extends OAuthOptions {
      user?: User;
      project?: string | number;
    }

    interface Instance { }
  }
  interface Options extends OAuthMixin.Options { }

  interface Instance extends OAuthMixin.Instance { }
}

export declare namespace ExportedApi {
  interface CoreOptions {
    element?: string | Element | DocumentFragment;
    handleChunkLoaded?: () => void;
  }
  namespace CoreMixin {
    interface Options extends CoreOptions { }

    interface Instance {
      getElement(): Element | DocumentFragment | undefined;
    }
  }
  interface Options extends CoreMixin.Options { }

  interface Instance extends CoreMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace DataMixin {
    type BlockShowOptions = {
      /** block content */
      block: Block | string;
      /** autosaves */
      revisions?: BlockRevision[];
      /** comments */
      comments?: Comment[];
      /** blocks */
      blocks?: Block[];
      /** template identifier for email */
      templateId?: string | number;
    };

    type EmailShowOptions = {
      /** email content */
      email: Email | string;
      /** autosaves */
      autosaves?: EmailRevision[];
      /** comments */
      comments?: Comment[];
      /** blocks */
      blocks?: Block[];
      /** template identifier for block */
      templateId?: number;
    };

    type Content = string | Email | EmailShowOptions;

    type ReadEmailHandler = (id: string) => MayBePromise<Email>;
    type ReadEmailAutosavesHandler = (emailId: string) => MayBePromise<EmailRevision[]>;
    type ReadBlocksHandler = (project: string) => MayBePromise<Block[]>;
    type ReadTemplateBlocksHandler = (block: { emailId: string; project: string }) => MayBePromise<Block[]>;
    type ReadCommentsHandler = (emailId: string) => MayBePromise<Comment[]>;

    type EmailHandler = AppListener<Email>;
    type HtmlHandler = AppListener<string>;

    type TestEmailSendEventPayload = {
      project?: string;
      email_id?: string;
      subject?: string;
      email?: string;
      code?: string;
      from_name?: string;
    };

    type TestEmailSendHandler = AppListener<TestEmailSendEventPayload, false | void>;

    type TestEmailModalSendHandler = AppListener<Email, false | void>;

    type LivePreviewHandler = AppListener<{ project?: string; id: string; subject?: string; html: string }>;

    type ShareHandler = AppListener<{ project?: string; id: string }>;

    type PreviewHandler = AppListener<{ project?: string; id: string }>;

    type ValidateEvent = AppListener<CodeError[]>;

    interface Events {
      /** read email handler */
      handleReadEmail: AppEvent<ReadEmailHandler>;
      /** fires when email saved */
      handleSaveEmail: SaveEvent<Email>;
      /** fires when email delete */
      handleRemoveEmail: RemoveEvent<Email>;

      /**  read autosaves handler */
      handleReadEmailRevisions: AppEvent<ReadEmailAutosavesHandler>;
      /** fires when email autosave */
      handleEmailAutosave: CreateEvent<EmailRevision>;
      /** fires when email autosave delete */
      handleRemoveEmailAutoSave: RemoveEvent<EmailRevision>;
      /** read common blocks handler */
      handleReadCommonBlocks: AppEvent<ReadBlocksHandler>;
      /** read template blocks handler */
      handleReadTemplateBlocks: AppEvent<ReadTemplateBlocksHandler>;
      /** read blocks handler */
      handleReadBlocks: AppEvent<ReadBlocksHandler>;
      /** fires when block save */
      handleSaveBlock: SaveEvent<Block>;
      /** fires when block delete */
      handleRemoveBlock: RemoveEvent<Block>;

      /** read comments handler */
      handleReadComments: AppEvent<ReadCommentsHandler>;
      /** fires when comment save */
      handleSaveComment: SaveEvent<Comment>;
      /** fires when comment delete */
      handleRemoveComment: RemoveEvent<Comment>;

      /** fires when user clicked on 'save' button */
      handleSaveButtonClick: AppEvent<EmailHandler>;
      /** fires when user clicked on 'next' button */
      handleNextButtonClick: AppEvent<EmailHandler>;
      /** fires when user clicked on 'previous' button */
      handlePreviousButtonClick: AppEvent<EmailHandler>;
      /** fires when email iframe inited */
      handleEmailInit: AppEvent<EmailHandler>;
      /** fires when email changed */
      handleEmailChanged: AppEvent<EmailHandler>;
      /** fires when email subject inited */
      handleSubjectChanged: (
        listener: (subject: string) => MayBePromise<void>,
        priority?: number,
        thisArg?: any,
      ) => () => void;
      /** fires when email subject inited */
      handlePreheaderChanged: (
        listener: (preheader: string) => MayBePromise<void>,
        priority?: number,
        thisArg?: any,
      ) => () => void;
      /** fires when email Html changed */
      handleHtmlChanged: AppEvent<HtmlHandler>;
      /** fires when test email send*/
      handleTestEmailSend: AppEvent<TestEmailSendHandler>;
      /** fires when open test email modal */
      handleTestEmailModal: AppEvent<TestEmailModalSendHandler>;
      /** fires when email clone */
      handleCloneEmail: AppEvent<EmailHandler>;
      /** fires when email share */
      handleShareEmail: AppEvent<ShareHandler>;
      /** fires when open live preview */
      handleLivePreviewEmail: AppEvent<LivePreviewHandler>;
      /** fires when open preview */
      handlePreviewEmail: AppEvent<PreviewHandler>;
      /** fires when email validate */
      handleValidate: AppEvent<ValidateEvent>;
    }

    type Listeners = { [K in keyof Events]?: Events[K] extends AppEvent<infer Listener> ? Listener : never };
    interface Options extends Listeners {
      /** entity content */
      content: Content;
    }

    interface Instance extends Events {
      /**
       * show block or email
       * @param content entity content
       */
      show(content: Content): Promise<void>;
      /** save current  email */
      save(): Promise<Email>;
      /**
       * get email from inner storage
       */
      getEmail(): Promise<CompiledEmail>;
      /**
       * merge meta into current email
       */
      setEmailMeta(meta?: Record<string, unknown>): void;
      /** merge meta into a block in the blocks cache */
      setBlockMeta(blockId: string, meta?: Record<string, unknown>): void;
      /**
       * get compiled email
       */
      compileEmail(email?: Email, all?: boolean | { text?: boolean; amp?: boolean }): Promise<CompiledEmail>;
      /**
       * get blocks from inner storage
       */
      getBlocks(): Promise<Block[]>;
      /**
       * get email satosaves
       * @param emailId email identifier
       */
      getEmailRevisions(): Promise<EmailRevision[]>;
      /**
       * get email comments
       */
      getComments(): Promise<Comment[]>;
      /**
       * get current code errors
       */
      getCodeErrors(): CodeError[] | undefined;
    }
  }
  interface Options extends DataMixin.Options {
    standaloneKey?: string;
  }

  interface Instance extends DataMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace DestroyableMixin {
    type DestroyListener = AppListener<ExportedApi.Instance>;
    interface Options {
      handleDestroy?: DestroyListener;
    }

    interface Instance {
      /** fires when app destroyed */
      handleDestroy: AppEvent<DestroyListener>;
      destroy(): void;
    }
  }
  interface Options extends DestroyableMixin.Options { }

  interface Instance extends DestroyableMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace SpinMixin {
    interface Options {
      element?: string | Element | DocumentFragment;
      initialSpinner?: false;
    }

    interface Instance { }
  }
  interface Options extends SpinMixin.Options { }

  interface Instance extends SpinMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace ImageHandlerMixin {
    type LoadEventPayload = { file: File; project: string };
    type FileProxyEventPayload = { url: string; project: string };
    type LoadImageListener = AppListener<LoadEventPayload, string | void>;
    type FileProxyListener = AppListener<FileProxyEventPayload, Blob | void>;
    type ProxyUrlListener = AppListener<FileProxyEventPayload, string | void>;
    interface Options {
      handleLoadImage?: LoadImageListener;
      handleFileProxy?: FileProxyListener;
      handleUrlProxy?: ProxyUrlListener;
    }

    interface Instance {
      /** fires when image loading */
      handleLoadImage: AppEvent<LoadImageListener>;
      handleFileProxy: AppEvent<FileProxyListener>;
      handleUrlProxy: AppEvent<ProxyUrlListener>;
    }
  }
  interface Options extends ImageHandlerMixin.Options { }

  interface Instance extends ImageHandlerMixin.Instance { }
}
export declare namespace ExportedApi {
  namespace LoadHandlerMixin {
    type LoadListener = AppListener<ExportedApi.Instance>;
    interface Options {
      handleLoad?: LoadListener;
    }

    interface Instance {
      /** fires when app loaded */
      handleLoad: AppEvent<LoadListener>;
      reset(options: ExportedApi.Options): Promise<ExportedApi.Instance>;
    }
  }
  interface Options extends LoadHandlerMixin.Options { }

  interface Instance extends LoadHandlerMixin.Instance { }
}
export declare namespace ExportedApi {
  type ConfigNotify = Notify & Partial<NotifyEvent> & { message: string | HTMLElement };
  namespace NotificationMixin {
    type NotifyListener = (e: NotifyEvent) => MayBePromise<ConfigNotify | string | false | void>;
    type ErrorListener = (e: Notify.ErrorEvent) => MayBePromise<ConfigNotify | string | false | void>;
    type SuccessListener = (e: Notify.SuccessEvent) => MayBePromise<ConfigNotify | string | false | void>;
    interface Options {
      handleNotify?: NotifyListener;
      handleError?: ErrorListener;
      handleSuccess?: SuccessListener;
    }

    interface Instance {
      handleNotify: AppEvent<NotifyListener>;
      handleError: AppEvent<ErrorListener>;
      handleSuccess: AppEvent<SuccessListener>;
      notify(config: ConfigNotify | string): void;
    }
  }
  interface Options extends NotificationMixin.Options { }

  interface Instance extends NotificationMixin.Instance { }
}

export interface EditStackData {
  serialize(): ArrayBuffer;
}

export interface EditStackSnapshot {
  resource: string;
  elements: unknown[];
}

export interface IUndoRedoService {
  /**
   * Undoes the last performed action, reverting the state to the previous step in history.
   * If the history is empty, this method does nothing.
   */
  undo: () => void;

  /**
   * Redoes an undone action, moving the state forward in history.
   * If there are no undone actions, this method does nothing.
   */
  redo: () => void;

  /**
   * Clears the entire history of changes, including both undone and redone operations.
   * After calling this method, both the `undo` and `redo` histories will be empty.
   */
  clear: () => void;

  /**
   * Returns an array of all previously performed changes that can be undone.
   * This represents the stack of actions available for `undo()`.
   * @returns An array of `EditStackData` objects representing past changes.
   */
  getPast: () => EditStackData[];

  /**
   * Returns an array of changes that have been undone and can be redone.
   * This represents the stack of actions available for `redo()`.
   * @returns An array of `EditStackData` objects representing future changes.
   */
  getFuture: () => EditStackData[];

  /**
   * Checks whether there is at least one action in history that can be undone.
   * @returns `true` if `undo()` can be performed, otherwise `false`.
   */
  canUndo: () => boolean;

  /**
   * Checks whether there is at least one undone action that can be redone.
   * @returns `true` if `redo()` can be performed, otherwise `false`.
   */
  canRedo: () => boolean;

  /**
   * Creates a snapshot of the current state, which can be saved and restored later.
   * Useful for serializing the change history.
   * @returns An `EditStackSnapshot` object containing the state of the change history.
   */
  createSnapshot: () => EditStackSnapshot;

  /**
   * Restores the change history state from the provided snapshot.
   * Allows loading a previously saved history.
   * @param snapshot An `EditStackSnapshot` object containing the saved history state.
   */
  restoreSnapshot: (snapshot: EditStackSnapshot) => void;
}

/**
 * Represents the result of a single operation within a batch request.
 *
 * @template T - The type of data returned by successful operations. Use `void` for operations
 *               that don't return data (e.g., delete operations).
 *
 * @example
 * // For a successful file copy operation
 * const result: OperationResult<FileInfo> = {
 *   id: 'file123',
 *   success: true,
 *   data: { id: 'file123-copy', name: 'file.txt', ... }
 * };
 *
 * @example
 * // For a failed operation
 * const result: OperationResult<void> = {
 *   id: 'file456',
 *   success: false,
 *   error: 'Permission denied'
 * };
 */
export interface OperationResult<T = void> {
  /**
   * Unique identifier of the item that was processed.
   * This should match the ID of the original item from the request.
   */
  requestId?: string;

  /**
   * Indicates whether the operation completed successfully.
   */
  success?: boolean;

  /**
   * The result data returned by successful operations.
   * Present only when `success` is `true` and the operation returns data.
   */
  data?: T;

  /**
   * Error.
   * Present only when `success` is `false`.
   */
  error?: FileManagerApiErrorInfo;
}

export interface FileManagerApiErrorInfo {
  message?: string;
  code?: string | number;
  status?: number;
  raw?: any;
  stack?: string;
}

export type BatchResult<T> = { success: boolean; error?: FileManagerApiErrorInfo; detailed?: OperationResult<T>[] };

/**
 * File information.
 */
export interface FileSystemItem {
  /** Unique file identifier */
  id: string;
  /** File name */
  name: string;
  /** Identifier of the folder the file belongs to */
  folderId: string;
  /** Item type - file or folder */
  isFolder?: boolean;
  /** File size */
  size?: number;
  /** File creation or upload date */
  date?: string;
  /** File MIME type */
  type?: string;
  /** File download URL (used if `getFile` method is not implemented) */
  url?: string;
  /** File thumbnail */
  thumbnail?: string;
  /** Alternative thumbnail URL */
  thumbnailUrl?: string;
  /** Image dimensions (width x height) */
  dimensions?: string;
  /** Aspect ratio */
  aspectRatio?: string;
  /** File extension */
  extension?: string;
  /** Whether the file is selected in the UI */
  selected?: boolean;
  /** Date when the file was last edited */
  lastEdited?: string;
  /** Number of children items (for folders) */
  childrenCount?: number;
}

/**
 * Represents partial updates to a file system item after an operation.
 * Contains only the fields that were changed during the operation.
 */
export type FileSystemItemUpdate = Partial<FileSystemItem> & { id: string };

/**
 * Options for {@link StorageProvider.getFileData} when loading file bytes (blob).
 */
export interface GetFileDataOptions {
  /**
   * When `true`, bypass the HTTP cache (`fetch` with `cache: 'no-store'`).
   * When `false`, allow normal browser caching.
   * When omitted, normal browser caching is used unless a caller applies a one-shot bypass after overwrite.
   */
  forceReload?: boolean;
}

/**
 * API response with pagination details.
 */
export interface ApiPaginationResponse {
  /** Current page number */
  page: number;
  /** Number of items per page */
  limit: number;
  /** Total number of items */
  total: number;
  /** Total number of pages */
  totalPages: number;
  /** Whether there is a next page */
  hasNext: boolean;
  /** Whether there is a previous page */
  hasPrev: boolean;
}

/**
 * Sorting state.
 */
export interface SortState {
  /** Field to sort by */
  sortBy: 'name' | 'size' | 'date' | 'type';
  /** Sort order */
  sortOrder: 'asc' | 'desc';
}

export interface StorageProviderController {
  /**
   * Invalidates the cache for a specific file system item.
   *
   * This method should be called when an item's data has changed externally
   * and the cached version is no longer valid. After invalidation, the next
   * access to this item will trigger a fresh fetch from the storage backend.
   *
   * @param itemId - The unique identifier of the file or folder to invalidate
   * @example
   * // After renaming a file, invalidate its cache
   * controller.invalidateItemCache(fileId);
   */
  invalidateItemCache(itemId: string): void;

  /**
   * Retrieves a cached file system item.
   *
   * @param itemId - The unique identifier of the file or folder
   * @returns The cached item or undefined if not found in cache
   */
  getCachedItem(itemId: string): FileSystemItem | undefined;
}

export interface UploadFileItemInput {
  /**
   * Arbitrary identifier used to match an upload result with this item.
   * If not provided, the result is matched by the order of items.
   */
  requestId?: string;

  /** File name. */
  name: string;

  /** File size in bytes. */
  size: number;

  /** MIME type of the file. */
  type: string;

  /** Target folder ID, or null if not applicable. */
  folderId?: string | null;

  /** File data as a Blob or File. */
  data: Blob | File;

  /** Optional file extension. */
  extension?: string;
}

export interface UploadFilesRequest {
  /**
   * List of files to upload. The order of items matters — if `requestId`
   * is omitted, results are matched to items by index.
   */
  items: UploadFileItemInput[];

  /** Target folder ID for batch upload, or null. */
  folderId?: string | null;
}

/**
 * Interface for storage providers.
 * Defines the contract for different storage backends (e.g., cloud APIs).
 */
export interface StorageProvider {
  /**
   * @default false
   * Client-side check for existing files or folders
   */
  validateDuplicates?: boolean;
  /**
   * Use the path as an identifier for folders
   */
  pathMode?: boolean;

  /**
   * Custom identifier for the root folder.
   * - This ID will be used internally for the root of the file tree.
   * - Defaults to an empty string `''` if not provided.
   */
  rootId?: string;

  /**
   * Path to the trash/recycle bin folder.
   * - Used when `useSoftDelete` is enabled or for trash operations.
   * - The provider will resolve this path to an actual folder ID.
   */
  trashPath?: string;

  /**
   * Path to the temporary folder for uploads and transient files.
   * - Used for operations where temporary storage is needed.
   * - The provider will resolve this path to an actual folder ID.
   */
  tempPath?: string;
  /**
   * @default true
   */
  ensureFolderTrailingSlash?: boolean;

  /**
   * Utility method for finding system files/folders by path.
   * By default, searches for folders through getFiles method.
   *
   * @param path - Path to the file or folder
   * @returns The found item or undefined if not found
   */
  findItemByPath?(path: string): MayBePromise<FileSystemItem | undefined>;

  /**
   * Clear cache for the specified folder path.
   * @param pathFolder - Path to folder inside project
   */
  clearCache?(pathFolder?: string | null): MayBePromise<void>;

  /**
   * Sets the controller for cache management.
   *
   * This method provides the storage provider with a controller interface
   * that allows it to communicate cache invalidation requests back to the file manager.
   *
   * @param controller - The controller instance for cache management
   * @example
   * // Store the controller for later use
   * setController(controller) {
   *   this.controller = controller;
   * }
   */
  setController?(controller: StorageProviderController): MayBePromise<void>;

  /**
   * Enables client-side soft delete implementation.
   * When enabled, delete operations will move items to trashPath instead of permanent deletion.
   *
   * @note If your backend already implements soft delete, keep this disabled
   * to avoid double soft-delete logic.
   *
   * @default false
   */
  useSoftDelete?: boolean;
  /**
   * Retrieve the file content as a binary blob.
   *
   * ⚠️ If this method is not implemented, the file will be downloaded
   * using the `url` property from the `FileInfo` object.
   *
   * @param file - File object
   * @param options - See {@link GetFileDataOptions}
   * @returns File contents as a Blob
   */
  getFileData?: (file: FileSystemItem, options?: GetFileDataOptions) => MayBePromise<Blob>;

  /**
   * Get URL for file access
   * @param file - File object
   * @returns File URL
   */
  getUrl?: (file: FileSystemItem) => MayBePromise<string>;

  /**
   * Get thumbnail URL for file
   * @param file - File object
   * @returns Thumbnail URL
   */
  getThumbnailUrl?: (file: FileSystemItem) => MayBePromise<string>;

  /**
   * Retrieve a list of files and folders.
   * Supports filtering, sorting, and pagination.
   *
   * @param options.folderId - Parent folder (or undefined for root)
   * @param options.search - Search query
   * @param options.sortBy - Field to sort by
   * @param options.sortOrder - Sort direction
   * @param options.page - Page number
   * @param options.limit - Number of items per page
   * @param options.itemType - Filter by item type
   * @returns List of files/folders and optional pagination details
   */
  getItems: (options: {
    folderId?: string;
    search?: string;
    sortBy?: SortState['sortBy'];
    sortOrder?: SortState['sortOrder'];
    page?: number;
    limit?: number;
    itemType: 'all' | 'file' | 'folder';
  }) => MayBePromise<{ items: FileSystemItem[]; pagination?: Partial<ApiPaginationResponse> }>;

  /**
   * Create a new folder.
   *
   * @param name - Folder name
   * @param parent - Parent folder (or undefined for root)
   * @returns The created folder object
   */
  createFolder: (name: string, parentid?: string, is_force_create?: boolean) => MayBePromise<FileSystemItem>;

  /**
   * Rename an item (file or folder).
   *
   * @param options.item - Item to rename (file or folder)
   * @param options.newName - New item name
   * @returns Updated item with changed fields
   */
  renameItem?: (item: FileSystemItem, newName: string) => MayBePromise<FileSystemItemUpdate>;

  /**
   * Delete an item (file or folder).
   * When useSoftDelete is enabled, moves item to trashPath instead of permanent deletion.
   *
   * @param item - Item to delete (file or folder)
   * @throws {Error} If deletion fails
   */
  deleteItem?: (item: FileSystemItem, options: { permanent: boolean }) => MayBePromise<void>;

  /**
   * Upload a file.
   *
   * @param file.name - File name
   * @param file.size - File size
   * @param file.type - MIME type
   * @param file.folderId - Target folder (or undefined for root)
   * @param file.data - File data
   * @param file.thumbnail - Thumbnail image
   * @param file.dimensions - Image dimensions
   * @param file.aspectRatio - Aspect ratio
   * @param file.extension - File extension
   * @returns The uploaded file with changed fields
   */
  uploadFile?: (file: {
    name: string;
    size: number;
    type: string;
    folderId?: string;
    data: Blob | File;
    thumbnail?: string;
    dimensions?: string;
    aspectRatio?: string;
    extension?: string;
  }) => MayBePromise<FileSystemItemUpdate>;

  /**
   * Uploads multiple files and returns a batch result containing metadata
   * for each uploaded file.
   */
  uploadFiles?: (request: UploadFilesRequest) => MayBePromise<BatchResult<FileSystemItem>>;

  /**
   * Upload a file by URL.
   *
   * ⚠️ Implementation should check if the file already belongs
   * to the current server. If it does, return the existing file object
   * instead of uploading it again.
   *
   * @param url - File URL
   * @param folderId - Target folder (or undefined for root). If not specified,
   * uses the root folder.
   * @param options - Optional. eventSource — upload origin for integrator logic
   *   (e.g. disable proxy when uploading from stock sources: imageStock, iconStock, gif).
   * @returns The uploaded or existing complete file object
   */
  uploadFileByUrl: (
    url: string,
    folderId?: string,
    options?: { eventSource?: 'upload' | 'uploadByUrl' | 'pixie' | 'iconStock' | 'imageStock' | 'gif' }
  ) => MayBePromise<FileSystemItem>;

  /**
   * Delete multiple items (files or folders).
   *
   * @param items - Array of items to delete (files or folders)
   * @param options - Delete options
   * @returns Batch operation result with success/failure details
   */
  deleteItems?: (items: FileSystemItem[], options: { permanent: boolean }) => MayBePromise<BatchResult<never>>;

  /**
   * Move a single item to the target folder
   * @param item - Item to move (file or folder)
   * @param targetFolderId - Destination folder. If undefined, uses root folder
   * @returns The moved item with changed fields
   */
  moveItem?: (item: FileSystemItem, targetFolderId?: string) => MayBePromise<FileSystemItemUpdate>;

  /**
   * Move multiple items to the target folder
   * @param items - Array of items to move (files or folders)
   * @param targetFolderId - Destination folder. If undefined, uses root folder
   * @returns Batch operation result with success/failure details
   */
  moveItems?: (items: FileSystemItem[], targetFolderId?: string) => MayBePromise<BatchResult<FileSystemItemUpdate>>;

  /**
   * Clear all items from trash folder permanently
   * @returns Result object with success flag and optional count of deleted items
   */
  cleanTrash?: () => MayBePromise<{ success: boolean; deletedCount?: number }>;

  /**
   * Copy a single item to the target folder
   * @param item - Item to copy (file or folder)
   * @param targetFolderId - Destination folder. If undefined, uses root folder
   * @returns The copied item with changed fields
   */
  copyItem?: (item: FileSystemItem, targetFolderId?: string) => MayBePromise<FileSystemItemUpdate>;

  /**
   * Copy multiple items to the target folder
   * @param items - Array of items to copy (files or folders)
   * @param targetFolderId - Destination folder. If undefined, uses root folder
   * @returns Batch operation result with success/failure details
   */
  copyItems?: (items: FileSystemItem[], targetFolderId?: string) => MayBePromise<BatchResult<FileSystemItemUpdate>>;
  /**
   * Find a file by its URL.  
   * @param url - File URL
   * @param folderId - Target folder (or undefined for root). If not specified,
   * uses the root folder.
   * @returns The existing file object if the file already belongs to the current server, otherwise undefined
   * Find file by URL. Implementation should check if the file already belongs
   * to the current server. If it does, return the existing file object
   * instead of uploading it again.
   * @returns 
   */   
  findFileByUrl?: (url: string, folderId?: string) => MayBePromise<FileSystemItem | undefined>;

  /**
   * Update file metadata or content.
   *
   * @param file - File to update
   * @param updates - Object with fields to update (name, type, data, thumbnail, etc.)
   * @returns Updated file with changed fields
   */
  updateFile?: (
    file: FileSystemItem,
    updates: {
      name?: string;
      type?: string;
      data?: Blob | string;
      thumbnail?: string;
      dimensions?: string;
      aspectRatio?: string;
      extension?: string;
    },
  ) => MayBePromise<FileSystemItemUpdate>;
}

export declare namespace ExportedApi {
  export interface Options {
    storageProvider?: StorageProvider;
  }

  export interface FileManagerOptions {
    /**
     * Maximum file size in bytes for client-side compression. Files larger than this will not be compressed.
     * Set to 0 or undefined to disable compression.
     * @default 5 * 1024 * 1024 (5 MB)
     */
    compressMaxSize?: number;
    /**
     * Maximum width or height in pixels for client-side image compression. Images larger than this will be resized.
     * Set to 0 or undefined to disable resizing.
     * @default 2000
     */
    compressMaxWidthOrHeight?: number;
    /**
     * Expand all folders in root on init
     * @default true
     */
    expandRootFolderOnInit?: boolean;
    /**
     * Enables trash functionality for deleted files.
     * When enabled, deleted files are moved to trash instead of permanent deletion.
     * @default true
     */
    enableTrash?: boolean;

    /**
     * Enables paging in the file manager view.
     * If false or undefined, paging is disabled and all items are loaded at once.
     * @default true
     */
    enablePagination?: boolean;

    /**
     * When `true` (default) and {@link enablePagination} is `false` only: requests for `itemType: 'folder'` or `'file'`
     * load the catalog once as `all` (single `getItems` call and one TreeCache key), then filter client-side.
     * Ignored when server-side pagination is enabled (`enablePagination` not `false`).
     * Set `false` if your backend must use separate folder vs file list semantics.
     * @default true
     */
    unifiedCatalogFetch?: boolean;

    /**
     * Enables the ability to rename folders within the file manager.
     * If false or undefined, renaming folders is disabled.
     * @default true
     */
    enableRenameFolder?: boolean;

    /**
     * Enables the ability to rename files within the file manager.
     * If false or undefined, renaming files is disabled.
     * @default true
     */
    enableRenameFile?: boolean;

    /**
     * Enables the ability to update file metadata or content.
     * If false or undefined, updating files is disabled.
     * @default true
     */
    enableUpdateFile?: boolean;

    /**
     * Enables file editing capabilities.
     * Includes functions for modifying file content or properties.
     * @default true
     */
    enableEdit?: boolean;
    /**
     * Enables copying files.
     * Allows creating copies of files.
     * @default true
     */
    enableMoveFile?: boolean;
    /**
     * Enables copying folders.
     * Allows creating copies of folders.
     * @default true
     */
    enableMoveFolder?: boolean;
    /**
     * Enables copying files.
     * Allows creating copies of files.
     * @default true
     */
    enableCopyFile?: boolean;
    /**
     * Enables copying folders.
     * Allows creating copies of folders.
     * @default true
     */
    enableCopyFolder?: boolean;
    /**
     * Enables deleting files and folders.
     * When trash is enabled, files are moved to trash, otherwise permanently deleted.
     * @default true
     */
    enableDelete?: boolean;
    /**
     * Default folder name
     */
    defaultFolderName?: string;

    /**
     * Enables multiple selection of files and folders.
     * Allows selecting multiple items for batch operations.
     * @default true
     */
    multiSelect?: boolean;

    /**
     * Whitelist of entries in the file list sort dropdown.
     * Each string combines sort field and direction (e.g. `date-desc` for newest first).
     * If omitted or empty, the file-manager UI shows all built-in sort modes.
     * Pass a subset when the platform does not implement every `sortBy` / `sortOrder` pair.
     * @example ['date-desc', 'date-asc', 'name-asc', 'name-desc'] // omit size and type sorts
     */
    sortOptions?: (
      | 'date-desc'
      | 'date-asc'
      | 'size-desc'
      | 'size-asc'
      | 'name-asc'
      | 'name-desc'
      | 'type-asc'
    )[];
    /*
     * When thumbnail/thumbnailUrl are missing, use `file.url` for table/grid preview (images only).
     * Forwarded to FileManager `config` (@emailmaker/filemanager).
     */
    previewFallbackToFileUrl?: boolean;
    /**
     * Client-side deduplication of upload names and related flows (see @emailmaker/filemanager `Config`).
     */
    dedupeUploadNamesOnClient?: boolean;
    /**
     * When enabled, "Save copy" in the image editor targets the current folder instead of the default one.
     */
    saveCopyToCurrentFolder?: boolean;

    /**
     * Enables client-side sorting of files.
     * - If `true`, default sorting is applied (by name ascending).
     * - If a function is provided, it receives the current items, optional `sortBy` field,
     *   and optional `sortOrder`, and should return a new sorted array of files.
     * @default false
     */
    clientSideSorting?:
    | boolean
    | ((
      items: FileSystemItem[],
      sortBy?: SortState['sortBy'],
      sortOrder?: SortState['sortOrder'],
    ) => FileSystemItem[]);

    /**
     * Enables client-side pagination of files.
     * - If `true`, default slicing based on `page` and `limit` is applied.
     * - If a function is provided, it receives the current items, `page`, and `limit`,
     *   and should return a paginated array of files.
     * @default false
     */
    clientSidePaging?: boolean | ((items: FileSystemItem[], page?: number, limit?: number) => FileSystemItem[]);

    /**
     * Enables client-side filtering of files.
     * - If `true`, default filtering by `search` text is applied.
     * - If a function is provided, it receives the current items and optional `search` string,
     *   and should return a filtered array of files.
     * @default false
     */
    clientSideFilter?: boolean | ((items: FileSystemItem[], search?: string) => FileSystemItem[]);
    /**
     * Show filemanager notifications
     * @default true
     */
    showNotifications?: boolean;
    /**
     * Configuration for cache behavior in the file manager.
     * Defines caching strategy for performance optimization.
     */
    cacheStrategy?: {
      /**
       * Time-to-live (TTL) in milliseconds for cached items.
       * After this period, cached items will be considered stale.
       * @default 1800000 (30 minutes)
       */
      ttl?: number;

      /**
       * TTL in milliseconds for cached errors (failed loads). While fresh, the same error is reused without a new request.
       * When omitted, matches {@link cacheStrategy.ttl}.
       */
      errorTtl?: number;

      /**
       * Allows inserting new items into sorted lists without marking the view as stale.
       * Useful for dynamically adding items without full cache refresh.
       * @default false
       */
      allowSortedInsert?: boolean;

      /**
       * Allows inserting new items that may not match current filters without marking the view as stale.
       * @default false
       */
      allowSearchInsert?: boolean;

      /**
       * Marks the view as stale when a paginated page is full and cannot accommodate new items.
       * @default true
       */
      invalidateOnPaginationFull?: boolean;

      /**
       * Custom comparator function for sorting entities.
       * Receives two entities and optional query parameters, should return -1, 0, or 1.
       * @default File/folder name comparison
       */
      comparator?: (a: FileSystemItem, b: FileSystemItem, params?: any) => number;

      /**
       * Function to determine if a given entity matches the current filters.
       * Returns `true` if the entity should be included.
       * @default File/folder name search
       */
      filterMatch?: (entity: FileSystemItem, params?: any) => boolean;

      /**
       * Number of pages to preload before current page.
       * Pages are loaded in a single request with increased pageSize.
       * @default 0
       */
      preloadPagesBefore?: number;

      /**
       * Number of pages to preload after current page.
       * Pages are loaded in a single request with increased pageSize.
       * @default 3
       */
      preloadPagesAfter?: number;
    };
  }

  /**
   * **`Config`** extension: file-manager options when **`imageCenterFileManagerView`** /
   **`storageProvider`** integrations are enabled, plus optional resource/backend proxy overrides.
   * Merges with the larger **`ExportedApi.Config`** above.
   */
  type ResourceProxyResourceType = 'generic' | 'stockImages' | 'emFiles' | 'cdn';

  type ResourceProxyMatchContext = {
    url: string;
    resourceType: ResourceProxyResourceType;
    intent: 'display' | 'downloadBlob' | 'metadata';
  };

  type MatchedTemplateTokens = {
    [key: `matched_${string}`]: string | undefined;
  };

  type ResourceProxyBuildContext = MatchedTemplateTokens & {
    url: string;
    proxyBase?: string;
    resourceType: ResourceProxyResourceType;
    intent: 'display' | 'downloadBlob' | 'metadata';
  };

  type ResourceProxyRule = {
    id?: string;
    match?: string | string[] | ((context: ResourceProxyMatchContext) => boolean);
    proxyBase?: string;
    rewrite?: string | string[] | ((context: ResourceProxyBuildContext) => string);
  };

  type ResourceProxyValue = string | ResourceProxyRule | Array<string | ResourceProxyRule>;
  type ResourceProxyConfig = ResourceProxyValue;

  type ResourceProxyPolicy = {
    recoveryTtlMs?: number;
    proxyBlobFetch?: boolean;
    proxyCdn?: boolean;
    proxyEmFiles?: boolean;
    proxyStockImages?: boolean;
  };

  type BackendProxyRequestType = 'generic' | 'emFiles' | 'ai';

  type BackendProxyMatchContext = {
    url: string;
    method?: string;
    requestType: BackendProxyRequestType;
  };

  type BackendProxyBuildContext = MatchedTemplateTokens & {
    url: string;
    proxyBase?: string;
    method?: string;
    requestType: BackendProxyRequestType;
  };

  type BackendProxyRule = {
    id?: string;
    match?: string | string[] | ((context: BackendProxyMatchContext) => boolean);
    proxyBase?: string;
    rewrite?: string | string[] | ((context: BackendProxyBuildContext) => string);
  };

  type BackendProxyValue = string | BackendProxyRule | Array<string | BackendProxyRule>;
  type BackendProxyConfig = BackendProxyValue;

  type BackendProxyPolicy = {
    proxyEmFiles?: boolean;
    proxyAi?: boolean;
  };

  export interface Config {
    /** UI + behavior for bundled file picker (timeouts, paging, trash, thumbnails, providers). */
    fileManager?: FileManagerOptions;
    resourceProxy?: ResourceProxyConfig;
    resourceProxyPolicy?: ResourceProxyPolicy;
    backendProxy?: BackendProxyConfig;
    backendProxyPolicy?: BackendProxyPolicy;
  }
}

export declare namespace ExportedApi {
  namespace UndoRedoMixin {
    interface Instance {
      /**
       * An instance of `IUndoRedoService` that manages undo and redo operations.
       */
      undoRedoService: IUndoRedoService;
    }
  }

  interface Instance extends UndoRedoMixin.Instance { }
}

export declare namespace ExportedApi {
  interface Instance {
    /** Replace options and reload app state (`init`-equivalent for an existing mount; avoid duplicate `init` on same DOM node). */
    reset(options: Options): Promise<Instance>;
  }
}

/** Application instance after `init()`; merged from all `ExportedApi.Instance` declarations. */
export type Instance = ExportedApi.Instance;

/** Options for `init()`; merged from all `ExportedApi.Options` declarations (handlers, content, auth, config, …). */
export type Options = ExportedApi.Options;

/**
 * Initialize the EmailMaker / plugin application instance.
 * @param options - Full option bag; see {@link Options} / `ExportedApi` in this package’s `.d.ts`.
 * @returns Promise resolving to the runtime instance (events, `show`, `save`, `destroy`, …).
 */
export function init(options: Options): Promise<Instance>;
/**
 * Parse AMP-aware email source into **`ParsedAMP`** (HTML preview, AMP part, opaque `code`).
 * @param code - Raw markup string **or** wrapper `{ code: string }` as accepted by the runtime.
 */
export function parseAMP(code: string | { code: string }): Promise<ParsedAMP>;
/**
 * Default content-styles preset for the current product build. Spread into `init({ commonStyles })` as needed.
 * Partial option trees are deep-merged with this object at runtime; persisted email `common_styles` override plugin defaults when loaded.
 */
export declare const COMMON_STYLES: Readonly<CommonStyles>;
/** Build/version string exposed at runtime (`package.json` counterpart for the bundled SDK). */
export const version: string;

/** File manager and integration errors surfaced to host apps (subset used by storage layers). */
export declare namespace errors {
  /**
   * FileManagerApiError
   * @example
   * ```typescript
   * throw new errors.FileManagerApiError(
   *   'File not found',
   *   'FileNotFound',
   *   404
   * );
   * ```
   */
  export class FileManagerApiError extends Error implements FileManager.IFileManagerApiError {
    public readonly code: FileManager.FileManagerErrorCode;
    public readonly httpStatus?: number;
    public readonly details?: unknown;

    constructor(message: string, code: FileManager.FileManagerErrorCode, httpStatus?: number, details?: unknown);
  }
}

export declare namespace helpers {
  /**
   * mapHttpStatusToErrorCode
   * @example
   * ```typescript
   * helpers.mapHttpStatusToErrorCode(404);
   * ```
   */
  export function mapHttpStatusToErrorCode(
    status: number,
    defaultCode?: FileManager.FileManagerErrorCode,
  ): FileManager.FileManagerErrorCode;
}
