{"version":3,"file":"index.mjs","names":["kEmitter","kBoundListener","socket: WebSocket","transport: WebSocketTransport","client: WebSocketOverride","transport: WebSocketClassTransport","createConnection: () => WebSocket","socket: WebSocketOverride"],"sources":["../../../../src/interceptors/WebSocket/utils/bindEvent.ts","../../../../src/interceptors/WebSocket/utils/events.ts","../../../../src/interceptors/WebSocket/WebSocketClientConnection.ts","../../../../src/interceptors/WebSocket/WebSocketOverride.ts","../../../../src/interceptors/WebSocket/WebSocketServerConnection.ts","../../../../src/interceptors/WebSocket/WebSocketClassTransport.ts","../../../../src/interceptors/WebSocket/index.ts"],"sourcesContent":["type EventWithTarget<E extends Event, T> = E & { target: T }\n\nexport function bindEvent<E extends Event, T>(\n  target: T,\n  event: E\n): EventWithTarget<E, T> {\n  Object.defineProperties(event, {\n    target: {\n      value: target,\n      enumerable: true,\n      writable: true,\n    },\n    currentTarget: {\n      value: target,\n      enumerable: true,\n      writable: true,\n    },\n  })\n\n  return event as EventWithTarget<E, T>\n}\n","const kCancelable = Symbol('kCancelable')\nconst kDefaultPrevented = Symbol('kDefaultPrevented')\n\n/**\n * A `MessageEvent` superset that supports event cancellation\n * in Node.js. It's rather non-intrusive so it can be safely\n * used in the browser as well.\n *\n * @see https://github.com/nodejs/node/issues/51767\n */\nexport class CancelableMessageEvent<T = any> extends MessageEvent<T> {\n  [kCancelable]: boolean;\n  [kDefaultPrevented]: boolean\n\n  constructor(type: string, init: MessageEventInit<T>) {\n    super(type, init)\n    this[kCancelable] = !!init.cancelable\n    this[kDefaultPrevented] = false\n  }\n\n  get cancelable() {\n    return this[kCancelable]\n  }\n\n  set cancelable(nextCancelable) {\n    this[kCancelable] = nextCancelable\n  }\n\n  get defaultPrevented() {\n    return this[kDefaultPrevented]\n  }\n\n  set defaultPrevented(nextDefaultPrevented) {\n    this[kDefaultPrevented] = nextDefaultPrevented\n  }\n\n  public preventDefault(): void {\n    if (this.cancelable && !this[kDefaultPrevented]) {\n      this[kDefaultPrevented] = true\n    }\n  }\n}\n\ninterface CloseEventInit extends EventInit {\n  code?: number\n  reason?: string\n  wasClean?: boolean\n}\n\nexport class CloseEvent extends Event {\n  public code: number\n  public reason: string\n  public wasClean: boolean\n\n  constructor(type: string, init: CloseEventInit = {}) {\n    super(type, init)\n    this.code = init.code === undefined ? 0 : init.code\n    this.reason = init.reason === undefined ? '' : init.reason\n    this.wasClean = init.wasClean === undefined ? false : init.wasClean\n  }\n}\n\nexport class CancelableCloseEvent extends CloseEvent {\n  [kCancelable]: boolean;\n  [kDefaultPrevented]: boolean\n\n  constructor(type: string, init: CloseEventInit = {}) {\n    super(type, init)\n    this[kCancelable] = !!init.cancelable\n    this[kDefaultPrevented] = false\n  }\n\n  get cancelable() {\n    return this[kCancelable]\n  }\n\n  set cancelable(nextCancelable) {\n    this[kCancelable] = nextCancelable\n  }\n\n  get defaultPrevented() {\n    return this[kDefaultPrevented]\n  }\n\n  set defaultPrevented(nextDefaultPrevented) {\n    this[kDefaultPrevented] = nextDefaultPrevented\n  }\n\n  public preventDefault(): void {\n    if (this.cancelable && !this[kDefaultPrevented]) {\n      this[kDefaultPrevented] = true\n    }\n  }\n}\n","import type { WebSocketData, WebSocketTransport } from './WebSocketTransport'\nimport type { WebSocketEventListener } from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\nimport { createRequestId } from '../../createRequestId'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\n\nexport interface WebSocketClientEventMap {\n  message: MessageEvent<WebSocketData>\n  close: CloseEvent\n}\n\nexport abstract class WebSocketClientConnectionProtocol {\n  abstract id: string\n  abstract url: URL\n  public abstract send(data: WebSocketData): void\n  public abstract close(code?: number, reason?: string): void\n\n  public abstract addEventListener<\n    EventType extends keyof WebSocketClientEventMap,\n  >(\n    type: EventType,\n    listener: WebSocketEventListener<WebSocketClientEventMap[EventType]>,\n    options?: AddEventListenerOptions | boolean\n  ): void\n\n  public abstract removeEventListener<\n    EventType extends keyof WebSocketClientEventMap,\n  >(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketClientEventMap[EventType]>,\n    options?: EventListenerOptions | boolean\n  ): void\n}\n\n/**\n * The WebSocket client instance represents an incoming\n * client connection. The user can control the connection,\n * send and receive events.\n */\nexport class WebSocketClientConnection implements WebSocketClientConnectionProtocol {\n  public readonly id: string\n  public readonly url: URL\n\n  private [kEmitter]: EventTarget\n\n  constructor(\n    public readonly socket: WebSocket,\n    private readonly transport: WebSocketTransport\n  ) {\n    this.id = createRequestId()\n    this.url = new URL(socket.url)\n    this[kEmitter] = new EventTarget()\n\n    // Emit outgoing client data (\"ws.send()\") as \"message\"\n    // events on the \"client\" connection.\n    this.transport.addEventListener('outgoing', (event) => {\n      const message = bindEvent(\n        this.socket,\n        new CancelableMessageEvent('message', {\n          data: event.data,\n          origin: event.origin,\n          cancelable: true,\n        })\n      )\n\n      this[kEmitter].dispatchEvent(message)\n\n      // This is a bit silly but forward the cancellation state\n      // of the \"client\" message event to the \"outgoing\" transport event.\n      // This way, other agens (like \"server\" connection) can know\n      // whether the client listener has pervented the default.\n      if (message.defaultPrevented) {\n        event.preventDefault()\n      }\n    })\n\n    /**\n     * Emit the \"close\" event on the \"client\" connection\n     * whenever the underlying transport is closed.\n     * @note \"client.close()\" does NOT dispatch the \"close\"\n     * event on the WebSocket because it uses non-configurable\n     * close status code. Thus, we listen to the transport\n     * instead of the WebSocket's \"close\" event.\n     */\n    this.transport.addEventListener('close', (event) => {\n      this[kEmitter].dispatchEvent(\n        bindEvent(this.socket, new CloseEvent('close', event))\n      )\n    })\n  }\n\n  /**\n   * Listen for the outgoing events from the connected WebSocket client.\n   */\n  public addEventListener<EventType extends keyof WebSocketClientEventMap>(\n    type: EventType,\n    listener: WebSocketEventListener<WebSocketClientEventMap[EventType]>,\n    options?: AddEventListenerOptions | boolean\n  ): void {\n    if (!Reflect.has(listener, kBoundListener)) {\n      const boundListener = listener.bind(this.socket)\n\n      // Store the bound listener on the original listener\n      // so the exact bound function can be accessed in \"removeEventListener()\".\n      Object.defineProperty(listener, kBoundListener, {\n        value: boundListener,\n        enumerable: false,\n        configurable: false,\n      })\n    }\n\n    this[kEmitter].addEventListener(\n      type,\n      Reflect.get(listener, kBoundListener) as EventListener,\n      options\n    )\n  }\n\n  /**\n   * Removes the listener for the given event.\n   */\n  public removeEventListener<EventType extends keyof WebSocketClientEventMap>(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketClientEventMap[EventType]>,\n    options?: EventListenerOptions | boolean\n  ): void {\n    this[kEmitter].removeEventListener(\n      event,\n      Reflect.get(listener, kBoundListener) as EventListener,\n      options\n    )\n  }\n\n  /**\n   * Send data to the connected client.\n   */\n  public send(data: WebSocketData): void {\n    this.transport.send(data)\n  }\n\n  /**\n   * Close the WebSocket connection.\n   * @param {number} code A status code (see https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1).\n   * @param {string} reason A custom connection close reason.\n   */\n  public close(code?: number, reason?: string): void {\n    this.transport.close(code, reason)\n  }\n}\n","import { invariant } from 'outvariant'\nimport { DeferredPromise } from '@open-draft/deferred-promise'\nimport type { WebSocketData } from './WebSocketTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport { CloseEvent } from './utils/events'\nimport { resolveWebSocketUrl } from '../../utils/resolveWebSocketUrl'\n\nexport type WebSocketEventListener<\n  EventType extends WebSocketEventMap[keyof WebSocketEventMap] = Event,\n> = (this: WebSocket, event: EventType) => void\n\nconst WEBSOCKET_CLOSE_CODE_RANGE_ERROR =\n  'InvalidAccessError: close code out of user configurable range'\n\nexport const kPassthroughPromise = Symbol('kPassthroughPromise')\nexport const kOnSend = Symbol('kOnSend')\nexport const kClose = Symbol('kClose')\n\nexport class WebSocketOverride extends EventTarget implements WebSocket {\n  static readonly CONNECTING = 0\n  static readonly OPEN = 1\n  static readonly CLOSING = 2\n  static readonly CLOSED = 3\n  readonly CONNECTING = 0\n  readonly OPEN = 1\n  readonly CLOSING = 2\n  readonly CLOSED = 3\n\n  public url: string\n  public protocol: string\n  public extensions: string\n  public binaryType: BinaryType\n  public readyState: WebSocket['readyState']\n  public bufferedAmount: number\n\n  private _onopen: WebSocketEventListener | null = null\n  private _onmessage: WebSocketEventListener<\n    MessageEvent<WebSocketData>\n  > | null = null\n  private _onerror: WebSocketEventListener | null = null\n  private _onclose: WebSocketEventListener<CloseEvent> | null = null\n\n  private [kPassthroughPromise]: DeferredPromise<boolean>\n  private [kOnSend]?: (data: WebSocketData) => void\n\n  constructor(url: string | URL, protocols?: string | Array<string>) {\n    super()\n    this.url = resolveWebSocketUrl(url)\n    this.protocol = ''\n    this.extensions = ''\n    this.binaryType = 'blob'\n    this.readyState = this.CONNECTING\n    this.bufferedAmount = 0\n\n    this[kPassthroughPromise] = new DeferredPromise<boolean>()\n\n    queueMicrotask(async () => {\n      if (await this[kPassthroughPromise]) {\n        return\n      }\n\n      this.protocol =\n        typeof protocols === 'string'\n          ? protocols\n          : Array.isArray(protocols) && protocols.length > 0\n            ? protocols[0]\n            : ''\n\n      /**\n       * @note Check that nothing has prevented this connection\n       * (e.g. called `client.close()` in the connection listener).\n       * If the connection has been prevented, never dispatch the open event,.\n       */\n      if (this.readyState === this.CONNECTING) {\n        this.readyState = this.OPEN\n        this.dispatchEvent(bindEvent(this, new Event('open')))\n      }\n    })\n  }\n\n  set onopen(listener: WebSocketEventListener | null) {\n    this.removeEventListener('open', this._onopen)\n    this._onopen = listener\n    if (listener !== null) {\n      this.addEventListener('open', listener)\n    }\n  }\n  get onopen(): WebSocketEventListener | null {\n    return this._onopen\n  }\n\n  set onmessage(\n    listener: WebSocketEventListener<MessageEvent<WebSocketData>> | null\n  ) {\n    this.removeEventListener(\n      'message',\n      this._onmessage as WebSocketEventListener\n    )\n    this._onmessage = listener\n    if (listener !== null) {\n      this.addEventListener('message', listener)\n    }\n  }\n  get onmessage(): WebSocketEventListener<MessageEvent<WebSocketData>> | null {\n    return this._onmessage\n  }\n\n  set onerror(listener: WebSocketEventListener | null) {\n    this.removeEventListener('error', this._onerror)\n    this._onerror = listener\n    if (listener !== null) {\n      this.addEventListener('error', listener)\n    }\n  }\n  get onerror(): WebSocketEventListener | null {\n    return this._onerror\n  }\n\n  set onclose(listener: WebSocketEventListener<CloseEvent> | null) {\n    this.removeEventListener('close', this._onclose as WebSocketEventListener)\n    this._onclose = listener\n    if (listener !== null) {\n      this.addEventListener('close', listener)\n    }\n  }\n  get onclose(): WebSocketEventListener<CloseEvent> | null {\n    return this._onclose\n  }\n\n  /**\n   * @see https://websockets.spec.whatwg.org/#ref-for-dom-websocket-send%E2%91%A0\n   */\n  public send(data: WebSocketData): void {\n    if (this.readyState === this.CONNECTING) {\n      this.close()\n      throw new DOMException('InvalidStateError')\n    }\n\n    // Sending when the socket is about to close\n    // discards the sent data.\n    if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n      return\n    }\n\n    // Buffer the data to send in this even loop\n    // but send it in the next.\n    this.bufferedAmount += getDataSize(data)\n\n    queueMicrotask(() => {\n      // This is a bit optimistic but since no actual data transfer\n      // is involved, all the data will be \"sent\" on the next tick.\n      this.bufferedAmount = 0\n\n      /**\n       * @note Notify the parent about outgoing data.\n       * This notifies the transport and the connection\n       * listens to the outgoing data to emit the \"message\" event.\n       */\n      this[kOnSend]?.(data)\n    })\n  }\n\n  public close(code: number = 1000, reason?: string): void {\n    invariant(code, WEBSOCKET_CLOSE_CODE_RANGE_ERROR)\n    invariant(\n      code === 1000 || (code >= 3000 && code <= 4999),\n      WEBSOCKET_CLOSE_CODE_RANGE_ERROR\n    )\n\n    this[kClose](code, reason)\n  }\n\n  private [kClose](\n    code: number = 1000,\n    reason?: string,\n    wasClean = true\n  ): void {\n    /**\n     * @note Move this check here so that even internal closures,\n     * like those triggered by the `server` connection, are not\n     * performed twice.\n     */\n    if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {\n      return\n    }\n\n    this.readyState = this.CLOSING\n\n    queueMicrotask(() => {\n      this.readyState = this.CLOSED\n\n      this.dispatchEvent(\n        bindEvent(\n          this,\n          new CloseEvent('close', {\n            code,\n            reason,\n            wasClean,\n          })\n        )\n      )\n\n      // Remove all event listeners once the socket is closed.\n      this._onopen = null\n      this._onmessage = null\n      this._onerror = null\n      this._onclose = null\n    })\n  }\n\n  public addEventListener<K extends keyof WebSocketEventMap>(\n    type: K,\n    listener: (this: WebSocket, event: WebSocketEventMap[K]) => void,\n    options?: boolean | AddEventListenerOptions\n  ): void\n  public addEventListener(\n    type: string,\n    listener: EventListenerOrEventListenerObject,\n    options?: boolean | AddEventListenerOptions\n  ): void\n  public addEventListener(\n    type: unknown,\n    listener: unknown,\n    options?: unknown\n  ): void {\n    return super.addEventListener(\n      type as string,\n      listener as EventListener,\n      options as AddEventListenerOptions\n    )\n  }\n\n  removeEventListener<K extends keyof WebSocketEventMap>(\n    type: K,\n    callback: EventListenerOrEventListenerObject | null,\n    options?: boolean | EventListenerOptions\n  ): void {\n    return super.removeEventListener(type, callback, options)\n  }\n}\n\nfunction getDataSize(data: WebSocketData): number {\n  if (typeof data === 'string') {\n    return data.length\n  }\n\n  if (data instanceof Blob) {\n    return data.size\n  }\n\n  return data.byteLength\n}\n","import { invariant } from 'outvariant'\nimport {\n  kClose,\n  WebSocketEventListener,\n  WebSocketOverride,\n} from './WebSocketOverride'\nimport type { WebSocketData } from './WebSocketTransport'\nimport type { WebSocketClassTransport } from './WebSocketClassTransport'\nimport { bindEvent } from './utils/bindEvent'\nimport {\n  CancelableMessageEvent,\n  CancelableCloseEvent,\n  CloseEvent,\n} from './utils/events'\n\nconst kEmitter = Symbol('kEmitter')\nconst kBoundListener = Symbol('kBoundListener')\nconst kSend = Symbol('kSend')\n\nexport interface WebSocketServerEventMap {\n  open: Event\n  message: MessageEvent<WebSocketData>\n  error: Event\n  close: CloseEvent\n}\n\nexport abstract class WebSocketServerConnectionProtocol {\n  public abstract connect(): void\n  public abstract send(data: WebSocketData): void\n  public abstract close(): void\n\n  public abstract addEventListener<\n    EventType extends keyof WebSocketServerEventMap,\n  >(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketServerEventMap[EventType]>,\n    options?: AddEventListenerOptions | boolean\n  ): void\n\n  public abstract removeEventListener<\n    EventType extends keyof WebSocketServerEventMap,\n  >(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketServerEventMap[EventType]>,\n    options?: EventListenerOptions | boolean\n  ): void\n}\n\n/**\n * The WebSocket server instance represents the actual production\n * WebSocket server connection. It's idle by default but you can\n * establish it by calling `server.connect()`.\n */\nexport class WebSocketServerConnection implements WebSocketServerConnectionProtocol {\n  /**\n   * A WebSocket instance connected to the original server.\n   */\n  private realWebSocket?: WebSocket\n  private mockCloseController: AbortController\n  private realCloseController: AbortController\n  private [kEmitter]: EventTarget\n\n  constructor(\n    private readonly client: WebSocketOverride,\n    private readonly transport: WebSocketClassTransport,\n    private readonly createConnection: () => WebSocket\n  ) {\n    this[kEmitter] = new EventTarget()\n    this.mockCloseController = new AbortController()\n    this.realCloseController = new AbortController()\n\n    // Automatically forward outgoing client events\n    // to the actual server unless the outgoing message event\n    // has been prevented. The \"outgoing\" transport event it\n    // dispatched by the \"client\" connection.\n    this.transport.addEventListener('outgoing', (event) => {\n      // Ignore client messages if the server connection\n      // hasn't been established yet. Nowhere to forward.\n      if (typeof this.realWebSocket === 'undefined') {\n        return\n      }\n\n      // Every outgoing client message can prevent this forwarding\n      // by preventing the default of the outgoing message event.\n      // This listener will be added before user-defined listeners,\n      // so execute the logic on the next tick.\n      queueMicrotask(() => {\n        if (!event.defaultPrevented) {\n          /**\n           * @note Use the internal send mechanism so consumers can tell\n           * apart direct user calls to `server.send()` and internal calls.\n           * E.g. MSW has to ignore this internal call to log out messages correctly.\n           */\n          this[kSend](event.data)\n        }\n      })\n    })\n\n    this.transport.addEventListener(\n      'incoming',\n      this.handleIncomingMessage.bind(this)\n    )\n  }\n\n  /**\n   * The `WebSocket` instance connected to the original server.\n   * Accessing this before calling `server.connect()` will throw.\n   */\n  public get socket(): WebSocket {\n    invariant(\n      this.realWebSocket,\n      'Cannot access \"socket\" on the original WebSocket server object: the connection is not open. Did you forget to call `server.connect()`?'\n    )\n\n    return this.realWebSocket\n  }\n\n  /**\n   * Open connection to the original WebSocket server.\n   */\n  public connect(): void {\n    invariant(\n      !this.realWebSocket || this.realWebSocket.readyState !== WebSocket.OPEN,\n      'Failed to call \"connect()\" on the original WebSocket instance: the connection already open'\n    )\n\n    const realWebSocket = this.createConnection()\n\n    // Inherit the binary type from the mock WebSocket client.\n    realWebSocket.binaryType = this.client.binaryType\n\n    // Allow the interceptor to listen to when the server connection\n    // has been established. This isn't necessary to operate with the connection\n    // but may be beneficial in some cases (like conditionally adding logging).\n    realWebSocket.addEventListener(\n      'open',\n      (event) => {\n        this[kEmitter].dispatchEvent(\n          bindEvent(this.realWebSocket!, new Event('open', event))\n        )\n      },\n      { once: true }\n    )\n\n    realWebSocket.addEventListener('message', (event) => {\n      // Dispatch the \"incoming\" transport event instead of\n      // invoking the internal handler directly. This way,\n      // anyone can listen to the \"incoming\" event but this\n      // class is the one resulting in it.\n      this.transport.dispatchEvent(\n        bindEvent(\n          this.realWebSocket!,\n          new MessageEvent('incoming', {\n            data: event.data,\n            origin: event.origin,\n          })\n        )\n      )\n    })\n\n    // Close the original connection when the mock client closes.\n    // E.g. \"client.close()\" was called. This is never forwarded anywhere.\n    this.client.addEventListener(\n      'close',\n      (event) => {\n        this.handleMockClose(event)\n      },\n      {\n        signal: this.mockCloseController.signal,\n      }\n    )\n\n    // Forward the \"close\" event to let the interceptor handle\n    // closures initiated by the original server.\n    realWebSocket.addEventListener(\n      'close',\n      (event) => {\n        this.handleRealClose(event)\n      },\n      {\n        signal: this.realCloseController.signal,\n      }\n    )\n\n    realWebSocket.addEventListener('error', () => {\n      const errorEvent = bindEvent(\n        realWebSocket,\n        new Event('error', { cancelable: true })\n      )\n\n      // Emit the \"error\" event on the `server` connection\n      // to let the interceptor react to original server errors.\n      this[kEmitter].dispatchEvent(errorEvent)\n\n      // If the error event from the original server hasn't been prevented,\n      // forward it to the underlying client.\n      if (!errorEvent.defaultPrevented) {\n        this.client.dispatchEvent(bindEvent(this.client, new Event('error')))\n      }\n    })\n\n    this.realWebSocket = realWebSocket\n  }\n\n  /**\n   * Listen for the incoming events from the original WebSocket server.\n   */\n  public addEventListener<EventType extends keyof WebSocketServerEventMap>(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketServerEventMap[EventType]>,\n    options?: AddEventListenerOptions | boolean\n  ): void {\n    if (!Reflect.has(listener, kBoundListener)) {\n      const boundListener = listener.bind(this.client)\n\n      // Store the bound listener on the original listener\n      // so the exact bound function can be accessed in \"removeEventListener()\".\n      Object.defineProperty(listener, kBoundListener, {\n        value: boundListener,\n        enumerable: false,\n      })\n    }\n\n    this[kEmitter].addEventListener(\n      event,\n      Reflect.get(listener, kBoundListener) as EventListener,\n      options\n    )\n  }\n\n  /**\n   * Remove the listener for the given event.\n   */\n  public removeEventListener<EventType extends keyof WebSocketServerEventMap>(\n    event: EventType,\n    listener: WebSocketEventListener<WebSocketServerEventMap[EventType]>,\n    options?: EventListenerOptions | boolean\n  ): void {\n    this[kEmitter].removeEventListener(\n      event,\n      Reflect.get(listener, kBoundListener) as EventListener,\n      options\n    )\n  }\n\n  /**\n   * Send data to the original WebSocket server.\n   * @example\n   * server.send('hello')\n   * server.send(new Blob(['hello']))\n   * server.send(new TextEncoder().encode('hello'))\n   */\n  public send(data: WebSocketData): void {\n    this[kSend](data)\n  }\n\n  private [kSend](data: WebSocketData): void {\n    const { realWebSocket } = this\n\n    invariant(\n      realWebSocket,\n      'Failed to call \"server.send()\" for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n      this.client.url\n    )\n\n    // Silently ignore writes on the closed original WebSocket.\n    if (\n      realWebSocket.readyState === WebSocket.CLOSING ||\n      realWebSocket.readyState === WebSocket.CLOSED\n    ) {\n      return\n    }\n\n    // Delegate the send to when the original connection is open.\n    // Unlike the mock, connecting to the original server may take time\n    // so we cannot call this on the next tick.\n    if (realWebSocket.readyState === WebSocket.CONNECTING) {\n      realWebSocket.addEventListener(\n        'open',\n        () => {\n          realWebSocket.send(data)\n        },\n        { once: true }\n      )\n      return\n    }\n\n    // Send the data to the original WebSocket server.\n    realWebSocket.send(data)\n  }\n\n  /**\n   * Close the actual server connection.\n   */\n  public close(): void {\n    const { realWebSocket } = this\n\n    invariant(\n      realWebSocket,\n      'Failed to close server connection for \"%s\": the connection is not open. Did you forget to call \"server.connect()\"?',\n      this.client.url\n    )\n\n    // Remove the \"close\" event listener from the server\n    // so it doesn't close the underlying WebSocket client\n    // when you call \"server.close()\". This also prevents the\n    // `close` event on the `server` connection from being dispatched twice.\n    this.realCloseController.abort()\n\n    if (\n      realWebSocket.readyState === WebSocket.CLOSING ||\n      realWebSocket.readyState === WebSocket.CLOSED\n    ) {\n      return\n    }\n\n    // Close the actual client connection.\n    realWebSocket.close()\n\n    // Dispatch the \"close\" event on the `server` connection.\n    queueMicrotask(() => {\n      this[kEmitter].dispatchEvent(\n        bindEvent(\n          this.realWebSocket,\n          new CancelableCloseEvent('close', {\n            /**\n             * @note `server.close()` in the interceptor\n             * always results in clean closures.\n             */\n            code: 1000,\n            cancelable: true,\n          })\n        )\n      )\n    })\n  }\n\n  private handleIncomingMessage(event: MessageEvent<WebSocketData>): void {\n    // Clone the event to dispatch it on this class\n    // once again and prevent the \"already being dispatched\"\n    // exception. Clone it here so we can observe this event\n    // being prevented in the \"server.on()\" listeners.\n    const messageEvent = bindEvent(\n      event.target,\n      new CancelableMessageEvent('message', {\n        data: event.data,\n        origin: event.origin,\n        cancelable: true,\n      })\n    )\n\n    /**\n     * @note Emit \"message\" event on the server connection\n     * instance to let the interceptor know about these\n     * incoming events from the original server. In that listener,\n     * the interceptor can modify or skip the event forwarding\n     * to the mock WebSocket instance.\n     */\n    this[kEmitter].dispatchEvent(messageEvent)\n\n    /**\n     * @note Forward the incoming server events to the client.\n     * Preventing the default on the message event stops this.\n     */\n    if (!messageEvent.defaultPrevented) {\n      this.client.dispatchEvent(\n        bindEvent(\n          /**\n           * @note Bind the forwarded original server events\n           * to the mock WebSocket instance so it would\n           * dispatch them straight away.\n           */\n          this.client,\n          // Clone the message event again to prevent\n          // the \"already being dispatched\" exception.\n          new MessageEvent('message', {\n            data: event.data,\n            origin: event.origin,\n          })\n        )\n      )\n    }\n  }\n\n  private handleMockClose(_event: Event): void {\n    // Close the original connection if the mock client closes.\n    if (this.realWebSocket) {\n      this.realWebSocket.close()\n    }\n  }\n\n  private handleRealClose(event: CloseEvent): void {\n    // For closures originating from the original server,\n    // remove the \"close\" listener from the mock client.\n    // original close -> (?) client[kClose]() --X--> \"close\" (again).\n    this.mockCloseController.abort()\n\n    const closeEvent = bindEvent(\n      this.realWebSocket,\n      new CancelableCloseEvent('close', {\n        code: event.code,\n        reason: event.reason,\n        wasClean: event.wasClean,\n        cancelable: true,\n      })\n    )\n\n    this[kEmitter].dispatchEvent(closeEvent)\n\n    // If the close event from the server hasn't been prevented,\n    // forward the closure to the mock client.\n    if (!closeEvent.defaultPrevented) {\n      // Close the intercepted client forcefully to\n      // allow non-configurable status codes from the server.\n      // If the socket has been closed by now, no harm calling\n      // this again—it will have no effect.\n      this.client[kClose](event.code, event.reason)\n    }\n  }\n}\n","import { bindEvent } from './utils/bindEvent'\nimport {\n  StrictEventListenerOrEventListenerObject,\n  WebSocketData,\n  WebSocketTransport,\n  WebSocketTransportEventMap,\n} from './WebSocketTransport'\nimport { kOnSend, kClose, WebSocketOverride } from './WebSocketOverride'\nimport { CancelableMessageEvent, CloseEvent } from './utils/events'\n\n/**\n * Abstraction over the given mock `WebSocket` instance that allows\n * for controlling that instance (e.g. sending and receiving messages).\n */\nexport class WebSocketClassTransport\n  extends EventTarget\n  implements WebSocketTransport\n{\n  constructor(protected readonly socket: WebSocketOverride) {\n    super()\n\n    // Emit the \"close\" event on the transport if the close\n    // originates from the WebSocket client. E.g. the application\n    // calls \"ws.close()\", not the interceptor.\n    this.socket.addEventListener('close', (event) => {\n      this.dispatchEvent(bindEvent(this.socket, new CloseEvent('close', event)))\n    })\n\n    /**\n     * Emit the \"outgoing\" event on the transport\n     * whenever the WebSocket client sends data (\"ws.send()\").\n     */\n    this.socket[kOnSend] = (data) => {\n      this.dispatchEvent(\n        bindEvent(\n          this.socket,\n          // Dispatch this as cancelable because \"client\" connection\n          // re-creates this message event (cannot dispatch the same event).\n          new CancelableMessageEvent('outgoing', {\n            data,\n            origin: this.socket.url,\n            cancelable: true,\n          })\n        )\n      )\n    }\n  }\n\n  public addEventListener<EventType extends keyof WebSocketTransportEventMap>(\n    type: EventType,\n    callback: StrictEventListenerOrEventListenerObject<\n      WebSocketTransportEventMap[EventType]\n    > | null,\n    options?: boolean | AddEventListenerOptions\n  ): void {\n    return super.addEventListener(type, callback as EventListener, options)\n  }\n\n  public dispatchEvent<EventType extends keyof WebSocketTransportEventMap>(\n    event: WebSocketTransportEventMap[EventType]\n  ): boolean {\n    return super.dispatchEvent(event)\n  }\n\n  public send(data: WebSocketData): void {\n    queueMicrotask(() => {\n      if (\n        this.socket.readyState === this.socket.CLOSING ||\n        this.socket.readyState === this.socket.CLOSED\n      ) {\n        return\n      }\n\n      const dispatchEvent = () => {\n        this.socket.dispatchEvent(\n          bindEvent(\n            /**\n             * @note Setting this event's \"target\" to the\n             * WebSocket override instance is important.\n             * This way it can tell apart original incoming events\n             * (must be forwarded to the transport) from the\n             * mocked message events like the one below\n             * (must be dispatched on the client instance).\n             */\n            this.socket,\n            new MessageEvent('message', {\n              data,\n              origin: this.socket.url,\n            })\n          )\n        )\n      }\n\n      if (this.socket.readyState === this.socket.CONNECTING) {\n        this.socket.addEventListener(\n          'open',\n          () => {\n            dispatchEvent()\n          },\n          { once: true }\n        )\n      } else {\n        dispatchEvent()\n      }\n    })\n  }\n\n  public close(code: number, reason?: string): void {\n    /**\n     * @note Call the internal close method directly\n     * to allow closing the connection with the status codes\n     * that are non-configurable by the user (> 1000 <= 1015).\n     */\n    this.socket[kClose](code, reason)\n  }\n}\n","import { Interceptor } from '../../Interceptor'\nimport {\n  WebSocketClientConnectionProtocol,\n  WebSocketClientConnection,\n  type WebSocketClientEventMap,\n} from './WebSocketClientConnection'\nimport {\n  WebSocketServerConnectionProtocol,\n  WebSocketServerConnection,\n  type WebSocketServerEventMap,\n} from './WebSocketServerConnection'\nimport { WebSocketClassTransport } from './WebSocketClassTransport'\nimport {\n  kClose,\n  kPassthroughPromise,\n  WebSocketOverride,\n} from './WebSocketOverride'\nimport { bindEvent } from './utils/bindEvent'\nimport { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'\nimport { emitAsync } from '../../utils/emitAsync'\n\nexport {\n  type WebSocketData,\n  type WebSocketTransport,\n} from './WebSocketTransport'\nexport {\n  WebSocketClientEventMap,\n  WebSocketClientConnectionProtocol,\n  WebSocketClientConnection,\n  WebSocketServerEventMap,\n  WebSocketServerConnectionProtocol,\n  WebSocketServerConnection,\n}\n\nexport {\n  CloseEvent,\n  CancelableCloseEvent,\n  CancelableMessageEvent,\n} from './utils/events'\n\nexport type WebSocketEventMap = {\n  connection: [args: WebSocketConnectionData]\n}\n\nexport type WebSocketConnectionData = {\n  /**\n   * The incoming WebSocket client connection.\n   */\n  client: WebSocketClientConnection\n\n  /**\n   * The original WebSocket server connection.\n   */\n  server: WebSocketServerConnection\n\n  /**\n   * The connection information.\n   */\n  info: {\n    /**\n     * The protocols supported by the WebSocket client.\n     */\n    protocols: string | Array<string> | undefined\n  }\n}\n\n/**\n * Intercept the outgoing WebSocket connections created using\n * the global `WebSocket` class.\n */\nexport class WebSocketInterceptor extends Interceptor<WebSocketEventMap> {\n  static symbol = Symbol('websocket')\n\n  constructor() {\n    super(WebSocketInterceptor.symbol)\n  }\n\n  protected checkEnvironment(): boolean {\n    return hasConfigurableGlobal('WebSocket')\n  }\n\n  protected setup(): void {\n    const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor(\n      globalThis,\n      'WebSocket'\n    )\n\n    const WebSocketProxy = new Proxy(globalThis.WebSocket, {\n      construct: (\n        target,\n        args: ConstructorParameters<typeof globalThis.WebSocket>,\n        newTarget\n      ) => {\n        const [url, protocols] = args\n\n        const createConnection = (): WebSocket => {\n          return Reflect.construct(target, args, newTarget)\n        }\n\n        // All WebSocket instances are mocked and don't forward\n        // any events to the original server (no connection established).\n        // To forward the events, the user must use the \"server.send()\" API.\n        const socket = new WebSocketOverride(url, protocols)\n        const transport = new WebSocketClassTransport(socket)\n\n        // Emit the \"connection\" event to the interceptor on the next tick\n        // so the client can modify WebSocket options, like \"binaryType\"\n        // while the connection is already pending.\n        queueMicrotask(async () => {\n          try {\n            const server = new WebSocketServerConnection(\n              socket,\n              transport,\n              createConnection\n            )\n\n            const hasConnectionListeners =\n              this.emitter.listenerCount('connection') > 0\n\n            // The \"globalThis.WebSocket\" class stands for\n            // the client-side connection. Assume it's established\n            // as soon as the WebSocket instance is constructed.\n            await emitAsync(this.emitter, 'connection', {\n              client: new WebSocketClientConnection(socket, transport),\n              server,\n              info: {\n                protocols,\n              },\n            })\n\n            if (hasConnectionListeners) {\n              socket[kPassthroughPromise].resolve(false)\n            } else {\n              socket[kPassthroughPromise].resolve(true)\n\n              server.connect()\n\n              // Forward the \"open\" event from the original server\n              // to the mock WebSocket client in the case of a passthrough connection.\n              server.addEventListener('open', () => {\n                socket.dispatchEvent(bindEvent(socket, new Event('open')))\n\n                // Forward the original connection protocol to the\n                // mock WebSocket client.\n                if (server['realWebSocket']) {\n                  socket.protocol = server['realWebSocket'].protocol\n                }\n              })\n            }\n          } catch (error) {\n            /**\n             * @note Translate unhandled exceptions during the connection\n             * handling (i.e. interceptor exceptions) as WebSocket connection\n             * closures with error. This prevents from the exceptions occurring\n             * in `queueMicrotask` from being process-wide and uncatchable.\n             */\n            if (error instanceof Error) {\n              socket.dispatchEvent(new Event('error'))\n\n              // No need to close the connection if it's already being closed.\n              // E.g. the interceptor called `client.close()` and then threw an error.\n              if (\n                socket.readyState !== WebSocket.CLOSING &&\n                socket.readyState !== WebSocket.CLOSED\n              ) {\n                socket[kClose](1011, error.message, false)\n              }\n\n              console.error(error)\n            }\n          }\n        })\n\n        return socket\n      },\n    })\n\n    Object.defineProperty(globalThis, 'WebSocket', {\n      value: WebSocketProxy,\n      configurable: true,\n    })\n\n    this.subscriptions.push(() => {\n      Object.defineProperty(\n        globalThis,\n        'WebSocket',\n        originalWebSocketDescriptor!\n      )\n    })\n  }\n}\n"],"mappings":"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"}