{"version":3,"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\n/** When any of the option values are changed, we should reinitialize the socket */\nexport const getOptionsThatShouldCauseRestartWhenChanged = (\n  options: Options\n) => [\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<T extends WebSocket, TOpts extends Options>({\n  options,\n  createSocket,\n  createSocketMemoKey: createOptionsMemoKey\n}: {\n  options: TOpts;\n  createSocket: (options: TOpts) => T;\n  createSocketMemoKey: (options: TOpts) => string;\n}) {\n  // ensure we only reconnect when necessary\n  const shouldReconnect = createOptionsMemoKey(options);\n  // biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>\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  // finally, initialize the socket\n  useEffect(() => {\n    // we haven't yet restarted the socket\n    if (socketInitializedRef.current === socket) {\n      // create new socket\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      // 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]);\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 { Options, ProtocolsProvider, UrlProvider } from \"./ws\";\n\ntype UseWebSocketOptions = Options & 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":";;;;;AAAA,SAAS,WAAW,cAAc;AAY3B,IAAM,kCAAkC,CAC7C,QACA,YACG;AACH,QAAM,cAAc,OAAO,OAAO;AAClC,cAAY,UAAU;AAEtB,YAAU,MAAM;AACd,UAAM,SAAwC,CAAC,UAAO;AApB1D;AAqBM,qCAAY,YAAZ,mBAAqB,WAArB,4BAA8B;AAAA;AAChC,UAAM,YAA8C,CAAC,UAAO;AAtBhE;AAuBM,qCAAY,YAAZ,mBAAqB,cAArB,4BAAiC;AAAA;AACnC,UAAM,UAA0C,CAAC,UAAO;AAxB5D;AAyBM,qCAAY,YAAZ,mBAAqB,YAArB,4BAA+B;AAAA;AACjC,UAAM,UAA0C,CAAC,UAAO;AA1B5D;AA2BM,qCAAY,YAAZ,mBAAqB,YAArB,4BAA+B;AAAA;AAEjC,WAAO,iBAAiB,QAAQ,MAAM;AACtC,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,SAAS,OAAO;AACxC,WAAO,iBAAiB,WAAW,SAAS;AAE5C,WAAO,MAAM;AACX,aAAO,oBAAoB,QAAQ,MAAM;AACzC,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,SAAS,OAAO;AAC3C,aAAO,oBAAoB,WAAW,SAAS;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AACb;;;ACzCA,SAAS,aAAAA,YAAW,SAAS,UAAAC,SAAQ,gBAAgB;AAM9C,IAAM,8CAA8C,CACzD,YACG;AAAA,EACH,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAMO,SAAS,gBAA4D;AAAA,EAC1E;AAAA,EACA;AAAA,EACA,qBAAqB;AACvB,GAIG;AAED,QAAM,kBAAkB,qBAAqB,OAAO;AAEpD,QAAM,gBAAgB,QAAQ,MAAM;AAClC,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,CAAC,QAAQ,SAAS,IAAI;AAAA,IAAY;AAAA;AAAA,MAEtC,aAAa,EAAE,GAAG,eAAe,aAAa,KAAK,CAAC;AAAA;AAAA,EACtD;AAGA,QAAM,uBAAuBA,QAAiB,IAAI;AAGlD,QAAM,kBAAkBA,QAAO,YAAY;AAC3C,kBAAgB,UAAU;AAG1B,EAAAD,WAAU,MAAM;AAEd,QAAI,qBAAqB,YAAY,QAAQ;AAE3C,YAAM,YAAY,gBAAgB,QAAQ;AAAA,QACxC,GAAG;AAAA;AAAA;AAAA,QAGH,aAAa;AAAA,MACf,CAAC;AAGD,gBAAU,SAAS;AAAA,IACrB,OAAO;AAEL,UAAI,CAAC,qBAAqB,WAAW,cAAc,gBAAgB,MAAM;AACvE,eAAO,UAAU;AAAA,MACnB;AAEA,2BAAqB,UAAU;AAE/B,aAAO,MAAM;AACX,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,SAAO;AACT;;;ACrEe,SAAR,aACL,KACA,WACA,UAA+B,CAAC,GAChC;AACA,QAAM,SAAS,gBAAgB;AAAA,IAC7B;AAAA,IACA,cAAc,CAACE,aAAY,IAAI,sBAAU,KAAK,WAAWA,QAAO;AAAA,IAChE,qBAAqB,CAACA,aACpB,KAAK,UAAU;AAAA;AAAA;AAAA,MAGb;AAAA,MACA;AAAA,MACA,GAAG,4CAA4CA,QAAO;AAAA,IACxD,CAAC;AAAA,EACL,CAAC;AAED,kCAAgC,QAAQ,OAAO;AAE/C,SAAO;AACT;","names":["useEffect","useRef","options"]}