{"version":3,"file":"useRealtimeStream.mjs","sources":["../../../src/lib/realtime/useRealtimeStream.ts"],"sourcesContent":["/**\n * @file Use Realtime Stream Hook\n * @description Hook to subscribe to real-time updates for a specific channel.\n *\n * This hook provides WebSocket/SSE real-time communication, distinct from\n * the streaming/ module hooks which handle React 18 SSR HTML streaming.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { useRealtimeContext } from './RealtimeProvider';\n\n/**\n * Realtime stream subscription options\n */\nexport interface UseRealtimeStreamOptions<T> {\n  enabled?: boolean;\n  onMessage?: (data: T) => void;\n  onError?: (error: Error) => void;\n  transform?: (data: unknown) => T;\n}\n\n/**\n * Realtime stream subscription result\n */\nexport interface UseRealtimeStreamResult<T> {\n  isConnected: boolean;\n  lastMessage: T | null;\n  messages: T[];\n  send: (data: unknown) => void;\n  clear: () => void;\n}\n\n/**\n * Hook to subscribe to a realtime stream channel\n *\n * @example\n * ```tsx\n * function ChatComponent() {\n *   const { messages, send, isConnected } = useRealtimeStream<ChatMessage>('chat');\n *\n *   return (\n *     <div>\n *       {messages.map(msg => <div key={msg.id}>{msg.text}</div>)}\n *       <button onClick={() => send({ text: 'Hello!' })}>Send</button>\n *     </div>\n *   );\n * }\n * ```\n */\nexport function useRealtimeStream<T = unknown>(\n  channel: string,\n  options: UseRealtimeStreamOptions<T> = {}\n): UseRealtimeStreamResult<T> {\n  const { enabled = true, onMessage, onError, transform } = options;\n\n  const { isConnected, subscribe, send: contextSend } = useRealtimeContext();\n  const [lastMessage, setLastMessage] = useState<T | null>(null);\n  const [messages, setMessages] = useState<T[]>([]);\n\n  const onMessageRef = useRef(onMessage);\n  const onErrorRef = useRef(onError);\n  const transformRef = useRef(transform);\n\n  // Keep refs updated\n  useEffect(() => {\n    onMessageRef.current = onMessage;\n    onErrorRef.current = onError;\n    transformRef.current = transform;\n  }, [onMessage, onError, transform]);\n\n  // Subscribe to channel\n  useEffect(() => {\n    if (!enabled) return;\n\n    return subscribe(channel, (data: unknown) => {\n      try {\n        const transformed = transformRef.current ? transformRef.current(data) : (data as T);\n\n        setLastMessage(transformed);\n        setMessages((prev) => [...prev, transformed]);\n        onMessageRef.current?.(transformed);\n      } catch (error) {\n        console.error(`[useRealtimeStream] Error processing message on ${channel}:`, error);\n        onErrorRef.current?.(error as Error);\n      }\n    });\n  }, [channel, enabled, subscribe]);\n\n  /**\n   * Send data to the channel\n   */\n  const send = useCallback(\n    (data: unknown) => {\n      contextSend(channel, data);\n    },\n    [channel, contextSend]\n  );\n\n  /**\n   * Clear message history\n   */\n  const clear = useCallback(() => {\n    setLastMessage(null);\n    setMessages([]);\n  }, []);\n\n  return {\n    isConnected,\n    lastMessage,\n    messages,\n    send,\n    clear,\n  };\n}\n\n/**\n * Hook to subscribe to multiple channels\n *\n * NOTE: This is a simplified version. For production use, consider\n * using a single subscription with channel filtering instead.\n *\n * @param channels - Array of channel names to subscribe to\n * @param options - Subscription options\n * @returns Channel count and options (placeholder for multi-channel support)\n *\n * @example\n * ```tsx\n * // Use with caution - prefer single subscription with filtering\n * const result = useMultiRealtimeStream(['chat', 'notifications']);\n * ```\n */\nexport function useMultiRealtimeStream<T = unknown>(\n  channels: string[],\n  options: UseRealtimeStreamOptions<T> = {}\n): { channelCount: number; options: UseRealtimeStreamOptions<T> } {\n  // This pattern avoids the React hooks rules violation\n  // In practice, use a single subscription with channel filtering\n  return { channelCount: channels.length, options };\n}\n\n/**\n * Hook to get realtime connection state\n */\nexport function useRealtimeConnection(): {\n  connectionState: string;\n  isConnected: boolean;\n  connect: () => void;\n  disconnect: () => void;\n} {\n  const { connectionState, isConnected, connect, disconnect } = useRealtimeContext();\n\n  return {\n    connectionState,\n    isConnected,\n    connect,\n    disconnect,\n  };\n}\n\n/**\n * Hook for buffered realtime stream updates (debounced)\n */\nexport function useBufferedRealtimeStream<T = unknown>(\n  channel: string,\n  bufferMs: number = 100,\n  options: UseRealtimeStreamOptions<T> = {}\n): UseRealtimeStreamResult<T> {\n  const [bufferedMessages, setBufferedMessages] = useState<T[]>([]);\n  const [lastMessage, setLastMessage] = useState<T | null>(null);\n  const bufferRef = useRef<T[]>([]);\n  const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n  const flushBuffer = useCallback(() => {\n    if (bufferRef.current.length > 0) {\n      setBufferedMessages((prev) => [...prev, ...bufferRef.current]);\n      const lastMsg = bufferRef.current[bufferRef.current.length - 1];\n      if (lastMsg !== undefined) {\n        setLastMessage(lastMsg);\n      }\n      bufferRef.current = [];\n    }\n  }, []);\n\n  const streamResult = useRealtimeStream<T>(channel, {\n    ...options,\n    onMessage: (data) => {\n      bufferRef.current.push(data);\n\n      if (timeoutRef.current) {\n        clearTimeout(timeoutRef.current);\n      }\n\n      timeoutRef.current = setTimeout(flushBuffer, bufferMs);\n      options.onMessage?.(data);\n    },\n  });\n\n  // Cleanup timeout\n  useEffect(() => {\n    return () => {\n      if (timeoutRef.current) {\n        clearTimeout(timeoutRef.current);\n      }\n    };\n  }, []);\n\n  return {\n    ...streamResult,\n    lastMessage,\n    messages: bufferedMessages,\n    clear: useCallback(() => {\n      bufferRef.current = [];\n      setBufferedMessages([]);\n      setLastMessage(null);\n    }, []),\n  };\n}\n\n/**\n * Hook to track realtime stream presence (who's online)\n *\n * @param channel - The channel to track presence for\n * @returns Object containing list of users and count\n *\n * @example\n * ```tsx\n * function OnlineUsers() {\n *   const { users, count } = useRealtimePresence('chat-room');\n *   return <div>{count} users online</div>;\n * }\n * ```\n */\nexport function useRealtimePresence(channel: string): {\n  users: string[];\n  count: number;\n} {\n  const [users, setUsers] = useState<string[]>([]);\n\n  useRealtimeStream<{ type: string; userId: string; users?: string[] }>(`presence:${channel}`, {\n    onMessage: (data) => {\n      switch (data.type) {\n        case 'join':\n          setUsers((prev) => [...prev, data.userId]);\n          break;\n        case 'leave':\n          setUsers((prev) => prev.filter((id) => id !== data.userId));\n          break;\n        case 'sync':\n          if (data.users) {\n            setUsers(data.users);\n          }\n          break;\n      }\n    },\n  });\n\n  return { users, count: users.length };\n}\n"],"names":["useRealtimeStream","channel","options","enabled","onMessage","onError","transform","isConnected","subscribe","contextSend","useRealtimeContext","lastMessage","setLastMessage","useState","messages","setMessages","onMessageRef","useRef","onErrorRef","transformRef","useEffect","data","transformed","prev","error","send","useCallback","clear","useMultiRealtimeStream","channels","useRealtimeConnection","connectionState","connect","disconnect","useBufferedRealtimeStream","bufferMs","bufferedMessages","setBufferedMessages","bufferRef","timeoutRef","flushBuffer","lastMsg","streamResult","useRealtimePresence","users","setUsers","id"],"mappings":";;AAiDO,SAASA,EACdC,GACAC,IAAuC,IACX;AAC5B,QAAM,EAAE,SAAAC,IAAU,IAAM,WAAAC,GAAW,SAAAC,GAAS,WAAAC,MAAcJ,GAEpD,EAAE,aAAAK,GAAa,WAAAC,GAAW,MAAMC,EAAA,IAAgBC,EAAA,GAChD,CAACC,GAAaC,CAAc,IAAIC,EAAmB,IAAI,GACvD,CAACC,GAAUC,CAAW,IAAIF,EAAc,CAAA,CAAE,GAE1CG,IAAeC,EAAOb,CAAS,GAC/Bc,IAAaD,EAAOZ,CAAO,GAC3Bc,IAAeF,EAAOX,CAAS;AAGrC,EAAAc,EAAU,MAAM;AACd,IAAAJ,EAAa,UAAUZ,GACvBc,EAAW,UAAUb,GACrBc,EAAa,UAAUb;AAAA,EACzB,GAAG,CAACF,GAAWC,GAASC,CAAS,CAAC,GAGlCc,EAAU,MAAM;AACd,QAAKjB;AAEL,aAAOK,EAAUP,GAAS,CAACoB,MAAkB;AAC3C,YAAI;AACF,gBAAMC,IAAcH,EAAa,UAAUA,EAAa,QAAQE,CAAI,IAAKA;AAEzE,UAAAT,EAAeU,CAAW,GAC1BP,EAAY,CAACQ,MAAS,CAAC,GAAGA,GAAMD,CAAW,CAAC,GAC5CN,EAAa,UAAUM,CAAW;AAAA,QACpC,SAASE,GAAO;AACd,kBAAQ,MAAM,mDAAmDvB,CAAO,KAAKuB,CAAK,GAClFN,EAAW,UAAUM,CAAc;AAAA,QACrC;AAAA,MACF,CAAC;AAAA,EACH,GAAG,CAACvB,GAASE,GAASK,CAAS,CAAC;AAKhC,QAAMiB,IAAOC;AAAA,IACX,CAACL,MAAkB;AACjB,MAAAZ,EAAYR,GAASoB,CAAI;AAAA,IAC3B;AAAA,IACA,CAACpB,GAASQ,CAAW;AAAA,EAAA,GAMjBkB,IAAQD,EAAY,MAAM;AAC9B,IAAAd,EAAe,IAAI,GACnBG,EAAY,CAAA,CAAE;AAAA,EAChB,GAAG,CAAA,CAAE;AAEL,SAAO;AAAA,IACL,aAAAR;AAAA,IACA,aAAAI;AAAA,IACA,UAAAG;AAAA,IACA,MAAAW;AAAA,IACA,OAAAE;AAAA,EAAA;AAEJ;AAkBO,SAASC,EACdC,GACA3B,IAAuC,IACyB;AAGhE,SAAO,EAAE,cAAc2B,EAAS,QAAQ,SAAA3B,EAAA;AAC1C;AAKO,SAAS4B,IAKd;AACA,QAAM,EAAE,iBAAAC,GAAiB,aAAAxB,GAAa,SAAAyB,GAAS,YAAAC,EAAA,IAAevB,EAAA;AAE9D,SAAO;AAAA,IACL,iBAAAqB;AAAA,IACA,aAAAxB;AAAA,IACA,SAAAyB;AAAA,IACA,YAAAC;AAAA,EAAA;AAEJ;AAKO,SAASC,EACdjC,GACAkC,IAAmB,KACnBjC,IAAuC,CAAA,GACX;AAC5B,QAAM,CAACkC,GAAkBC,CAAmB,IAAIxB,EAAc,CAAA,CAAE,GAC1D,CAACF,GAAaC,CAAc,IAAIC,EAAmB,IAAI,GACvDyB,IAAYrB,EAAY,EAAE,GAC1BsB,IAAatB,EAAkD,MAAS,GAExEuB,IAAcd,EAAY,MAAM;AACpC,QAAIY,EAAU,QAAQ,SAAS,GAAG;AAChC,MAAAD,EAAoB,CAACd,MAAS,CAAC,GAAGA,GAAM,GAAGe,EAAU,OAAO,CAAC;AAC7D,YAAMG,IAAUH,EAAU,QAAQA,EAAU,QAAQ,SAAS,CAAC;AAC9D,MAAIG,MAAY,UACd7B,EAAe6B,CAAO,GAExBH,EAAU,UAAU,CAAA;AAAA,IACtB;AAAA,EACF,GAAG,CAAA,CAAE,GAECI,IAAe1C,EAAqBC,GAAS;AAAA,IACjD,GAAGC;AAAA,IACH,WAAW,CAACmB,MAAS;AACnB,MAAAiB,EAAU,QAAQ,KAAKjB,CAAI,GAEvBkB,EAAW,WACb,aAAaA,EAAW,OAAO,GAGjCA,EAAW,UAAU,WAAWC,GAAaL,CAAQ,GACrDjC,EAAQ,YAAYmB,CAAI;AAAA,IAC1B;AAAA,EAAA,CACD;AAGD,SAAAD,EAAU,MACD,MAAM;AACX,IAAImB,EAAW,WACb,aAAaA,EAAW,OAAO;AAAA,EAEnC,GACC,CAAA,CAAE,GAEE;AAAA,IACL,GAAGG;AAAA,IACH,aAAA/B;AAAA,IACA,UAAUyB;AAAA,IACV,OAAOV,EAAY,MAAM;AACvB,MAAAY,EAAU,UAAU,CAAA,GACpBD,EAAoB,CAAA,CAAE,GACtBzB,EAAe,IAAI;AAAA,IACrB,GAAG,CAAA,CAAE;AAAA,EAAA;AAET;AAgBO,SAAS+B,EAAoB1C,GAGlC;AACA,QAAM,CAAC2C,GAAOC,CAAQ,IAAIhC,EAAmB,CAAA,CAAE;AAE/C,SAAAb,EAAsE,YAAYC,CAAO,IAAI;AAAA,IAC3F,WAAW,CAACoB,MAAS;AACnB,cAAQA,EAAK,MAAA;AAAA,QACX,KAAK;AACH,UAAAwB,EAAS,CAACtB,MAAS,CAAC,GAAGA,GAAMF,EAAK,MAAM,CAAC;AACzC;AAAA,QACF,KAAK;AACH,UAAAwB,EAAS,CAACtB,MAASA,EAAK,OAAO,CAACuB,MAAOA,MAAOzB,EAAK,MAAM,CAAC;AAC1D;AAAA,QACF,KAAK;AACH,UAAIA,EAAK,SACPwB,EAASxB,EAAK,KAAK;AAErB;AAAA,MAAA;AAAA,IAEN;AAAA,EAAA,CACD,GAEM,EAAE,OAAAuB,GAAO,OAAOA,EAAM,OAAA;AAC/B;"}