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