{"version":3,"sources":["../src/stream.ts"],"sourcesContent":["export interface SSEOptions {\n  readonly withCredentials?: boolean\n  readonly eventSource?: SSEConstructor\n  readonly onOpen?: (event: Event) => void\n  readonly onMessage?: (event: MessageEvent) => void\n  readonly onError?: (event: Event) => void\n}\n\nexport interface SSEClient {\n  readonly source: EventSource\n  close(): void\n}\n\nexport type SSEConstructor = new (url: string, options?: EventSourceInit) => EventSource\n\nexport function createSSE(url: string, options: SSEOptions = {}): SSEClient {\n  const EventSourceImpl = options.eventSource ?? globalThis.EventSource\n  if (!EventSourceImpl) throw new Error('HTTP: 当前环境没有可用的 EventSource')\n  const source = new EventSourceImpl(url, { withCredentials: options.withCredentials ?? false })\n  if (options.onOpen) source.addEventListener('open', options.onOpen)\n  if (options.onMessage) source.addEventListener('message', options.onMessage)\n  if (options.onError) source.addEventListener('error', options.onError)\n  return {\n    source,\n    close: () => source.close()\n  }\n}\n\nexport interface WebSocketOptions {\n  readonly protocols?: string | readonly string[]\n  readonly webSocket?: WebSocketConstructor\n  readonly autoReconnect?: boolean\n  readonly reconnectDelay?: number\n}\n\nexport interface WebSocketClient {\n  readonly socket: WebSocket | null\n  readonly state: WebSocketState\n  connect(): void\n  send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void\n  close(code?: number, reason?: string): void\n  on<K extends WebSocketEventName>(event: K, listener: WebSocketEventListener<K>): () => void\n}\n\nexport type WebSocketState = 'idle' | 'connecting' | 'open' | 'closed'\nexport type WebSocketEventName = 'open' | 'message' | 'error' | 'close'\nexport type WebSocketEventListener<K extends WebSocketEventName> =\n  K extends 'message' ? (event: MessageEvent) => void\n    : K extends 'close' ? (event: CloseEvent) => void\n      : (event: Event) => void\nexport type WebSocketConstructor = new (\n  url: string,\n  protocols?: string | string[]\n) => WebSocket\n\nexport function createWebSocket(url: string, options: WebSocketOptions = {}): WebSocketClient {\n  const WebSocketImpl = options.webSocket ?? globalThis.WebSocket\n  if (!WebSocketImpl) throw new Error('HTTP: 当前环境没有可用的 WebSocket')\n  const reconnectDelay = options.reconnectDelay ?? 1_000\n  if (!Number.isFinite(reconnectDelay) || reconnectDelay < 0) {\n    throw new Error('HTTP: reconnectDelay 必须是大于等于 0 的有限数字')\n  }\n\n  const listeners = new Map<WebSocketEventName, Set<(event: Event) => void>>()\n  let socket: WebSocket | null = null\n  let state: WebSocketState = 'idle'\n  let manuallyClosed = false\n  let reconnectTimer: ReturnType<typeof setTimeout> | undefined\n\n  const client: WebSocketClient = {\n    get socket(): WebSocket | null { return socket },\n    get state(): WebSocketState { return state },\n    connect,\n    send(data) {\n      if (!socket || state !== 'open') throw new Error('HTTP: WebSocket 尚未连接')\n      socket.send(data)\n    },\n    close(code, reason) {\n      manuallyClosed = true\n      if (reconnectTimer !== undefined) clearTimeout(reconnectTimer)\n      socket?.close(code, reason)\n      if (!socket) state = 'closed'\n    },\n    on(event, listener) {\n      let eventListeners = listeners.get(event)\n      if (!eventListeners) {\n        eventListeners = new Set()\n        listeners.set(event, eventListeners)\n      }\n      eventListeners.add(listener as (event: Event) => void)\n      return () => eventListeners?.delete(listener as (event: Event) => void)\n    }\n  }\n\n  connect()\n  return client\n\n  function connect(): void {\n    if (state === 'connecting' || state === 'open') return\n    manuallyClosed = false\n    state = 'connecting'\n    const protocols = options.protocols === undefined\n      ? undefined\n      : typeof options.protocols === 'string' ? options.protocols : [...options.protocols]\n    socket = new WebSocketImpl(url, protocols)\n    socket.addEventListener('open', event => {\n      state = 'open'\n      notify('open', event)\n    })\n    socket.addEventListener('message', event => notify('message', event))\n    socket.addEventListener('error', event => notify('error', event))\n    socket.addEventListener('close', event => {\n      state = 'closed'\n      socket = null\n      notify('close', event)\n      if (options.autoReconnect && !manuallyClosed) {\n        reconnectTimer = setTimeout(() => {\n          reconnectTimer = undefined\n          connect()\n        }, reconnectDelay)\n      }\n    })\n  }\n\n  function notify(event: WebSocketEventName, value: Event): void {\n    for (const listener of [...(listeners.get(event) ?? [])]) listener(value)\n  }\n}\n"],"mappings":"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","names":[]}