@@ -55,7 +55,7 @@ public final class RealtimeClientV2: Sendable {
5555 }
5656
5757 private let statusSubject = AsyncValueSubject < RealtimeClientStatus > ( . disconnected)
58- private let heartbeatSubject = AsyncValueSubject < RealtimeMessageV2 ? > ( nil )
58+ private let heartbeatSubject = AsyncValueSubject < HeartbeatStatus ? > ( nil )
5959
6060 /// Listen for connection status changes.
6161 ///
@@ -73,7 +73,7 @@ public final class RealtimeClientV2: Sendable {
7373 /// Listen for heartbeat checks.
7474 ///
7575 /// You can also use ``onHeartbeat(_:)`` for a closure based method.
76- public var heartbeat : AsyncStream < RealtimeMessageV2 > {
76+ public var heartbeat : AsyncStream < HeartbeatStatus > {
7777 heartbeatSubject. values. compactMap { $0 } . eraseToStream ( )
7878 }
7979
@@ -95,7 +95,7 @@ public final class RealtimeClientV2: Sendable {
9595 ///
9696 /// - Nite: Use ``heartbeat`` if you prefer to use Async/Await.
9797 public func onHeartbeat(
98- _ listener: @escaping @Sendable ( RealtimeMessageV2 ) -> Void
98+ _ listener: @escaping @Sendable ( HeartbeatStatus ) -> Void
9999 ) -> RealtimeSubscription {
100100 let task = heartbeatSubject. onChange { message in
101101 guard let message else { return }
@@ -243,14 +243,15 @@ public final class RealtimeClientV2: Sendable {
243243
244244 private func onClose( code: Int ? , reason: String ? ) {
245245 options. logger? . debug (
246- " WebSocket closed. Code: \( code? . description ?? " <none> " ) , Reason: \( reason ?? " <none> " ) " )
246+ " WebSocket closed. Code: \( code? . description ?? " <none> " ) , Reason: \( reason ?? " <none> " ) "
247+ )
247248
248249 reconnect ( )
249250 }
250251
251- private func reconnect( ) {
252+ private func reconnect( disconnectReason : String ? = nil ) {
252253 Task {
253- disconnect ( )
254+ disconnect ( reason : disconnectReason )
254255 await connect ( reconnect: true )
255256 }
256257 }
@@ -294,7 +295,8 @@ public final class RealtimeClientV2: Sendable {
294295 }
295296
296297 @available (
297- * , deprecated,
298+ * ,
299+ deprecated,
298300 message:
299301 " Client handles channels automatically, this method will be removed on the next major release. "
300302 )
@@ -396,6 +398,11 @@ public final class RealtimeClientV2: Sendable {
396398 }
397399
398400 private func sendHeartbeat( ) async {
401+ if status != . connected {
402+ heartbeatSubject. yield ( . disconnected)
403+ return
404+ }
405+
399406 let pendingHeartbeatRef : String ? = mutableState. withValue {
400407 if $0. pendingHeartbeatRef != nil {
401408 $0. pendingHeartbeatRef = nil
@@ -417,10 +424,12 @@ public final class RealtimeClientV2: Sendable {
417424 payload: [ : ]
418425 )
419426 )
427+ heartbeatSubject. yield ( . sent)
420428 await setAuth ( )
421429 } else {
422430 options. logger? . debug ( " Heartbeat timeout " )
423- reconnect ( )
431+ heartbeatSubject. yield ( . timeout)
432+ reconnect ( disconnectReason: " heartbeat timeout " )
424433 }
425434 }
426435
@@ -478,7 +487,7 @@ public final class RealtimeClientV2: Sendable {
478487
479488 private func onMessage( _ message: RealtimeMessageV2 ) async {
480489 if message. topic == " phoenix " , message. event == " phx_reply " {
481- heartbeatSubject. yield ( message)
490+ heartbeatSubject. yield ( message. status == . ok ? . ok : . error )
482491 }
483492
484493 let channel = mutableState. withValue {
@@ -516,7 +525,8 @@ public final class RealtimeClientV2: Sendable {
516525
517526 Error:
518527 \( error)
519- """ )
528+ """
529+ )
520530 }
521531 }
522532
0 commit comments