import { watch, type FSWatcher } from 'node:fs' import { basename, dirname } from 'node:path' export type TranscriptNativeWatcher = { /** Best-effort bind; false keeps the caller in reconciliation-only mode. */ bind: () => boolean /** Detach from an identity that may no longer represent the watched path. */ invalidate: () => void needsRebind: () => boolean dispose: () => void } /** Native watches only accelerate polling reconciliation: remote filesystems may reject them while files remain readable, so retry binding without owning liveness. */ export function createTranscriptNativeWatcher( filePath: string, onEvent: () => void, onError: () => void, options: { watchParent?: boolean } = {} ): TranscriptNativeWatcher { const watchedName = basename(filePath) let disposed = false let watcher: FSWatcher | null = null let rebindNeeded = true function invalidateCandidate(candidate: FSWatcher): void { if (watcher !== candidate) { return } watcher = null rebindNeeded = true candidate.close() } return { bind(): boolean { if (disposed || watcher) { return watcher !== null } let nextWatcher: FSWatcher try { // Parent watches survive replacement; append-only readers can watch one file to avoid sibling events. nextWatcher = watch( options.watchParent === false ? filePath : dirname(filePath), (event, changedName) => { if (changedName !== null && changedName.toString() !== watchedName) { return } // Why: a parent replacement may emit rename without a watcher error. if (event === 'rename') { invalidateCandidate(nextWatcher) } onEvent() } ) } catch { rebindNeeded = true return false } // Why: an active tail should not keep a headless runtime alive during shutdown. nextWatcher.unref?.() nextWatcher.on('error', () => { if (disposed || watcher !== nextWatcher) { return } invalidateCandidate(nextWatcher) onError() }) watcher = nextWatcher rebindNeeded = false return true }, invalidate(): void { if (watcher) { invalidateCandidate(watcher) } else { rebindNeeded = true } }, needsRebind: () => rebindNeeded, dispose(): void { disposed = true watcher?.close() watcher = null rebindNeeded = false } } }