PrivatemessageRing buffer for messages - automatically handles overflow
PrivatebufferCurrent write position in ring buffer
PrivatemaxFixed maximum number of messages to buffer.
DEFAULT_MAX_BUFFER_SIZE — the constant.
PrivatehasWhether buffer has wrapped around
Private ReadonlyoriginalOriginal console methods
PrivatelistenersCallbacks for new messages
PrivateisFlag to ensure we only intercept once
Whether console.* is currently being intercepted by this instance.
Start intercepting console methods. Idempotent — safe to call repeatedly.
After patch(), every console.log/warn/error/info/debug call also lands in the ring buffer. Reverse with dispose.
PrivateextractThe stack of the first real Error among args, falling back to the first
duck-typed stack carrier, or undefined.
Scans ALL args rather than just the first: every log.* call formats its
message into args[0] as a STRING and passes the error along behind it, so
looking only at args[0] could never find one.
Two passes so a real Error always wins over a duck-typed stack carrier:
getErrorStack also accepts a plain { stack: '…' } object, so a single
pass would let console.error('failed', { stack: 'context' }, realError)
record the context string instead of realError.stack. The real Error is
the diagnostic worth keeping. The priority pass uses isGenuineError
(instance or realm-proof [[Class]] brand — so a cross-realm Error gets
the same precedence as a same-realm one), NOT the wider isErrorLike:
its { name, message, stack } triple fallback would let a context bag
carrying all three strings shadow a real Error behind it. Duck-typed
carriers belong in the fallback pass only.
Deliberately does NOT fabricate a stack. This used to synthesize
new Error().stack whenever a message merely contained the word "error",
which produced a plausible-looking trace rooted inside this interceptor —
worse than no stack, because someone reading the bug report would follow it.
PrivatecaptureGet all buffered messages in chronological order
Clear the message buffer
Add a listener for new messages
Get original console methods
Get buffer statistics
Restore the original console methods and stop intercepting.
After dispose(), captureMessage() is no longer reachable through
console.log etc. The buffer is preserved (callers can still read
getBufferedMessages()), and the singleton slot is left intact —
call ConsoleInterceptor.disposeInstance to clear it.
The interceptor class type, re-exported for typing the singleton proxy.