/** * StateManager: write-through cache — every set/delete persists immediately to disk (atomic temp → rename). */ import type { DslState } from "../types/dsl/index.js"; export interface StrategyState { address: string; preset: string; intervalMs: number; wallet: string; activeAssets: string[]; createdAt: string; updatedAt: string; } export declare class StateManager { private readonly baseDir; private readonly memory; private readonly mutex; constructor(baseDir: string); /** * Serialize concurrent read-modify-write operations on the same DSL state key. * * Concurrent calls with the SAME `key` are queued and run strictly FIFO. * Concurrent calls with DIFFERENT keys run in parallel — no false contention. * * Usage: * await stateManager.withKeyLock(key, async () => { * const state = await stateManager.getOrLoad(key); * await stateManager.set(key, { ...state, ...patch }); * }); * * NON-REENTRANT: do not call withKeyLock(sameKey, ...) from inside an fn * that already holds sameKey — that will deadlock. */ withKeyLock(key: string, fn: () => Promise | T): Promise; get(key: string): T | undefined; getOrLoad(key: string): Promise; /** * Same rules as {@link hydrate} for dsl-* JSON: inactive, wrong version, or invalid shape → do not cache. * Lazy-fills `correlationId` (UUID v4) and `triggerReason` (`"position_opened"`) for state files * written before those fields existed; the in-memory copy carries the backfilled values until the * next `set()` persists them to disk. */ private parseDslStateForCache; set(key: string, value: unknown): Promise; listStrategyIds(): Promise; listDslKeys(prefix: string): Promise; /** Returns all active DSL states for a given strategy address. */ listDslStates(address: string): Promise; /** * Active DSL states for a strategy from the in-memory cache only (after {@link hydrate}). * Used by sync gateway helpers; does not read disk. */ listActiveDslStatesSync(address: string): DslState[]; /** Strategy addresses that have at least one `dsl-*` key in memory (non-archived prefix). */ listStrategyIdsWithDslSync(): string[]; /** * Same matching rules as {@link getDslStateByAsset} but reads only the hydrated memory map. */ getDslStateByAssetSync(address: string, asset: string, dex?: string): DslState | undefined; findDslStateByAssetAcrossStrategiesSync(asset: string): { address: string; state: DslState; } | undefined; getDslState(address: string, asset: string, dex: string): Promise; /** * Resolve active DSL state by strategy address + asset (+ optional dex). * Matches after {@link normalizeDslCoinDex} (e.g. `xyz:GOLD` / `GOLD` + `xyz`). * If `dex` is omitted and the query is base-only, a single active row with that base wins. */ getDslStateByAsset(address: string, asset: string, dex?: string): Promise; setDslState(address: string, asset: string, dex: string, state: DslState): Promise; getStrategyState(address: string): StrategyState | undefined; setStrategyState(address: string, state: StrategyState): Promise; /** * Removes the key from memory and deletes its file from disk. * Callers (e.g. DSL) that want to keep an archive must write it (e.g. via archivedDslPath) * before calling deleteKey/deleteDslState, to avoid creating a duplicate archive. */ deleteKey(key: string): Promise; deleteDslState(address: string, asset: string, dex: string): Promise; /** * Atomically archives closed state (temp → rename) and removes the live key. * Archived files keep close history; the live key is removed so a new position for the same asset gets a fresh file. */ archiveAndDeleteDslState(address: string, asset: string, dex: string, closedState: DslState): Promise; /** * Load existing state from disk into memory (hydration). Call before processing * events so open positions and strategy state are available. */ hydrate(): Promise; /** * Return per-strategy count of active DSL positions (used slots). Reads live keys from disk * so counts stay correct if files appear outside this process. */ getUsedSlotsByStrategy(addresses: string[]): Promise>; /** Rename strategy directory to archived; drop cached keys for that address. */ archiveStrategyDir(address: string): Promise; private keyToPath; /** Write JSON to an absolute file path via temp + rename (crash-safe contents). */ private atomicWriteAbsolute; private atomicWrite; } //# sourceMappingURL=state-manager.d.ts.map