chore: initialize recovered claude workspace
This commit is contained in:
99
src/utils/abortController.ts
Normal file
99
src/utils/abortController.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { setMaxListeners } from 'events'
|
||||
|
||||
/**
|
||||
* Default max listeners for standard operations
|
||||
*/
|
||||
const DEFAULT_MAX_LISTENERS = 50
|
||||
|
||||
/**
|
||||
* Creates an AbortController with proper event listener limits set.
|
||||
* This prevents MaxListenersExceededWarning when multiple listeners
|
||||
* are attached to the abort signal.
|
||||
*
|
||||
* @param maxListeners - Maximum number of listeners (default: 50)
|
||||
* @returns AbortController with configured listener limit
|
||||
*/
|
||||
export function createAbortController(
|
||||
maxListeners: number = DEFAULT_MAX_LISTENERS,
|
||||
): AbortController {
|
||||
const controller = new AbortController()
|
||||
setMaxListeners(maxListeners, controller.signal)
|
||||
return controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates abort from a parent to a weakly-referenced child controller.
|
||||
* Both parent and child are weakly held — neither direction creates a
|
||||
* strong reference that could prevent GC.
|
||||
* Module-scope function avoids per-call closure allocation.
|
||||
*/
|
||||
function propagateAbort(
|
||||
this: WeakRef<AbortController>,
|
||||
weakChild: WeakRef<AbortController>,
|
||||
): void {
|
||||
const parent = this.deref()
|
||||
weakChild.deref()?.abort(parent?.signal.reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an abort handler from a weakly-referenced parent signal.
|
||||
* Both parent and handler are weakly held — if either has been GC'd
|
||||
* or the parent already aborted ({once: true}), this is a no-op.
|
||||
* Module-scope function avoids per-call closure allocation.
|
||||
*/
|
||||
function removeAbortHandler(
|
||||
this: WeakRef<AbortController>,
|
||||
weakHandler: WeakRef<(...args: unknown[]) => void>,
|
||||
): void {
|
||||
const parent = this.deref()
|
||||
const handler = weakHandler.deref()
|
||||
if (parent && handler) {
|
||||
parent.signal.removeEventListener('abort', handler)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child AbortController that aborts when its parent aborts.
|
||||
* Aborting the child does NOT affect the parent.
|
||||
*
|
||||
* Memory-safe: Uses WeakRef so the parent doesn't retain abandoned children.
|
||||
* If the child is dropped without being aborted, it can still be GC'd.
|
||||
* When the child IS aborted, the parent listener is removed to prevent
|
||||
* accumulation of dead handlers.
|
||||
*
|
||||
* @param parent - The parent AbortController
|
||||
* @param maxListeners - Maximum number of listeners (default: 50)
|
||||
* @returns Child AbortController
|
||||
*/
|
||||
export function createChildAbortController(
|
||||
parent: AbortController,
|
||||
maxListeners?: number,
|
||||
): AbortController {
|
||||
const child = createAbortController(maxListeners)
|
||||
|
||||
// Fast path: parent already aborted, no listener setup needed
|
||||
if (parent.signal.aborted) {
|
||||
child.abort(parent.signal.reason)
|
||||
return child
|
||||
}
|
||||
|
||||
// WeakRef prevents the parent from keeping an abandoned child alive.
|
||||
// If all strong references to child are dropped without aborting it,
|
||||
// the child can still be GC'd — the parent only holds a dead WeakRef.
|
||||
const weakChild = new WeakRef(child)
|
||||
const weakParent = new WeakRef(parent)
|
||||
const handler = propagateAbort.bind(weakParent, weakChild)
|
||||
|
||||
parent.signal.addEventListener('abort', handler, { once: true })
|
||||
|
||||
// Auto-cleanup: remove parent listener when child is aborted (from any source).
|
||||
// Both parent and handler are weakly held — if either has been GC'd or the
|
||||
// parent already aborted ({once: true}), the cleanup is a harmless no-op.
|
||||
child.signal.addEventListener(
|
||||
'abort',
|
||||
removeAbortHandler.bind(weakParent, new WeakRef(handler)),
|
||||
{ once: true },
|
||||
)
|
||||
|
||||
return child
|
||||
}
|
||||
Reference in New Issue
Block a user