import EventEmitter from "eventemitter3"; import logger from "./logger"; import { PeerError, PromiseEvents } from "./peerError"; export class EventEmitterWithPromise< AwaitType extends EventEmitter, OpenType, ErrorType extends string, Events extends PromiseEvents, > extends EventEmitter implements Promise { protected _open = false; readonly [Symbol.toStringTag]: string; catch( onrejected?: | ((reason: PeerError<`${ErrorType}`>) => PromiseLike | TResult) | undefined | null, ): Promise { return this.then(undefined, onrejected); } finally(onfinally?: (() => void) | undefined | null): Promise { return this.then().finally(onfinally); } then( onfulfilled?: | ((value: AwaitType) => PromiseLike | TResult1) | undefined | null, onrejected?: | ((reason: any) => PromiseLike | TResult2) | undefined | null, ): Promise { const p = new Promise((resolve, reject) => { const onOpen = () => { // @ts-expect-error this.off("error", onError); // Remove 'then' to prevent potential recursion issues // `await` will wait for a Promise-like to resolve recursively resolve?.(proxyWithoutThen(this)); }; const onError = (err: PeerError<`${ErrorType}`>) => { // @ts-expect-error this.off("open", onOpen); reject(err); }; if (this._open) { onOpen(); return; } // @ts-expect-error this.once("open", onOpen); // @ts-expect-error this.once("error", onError); }); return p.then(onfulfilled, onrejected); } /** * Emits a typed error message. * * @internal */ emitError(type: ErrorType, err: string | Error): void { logger.error("Error:", err); // @ts-expect-error this.emit("error", new PeerError<`${ErrorType}`>(`${type}`, err)); } } function proxyWithoutThen(obj: T): Omit { return new Proxy(obj, { get(target, p, receiver) { if (p === "then") { return undefined; } return Reflect.get(target, p, receiver); }, }); }