/**
 * [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) with [Streams API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API)
 *
 * @see https://web.dev/websocketstream/
 */
export class BaseWebSocketStream {
    constructor(url, options = {}) {
        Object.defineProperty(this, "url", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "connection", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "closed", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "close", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        if (options.signal?.aborted) {
            throw new DOMException("This operation was aborted", "AbortError");
        }
        this.url = url;
        const ws = this.openWebSocket(url, options);
        const closeWithInfo = ({ code, reason } = {}) => ws.close(code, reason);
        this.connection = new Promise((resolve, reject) => {
            ws.onopen = () => {
                resolve({
                    readable: new ReadableStream({
                        start(controller) {
                            ws.onmessage = ({ data }) => controller.enqueue(data);
                            ws.onerror = (e) => controller.error(e);
                        },
                        cancel: closeWithInfo,
                    }),
                    writable: new WritableStream({
                        write(chunk) {
                            ws.send(chunk);
                        },
                        abort() {
                            ws.close();
                        },
                        close: closeWithInfo,
                    }),
                    protocol: ws.protocol,
                    extensions: ws.extensions,
                });
                ws.removeEventListener("error", reject);
            };
            ws.addEventListener("error", reject);
        });
        this.closed = new Promise((resolve, reject) => {
            ws.onclose = ({ code, reason }) => {
                resolve({ code, reason });
                ws.removeEventListener("error", reject);
            };
            ws.addEventListener("error", reject);
        });
        if (options.signal) {
            // eslint-disable-next-line no-param-reassign
            options.signal.onabort = () => ws.close();
        }
        this.close = closeWithInfo;
    }
}
