import type Database from 'better-sqlite3'; /** Options for lock acquisition */ export interface LockOptions { /** Lock name (e.g., "kanban:sprint-2026050301") */ name: string; /** Unique identifier for the lock holder (e.g., PID + timestamp) */ owner: string; /** Max wait time in ms (default: 5000) */ timeoutMs?: number; /** Lock considered stale after this many ms (default: 60000) */ staleMs?: number; /** Retry interval in ms (default: 50) */ retryIntervalMs?: number; } /** Handle returned after successful lock acquisition */ export interface LockHandle { /** The lock name */ name: string; /** The owner identifier */ owner: string; /** Release the lock */ release: () => void; } /** * Generate a unique owner string using PID and timestamp. */ export declare function generateLockOwner(): string; /** * Clear stale locks for a given lock name. * A lock is stale if COALESCE(last_heartbeat, acquired_at) is older than now - staleMs. * Per FS-SS-003-0004 VR-003. * * @returns Number of stale locks cleared */ export declare function clearStaleLocks(db: Database.Database, name: string, staleMs?: number): number; /** * Attempt to acquire a lock (single attempt, no retry). * Uses TEXT (ISO 8601) for acquired_at per FS-SS-003-0003 Data Model. * * @returns true if acquired, false if lock is held by another owner */ export declare function tryAcquireLock(db: Database.Database, name: string, owner: string): boolean; /** * Refresh/heartbeat a lock — update last_heartbeat timestamp. * Per FS-SS-003-0004 VR-005: operations exceeding the stale threshold * must explicitly extend their lock. * * @returns true if the lock was refreshed, false if not found or wrong owner */ export declare function refreshLock(db: Database.Database, name: string, owner: string): boolean; /** * Get information about a lock (if held). */ export declare function getLockInfo(db: Database.Database, name: string): { owner: string; acquiredAt: string; lastHeartbeat: string | null; } | null; /** * Acquire an advisory lock with timeout and stale detection. * Implements the retry loop with configurable timeout. * * Per FS-SS-003-0003 VR-008: re-evaluates lock staleness at intervals no * greater than the advisory lock acquisition timeout. The default retry * interval (50ms) is well below the default timeout (5000ms), so each * retry iteration satisfies this bound. * * @throws LockTimeoutError if the lock cannot be acquired within timeoutMs (ERR-LOCK-002) */ export declare function acquireLock(db: Database.Database, opts: LockOptions): LockHandle; /** * Acquire multiple advisory locks in alphabetical order. * Per FS-SS-003-0003 VR-006/VR-007: locks must be acquired in alphabetical * order by lock name to prevent deadlocks. * * On partial failure (some locks acquired but a later one times out), * all acquired locks are released before the error is thrown. * * @throws LockTimeoutError if any lock cannot be acquired */ export declare function acquireLocks(db: Database.Database, lockNames: string[], owner: string, opts?: Omit): LockHandle[]; /** * Release an advisory lock. * Only the owner can release their own lock. * * @returns true if the lock was released, false if not found or wrong owner */ export declare function releaseLock(db: Database.Database, name: string, owner: string): boolean; /** * Force-release a lock regardless of owner. * Use with caution — only for administrative purposes. */ export declare function forceReleaseLock(db: Database.Database, name: string): boolean; /** * Execute a function within a lock context, guaranteeing release in finally. * Per FS-SS-003-0003 VR-003: locks must be released upon operation completion * (success, failure, or exception). * * @param db - Database connection * @param opts - Lock acquisition options * @param fn - Function to execute while holding the lock * @returns The return value of fn * @throws LockTimeoutError if the lock cannot be acquired */ export declare function withLock(db: Database.Database, opts: LockOptions, fn: () => T): T; //# sourceMappingURL=locks.d.ts.map