react-realtime-hooks 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/index.cjs +168 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -2
- package/dist/index.d.ts +8 -2
- package/dist/index.js +168 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -350,7 +350,7 @@ export function NetworkIndicator() {
|
|
|
350
350
|
| `parseMessage` | `(event) => TIncoming` | raw `event.data` | Incoming parser |
|
|
351
351
|
| `serializeMessage` | `(message) => ...` | JSON/string passthrough | Outgoing serializer |
|
|
352
352
|
| `reconnect` | `false \| UseReconnectOptions` | enabled | Reconnect configuration |
|
|
353
|
-
| `heartbeat` | `false \|
|
|
353
|
+
| `heartbeat` | `false \| UseWebSocketHeartbeatOptions` | disabled unless configured | Heartbeat configuration |
|
|
354
354
|
| `shouldReconnect` | `(event) => boolean` | `true` | Reconnect gate on close |
|
|
355
355
|
| `onOpen` | `(event, socket) => void` | `undefined` | Open callback |
|
|
356
356
|
| `onMessage` | `(message, event) => void` | `undefined` | Message callback |
|
|
@@ -375,6 +375,10 @@ export function NetworkIndicator() {
|
|
|
375
375
|
| `reconnect` | `() => void` | Manual reconnect |
|
|
376
376
|
| `send` | `(message) => boolean` | Sends an outgoing payload |
|
|
377
377
|
|
|
378
|
+
When you configure `useWebSocket` heartbeat, you can also set `timeoutAction` and
|
|
379
|
+
`errorAction` to `"none"`, `"close"`, or `"reconnect"`. The default is
|
|
380
|
+
`"reconnect"` when reconnect is enabled and `"close"` otherwise.
|
|
381
|
+
|
|
378
382
|
</details>
|
|
379
383
|
|
|
380
384
|
<details>
|
|
@@ -464,6 +468,7 @@ export function NetworkIndicator() {
|
|
|
464
468
|
| `startOnMount` | `boolean` | `true` | Starts immediately |
|
|
465
469
|
| `onBeat` | `() => void` | `undefined` | Called on every beat |
|
|
466
470
|
| `onTimeout` | `() => void` | `undefined` | Called on timeout |
|
|
471
|
+
| `onError` | `(error) => void` | `undefined` | Called when `beat()` throws or rejects |
|
|
467
472
|
|
|
468
473
|
### Result
|
|
469
474
|
|
|
@@ -507,7 +512,7 @@ export function NetworkIndicator() {
|
|
|
507
512
|
|
|
508
513
|
- `useEventSource` is receive-only by design. SSE is not a bidirectional transport.
|
|
509
514
|
- `useWebSocket` heartbeat support is client-side. You still define your own server ping/pong protocol.
|
|
510
|
-
- If `parseMessage` throws, the hook moves into `error` and
|
|
515
|
+
- If `parseMessage` throws, the hook closes the current transport, moves into `error`, stores `lastError`, and stops auto-reconnect until manual `open()` or `reconnect()`.
|
|
511
516
|
- `connect: false` keeps the hook in `idle` until `open()` is called.
|
|
512
517
|
- Manual `close()` is sticky. The hook stays closed until `open()` or `reconnect()` is called.
|
|
513
518
|
- No transport polyfills are bundled. Provide your own runtime support where needed.
|
package/dist/index.cjs
CHANGED
|
@@ -404,6 +404,7 @@ var useHeartbeat = (options) => {
|
|
|
404
404
|
const startOnMount = options.startOnMount ?? true;
|
|
405
405
|
const intervalRef = react.useRef(createManagedInterval());
|
|
406
406
|
const timeoutRef = react.useRef(createManagedTimeout());
|
|
407
|
+
const generationRef = react.useRef(0);
|
|
407
408
|
const [state, setState] = react.useState(
|
|
408
409
|
() => createInitialState2(enabled && startOnMount)
|
|
409
410
|
);
|
|
@@ -430,8 +431,7 @@ var useHeartbeat = (options) => {
|
|
|
430
431
|
handleTimeout();
|
|
431
432
|
}, options.timeoutMs);
|
|
432
433
|
});
|
|
433
|
-
const
|
|
434
|
-
const performedAt = Date.now();
|
|
434
|
+
const handleBeatSuccess = react.useEffectEvent((performedAt) => {
|
|
435
435
|
commitState((current) => ({
|
|
436
436
|
...current,
|
|
437
437
|
hasTimedOut: false,
|
|
@@ -439,7 +439,35 @@ var useHeartbeat = (options) => {
|
|
|
439
439
|
}));
|
|
440
440
|
scheduleTimeout();
|
|
441
441
|
options.onBeat?.();
|
|
442
|
-
|
|
442
|
+
});
|
|
443
|
+
const handleBeatError = react.useEffectEvent((error) => {
|
|
444
|
+
timeoutRef.current.cancel();
|
|
445
|
+
options.onError?.(error);
|
|
446
|
+
});
|
|
447
|
+
const runBeat = react.useEffectEvent(() => {
|
|
448
|
+
const generation = generationRef.current;
|
|
449
|
+
const completeBeat = (result) => {
|
|
450
|
+
if (generation !== generationRef.current || result === false) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
handleBeatSuccess(Date.now());
|
|
454
|
+
};
|
|
455
|
+
const failBeat = (error) => {
|
|
456
|
+
if (generation !== generationRef.current) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
handleBeatError(error);
|
|
460
|
+
};
|
|
461
|
+
try {
|
|
462
|
+
const result = options.beat?.();
|
|
463
|
+
if (result !== null && typeof result === "object" && "then" in result) {
|
|
464
|
+
void Promise.resolve(result).then(completeBeat, failBeat);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
completeBeat(result);
|
|
468
|
+
} catch (error) {
|
|
469
|
+
failBeat(error);
|
|
470
|
+
}
|
|
443
471
|
});
|
|
444
472
|
const start = () => {
|
|
445
473
|
if (!enabled) {
|
|
@@ -457,6 +485,7 @@ var useHeartbeat = (options) => {
|
|
|
457
485
|
}));
|
|
458
486
|
};
|
|
459
487
|
const stop = () => {
|
|
488
|
+
generationRef.current += 1;
|
|
460
489
|
intervalRef.current.cancel();
|
|
461
490
|
timeoutRef.current.cancel();
|
|
462
491
|
commitState((current) => ({
|
|
@@ -502,6 +531,7 @@ var useHeartbeat = (options) => {
|
|
|
502
531
|
return void 0;
|
|
503
532
|
}, [enabled, options.intervalMs, startOnMount]);
|
|
504
533
|
react.useEffect(() => () => {
|
|
534
|
+
generationRef.current += 1;
|
|
505
535
|
intervalRef.current.cancel();
|
|
506
536
|
timeoutRef.current.cancel();
|
|
507
537
|
}, []);
|
|
@@ -607,6 +637,7 @@ var toProtocolsDependency = (protocols) => {
|
|
|
607
637
|
return Array.isArray(protocols) ? protocols.join("|") : protocols;
|
|
608
638
|
};
|
|
609
639
|
var toHeartbeatConfig = (heartbeat) => heartbeat === void 0 || heartbeat === false ? null : heartbeat;
|
|
640
|
+
var isSocketActive = (socket) => socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING;
|
|
610
641
|
var useWebSocket = (options) => {
|
|
611
642
|
const connect = options.connect ?? true;
|
|
612
643
|
const supported = isWebSocketSupported();
|
|
@@ -618,6 +649,8 @@ var useWebSocket = (options) => {
|
|
|
618
649
|
const manualOpenRef = react.useRef(false);
|
|
619
650
|
const skipCloseReconnectRef = react.useRef(false);
|
|
620
651
|
const suppressReconnectRef = react.useRef(false);
|
|
652
|
+
const pendingCloseActionRef = react.useRef(null);
|
|
653
|
+
const terminalErrorRef = react.useRef(null);
|
|
621
654
|
const [openNonce, setOpenNonce] = react.useState(0);
|
|
622
655
|
const [state, setState] = react.useState(
|
|
623
656
|
() => createInitialState3(connect ? "connecting" : "idle")
|
|
@@ -635,6 +668,7 @@ var useWebSocket = (options) => {
|
|
|
635
668
|
const heartbeatConfig = toHeartbeatConfig(
|
|
636
669
|
options.heartbeat
|
|
637
670
|
);
|
|
671
|
+
const defaultHeartbeatAction = options.reconnect === false ? "close" : "reconnect";
|
|
638
672
|
const heartbeatHookOptions = heartbeatConfig === null ? {
|
|
639
673
|
enabled: false,
|
|
640
674
|
intervalMs: 1e3,
|
|
@@ -670,6 +704,27 @@ var useWebSocket = (options) => {
|
|
|
670
704
|
if (heartbeatConfig !== null && heartbeatConfig.onTimeout !== void 0) {
|
|
671
705
|
heartbeatHookOptions.onTimeout = heartbeatConfig.onTimeout;
|
|
672
706
|
}
|
|
707
|
+
if (heartbeatConfig !== null) {
|
|
708
|
+
const onTimeout = heartbeatHookOptions.onTimeout;
|
|
709
|
+
heartbeatHookOptions.onTimeout = () => {
|
|
710
|
+
applyHeartbeatAction(
|
|
711
|
+
heartbeatConfig.timeoutAction ?? defaultHeartbeatAction,
|
|
712
|
+
new Event("heartbeat-timeout"),
|
|
713
|
+
"heartbeat-timeout"
|
|
714
|
+
);
|
|
715
|
+
onTimeout?.();
|
|
716
|
+
};
|
|
717
|
+
const onError = heartbeatConfig.onError;
|
|
718
|
+
heartbeatHookOptions.onError = (error) => {
|
|
719
|
+
const event = error instanceof Event ? error : new Event("heartbeat-error");
|
|
720
|
+
applyHeartbeatAction(
|
|
721
|
+
heartbeatConfig.errorAction ?? heartbeatConfig.timeoutAction ?? defaultHeartbeatAction,
|
|
722
|
+
event,
|
|
723
|
+
"error"
|
|
724
|
+
);
|
|
725
|
+
onError?.(error);
|
|
726
|
+
};
|
|
727
|
+
}
|
|
673
728
|
const heartbeat = useHeartbeat(
|
|
674
729
|
heartbeatHookOptions
|
|
675
730
|
);
|
|
@@ -685,10 +740,46 @@ var useWebSocket = (options) => {
|
|
|
685
740
|
}
|
|
686
741
|
socketRef.current = null;
|
|
687
742
|
socketKeyRef.current = null;
|
|
688
|
-
if (socket2
|
|
743
|
+
if (isSocketActive(socket2)) {
|
|
689
744
|
socket2.close(code, reason);
|
|
690
745
|
}
|
|
691
746
|
});
|
|
747
|
+
const applyHeartbeatAction = react.useEffectEvent(
|
|
748
|
+
(action, error, reconnectTrigger) => {
|
|
749
|
+
heartbeat.stop();
|
|
750
|
+
if (action === "none") {
|
|
751
|
+
commitState((current) => ({
|
|
752
|
+
...current,
|
|
753
|
+
lastChangedAt: Date.now(),
|
|
754
|
+
lastError: error
|
|
755
|
+
}));
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
const shouldReconnect = action === "reconnect" && reconnectEnabled && (options.shouldReconnect?.(error) ?? true);
|
|
759
|
+
manualOpenRef.current = false;
|
|
760
|
+
terminalErrorRef.current = shouldReconnect ? null : error;
|
|
761
|
+
const socket2 = socketRef.current;
|
|
762
|
+
if (socket2 === null || !isSocketActive(socket2)) {
|
|
763
|
+
commitState((current) => ({
|
|
764
|
+
...current,
|
|
765
|
+
lastChangedAt: Date.now(),
|
|
766
|
+
lastError: error,
|
|
767
|
+
status: shouldReconnect ? "reconnecting" : "error"
|
|
768
|
+
}));
|
|
769
|
+
if (shouldReconnect) {
|
|
770
|
+
reconnect.schedule(reconnectTrigger);
|
|
771
|
+
}
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
pendingCloseActionRef.current = {
|
|
775
|
+
error,
|
|
776
|
+
reconnectTrigger: shouldReconnect ? reconnectTrigger : null
|
|
777
|
+
};
|
|
778
|
+
skipCloseReconnectRef.current = true;
|
|
779
|
+
suppressReconnectRef.current = true;
|
|
780
|
+
closeSocket();
|
|
781
|
+
}
|
|
782
|
+
);
|
|
692
783
|
const parseMessage = react.useEffectEvent((event) => {
|
|
693
784
|
const parser = options.parseMessage ?? defaultParseMessage;
|
|
694
785
|
return parser(event);
|
|
@@ -701,7 +792,9 @@ var useWebSocket = (options) => {
|
|
|
701
792
|
});
|
|
702
793
|
const handleOpen = react.useEffectEvent((event, socket2) => {
|
|
703
794
|
manualCloseRef.current = false;
|
|
795
|
+
manualOpenRef.current = false;
|
|
704
796
|
suppressReconnectRef.current = false;
|
|
797
|
+
terminalErrorRef.current = null;
|
|
705
798
|
reconnect.markConnected();
|
|
706
799
|
heartbeat.start();
|
|
707
800
|
commitState((current) => ({
|
|
@@ -725,11 +818,19 @@ var useWebSocket = (options) => {
|
|
|
725
818
|
options.onMessage?.(message, event);
|
|
726
819
|
} catch {
|
|
727
820
|
const parseError = new Event("error");
|
|
821
|
+
terminalErrorRef.current = parseError;
|
|
822
|
+
manualOpenRef.current = false;
|
|
823
|
+
skipCloseReconnectRef.current = true;
|
|
824
|
+
suppressReconnectRef.current = true;
|
|
825
|
+
reconnect.cancel();
|
|
826
|
+
heartbeat.stop();
|
|
728
827
|
commitState((current) => ({
|
|
729
828
|
...current,
|
|
829
|
+
lastChangedAt: Date.now(),
|
|
730
830
|
lastError: parseError,
|
|
731
831
|
status: "error"
|
|
732
832
|
}));
|
|
833
|
+
closeSocket(1003, "parse-error");
|
|
733
834
|
}
|
|
734
835
|
});
|
|
735
836
|
const handleError = react.useEffectEvent((event) => {
|
|
@@ -746,8 +847,38 @@ var useWebSocket = (options) => {
|
|
|
746
847
|
socketKeyRef.current = null;
|
|
747
848
|
heartbeat.stop();
|
|
748
849
|
updateBufferedAmount();
|
|
850
|
+
const pendingCloseAction = pendingCloseActionRef.current;
|
|
851
|
+
pendingCloseActionRef.current = null;
|
|
852
|
+
const terminalError = terminalErrorRef.current;
|
|
749
853
|
const skipCloseReconnect = skipCloseReconnectRef.current;
|
|
750
854
|
skipCloseReconnectRef.current = false;
|
|
855
|
+
if (pendingCloseAction !== null) {
|
|
856
|
+
suppressReconnectRef.current = false;
|
|
857
|
+
commitState((current) => ({
|
|
858
|
+
...current,
|
|
859
|
+
lastChangedAt: Date.now(),
|
|
860
|
+
lastCloseEvent: event,
|
|
861
|
+
lastError: pendingCloseAction.error ?? current.lastError,
|
|
862
|
+
status: pendingCloseAction.reconnectTrigger === null ? "error" : "reconnecting"
|
|
863
|
+
}));
|
|
864
|
+
options.onClose?.(event);
|
|
865
|
+
if (pendingCloseAction.reconnectTrigger !== null) {
|
|
866
|
+
reconnect.schedule(pendingCloseAction.reconnectTrigger);
|
|
867
|
+
}
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
if (terminalError !== null) {
|
|
871
|
+
suppressReconnectRef.current = false;
|
|
872
|
+
commitState((current) => ({
|
|
873
|
+
...current,
|
|
874
|
+
lastChangedAt: Date.now(),
|
|
875
|
+
lastCloseEvent: event,
|
|
876
|
+
lastError: terminalError,
|
|
877
|
+
status: "error"
|
|
878
|
+
}));
|
|
879
|
+
options.onClose?.(event);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
751
882
|
const shouldReconnect = !suppressReconnectRef.current && !skipCloseReconnect && reconnectEnabled && (options.shouldReconnect?.(event) ?? true);
|
|
752
883
|
commitState((current) => ({
|
|
753
884
|
...current,
|
|
@@ -766,6 +897,7 @@ var useWebSocket = (options) => {
|
|
|
766
897
|
manualCloseRef.current = false;
|
|
767
898
|
manualOpenRef.current = true;
|
|
768
899
|
suppressReconnectRef.current = false;
|
|
900
|
+
terminalErrorRef.current = null;
|
|
769
901
|
reconnect.cancel();
|
|
770
902
|
setOpenNonce((current) => current + 1);
|
|
771
903
|
};
|
|
@@ -774,6 +906,7 @@ var useWebSocket = (options) => {
|
|
|
774
906
|
manualOpenRef.current = true;
|
|
775
907
|
skipCloseReconnectRef.current = true;
|
|
776
908
|
suppressReconnectRef.current = true;
|
|
909
|
+
terminalErrorRef.current = null;
|
|
777
910
|
heartbeat.stop();
|
|
778
911
|
closeSocket();
|
|
779
912
|
suppressReconnectRef.current = false;
|
|
@@ -783,6 +916,7 @@ var useWebSocket = (options) => {
|
|
|
783
916
|
manualCloseRef.current = true;
|
|
784
917
|
manualOpenRef.current = false;
|
|
785
918
|
suppressReconnectRef.current = true;
|
|
919
|
+
terminalErrorRef.current = null;
|
|
786
920
|
reconnect.cancel();
|
|
787
921
|
heartbeat.stop();
|
|
788
922
|
commitState((current) => ({
|
|
@@ -820,7 +954,7 @@ var useWebSocket = (options) => {
|
|
|
820
954
|
}));
|
|
821
955
|
return;
|
|
822
956
|
}
|
|
823
|
-
const shouldConnect = connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running";
|
|
957
|
+
const shouldConnect = terminalErrorRef.current === null && (connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running");
|
|
824
958
|
const nextSocketKey = `${resolvedUrl}::${protocolsDependency}::${options.binaryType ?? "blob"}`;
|
|
825
959
|
if (!shouldConnect) {
|
|
826
960
|
if (socketRef.current !== null) {
|
|
@@ -830,7 +964,7 @@ var useWebSocket = (options) => {
|
|
|
830
964
|
socketKeyRef.current = null;
|
|
831
965
|
commitState((current) => ({
|
|
832
966
|
...current,
|
|
833
|
-
status: manualCloseRef.current ? "closed" : "idle"
|
|
967
|
+
status: terminalErrorRef.current !== null ? "error" : manualCloseRef.current ? "closed" : "idle"
|
|
834
968
|
}));
|
|
835
969
|
return;
|
|
836
970
|
}
|
|
@@ -885,12 +1019,13 @@ var useWebSocket = (options) => {
|
|
|
885
1019
|
react.useEffect(() => () => {
|
|
886
1020
|
suppressReconnectRef.current = true;
|
|
887
1021
|
socketKeyRef.current = null;
|
|
1022
|
+
terminalErrorRef.current = null;
|
|
888
1023
|
const socket2 = socketRef.current;
|
|
889
1024
|
socketRef.current = null;
|
|
890
1025
|
if (socket2 === null) {
|
|
891
1026
|
return;
|
|
892
1027
|
}
|
|
893
|
-
if (socket2
|
|
1028
|
+
if (isSocketActive(socket2)) {
|
|
894
1029
|
socket2.close();
|
|
895
1030
|
}
|
|
896
1031
|
}, []);
|
|
@@ -981,6 +1116,7 @@ var useEventSource = (options) => {
|
|
|
981
1116
|
const manualOpenRef = react.useRef(false);
|
|
982
1117
|
const skipErrorReconnectRef = react.useRef(false);
|
|
983
1118
|
const suppressReconnectRef = react.useRef(false);
|
|
1119
|
+
const terminalErrorRef = react.useRef(null);
|
|
984
1120
|
const [openNonce, setOpenNonce] = react.useState(0);
|
|
985
1121
|
const [state, setState] = react.useState(
|
|
986
1122
|
() => createInitialState4(connect ? "connecting" : "idle")
|
|
@@ -1014,7 +1150,9 @@ var useEventSource = (options) => {
|
|
|
1014
1150
|
});
|
|
1015
1151
|
const handleOpen = react.useEffectEvent((event, source) => {
|
|
1016
1152
|
manualCloseRef.current = false;
|
|
1153
|
+
manualOpenRef.current = false;
|
|
1017
1154
|
suppressReconnectRef.current = false;
|
|
1155
|
+
terminalErrorRef.current = null;
|
|
1018
1156
|
reconnect.markConnected();
|
|
1019
1157
|
commitState((current) => ({
|
|
1020
1158
|
...current,
|
|
@@ -1040,8 +1178,14 @@ var useEventSource = (options) => {
|
|
|
1040
1178
|
options.onMessage?.(message, event);
|
|
1041
1179
|
} catch {
|
|
1042
1180
|
const parseError = new Event("error");
|
|
1181
|
+
terminalErrorRef.current = parseError;
|
|
1182
|
+
manualOpenRef.current = false;
|
|
1183
|
+
suppressReconnectRef.current = true;
|
|
1184
|
+
reconnect.cancel();
|
|
1185
|
+
closeEventSource();
|
|
1043
1186
|
commitState((current) => ({
|
|
1044
1187
|
...current,
|
|
1188
|
+
lastChangedAt: Date.now(),
|
|
1045
1189
|
lastError: parseError,
|
|
1046
1190
|
status: "error"
|
|
1047
1191
|
}));
|
|
@@ -1049,6 +1193,17 @@ var useEventSource = (options) => {
|
|
|
1049
1193
|
}
|
|
1050
1194
|
);
|
|
1051
1195
|
const handleError = react.useEffectEvent((event, source) => {
|
|
1196
|
+
const terminalError = terminalErrorRef.current;
|
|
1197
|
+
if (terminalError !== null) {
|
|
1198
|
+
suppressReconnectRef.current = false;
|
|
1199
|
+
commitState((current) => ({
|
|
1200
|
+
...current,
|
|
1201
|
+
lastChangedAt: Date.now(),
|
|
1202
|
+
lastError: terminalError,
|
|
1203
|
+
status: "error"
|
|
1204
|
+
}));
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1052
1207
|
const skipErrorReconnect = skipErrorReconnectRef.current;
|
|
1053
1208
|
skipErrorReconnectRef.current = false;
|
|
1054
1209
|
const shouldReconnect = !suppressReconnectRef.current && !skipErrorReconnect && reconnectEnabled && (options.shouldReconnect?.(event) ?? true);
|
|
@@ -1075,6 +1230,7 @@ var useEventSource = (options) => {
|
|
|
1075
1230
|
manualCloseRef.current = false;
|
|
1076
1231
|
manualOpenRef.current = true;
|
|
1077
1232
|
suppressReconnectRef.current = false;
|
|
1233
|
+
terminalErrorRef.current = null;
|
|
1078
1234
|
reconnect.cancel();
|
|
1079
1235
|
setOpenNonce((current) => current + 1);
|
|
1080
1236
|
};
|
|
@@ -1083,6 +1239,7 @@ var useEventSource = (options) => {
|
|
|
1083
1239
|
manualOpenRef.current = true;
|
|
1084
1240
|
skipErrorReconnectRef.current = true;
|
|
1085
1241
|
suppressReconnectRef.current = true;
|
|
1242
|
+
terminalErrorRef.current = null;
|
|
1086
1243
|
closeEventSource();
|
|
1087
1244
|
suppressReconnectRef.current = false;
|
|
1088
1245
|
reconnect.schedule("manual");
|
|
@@ -1091,6 +1248,7 @@ var useEventSource = (options) => {
|
|
|
1091
1248
|
manualCloseRef.current = true;
|
|
1092
1249
|
manualOpenRef.current = false;
|
|
1093
1250
|
suppressReconnectRef.current = true;
|
|
1251
|
+
terminalErrorRef.current = null;
|
|
1094
1252
|
reconnect.cancel();
|
|
1095
1253
|
closeEventSource();
|
|
1096
1254
|
commitState((current) => ({
|
|
@@ -1117,7 +1275,7 @@ var useEventSource = (options) => {
|
|
|
1117
1275
|
}));
|
|
1118
1276
|
return;
|
|
1119
1277
|
}
|
|
1120
|
-
const shouldConnect = connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running";
|
|
1278
|
+
const shouldConnect = terminalErrorRef.current === null && (connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running");
|
|
1121
1279
|
const nextEventSourceKey = [
|
|
1122
1280
|
resolvedUrl,
|
|
1123
1281
|
options.withCredentials ? "credentials" : "anonymous",
|
|
@@ -1131,7 +1289,7 @@ var useEventSource = (options) => {
|
|
|
1131
1289
|
eventSourceKeyRef.current = null;
|
|
1132
1290
|
commitState((current) => ({
|
|
1133
1291
|
...current,
|
|
1134
|
-
status: manualCloseRef.current ? "closed" : "idle"
|
|
1292
|
+
status: terminalErrorRef.current !== null ? "error" : manualCloseRef.current ? "closed" : "idle"
|
|
1135
1293
|
}));
|
|
1136
1294
|
return;
|
|
1137
1295
|
}
|
|
@@ -1193,6 +1351,7 @@ var useEventSource = (options) => {
|
|
|
1193
1351
|
react.useEffect(() => () => {
|
|
1194
1352
|
suppressReconnectRef.current = true;
|
|
1195
1353
|
eventSourceKeyRef.current = null;
|
|
1354
|
+
terminalErrorRef.current = null;
|
|
1196
1355
|
const source = eventSourceRef.current;
|
|
1197
1356
|
eventSourceRef.current = null;
|
|
1198
1357
|
if (source !== null) {
|