react-realtime-hooks 1.4.0 → 1.4.1
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/dist/index.cjs +114 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +114 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -803,9 +803,95 @@ var resolveUrlProvider = (url) => {
|
|
|
803
803
|
const resolved = typeof url === "function" ? url() : url;
|
|
804
804
|
return normalizeResolvedUrl(resolved ?? null);
|
|
805
805
|
};
|
|
806
|
+
var createInitialState3 = () => ({
|
|
807
|
+
manualClose: false,
|
|
808
|
+
manualOpen: false,
|
|
809
|
+
pendingCloseAction: null,
|
|
810
|
+
reconnectSuppressed: false,
|
|
811
|
+
skipNextCloseReconnect: false,
|
|
812
|
+
terminalError: null
|
|
813
|
+
});
|
|
814
|
+
var useWebSocketController = () => {
|
|
815
|
+
const ref = useRef(null);
|
|
816
|
+
if (ref.current === null) {
|
|
817
|
+
ref.current = createInitialState3();
|
|
818
|
+
}
|
|
819
|
+
const state = ref.current;
|
|
820
|
+
const controllerRef = useRef(null);
|
|
821
|
+
if (controllerRef.current === null) {
|
|
822
|
+
controllerRef.current = {
|
|
823
|
+
clearReconnectSuppression: () => {
|
|
824
|
+
state.reconnectSuppressed = false;
|
|
825
|
+
},
|
|
826
|
+
consumePendingCloseAction: () => {
|
|
827
|
+
const action = state.pendingCloseAction;
|
|
828
|
+
state.pendingCloseAction = null;
|
|
829
|
+
return action;
|
|
830
|
+
},
|
|
831
|
+
consumeSkipNextCloseReconnect: () => {
|
|
832
|
+
const skip = state.skipNextCloseReconnect;
|
|
833
|
+
state.skipNextCloseReconnect = false;
|
|
834
|
+
return skip;
|
|
835
|
+
},
|
|
836
|
+
hasManualCloseRequested: () => state.manualClose,
|
|
837
|
+
hasManualOpenRequested: () => state.manualOpen,
|
|
838
|
+
isReconnectSuppressed: () => state.reconnectSuppressed,
|
|
839
|
+
noteEffectInitiatedClose: () => {
|
|
840
|
+
state.reconnectSuppressed = true;
|
|
841
|
+
},
|
|
842
|
+
noteHeartbeatActiveSocketClose: (input) => {
|
|
843
|
+
state.manualOpen = false;
|
|
844
|
+
state.terminalError = input.reconnectTrigger === null ? input.error : null;
|
|
845
|
+
state.pendingCloseAction = input;
|
|
846
|
+
state.skipNextCloseReconnect = true;
|
|
847
|
+
state.reconnectSuppressed = true;
|
|
848
|
+
},
|
|
849
|
+
noteHeartbeatNoActiveSocket: ({ shouldReconnect, error }) => {
|
|
850
|
+
state.manualOpen = false;
|
|
851
|
+
state.terminalError = shouldReconnect ? null : error;
|
|
852
|
+
},
|
|
853
|
+
noteParseError: (error) => {
|
|
854
|
+
state.terminalError = error;
|
|
855
|
+
state.manualOpen = false;
|
|
856
|
+
state.skipNextCloseReconnect = true;
|
|
857
|
+
state.reconnectSuppressed = true;
|
|
858
|
+
},
|
|
859
|
+
noteSocketOpened: () => {
|
|
860
|
+
state.manualClose = false;
|
|
861
|
+
state.manualOpen = false;
|
|
862
|
+
state.reconnectSuppressed = false;
|
|
863
|
+
state.terminalError = null;
|
|
864
|
+
},
|
|
865
|
+
noteUserCloseRequested: () => {
|
|
866
|
+
state.manualClose = true;
|
|
867
|
+
state.manualOpen = false;
|
|
868
|
+
state.reconnectSuppressed = true;
|
|
869
|
+
state.terminalError = null;
|
|
870
|
+
},
|
|
871
|
+
noteUserOpenRequested: () => {
|
|
872
|
+
state.manualClose = false;
|
|
873
|
+
state.manualOpen = true;
|
|
874
|
+
state.reconnectSuppressed = false;
|
|
875
|
+
state.terminalError = null;
|
|
876
|
+
},
|
|
877
|
+
noteUserReconnectClosed: () => {
|
|
878
|
+
state.reconnectSuppressed = false;
|
|
879
|
+
},
|
|
880
|
+
noteUserReconnectRequested: () => {
|
|
881
|
+
state.manualClose = false;
|
|
882
|
+
state.manualOpen = true;
|
|
883
|
+
state.skipNextCloseReconnect = true;
|
|
884
|
+
state.reconnectSuppressed = true;
|
|
885
|
+
state.terminalError = null;
|
|
886
|
+
},
|
|
887
|
+
peekTerminalError: () => state.terminalError
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
return controllerRef.current;
|
|
891
|
+
};
|
|
806
892
|
|
|
807
893
|
// src/hooks/useWebSocket.ts
|
|
808
|
-
var
|
|
894
|
+
var createInitialState4 = (status = "idle") => ({
|
|
809
895
|
bufferedAmount: 0,
|
|
810
896
|
lastChangedAt: null,
|
|
811
897
|
lastCloseEvent: null,
|
|
@@ -848,15 +934,10 @@ var useWebSocket = (options) => {
|
|
|
848
934
|
const activeSocketEpochRef = useRef(null);
|
|
849
935
|
const closingSocketEpochRef = useRef(null);
|
|
850
936
|
const nextSocketEpochRef = useRef(0);
|
|
851
|
-
const
|
|
852
|
-
const manualOpenRef = useRef(false);
|
|
853
|
-
const skipCloseReconnectRef = useRef(false);
|
|
854
|
-
const suppressReconnectRef = useRef(false);
|
|
855
|
-
const pendingCloseActionRef = useRef(null);
|
|
856
|
-
const terminalErrorRef = useRef(null);
|
|
937
|
+
const controller = useWebSocketController();
|
|
857
938
|
const [openNonce, setOpenNonce] = useState(0);
|
|
858
939
|
const [state, setState] = useState(
|
|
859
|
-
() =>
|
|
940
|
+
() => createInitialState4(connect ? "connecting" : "idle")
|
|
860
941
|
);
|
|
861
942
|
const stateRef = useRef(state);
|
|
862
943
|
stateRef.current = state;
|
|
@@ -976,10 +1057,9 @@ var useWebSocket = (options) => {
|
|
|
976
1057
|
return;
|
|
977
1058
|
}
|
|
978
1059
|
const shouldReconnect = action === "reconnect" && reconnectEnabled && (options.shouldReconnect?.(error) ?? true);
|
|
979
|
-
manualOpenRef.current = false;
|
|
980
|
-
terminalErrorRef.current = shouldReconnect ? null : error;
|
|
981
1060
|
const socket2 = socketRef.current;
|
|
982
1061
|
if (socket2 === null || !isSocketActive(socket2)) {
|
|
1062
|
+
controller.noteHeartbeatNoActiveSocket({ error, shouldReconnect });
|
|
983
1063
|
commitState((current) => ({
|
|
984
1064
|
...current,
|
|
985
1065
|
lastChangedAt: Date.now(),
|
|
@@ -991,12 +1071,10 @@ var useWebSocket = (options) => {
|
|
|
991
1071
|
}
|
|
992
1072
|
return;
|
|
993
1073
|
}
|
|
994
|
-
|
|
1074
|
+
controller.noteHeartbeatActiveSocketClose({
|
|
995
1075
|
error,
|
|
996
1076
|
reconnectTrigger: shouldReconnect ? reconnectTrigger : null
|
|
997
|
-
};
|
|
998
|
-
skipCloseReconnectRef.current = true;
|
|
999
|
-
suppressReconnectRef.current = true;
|
|
1077
|
+
});
|
|
1000
1078
|
closeSocket({ trackClose: true });
|
|
1001
1079
|
}
|
|
1002
1080
|
);
|
|
@@ -1011,10 +1089,7 @@ var useWebSocket = (options) => {
|
|
|
1011
1089
|
}));
|
|
1012
1090
|
});
|
|
1013
1091
|
const handleOpen = useStableCallback((event, socket2) => {
|
|
1014
|
-
|
|
1015
|
-
manualOpenRef.current = false;
|
|
1016
|
-
suppressReconnectRef.current = false;
|
|
1017
|
-
terminalErrorRef.current = null;
|
|
1092
|
+
controller.noteSocketOpened();
|
|
1018
1093
|
reconnect.markConnected();
|
|
1019
1094
|
heartbeat.start();
|
|
1020
1095
|
commitState((current) => ({
|
|
@@ -1041,10 +1116,7 @@ var useWebSocket = (options) => {
|
|
|
1041
1116
|
cause: error,
|
|
1042
1117
|
kind: "parse-error"
|
|
1043
1118
|
});
|
|
1044
|
-
|
|
1045
|
-
manualOpenRef.current = false;
|
|
1046
|
-
skipCloseReconnectRef.current = true;
|
|
1047
|
-
suppressReconnectRef.current = true;
|
|
1119
|
+
controller.noteParseError(parseError);
|
|
1048
1120
|
reconnect.cancel();
|
|
1049
1121
|
heartbeat.stop();
|
|
1050
1122
|
options.onError?.(parseError);
|
|
@@ -1088,13 +1160,11 @@ var useWebSocket = (options) => {
|
|
|
1088
1160
|
}
|
|
1089
1161
|
heartbeat.stop();
|
|
1090
1162
|
updateBufferedAmount();
|
|
1091
|
-
const pendingCloseAction =
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
const skipCloseReconnect = skipCloseReconnectRef.current;
|
|
1095
|
-
skipCloseReconnectRef.current = false;
|
|
1163
|
+
const pendingCloseAction = controller.consumePendingCloseAction();
|
|
1164
|
+
const terminalError = controller.peekTerminalError();
|
|
1165
|
+
const skipCloseReconnect = controller.consumeSkipNextCloseReconnect();
|
|
1096
1166
|
if (pendingCloseAction !== null) {
|
|
1097
|
-
|
|
1167
|
+
controller.clearReconnectSuppression();
|
|
1098
1168
|
commitState((current) => ({
|
|
1099
1169
|
...current,
|
|
1100
1170
|
lastChangedAt: Date.now(),
|
|
@@ -1109,7 +1179,7 @@ var useWebSocket = (options) => {
|
|
|
1109
1179
|
return;
|
|
1110
1180
|
}
|
|
1111
1181
|
if (terminalError !== null) {
|
|
1112
|
-
|
|
1182
|
+
controller.clearReconnectSuppression();
|
|
1113
1183
|
commitState((current) => ({
|
|
1114
1184
|
...current,
|
|
1115
1185
|
lastChangedAt: Date.now(),
|
|
@@ -1120,7 +1190,7 @@ var useWebSocket = (options) => {
|
|
|
1120
1190
|
options.onClose?.(event);
|
|
1121
1191
|
return;
|
|
1122
1192
|
}
|
|
1123
|
-
const shouldReconnect = !
|
|
1193
|
+
const shouldReconnect = !controller.isReconnectSuppressed() && !skipCloseReconnect && reconnectEnabled && (options.shouldReconnect?.(event) ?? true);
|
|
1124
1194
|
commitState((current) => ({
|
|
1125
1195
|
...current,
|
|
1126
1196
|
lastChangedAt: Date.now(),
|
|
@@ -1131,33 +1201,23 @@ var useWebSocket = (options) => {
|
|
|
1131
1201
|
if (shouldReconnect) {
|
|
1132
1202
|
reconnect.schedule("close");
|
|
1133
1203
|
} else {
|
|
1134
|
-
|
|
1204
|
+
controller.clearReconnectSuppression();
|
|
1135
1205
|
}
|
|
1136
1206
|
});
|
|
1137
1207
|
const open = useStableCallback(() => {
|
|
1138
|
-
|
|
1139
|
-
manualOpenRef.current = true;
|
|
1140
|
-
suppressReconnectRef.current = false;
|
|
1141
|
-
terminalErrorRef.current = null;
|
|
1208
|
+
controller.noteUserOpenRequested();
|
|
1142
1209
|
reconnect.cancel();
|
|
1143
1210
|
setOpenNonce((current) => current + 1);
|
|
1144
1211
|
});
|
|
1145
1212
|
const reconnectNow = useStableCallback(() => {
|
|
1146
|
-
|
|
1147
|
-
manualOpenRef.current = true;
|
|
1148
|
-
skipCloseReconnectRef.current = true;
|
|
1149
|
-
suppressReconnectRef.current = true;
|
|
1150
|
-
terminalErrorRef.current = null;
|
|
1213
|
+
controller.noteUserReconnectRequested();
|
|
1151
1214
|
heartbeat.stop();
|
|
1152
1215
|
closeSocket();
|
|
1153
|
-
|
|
1216
|
+
controller.noteUserReconnectClosed();
|
|
1154
1217
|
reconnect.schedule("manual");
|
|
1155
1218
|
});
|
|
1156
1219
|
const close = useStableCallback((code, reason) => {
|
|
1157
|
-
|
|
1158
|
-
manualOpenRef.current = false;
|
|
1159
|
-
suppressReconnectRef.current = true;
|
|
1160
|
-
terminalErrorRef.current = null;
|
|
1220
|
+
controller.noteUserCloseRequested();
|
|
1161
1221
|
reconnect.cancel();
|
|
1162
1222
|
heartbeat.stop();
|
|
1163
1223
|
commitState((current) => ({
|
|
@@ -1199,22 +1259,22 @@ var useWebSocket = (options) => {
|
|
|
1199
1259
|
}));
|
|
1200
1260
|
return;
|
|
1201
1261
|
}
|
|
1202
|
-
const shouldConnect =
|
|
1262
|
+
const shouldConnect = controller.peekTerminalError() === null && (connect && !controller.hasManualCloseRequested() || controller.hasManualOpenRequested() || reconnect.status === "running");
|
|
1203
1263
|
const nextSocketKey = `${resolvedUrl}::${protocolsDependency}::${options.binaryType ?? "blob"}`;
|
|
1204
1264
|
if (!shouldConnect) {
|
|
1205
1265
|
if (socketRef.current !== null) {
|
|
1206
|
-
|
|
1266
|
+
controller.noteEffectInitiatedClose();
|
|
1207
1267
|
closeSocket();
|
|
1208
1268
|
}
|
|
1209
1269
|
socketKeyRef.current = null;
|
|
1210
1270
|
commitState((current) => ({
|
|
1211
1271
|
...current,
|
|
1212
|
-
status:
|
|
1272
|
+
status: controller.peekTerminalError() !== null ? "error" : controller.hasManualCloseRequested() ? "closed" : "idle"
|
|
1213
1273
|
}));
|
|
1214
1274
|
return;
|
|
1215
1275
|
}
|
|
1216
1276
|
if (socketRef.current !== null && socketKeyRef.current !== nextSocketKey) {
|
|
1217
|
-
|
|
1277
|
+
controller.noteEffectInitiatedClose();
|
|
1218
1278
|
closeSocket();
|
|
1219
1279
|
}
|
|
1220
1280
|
if (socketRef.current !== null) {
|
|
@@ -1281,6 +1341,7 @@ var useWebSocket = (options) => {
|
|
|
1281
1341
|
closeSocket,
|
|
1282
1342
|
commitState,
|
|
1283
1343
|
connect,
|
|
1344
|
+
controller,
|
|
1284
1345
|
handleClose,
|
|
1285
1346
|
handleError,
|
|
1286
1347
|
handleMessage,
|
|
@@ -1295,11 +1356,10 @@ var useWebSocket = (options) => {
|
|
|
1295
1356
|
supported
|
|
1296
1357
|
]);
|
|
1297
1358
|
useEffect(() => () => {
|
|
1298
|
-
|
|
1359
|
+
controller.noteEffectInitiatedClose();
|
|
1299
1360
|
socketKeyRef.current = null;
|
|
1300
1361
|
activeSocketEpochRef.current = null;
|
|
1301
1362
|
closingSocketEpochRef.current = null;
|
|
1302
|
-
terminalErrorRef.current = null;
|
|
1303
1363
|
const socket2 = socketRef.current;
|
|
1304
1364
|
socketRef.current = null;
|
|
1305
1365
|
if (socket2 === null) {
|
|
@@ -1308,7 +1368,7 @@ var useWebSocket = (options) => {
|
|
|
1308
1368
|
if (isSocketActive(socket2)) {
|
|
1309
1369
|
socket2.close();
|
|
1310
1370
|
}
|
|
1311
|
-
}, []);
|
|
1371
|
+
}, [controller]);
|
|
1312
1372
|
const stopHeartbeat = heartbeat.stop;
|
|
1313
1373
|
useEffect(() => {
|
|
1314
1374
|
if (state.status !== "open") {
|
|
@@ -1413,7 +1473,7 @@ var useWebSocket = (options) => {
|
|
|
1413
1473
|
socket
|
|
1414
1474
|
};
|
|
1415
1475
|
};
|
|
1416
|
-
var
|
|
1476
|
+
var createInitialState5 = (status = "idle") => ({
|
|
1417
1477
|
lastChangedAt: null,
|
|
1418
1478
|
lastError: null,
|
|
1419
1479
|
lastEventName: null,
|
|
@@ -1450,7 +1510,7 @@ var useEventSource = (options) => {
|
|
|
1450
1510
|
const terminalErrorRef = useRef(null);
|
|
1451
1511
|
const [openNonce, setOpenNonce] = useState(0);
|
|
1452
1512
|
const [state, setState] = useState(
|
|
1453
|
-
() =>
|
|
1513
|
+
() => createInitialState5(connect ? "connecting" : "idle")
|
|
1454
1514
|
);
|
|
1455
1515
|
const stateRef = useRef(state);
|
|
1456
1516
|
stateRef.current = state;
|