import type { FlowcoreEvent } from "../../contracts/event.js"; import type { Logger } from "../logger.js"; import type { PathwayPumpOptions, PumpState } from "./types.js"; /** * Registered pathway info needed for pump grouping. * `pumpGroup` defaults to `"default"` when omitted. */ interface PathwayRegistration { flowType: string; eventType: string; pumpGroup?: string; } /** * Filter selecting which pumps {@link PathwayPump.reset}, {@link PathwayPump.pause} and * {@link PathwayPump.resume} act on. * * - Omit everything → every pump. * - `keys` → exact `${flowType}::${pumpGroup}` targets. This is the only criterion that * can name a SET OF PAIRS, which `flowTypes` + `pumpGroups` cannot: those two form an * intersection, so `{flowTypes:["a","b"], pumpGroups:["hot"]}` means "hot on a AND hot * on b", never "a's hot and b's cold". * - `flowTypes` → every pump group on those flow types. * - `pumpGroups` → those pump groups on every flow type. * - `flowTypes` + `pumpGroups` → the intersection. * - `keys` combined with either → the UNION of the two selections, so a command can * target `"orders.0"` wholesale and `"invoices.0::hot"` precisely in one call. */ export interface PumpResetFilter { flowTypes?: string[]; pumpGroups?: string[]; /** Exact `${flowType}::${pumpGroup}` targets, as returned by {@link PathwayPump.reset}. */ keys?: string[]; } /** * Split a target into its `(flowType, pumpGroup)` parts. * * A bare `"orders.0"` targets every pump group on that flow type. A composite * `"orders.0::hot"` targets exactly one pump. The composite form is the same string the * `concurrency.byPumpGroup` option uses and the same string {@link PathwayPump.reset} * returns, so control-plane commands can carry it in the existing `sourceFlowTypes` array * without a new field. */ export declare function parsePumpTarget(target: string): { flowType: string; pumpGroup?: string; }; /** * Build a {@link PumpResetFilter} from a list of targets that mixes bare flow types and * composite `flowType::pumpGroup` keys. An empty or missing list means "every pump". */ export declare function pumpFilterFromTargets(targets?: string[] | null): PumpResetFilter | undefined; /** * PathwayPump orchestrates data pump instances for auto-fetching events from Flowcore. * * Groups registered pathways by `(flowType, pumpGroup)` and creates one FlowcoreDataPump * per group. Within one `flowType`, multiple `pumpGroup`s give independent state cursors, * processor concurrency, and restart backoff. Events are routed to PathwaysBuilder.process() * for handling. * * Resilience: per-group restarts on error use exponential backoff and keep retrying * indefinitely (capped at {@link RESTART_MAX_MS}). A failure during a restart attempt * does NOT stop further attempts — the loop continues until the pump is explicitly stopped * or the restart eventually succeeds. */ export declare class PathwayPump { private readonly stateManagerFactory; private readonly notifier; private readonly bufferSize; private readonly maxRedeliveryCount; private readonly concurrency; private readonly logger; private readonly stateManagerFactoryArity; private legacyFactoryWarningEmitted; private pulseConfig?; private pumps; private stateManagers; private running; private restartAttempts; private restartTimers; private groupMeta; /** * Keys of pumps whose delivery is paused. Paused pumps stay in {@link pumps} and keep * their state manager, their buffer and their cursor — only delivery stops. */ private paused; private dataPumpConstructor; private tenant; private dataCore; private apiKey; private baseUrl; private processEvent; constructor(options: PathwayPumpOptions, logger?: Logger); /** * Configure the pump with pathway builder context */ configure(config: { tenant: string; dataCore: string; apiKey: string; baseUrl: string; processEvent: (pathway: string, event: FlowcoreEvent) => Promise; }): void; /** * Start pumps for the given pathway registrations. * Groups by `(flowType, pumpGroup)` and creates one pump per group. */ start(pathways: PathwayRegistration[]): Promise; /** * Resolve a state manager for a `(flowType, pumpGroup)` pair, falling back to * the legacy single-arg factory shape when the user-supplied factory has arity 1. */ private resolveStateManager; /** * Resolve effective concurrency for one pump. * Order: `byPumpGroup` → `byFlowType` → `default`. */ private resolveConcurrency; /** * Start (or restart) a pump for a specific (flowType, pumpGroup) group. * * On error from the underlying pump, schedules an exponential-backoff restart * scoped to this group only. Restart attempts continue indefinitely (capped at * {@link RESTART_MAX_MS}); a synchronous failure during a restart attempt does * not stop the loop — it schedules another attempt. */ private startPumpForGroup; /** * Schedule a restart for one pump group with capped exponential backoff. * Multiple restart triggers for the same group within the backoff window are deduped. * A synchronous failure inside the scheduled restart re-arms another attempt — the * loop continues until the group is stopped or a restart succeeds. */ private scheduleRestart; /** * Stop all running pumps */ stop(): Promise; /** * Reset pumps to a specific position, or clear state and bounce if no position given. * Uses @flowcore/data-pump's restart() to reposition the cursor without recreating instances. * * Filter accepts: * - `string[]` → legacy: filter by flow type names * - `{ flowTypes?, pumpGroups? }` → narrow to matching `(flowType, pumpGroup)` pumps * * Both are supported for back-compat; the array form is equivalent to `{ flowTypes }`. * * @param position - Target position { timeBucket, eventId? }. If omitted, clears persisted state * and restarts pumps (pump will start from live position). * To replay from the very beginning, pass the first time bucket explicitly. * @param stopAt - Optional upper bound. The pump stops once it passes this time. Only * applied together with `position`. * @returns Array of `${flowType}::${pumpGroup}` keys for pumps that were reset. */ reset(position?: PumpState, filter?: string[] | PumpResetFilter, stopAt?: Date | null): Promise; /** * Pause delivery on the matching pumps. The pumps keep running: they keep fetching, * keep their buffer, keep their cursor and keep reporting pulses. Only delivery to the * registered handlers stops. * * A batch already inside a handler finishes and acknowledges, so the checkpoint stays * accurate and nothing is redelivered needlessly. * * @param filter - Which pumps to pause. Omit to pause every pump. See {@link PumpResetFilter}. * @returns Array of `${flowType}::${pumpGroup}` keys that were paused by this call. * An EMPTY array means the filter matched nothing — treat that as a failure, * not as a successful no-op. */ pause(filter?: PumpResetFilter): string[]; /** * Resume delivery on the matching pumps, continuing from the exact position where * {@link pause} stopped them. * * @param filter - Which pumps to resume. Omit to resume every pump. * @returns Array of `${flowType}::${pumpGroup}` keys that were resumed by this call. * An EMPTY array means the filter matched nothing. */ resume(filter?: PumpResetFilter): string[]; /** * Seed the paused set BEFORE {@link start}, so every matching pump is built already * paused. Use this to restore a persisted pause: calling {@link pause} after `start()` * would let the pumps deliver a batch in the gap. * * @param pumpKeys - `${flowType}::${pumpGroup}` keys. Keys with no matching registration * are kept, not dropped — prune them after `start()` with * {@link prunePausedPumps} once the registrations are known. */ setInitialPausedPumps(pumpKeys: string[]): void; /** * Drop paused keys that match no running pump, and return the keys still in effect. * Registrations change between deploys, so a stored set would otherwise grow forever. */ prunePausedPumps(): string[]; /** Whether delivery is paused for one `(flowType, pumpGroup)` pair. */ isPaused(flowType: string, pumpGroup?: string): boolean; /** Keys of every pump whose delivery is currently paused. */ get pausedGroups(): string[]; /** Keys of every pump this instance runs, as `${flowType}::${pumpGroup}`. */ get registeredPumpKeys(): string[]; setPulseConfig(pulseConfig: NonNullable): Promise; get isRunning(): boolean; /** * Unique flow types currently driven by at least one pump (back-compat with pre-2.4 API). */ get registeredFlowTypes(): string[]; /** * All `(flowType, pumpGroup)` pairs currently driven by a pump. */ get registeredPumpGroups(): Array<{ flowType: string; pumpGroup: string; }>; /** * Translate our notifier config into the exact shape `@flowcore/data-pump` reads. * * The pump discriminates on `notifier.type` and pulls `servers` / `intervalMs` off the * matching variant. `auth` and `dataSource` come from the top-level pump options, not * from here — anything extra placed on the notifier object is ignored. * * Emitting any other shape is silent: both discriminator checks resolve to `undefined` * and every pump falls through to the websocket notifier regardless of what the caller * configured. Keep this in lockstep with `FlowcoreDataPumpNotifierOptions`. */ private buildNotifierOptions; } export {}; //# sourceMappingURL=pathway-pump.d.ts.map