{"version":3,"file":"use-ws-BBm1tFJe.cjs","names":["onOpen: EventHandlerOptions[\"onOpen\"]","onMessage: EventHandlerOptions[\"onMessage\"]","onClose: EventHandlerOptions[\"onClose\"]","onError: EventHandlerOptions[\"onError\"]","WebSocket","options"],"sources":["../src/use-handlers.ts","../src/use-socket.ts","../src/use-ws.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\nimport type WebSocket from \"./ws\";\n\nexport type EventHandlerOptions = {\n  onOpen?: (event: WebSocketEventMap[\"open\"]) => void;\n  onMessage?: (event: WebSocketEventMap[\"message\"]) => void;\n  onClose?: (event: WebSocketEventMap[\"close\"]) => void;\n  onError?: (event: WebSocketEventMap[\"error\"]) => void;\n};\n\n/** Attaches event handlers to a WebSocket in a React Lifecycle-friendly way */\nexport const useAttachWebSocketEventHandlers = (\n  socket: WebSocket,\n  options: EventHandlerOptions\n) => {\n  const handlersRef = useRef(options);\n  handlersRef.current = options;\n\n  useEffect(() => {\n    const onOpen: EventHandlerOptions[\"onOpen\"] = (event) =>\n      handlersRef.current?.onOpen?.(event);\n    const onMessage: EventHandlerOptions[\"onMessage\"] = (event) =>\n      handlersRef.current?.onMessage?.(event);\n    const onClose: EventHandlerOptions[\"onClose\"] = (event) =>\n      handlersRef.current?.onClose?.(event);\n    const onError: EventHandlerOptions[\"onError\"] = (event) =>\n      handlersRef.current?.onError?.(event);\n\n    socket.addEventListener(\"open\", onOpen);\n    socket.addEventListener(\"close\", onClose);\n    socket.addEventListener(\"error\", onError);\n    socket.addEventListener(\"message\", onMessage);\n\n    return () => {\n      socket.removeEventListener(\"open\", onOpen);\n      socket.removeEventListener(\"close\", onClose);\n      socket.removeEventListener(\"error\", onError);\n      socket.removeEventListener(\"message\", onMessage);\n    };\n  }, [socket]);\n};\n","import { useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type WebSocket from \"./ws\";\nimport type { Options } from \"./ws\";\n\nexport type SocketOptions = Options & {\n  /** Whether the socket should be connected. Defaults to true. */\n  enabled?: boolean;\n};\n\n/** When any of the option values are changed, we should reinitialize the socket */\nexport const getOptionsThatShouldCauseRestartWhenChanged = (\n  options: SocketOptions\n) => [\n  // Note: enabled is handled separately to avoid creating a new socket on toggle\n  options.startClosed,\n  options.minUptime,\n  options.maxRetries,\n  options.connectionTimeout,\n  options.maxEnqueuedMessages,\n  options.maxReconnectionDelay,\n  options.minReconnectionDelay,\n  options.reconnectionDelayGrowFactor,\n  options.debug\n];\n\n/**\n * Initializes a PartySocket (or WebSocket) and keeps it stable across renders,\n * but reconnects and updates the reference when any of the connection args change.\n */\nexport function useStableSocket<\n  T extends WebSocket,\n  TOpts extends SocketOptions\n>({\n  options,\n  createSocket,\n  createSocketMemoKey: createOptionsMemoKey\n}: {\n  options: TOpts;\n  createSocket: (options: TOpts) => T;\n  createSocketMemoKey: (options: TOpts) => string;\n}) {\n  // extract enabled with default value of true\n  const { enabled = true } = options;\n\n  // ensure we only reconnect when necessary\n  const shouldReconnect = createOptionsMemoKey(options);\n  const socketOptions = useMemo(() => {\n    return options;\n  }, [shouldReconnect]);\n\n  // this is the socket we return\n  const [socket, setSocket] = useState<T>(() =>\n    // only connect on first mount\n    createSocket({ ...socketOptions, startClosed: true })\n  );\n\n  // keep track of the socket we initialized\n  const socketInitializedRef = useRef<T | null>(null);\n\n  // allow changing the socket factory without reconnecting\n  const createSocketRef = useRef(createSocket);\n  createSocketRef.current = createSocket;\n\n  // track the previous enabled state to detect changes\n  const prevEnabledRef = useRef(enabled);\n\n  // track the previous socketOptions reference to distinguish option changes\n  // from HMR/StrictMode effect re-runs. useMemo returns the same reference\n  // when the memo key hasn't changed, so referential equality tells us\n  // whether the connection options actually changed.\n  const prevSocketOptionsRef = useRef(socketOptions);\n\n  // finally, initialize the socket\n  useEffect(() => {\n    const optionsChanged = prevSocketOptionsRef.current !== socketOptions;\n    prevSocketOptionsRef.current = socketOptions;\n\n    // if disabled, close the socket and don't proceed with connection logic\n    if (!enabled) {\n      socket.close();\n      prevEnabledRef.current = enabled;\n      return;\n    }\n\n    // if enabled just changed from false to true, reconnect\n    if (!prevEnabledRef.current && enabled) {\n      socket.reconnect();\n      prevEnabledRef.current = enabled;\n      return;\n    }\n\n    prevEnabledRef.current = enabled;\n\n    // we haven't yet restarted the socket\n    if (socketInitializedRef.current === socket) {\n      if (optionsChanged) {\n        // connection options changed — create new socket with new config\n        const newSocket = createSocketRef.current({\n          ...socketOptions,\n          // when reconnecting because of options change, we always reconnect\n          // (startClosed only applies to initial mount)\n          startClosed: false\n        });\n\n        // update socket reference (this will cause the effect to run again)\n        setSocket(newSocket);\n      } else {\n        // HMR or React Strict Mode effect re-run — reconnect the existing\n        // socket instead of creating a new instance. This preserves the\n        // socket identity (event listeners, _pk, etc.) across Hot Module\n        // Replacement, preventing downstream code from losing its reference\n        // to the live socket.\n        if (socketOptions.startClosed !== true) {\n          socket.reconnect();\n        }\n        return () => {\n          socket.close();\n        };\n      }\n    } else {\n      // if this is the first time we are running the hook, connect...\n      if (!socketInitializedRef.current && socketOptions.startClosed !== true) {\n        socket.reconnect();\n      }\n      // track initialized socket so we know not to do it again\n      socketInitializedRef.current = socket;\n      // close the old socket the next time the socket changes or we unmount\n      return () => {\n        socket.close();\n      };\n    }\n  }, [socket, socketOptions, enabled]);\n\n  return socket;\n}\n","import { useAttachWebSocketEventHandlers } from \"./use-handlers\";\nimport {\n  getOptionsThatShouldCauseRestartWhenChanged,\n  useStableSocket\n} from \"./use-socket\";\nimport WebSocket from \"./ws\";\n\nimport type { EventHandlerOptions } from \"./use-handlers\";\nimport type { SocketOptions } from \"./use-socket\";\nimport type { ProtocolsProvider, UrlProvider } from \"./ws\";\n\ntype UseWebSocketOptions = SocketOptions & EventHandlerOptions;\n\n// A React hook that wraps PartySocket\nexport default function useWebSocket(\n  url: UrlProvider,\n  protocols?: ProtocolsProvider,\n  options: UseWebSocketOptions = {}\n) {\n  const socket = useStableSocket({\n    options,\n    createSocket: (options) => new WebSocket(url, protocols, options),\n    createSocketMemoKey: (options) =>\n      JSON.stringify([\n        // will reconnect if url or protocols are specified as a string.\n        // if they are functions, the WebSocket will handle reconnection\n        url,\n        protocols,\n        ...getOptionsThatShouldCauseRestartWhenChanged(options)\n      ])\n  });\n\n  useAttachWebSocketEventHandlers(socket, options);\n\n  return socket;\n}\n"],"mappings":";;;;;AAYA,MAAa,mCACX,QACA,YACG;CACH,MAAM,gCAAqB,QAAQ;AACnC,aAAY,UAAU;AAEtB,4BAAgB;EACd,MAAMA,UAAyC,UAC7C,YAAY,SAAS,SAAS,MAAM;EACtC,MAAMC,aAA+C,UACnD,YAAY,SAAS,YAAY,MAAM;EACzC,MAAMC,WAA2C,UAC/C,YAAY,SAAS,UAAU,MAAM;EACvC,MAAMC,WAA2C,UAC/C,YAAY,SAAS,UAAU,MAAM;AAEvC,SAAO,iBAAiB,QAAQ,OAAO;AACvC,SAAO,iBAAiB,SAAS,QAAQ;AACzC,SAAO,iBAAiB,SAAS,QAAQ;AACzC,SAAO,iBAAiB,WAAW,UAAU;AAE7C,eAAa;AACX,UAAO,oBAAoB,QAAQ,OAAO;AAC1C,UAAO,oBAAoB,SAAS,QAAQ;AAC5C,UAAO,oBAAoB,SAAS,QAAQ;AAC5C,UAAO,oBAAoB,WAAW,UAAU;;IAEjD,CAAC,OAAO,CAAC;;;;;;AC7Bd,MAAa,+CACX,YACG;CAEH,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACT;;;;;AAMD,SAAgB,gBAGd,EACA,SACA,cACA,qBAAqB,wBAKpB;CAED,MAAM,EAAE,UAAU,SAAS;CAI3B,MAAM,yCAA8B;AAClC,SAAO;IACN,CAHqB,qBAAqB,QAAQ,CAGjC,CAAC;CAGrB,MAAM,CAAC,QAAQ,uCAEb,aAAa;EAAE,GAAG;EAAe,aAAa;EAAM,CAAC,CACtD;CAGD,MAAM,yCAAwC,KAAK;CAGnD,MAAM,oCAAyB,aAAa;AAC5C,iBAAgB,UAAU;CAG1B,MAAM,mCAAwB,QAAQ;CAMtC,MAAM,yCAA8B,cAAc;AAGlD,4BAAgB;EACd,MAAM,iBAAiB,qBAAqB,YAAY;AACxD,uBAAqB,UAAU;AAG/B,MAAI,CAAC,SAAS;AACZ,UAAO,OAAO;AACd,kBAAe,UAAU;AACzB;;AAIF,MAAI,CAAC,eAAe,WAAW,SAAS;AACtC,UAAO,WAAW;AAClB,kBAAe,UAAU;AACzB;;AAGF,iBAAe,UAAU;AAGzB,MAAI,qBAAqB,YAAY,OACnC,KAAI,eAUF,WARkB,gBAAgB,QAAQ;GACxC,GAAG;GAGH,aAAa;GACd,CAAC,CAGkB;OACf;AAML,OAAI,cAAc,gBAAgB,KAChC,QAAO,WAAW;AAEpB,gBAAa;AACX,WAAO,OAAO;;;OAGb;AAEL,OAAI,CAAC,qBAAqB,WAAW,cAAc,gBAAgB,KACjE,QAAO,WAAW;AAGpB,wBAAqB,UAAU;AAE/B,gBAAa;AACX,WAAO,OAAO;;;IAGjB;EAAC;EAAQ;EAAe;EAAQ,CAAC;AAEpC,QAAO;;;;;ACxHT,SAAwB,aACtB,KACA,WACA,UAA+B,EAAE,EACjC;CACA,MAAM,SAAS,gBAAgB;EAC7B;EACA,eAAe,cAAY,IAAIC,iCAAU,KAAK,WAAWC,UAAQ;EACjE,sBAAsB,cACpB,KAAK,UAAU;GAGb;GACA;GACA,GAAG,4CAA4CA,UAAQ;GACxD,CAAC;EACL,CAAC;AAEF,iCAAgC,QAAQ,QAAQ;AAEhD,QAAO"}