import type { Observable } from 'rxjs';
import type { Action } from '../dispatcher';
import type { Dispatcher } from '../dispatcher/dispatcher.base';
import { type Effect, type EffectOptions } from './effects.module';
/**
 * Контекст эффекта в class-стиле — узкий надтип контекста EffectsModule. Рецепт читает
 * только эти два поля; остальное (services, externalStates) приходит через конструктор
 * класса и захватывается замыканием.
 */
export interface EffectCtx<TDispatcher, TExternalDispatchers = Record<string, never>> {
    /** Инстанс нашего class-диспетчера: `ofType(d.loadPosts)` + `d.applyPosts(...)`. */
    dispatcher: TDispatcher;
    /** Внешние диспетчеры (их экшены уже влиты в общий `action$`). */
    external: TExternalDispatchers;
}
/** Рецепт эффекта: отложенная функция, вызываемая один раз при `EffectsModule.start()`. */
export type EffectRecipe<TState, TDispatcher, TExternalDispatchers> = (action$: Observable<Action>, state$: Observable<TState>, ctx: EffectCtx<TDispatcher, TExternalDispatchers>) => Observable<unknown>;
/**
 * Публичный class-based слой эффектов. Эффекты объявляются как поля класса через
 * `this.effect(fn)`. Сервисы и внешние сторы передаются через конструктор и
 * захватываются в замыкание рецепта (`this.api`, `this.core$`).
 *
 * @example
 * ```ts
 * class PostsEffects extends Effects<PostsState, PostsDispatcher> {
 *   constructor(private readonly api: PostsEndpoints, private readonly core$: Observable<CoreState>) {
 *     super()
 *   }
 *
 *   readonly loadPosts = this.effect((action$, state$, { dispatcher: d }) =>
 *     action$.pipe(ofType(d.loadPosts), validateMap({ apiCall: () => fromRequest(this.api.getPosts.request()) })))
 *
 *   override onDestroy() { this.socket.disconnect() }
 * }
 * ```
 *
 * **Правило**: сервисы из конструктора (`this.api`) можно *захватывать в замыкание*
 * рецепта, но не дереференсить прямо в инициализаторе поля — parameter properties
 * присваиваются ПОСЛЕ инициализаторов полей derived-класса.
 */
export declare abstract class Effects<TState extends Record<string, any>, TDispatcher, TExternalDispatchers extends Record<string, Dispatcher<any>> = Record<string, never>> {
    #private;
    /**
     * Опт-аут для dev-проверки «забытых эффектов»: имена полей-функций, которые НЕ являются
     * эффектами (конструкторно-инъектированные зависимости — геттеры/фабрики, напр.
     * `resolveSocket: () => Socket`). Такие поля — не рецепты `this.effect(...)`, и без этого
     * списка `getEffects()` ложно ворнил бы на них.
     *
     * @example
     * ```ts
     * class PresenceEffects extends Effects<PresenceState, PresenceDispatcher> {
     *   static override nonEffectFields = ['resolveSocket']
     *   constructor(private resolveSocket: () => PresenceSocketService) { super() }
     *   connection = this.effect(...)
     * }
     * ```
     */
    static nonEffectFields: string[];
    /**
     * Регистрирует рецепт эффекта. Сам рецепт НЕ вызывается при конструировании — он
     * вызывается лениво при `EffectsModule.start()` с реальными потоками. Возвращает тот
     * же `fn`, так что поле остаётся вызываемым рецептом (удобно для юнит-тестов в изоляции).
     *
     * @param fn рецепт `(action$, state$, ctx) => Observable`
     * @param options опции эффекта (например, `resubscribeOnError`)
     */
    protected effect(fn: EffectRecipe<TState, TDispatcher, TExternalDispatchers>, options?: EffectOptions): EffectRecipe<TState, TDispatcher, TExternalDispatchers>;
    /**
     * Список module-совместимых эффектов в порядке объявления полей. Сборщик скармливает
     * его в `effectsModule.addEffects(...)`.
     *
     * Попутно (вне production) предупреждает о полях-функциях, не обёрнутых в `this.effect`.
     * @internal
     */
    getEffects(): Effect[];
    /** Опциональный teardown (закрыть сокет и т.п.) — вызывается сборщиком при `synapse.destroy()`. */
    onDestroy?(): void | Promise<void>;
}
