@graphql-hive/signal
Version:
139 lines (134 loc) • 4.05 kB
JavaScript
;
const isNode = !globalThis.Bun && globalThis.process?.release?.name === "node";
const controllerInSignalSy = Symbol("CONTROLLER_IN_SIGNAL");
const signalRegistry = new FinalizationRegistry(
(cb) => cb()
);
function abortSignalAny(signals) {
if (signals.length === 0) {
return void 0;
}
if (signals.length === 1) {
return signals[0];
}
if (!isNode) {
return AbortSignal.any(signals);
}
for (const signal of signals) {
if (signal.aborted) {
return signal;
}
}
const ctrl = new AbortController();
const ctrlRef = new WeakRef(ctrl);
const eventListenerPairs = [];
let retainedSignalsCount = signals.length;
for (const signal of signals) {
let abort2 = function() {
ctrlRef.deref()?.abort(signalRef.deref()?.reason);
};
const signalRef = new WeakRef(signal);
signal.addEventListener("abort", abort2);
eventListenerPairs.push([signalRef, abort2]);
signalRegistry.register(
signal,
() => (
// dispose when all of the signals have been GCed
!--retainedSignalsCount && dispose()
),
signal
);
}
function dispose() {
for (const [signalRef, abort2] of eventListenerPairs) {
const signal = signalRef.deref();
if (signal) {
signal.removeEventListener("abort", abort2);
signalRegistry.unregister(signal);
}
const ctrl2 = ctrlRef.deref();
if (ctrl2) {
signalRegistry.unregister(ctrl2.signal);
delete ctrl2.signal[controllerInSignalSy];
}
}
}
ctrl.signal.addEventListener("abort", dispose);
signalRegistry.register(ctrl.signal, dispose, ctrl.signal);
ctrl.signal[controllerInSignalSy] = ctrl;
return ctrl.signal;
}
function abortSignalAll(signals) {
if (signals.length === 0) {
return void 0;
}
if (signals.length === 1) {
return signals[0];
}
if (signals.every((signal) => signal.aborted)) {
const errors2 = signals.map((signal) => signal.reason).filter(
(reason) => reason != null && !reason?.toString?.()?.includes("AbortError")
);
if (errors2.length < 2) {
return signals[0];
} else {
return AbortSignal.abort(new AggregateError(errors2));
}
}
const ctrl = new AbortController();
const ctrlRef = new WeakRef(ctrl);
const eventListenerPairs = [];
let retainedSignalsCount = signals.length;
let remainingSignalsToAbort = signals.length;
const errors = /* @__PURE__ */ new Set();
for (const signal of signals) {
let onAbort2 = function() {
remainingSignalsToAbort--;
const reason = signal.reason;
if (reason != null && !reason?.toString().includes("AbortError")) {
errors.add(reason);
}
if (remainingSignalsToAbort === 0) {
let error;
if (errors.size < 2) {
error = errors.values().next().value;
} else {
error = new AggregateError(errors);
}
ctrlRef.deref()?.abort(error);
}
};
const signalRef = new WeakRef(signal);
signal.addEventListener("abort", onAbort2);
eventListenerPairs.push([signalRef, onAbort2]);
signalRegistry.register(
signal,
() => (
// dispose when all of the signals have been GCed
!--retainedSignalsCount && dispose()
),
signal
);
}
function dispose() {
for (const [signalRef, abort] of eventListenerPairs) {
const signal = signalRef.deref();
if (signal) {
signal.removeEventListener("abort", abort);
signalRegistry.unregister(signal);
}
}
const ctrl2 = ctrlRef.deref();
if (ctrl2) {
ctrl2.signal.removeEventListener("abort", dispose);
signalRegistry.unregister(ctrl2.signal);
delete ctrl2.signal[controllerInSignalSy];
}
}
ctrl.signal.addEventListener("abort", dispose);
signalRegistry.register(ctrl.signal, dispose, ctrl.signal);
ctrl.signal[controllerInSignalSy] = ctrl;
return ctrl.signal;
}
exports.abortSignalAll = abortSignalAll;
exports.abortSignalAny = abortSignalAny;