import type { Observable } from 'rxjs'; import type { IStorage } from '../../core'; import type { Action, DispatchFunction, EnhancedMiddleware, WatcherFunction } from './dispatcher.module'; import { type ApiRequestState } from './standalone'; /** * Маркер метода финализации диспетчера. * * Имя экшена/вотчера берётся из имени поля класса, но прочитать имена полей можно * только ПОСЛЕ полного конструирования инстанса (инициализаторы полей derived-класса * выполняются после конструктора базового класса). Поэтому имена назначаются отдельным * шагом-финализацией: * * 1. **Сборщик `createSynapse(factory)`** вызывает `dispatcher[FINALIZE]()` до старта * эффектов (эффекты читают `actionType` при сборке пайплайна). * 2. **Ленивая само-финализация** — страховка для standalone-использования и тестов: * первый dispatch экшена или первое обращение к реестру `dispatch`/`watchers` * финализирует инстанс, если это ещё не сделано. */ export declare const FINALIZE: unique symbol; /** * Вызываемая группа жизненного цикла API-запроса. * * Сам вызов группы — это `init` (намерение): сбрасывает статус в `idle` и пробрасывает * payload намерения дальше эффектам. Жизненный цикл — через методы-поля. * * `ofType(d.loadPosts)` ловит ТОЛЬКО init; чтобы среагировать на успех — * `ofType(d.loadPosts.success)`. */ export interface ApiActions extends DispatchFunction { loading: DispatchFunction; success: DispatchFunction; failure: DispatchFunction; reset: DispatchFunction; } /** * Keyed-вариант: статус хранится по ключу. `init`/`loading`/`success`/`reset` принимают * `key`, `failure` — `{ key, error }`. */ export interface KeyedApiActions extends DispatchFunction { loading: DispatchFunction; success: DispatchFunction; failure: DispatchFunction<{ key: string; error: string; }, { key: string; error: string; }>; reset: DispatchFunction; } /** Опции конструктора базового диспетчера. */ export interface DispatcherBaseOptions> { middlewares?: EnhancedMiddleware[]; } /** * Публичный class-based слой диспетчера. Экшены объявляются как поля класса через * фабрики `this.action` / `this.signal` / `this.apiActions` / `this.keyedApiActions` * / `this.watcher`. Имя экшена = имя поля. * * Внутреннее состояние базы — hard-private (`#`-поля/методы): их имена в отдельном * namespace и НЕ конфликтуют с полями-экшенами подкласса. Запрещённые имена экшенов — * только `protected`/публичная поверхность из `RESERVED_NAMES`. * * @example * ```ts * class PostsDispatcher extends Dispatcher { * readonly loadPosts = this.apiActions((s) => s.api.postsRequest) * readonly mounted = this.signal('Лента смонтирована') * readonly applyPosts = this.action((store, page: PostsFeedResponseDto) => * store.update((s) => { s.list = page.data })) * } * ``` */ export declare abstract class Dispatcher> { #private; protected readonly storage: IStorage; /** Поток всех экшенов модуля (его потребляет EffectsModule). */ readonly action$: Observable; constructor(storage: IStorage, options?: DispatcherBaseOptions); /** Реестр экшенов по имени — для middleware/devtools. */ get dispatch(): Record>; get watchers(): Record>; /** Алиас потока экшенов для совместимости с EffectsModule (`dispatcher.actions`). */ get actions(): Observable; /** * Экшен: handler в «рецептной» сигнатуре `(storage, params) => result`. * payload экшена = возвращаемое значение handler'а. */ protected action(handler: (storage: IStorage, params: TParams) => TResult | Promise, options?: { type?: string; meta?: Record; memoize?: (cur: TParams, prev: TParams, prevResult: TResult) => boolean; }): DispatchFunction; /** Чистый сигнал: `(_store, p) => p`. `description` уходит в meta. */ protected signal(description?: string): DispatchFunction; /** Вызываемая группа жизненного цикла API-запроса. Сам вызов = init (намерение). */ protected apiActions(accessor: (state: TState) => ApiRequestState): ApiActions; /** То же для статусов по ключу (`Record`). */ protected keyedApiActions(accessor: (state: TState) => Record): KeyedApiActions; protected watcher(config: { selector: (state: TState) => R; shouldTrigger?: (prev: R | undefined, current: R) => boolean; notifyAfterSubscribe?: boolean; type?: string; meta?: Record; }): WatcherFunction; use(...middlewares: EnhancedMiddleware[]): this; destroy(): void; /** * Финализация: скан own enumerable полей, назначение имён (`_assignType(имя поля)`) * и регистрация в реестрах `dispatch`/`watchers`. Идемпотентна. */ [FINALIZE](): void; }