π File detail
utils/bufferedWriter.ts
π§© .tsπ 101 linesπΎ 2,584 bytesπ text
β Back to All Filesπ― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes BufferedWriter and createBufferedWriter β mainly functions, hooks, or classes.
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
type WriteFn = (content: string) => void export type BufferedWriter = { write: (content: string) => void flush: () => void
π€ Exports (heuristic)
BufferedWritercreateBufferedWriter
π₯οΈ Source preview
type WriteFn = (content: string) => void
export type BufferedWriter = {
write: (content: string) => void
flush: () => void
dispose: () => void
}
export function createBufferedWriter({
writeFn,
flushIntervalMs = 1000,
maxBufferSize = 100,
maxBufferBytes = Infinity,
immediateMode = false,
}: {
writeFn: WriteFn
flushIntervalMs?: number
maxBufferSize?: number
maxBufferBytes?: number
immediateMode?: boolean
}): BufferedWriter {
let buffer: string[] = []
let bufferBytes = 0
let flushTimer: NodeJS.Timeout | null = null
// Batch detached by overflow that hasn't been written yet. Tracked so
// flush()/dispose() can drain it synchronously if the process exits
// before the setImmediate fires.
let pendingOverflow: string[] | null = null
function clearTimer(): void {
if (flushTimer) {
clearTimeout(flushTimer)
flushTimer = null
}
}
function flush(): void {
if (pendingOverflow) {
writeFn(pendingOverflow.join(''))
pendingOverflow = null
}
if (buffer.length === 0) return
writeFn(buffer.join(''))
buffer = []
bufferBytes = 0
clearTimer()
}
function scheduleFlush(): void {
if (!flushTimer) {
flushTimer = setTimeout(flush, flushIntervalMs)
}
}
// Detach the buffer synchronously so the caller never waits on writeFn.
// writeFn may block (e.g. errorLogSink.ts appendFileSync) β if overflow fires
// mid-render or mid-keystroke, deferring the write keeps the current tick
// short. Timer-based flushes already run outside user code paths so they
// stay synchronous.
function flushDeferred(): void {
if (pendingOverflow) {
// A previous overflow write is still queued. Coalesce into it to
// preserve ordering β writes land in a single setImmediate-ordered batch.
pendingOverflow.push(...buffer)
buffer = []
bufferBytes = 0
clearTimer()
return
}
const detached = buffer
buffer = []
bufferBytes = 0
clearTimer()
pendingOverflow = detached
setImmediate(() => {
const toWrite = pendingOverflow
pendingOverflow = null
if (toWrite) writeFn(toWrite.join(''))
})
}
return {
write(content: string): void {
if (immediateMode) {
writeFn(content)
return
}
buffer.push(content)
bufferBytes += content.length
scheduleFlush()
if (buffer.length >= maxBufferSize || bufferBytes >= maxBufferBytes) {
flushDeferred()
}
},
flush,
dispose(): void {
flush()
},
}
}