const DOM_EXCEPTION_CODES = {
'IndexSizeError': 1,
'HierarchyRequestError': 3,
'WrongDocumentError': 4,
'InvalidCharacterError': 5,
'NoModificationAllowedError': 7,
'NotFoundError': 8,
'NotSupportedError': 9,
'InvalidStateError': 11,
'SyntaxError': 12,
'InvalidModificationError': 13,
'NamespaceError': 14,
'InvalidAccessError': 15,
'TypeMismatchError': 17,
'SecurityError': 18,
'NetworkError': 19,
'AbortError': 20,
'URLMismatchError': 21,
'QuotaExceededError': 22,
'TimeoutError': 23,
'DataCloneError': 25,
};
class DOMException extends Error {
constructor(message = '', name = 'Error') {
super(message);
this.name = name;
this.code = DOM_EXCEPTION_CODES[name] || 0;
}
}
import { _eventTrusted } from 'node:events';
const _signalState = Symbol('AbortSignal.state');
const INTERNAL_TOKEN = Symbol('AbortSignal.internal');
const timeoutSignalStrongRefs = new Set();
function getSignalState(signal) {
const state = signal[_signalState];
if (!state) {
throw new TypeError('Illegal invocation');
}
return state;
}
function setupTimeoutTimer(weakSignal, milliseconds) {
const timeoutId = setTimeout(() => {
const s = weakSignal.deref();
if (s) {
timeoutSignalStrongRefs.delete(s);
abortSignal(s, new DOMException('The operation timed out.', 'TimeoutError'));
}
}, milliseconds);
timeoutId.unref();
}
function _preGcCleanup() {
for (const signal of timeoutSignalStrongRefs) {
const hasListeners = Object.values(signal._listeners).some(arr => arr.length > 0);
if (!hasListeners) {
timeoutSignalStrongRefs.delete(signal);
}
}
}
globalThis.__wasm_rquickjs_pre_gc = _preGcCleanup;
function abortSignal(signal, reason) {
const state = signal[_signalState];
if (!state || state.aborted) return;
state.aborted = true;
state.reason = reason;
const event = new Event('abort');
_eventTrusted.set(event, true);
signal.dispatchEvent(event);
}
class AbortSignal {
constructor(token) {
if (token !== INTERNAL_TOKEN) {
const err = new TypeError('Illegal constructor');
err.code = 'ERR_ILLEGAL_CONSTRUCTOR';
throw err;
}
this._listeners = Object.create(null);
Object.defineProperty(this, _signalState, {
value: {
aborted: false,
reason: undefined,
onabort: null,
},
writable: false,
enumerable: false,
configurable: false,
});
}
get aborted() {
return getSignalState(this).aborted;
}
get reason() {
return getSignalState(this).reason;
}
get onabort() {
return getSignalState(this).onabort;
}
set onabort(handler) {
getSignalState(this).onabort = handler;
}
static abort(reason) {
const signal = new AbortSignal(INTERNAL_TOKEN);
const state = signal[_signalState];
state.aborted = true;
state.reason = reason !== undefined
? reason
: new DOMException('This operation was aborted', 'AbortError');
return signal;
}
static timeout(milliseconds) {
const signal = new AbortSignal(INTERNAL_TOKEN);
signal[_signalState].isTimeout = true;
timeoutSignalStrongRefs.add(signal);
setupTimeoutTimer(new WeakRef(signal), milliseconds);
return signal;
}
static any(signals) {
if (!Array.isArray(signals)) {
throw new TypeError('signals must be an iterable');
}
const signal = new AbortSignal(INTERNAL_TOKEN);
const state = signal[_signalState];
for (const s of signals) {
if (s.aborted) {
state.aborted = true;
state.reason = s.reason;
return signal;
}
}
for (const s of signals) {
s.addEventListener('abort', function() {
if (!state.aborted) {
state.aborted = true;
state.reason = s.reason;
signal.dispatchEvent(new Event('abort'));
}
}, { once: true });
}
return signal;
}
throwIfAborted() {
const state = getSignalState(this);
if (state.aborted) {
throw state.reason;
}
}
addEventListener(type, listener, options) {
if (!listener) return;
const opts = typeof options === 'object' ? options : { capture: !!options };
if (type !== 'abort') return;
if (!this._listeners[type]) {
this._listeners[type] = [];
}
if (!this._listeners[type].find(l => l.listener === listener)) {
this._listeners[type].push({
listener,
capture: opts.capture || false,
once: opts.once || false,
});
}
}
removeEventListener(type, listener, options) {
if (!listener || !this._listeners[type]) return;
const capture = typeof options === 'boolean' ? options : !!(options && options.capture);
const index = this._listeners[type].findIndex(l => l.listener === listener && l.capture === capture);
if (index !== -1) {
this._listeners[type].splice(index, 1);
}
}
dispatchEvent(event) {
event.target = this;
const state = getSignalState(this);
if (state.onabort && event.type === 'abort') {
try {
state.onabort.call(this, event);
} catch (e) {
}
}
const entries = this._listeners[event.type];
if (!entries) return !event.defaultPrevented;
const listenersToCall = [...entries];
for (const item of listenersToCall) {
try {
item.listener.call(this, event);
} catch (e) {
}
if (item.once) {
const index = entries.indexOf(item);
if (index !== -1) {
entries.splice(index, 1);
}
}
}
return !event.defaultPrevented;
}
}
const _controllerSignal = Symbol('AbortController.signal');
function validateController(controller) {
if (!(controller instanceof AbortController) || !(controller[_controllerSignal])) {
throw new TypeError('Illegal invocation');
}
}
class AbortController {
constructor() {
this[_controllerSignal] = new AbortSignal(INTERNAL_TOKEN);
}
get signal() {
validateController(this);
return this[_controllerSignal];
}
abort(reason) {
validateController(this);
abortSignal(
this[_controllerSignal],
reason !== undefined
? reason
: new DOMException('The operation was aborted.', 'AbortError'),
);
}
}
const customInspect = Symbol.for('nodejs.util.inspect.custom');
AbortSignal.prototype[customInspect] = function(depth, opts) {
if (depth < 0) return 'AbortSignal';
const state = this[_signalState];
if (!state) return 'AbortSignal';
if (depth === 0) {
return `[AbortSignal]`;
}
return `AbortSignal { aborted: ${state.aborted} }`;
};
AbortController.prototype[customInspect] = function(depth, opts) {
if (depth !== null && depth < 0) return 'AbortController';
const signal = this.signal;
if (!signal) return 'AbortController';
const nextDepth = depth === null ? null : depth - 1;
const signalStr = (nextDepth !== null && nextDepth < 0) ? '[AbortSignal]' : signal[customInspect](nextDepth, opts);
return `AbortController { signal: ${signalStr} }`;
};
Object.defineProperty(AbortController.prototype, Symbol.toStringTag, {
value: 'AbortController',
configurable: true,
});
Object.defineProperty(AbortSignal.prototype, Symbol.toStringTag, {
value: 'AbortSignal',
configurable: true,
});
export { AbortController, AbortSignal, DOMException };