'use strict'; var errors = require('@solana/errors'); var subscribable = require('@solana/subscribable'); // src/websocket-channel.ts var t = globalThis.EventTarget; // ../ws-impl/dist/index.browser.mjs var e = globalThis.WebSocket; // src/websocket-channel.ts var NORMAL_CLOSURE_CODE = 1e3; function createWebSocketChannel({ sendBufferHighWatermark, signal, url }) { if (signal.aborted) { return Promise.reject(signal.reason); } let bufferDrainWatcher; let hasConnected = false; const listenerRemovers = /* @__PURE__ */ new Set(); function cleanupListeners() { listenerRemovers.forEach((r) => { r(); }); listenerRemovers.clear(); } function handleAbort() { cleanupListeners(); if (!hasConnected) { rejectOpen(signal.reason); } if (webSocket.readyState !== e.CLOSED && webSocket.readyState !== e.CLOSING) { webSocket.close(NORMAL_CLOSURE_CODE); } } function handleClose(ev) { cleanupListeners(); bufferDrainWatcher?.onCancel(); signal.removeEventListener("abort", handleAbort); webSocket.removeEventListener("close", handleClose); webSocket.removeEventListener("error", handleError); webSocket.removeEventListener("message", handleMessage); webSocket.removeEventListener("open", handleOpen); if (!signal.aborted && !(ev.wasClean && ev.code === NORMAL_CLOSURE_CODE)) { eventTarget.dispatchEvent( new CustomEvent("error", { detail: new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CONNECTION_CLOSED, { cause: ev }) }) ); } } function handleError(ev) { if (signal.aborted) { return; } if (!hasConnected) { const failedToConnectError = new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_FAILED_TO_CONNECT, { errorEvent: ev }); rejectOpen(failedToConnectError); eventTarget.dispatchEvent( new CustomEvent("error", { detail: failedToConnectError }) ); } } function handleMessage(ev) { if (signal.aborted) { return; } eventTarget.dispatchEvent(new CustomEvent("message", { detail: ev.data })); } const eventTarget = new t(); const dataPublisher = subscribable.getDataPublisherFromEventEmitter(eventTarget); function handleOpen() { hasConnected = true; resolveOpen({ ...dataPublisher, async send(message) { if (webSocket.readyState !== e.OPEN) { throw new errors.SolanaError(errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CONNECTION_CLOSED); } if (!bufferDrainWatcher && webSocket.bufferedAmount > sendBufferHighWatermark) { let onCancel; const promise = new Promise((resolve, reject) => { const intervalId = setInterval(() => { if (webSocket.readyState !== e.OPEN || !(webSocket.bufferedAmount > sendBufferHighWatermark)) { clearInterval(intervalId); bufferDrainWatcher = void 0; resolve(); } }, 16); onCancel = () => { bufferDrainWatcher = void 0; clearInterval(intervalId); reject( new errors.SolanaError( errors.SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CLOSED_BEFORE_MESSAGE_BUFFERED ) ); }; }); bufferDrainWatcher = { onCancel, promise }; } if (bufferDrainWatcher) { if (ArrayBuffer.isView(message) && !(message instanceof DataView)) { const TypedArrayConstructor = message.constructor; message = new TypedArrayConstructor(message); } await bufferDrainWatcher.promise; } webSocket.send(message); } }); } const webSocket = new e(url); signal.addEventListener("abort", handleAbort); webSocket.addEventListener("close", handleClose); webSocket.addEventListener("error", handleError); webSocket.addEventListener("message", handleMessage); webSocket.addEventListener("open", handleOpen); let rejectOpen; let resolveOpen; return new Promise((resolve, reject) => { rejectOpen = reject; resolveOpen = resolve; }); } exports.createWebSocketChannel = createWebSocketChannel; //# sourceMappingURL=index.browser.cjs.map //# sourceMappingURL=index.browser.cjs.map