react-realtime-hooks 1.0.1 → 1.0.2
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 +1 -1
- package/dist/index.cjs +56 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +56 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -507,7 +507,7 @@ export function NetworkIndicator() {
|
|
|
507
507
|
|
|
508
508
|
- `useEventSource` is receive-only by design. SSE is not a bidirectional transport.
|
|
509
509
|
- `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
|
|
510
|
+
- If `parseMessage` throws, the hook closes the current transport, moves into `error`, stores `lastError`, and stops auto-reconnect until manual `open()` or `reconnect()`.
|
|
511
511
|
- `connect: false` keeps the hook in `idle` until `open()` is called.
|
|
512
512
|
- Manual `close()` is sticky. The hook stays closed until `open()` or `reconnect()` is called.
|
|
513
513
|
- No transport polyfills are bundled. Provide your own runtime support where needed.
|
package/dist/index.cjs
CHANGED
|
@@ -618,6 +618,7 @@ var useWebSocket = (options) => {
|
|
|
618
618
|
const manualOpenRef = react.useRef(false);
|
|
619
619
|
const skipCloseReconnectRef = react.useRef(false);
|
|
620
620
|
const suppressReconnectRef = react.useRef(false);
|
|
621
|
+
const terminalErrorRef = react.useRef(null);
|
|
621
622
|
const [openNonce, setOpenNonce] = react.useState(0);
|
|
622
623
|
const [state, setState] = react.useState(
|
|
623
624
|
() => createInitialState3(connect ? "connecting" : "idle")
|
|
@@ -701,7 +702,9 @@ var useWebSocket = (options) => {
|
|
|
701
702
|
});
|
|
702
703
|
const handleOpen = react.useEffectEvent((event, socket2) => {
|
|
703
704
|
manualCloseRef.current = false;
|
|
705
|
+
manualOpenRef.current = false;
|
|
704
706
|
suppressReconnectRef.current = false;
|
|
707
|
+
terminalErrorRef.current = null;
|
|
705
708
|
reconnect.markConnected();
|
|
706
709
|
heartbeat.start();
|
|
707
710
|
commitState((current) => ({
|
|
@@ -725,11 +728,19 @@ var useWebSocket = (options) => {
|
|
|
725
728
|
options.onMessage?.(message, event);
|
|
726
729
|
} catch {
|
|
727
730
|
const parseError = new Event("error");
|
|
731
|
+
terminalErrorRef.current = parseError;
|
|
732
|
+
manualOpenRef.current = false;
|
|
733
|
+
skipCloseReconnectRef.current = true;
|
|
734
|
+
suppressReconnectRef.current = true;
|
|
735
|
+
reconnect.cancel();
|
|
736
|
+
heartbeat.stop();
|
|
728
737
|
commitState((current) => ({
|
|
729
738
|
...current,
|
|
739
|
+
lastChangedAt: Date.now(),
|
|
730
740
|
lastError: parseError,
|
|
731
741
|
status: "error"
|
|
732
742
|
}));
|
|
743
|
+
closeSocket(1003, "parse-error");
|
|
733
744
|
}
|
|
734
745
|
});
|
|
735
746
|
const handleError = react.useEffectEvent((event) => {
|
|
@@ -746,8 +757,21 @@ var useWebSocket = (options) => {
|
|
|
746
757
|
socketKeyRef.current = null;
|
|
747
758
|
heartbeat.stop();
|
|
748
759
|
updateBufferedAmount();
|
|
760
|
+
const terminalError = terminalErrorRef.current;
|
|
749
761
|
const skipCloseReconnect = skipCloseReconnectRef.current;
|
|
750
762
|
skipCloseReconnectRef.current = false;
|
|
763
|
+
if (terminalError !== null) {
|
|
764
|
+
suppressReconnectRef.current = false;
|
|
765
|
+
commitState((current) => ({
|
|
766
|
+
...current,
|
|
767
|
+
lastChangedAt: Date.now(),
|
|
768
|
+
lastCloseEvent: event,
|
|
769
|
+
lastError: terminalError,
|
|
770
|
+
status: "error"
|
|
771
|
+
}));
|
|
772
|
+
options.onClose?.(event);
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
751
775
|
const shouldReconnect = !suppressReconnectRef.current && !skipCloseReconnect && reconnectEnabled && (options.shouldReconnect?.(event) ?? true);
|
|
752
776
|
commitState((current) => ({
|
|
753
777
|
...current,
|
|
@@ -766,6 +790,7 @@ var useWebSocket = (options) => {
|
|
|
766
790
|
manualCloseRef.current = false;
|
|
767
791
|
manualOpenRef.current = true;
|
|
768
792
|
suppressReconnectRef.current = false;
|
|
793
|
+
terminalErrorRef.current = null;
|
|
769
794
|
reconnect.cancel();
|
|
770
795
|
setOpenNonce((current) => current + 1);
|
|
771
796
|
};
|
|
@@ -774,6 +799,7 @@ var useWebSocket = (options) => {
|
|
|
774
799
|
manualOpenRef.current = true;
|
|
775
800
|
skipCloseReconnectRef.current = true;
|
|
776
801
|
suppressReconnectRef.current = true;
|
|
802
|
+
terminalErrorRef.current = null;
|
|
777
803
|
heartbeat.stop();
|
|
778
804
|
closeSocket();
|
|
779
805
|
suppressReconnectRef.current = false;
|
|
@@ -783,6 +809,7 @@ var useWebSocket = (options) => {
|
|
|
783
809
|
manualCloseRef.current = true;
|
|
784
810
|
manualOpenRef.current = false;
|
|
785
811
|
suppressReconnectRef.current = true;
|
|
812
|
+
terminalErrorRef.current = null;
|
|
786
813
|
reconnect.cancel();
|
|
787
814
|
heartbeat.stop();
|
|
788
815
|
commitState((current) => ({
|
|
@@ -820,7 +847,7 @@ var useWebSocket = (options) => {
|
|
|
820
847
|
}));
|
|
821
848
|
return;
|
|
822
849
|
}
|
|
823
|
-
const shouldConnect = connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running";
|
|
850
|
+
const shouldConnect = terminalErrorRef.current === null && (connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running");
|
|
824
851
|
const nextSocketKey = `${resolvedUrl}::${protocolsDependency}::${options.binaryType ?? "blob"}`;
|
|
825
852
|
if (!shouldConnect) {
|
|
826
853
|
if (socketRef.current !== null) {
|
|
@@ -830,7 +857,7 @@ var useWebSocket = (options) => {
|
|
|
830
857
|
socketKeyRef.current = null;
|
|
831
858
|
commitState((current) => ({
|
|
832
859
|
...current,
|
|
833
|
-
status: manualCloseRef.current ? "closed" : "idle"
|
|
860
|
+
status: terminalErrorRef.current !== null ? "error" : manualCloseRef.current ? "closed" : "idle"
|
|
834
861
|
}));
|
|
835
862
|
return;
|
|
836
863
|
}
|
|
@@ -885,6 +912,7 @@ var useWebSocket = (options) => {
|
|
|
885
912
|
react.useEffect(() => () => {
|
|
886
913
|
suppressReconnectRef.current = true;
|
|
887
914
|
socketKeyRef.current = null;
|
|
915
|
+
terminalErrorRef.current = null;
|
|
888
916
|
const socket2 = socketRef.current;
|
|
889
917
|
socketRef.current = null;
|
|
890
918
|
if (socket2 === null) {
|
|
@@ -981,6 +1009,7 @@ var useEventSource = (options) => {
|
|
|
981
1009
|
const manualOpenRef = react.useRef(false);
|
|
982
1010
|
const skipErrorReconnectRef = react.useRef(false);
|
|
983
1011
|
const suppressReconnectRef = react.useRef(false);
|
|
1012
|
+
const terminalErrorRef = react.useRef(null);
|
|
984
1013
|
const [openNonce, setOpenNonce] = react.useState(0);
|
|
985
1014
|
const [state, setState] = react.useState(
|
|
986
1015
|
() => createInitialState4(connect ? "connecting" : "idle")
|
|
@@ -1014,7 +1043,9 @@ var useEventSource = (options) => {
|
|
|
1014
1043
|
});
|
|
1015
1044
|
const handleOpen = react.useEffectEvent((event, source) => {
|
|
1016
1045
|
manualCloseRef.current = false;
|
|
1046
|
+
manualOpenRef.current = false;
|
|
1017
1047
|
suppressReconnectRef.current = false;
|
|
1048
|
+
terminalErrorRef.current = null;
|
|
1018
1049
|
reconnect.markConnected();
|
|
1019
1050
|
commitState((current) => ({
|
|
1020
1051
|
...current,
|
|
@@ -1040,8 +1071,14 @@ var useEventSource = (options) => {
|
|
|
1040
1071
|
options.onMessage?.(message, event);
|
|
1041
1072
|
} catch {
|
|
1042
1073
|
const parseError = new Event("error");
|
|
1074
|
+
terminalErrorRef.current = parseError;
|
|
1075
|
+
manualOpenRef.current = false;
|
|
1076
|
+
suppressReconnectRef.current = true;
|
|
1077
|
+
reconnect.cancel();
|
|
1078
|
+
closeEventSource();
|
|
1043
1079
|
commitState((current) => ({
|
|
1044
1080
|
...current,
|
|
1081
|
+
lastChangedAt: Date.now(),
|
|
1045
1082
|
lastError: parseError,
|
|
1046
1083
|
status: "error"
|
|
1047
1084
|
}));
|
|
@@ -1049,6 +1086,17 @@ var useEventSource = (options) => {
|
|
|
1049
1086
|
}
|
|
1050
1087
|
);
|
|
1051
1088
|
const handleError = react.useEffectEvent((event, source) => {
|
|
1089
|
+
const terminalError = terminalErrorRef.current;
|
|
1090
|
+
if (terminalError !== null) {
|
|
1091
|
+
suppressReconnectRef.current = false;
|
|
1092
|
+
commitState((current) => ({
|
|
1093
|
+
...current,
|
|
1094
|
+
lastChangedAt: Date.now(),
|
|
1095
|
+
lastError: terminalError,
|
|
1096
|
+
status: "error"
|
|
1097
|
+
}));
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1052
1100
|
const skipErrorReconnect = skipErrorReconnectRef.current;
|
|
1053
1101
|
skipErrorReconnectRef.current = false;
|
|
1054
1102
|
const shouldReconnect = !suppressReconnectRef.current && !skipErrorReconnect && reconnectEnabled && (options.shouldReconnect?.(event) ?? true);
|
|
@@ -1075,6 +1123,7 @@ var useEventSource = (options) => {
|
|
|
1075
1123
|
manualCloseRef.current = false;
|
|
1076
1124
|
manualOpenRef.current = true;
|
|
1077
1125
|
suppressReconnectRef.current = false;
|
|
1126
|
+
terminalErrorRef.current = null;
|
|
1078
1127
|
reconnect.cancel();
|
|
1079
1128
|
setOpenNonce((current) => current + 1);
|
|
1080
1129
|
};
|
|
@@ -1083,6 +1132,7 @@ var useEventSource = (options) => {
|
|
|
1083
1132
|
manualOpenRef.current = true;
|
|
1084
1133
|
skipErrorReconnectRef.current = true;
|
|
1085
1134
|
suppressReconnectRef.current = true;
|
|
1135
|
+
terminalErrorRef.current = null;
|
|
1086
1136
|
closeEventSource();
|
|
1087
1137
|
suppressReconnectRef.current = false;
|
|
1088
1138
|
reconnect.schedule("manual");
|
|
@@ -1091,6 +1141,7 @@ var useEventSource = (options) => {
|
|
|
1091
1141
|
manualCloseRef.current = true;
|
|
1092
1142
|
manualOpenRef.current = false;
|
|
1093
1143
|
suppressReconnectRef.current = true;
|
|
1144
|
+
terminalErrorRef.current = null;
|
|
1094
1145
|
reconnect.cancel();
|
|
1095
1146
|
closeEventSource();
|
|
1096
1147
|
commitState((current) => ({
|
|
@@ -1117,7 +1168,7 @@ var useEventSource = (options) => {
|
|
|
1117
1168
|
}));
|
|
1118
1169
|
return;
|
|
1119
1170
|
}
|
|
1120
|
-
const shouldConnect = connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running";
|
|
1171
|
+
const shouldConnect = terminalErrorRef.current === null && (connect && !manualCloseRef.current || manualOpenRef.current || reconnect.status === "running");
|
|
1121
1172
|
const nextEventSourceKey = [
|
|
1122
1173
|
resolvedUrl,
|
|
1123
1174
|
options.withCredentials ? "credentials" : "anonymous",
|
|
@@ -1131,7 +1182,7 @@ var useEventSource = (options) => {
|
|
|
1131
1182
|
eventSourceKeyRef.current = null;
|
|
1132
1183
|
commitState((current) => ({
|
|
1133
1184
|
...current,
|
|
1134
|
-
status: manualCloseRef.current ? "closed" : "idle"
|
|
1185
|
+
status: terminalErrorRef.current !== null ? "error" : manualCloseRef.current ? "closed" : "idle"
|
|
1135
1186
|
}));
|
|
1136
1187
|
return;
|
|
1137
1188
|
}
|
|
@@ -1193,6 +1244,7 @@ var useEventSource = (options) => {
|
|
|
1193
1244
|
react.useEffect(() => () => {
|
|
1194
1245
|
suppressReconnectRef.current = true;
|
|
1195
1246
|
eventSourceKeyRef.current = null;
|
|
1247
|
+
terminalErrorRef.current = null;
|
|
1196
1248
|
const source = eventSourceRef.current;
|
|
1197
1249
|
eventSourceRef.current = null;
|
|
1198
1250
|
if (source !== null) {
|