react-realtime-hooks 1.3.3 → 1.4.0
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 +17 -1
- package/dist/index.cjs +148 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +148 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -168,11 +168,39 @@ interface UseWebSocketHeartbeatOptions<TOutgoing = unknown, TIncoming = TOutgoin
|
|
|
168
168
|
timeoutAction?: WebSocketHeartbeatAction;
|
|
169
169
|
errorAction?: WebSocketHeartbeatAction;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Controls how the hook surfaces the live `WebSocket.bufferedAmount`
|
|
173
|
+
* value through `state.bufferedAmount`.
|
|
174
|
+
*
|
|
175
|
+
* The native `WebSocket` does not emit any event when buffered bytes
|
|
176
|
+
* drain to the network, so by default `state.bufferedAmount` is only
|
|
177
|
+
* refreshed when the consumer calls `send(...)`, when a message
|
|
178
|
+
* arrives, or when the socket transitions to `open`. For UIs that need
|
|
179
|
+
* to display real-time backpressure (e.g. an outbound queue meter,
|
|
180
|
+
* a "flushing..." indicator, or a flow-control gauge), enable polling.
|
|
181
|
+
*
|
|
182
|
+
* - `false` (default): no polling. `state.bufferedAmount` updates only
|
|
183
|
+
* on the natural lifecycle events listed above.
|
|
184
|
+
* - `true`: poll once every 100ms while the socket is `open`.
|
|
185
|
+
* - `"raf"`: poll on every animation frame while the socket is `open`.
|
|
186
|
+
* Recommended for visual gauges that are tied to a render loop.
|
|
187
|
+
* - `{ intervalMs: N }`: poll every `N` milliseconds. `N` must be a
|
|
188
|
+
* positive integer; values <= 0 disable polling.
|
|
189
|
+
*
|
|
190
|
+
* Polling is automatically suspended when the socket is not in the
|
|
191
|
+
* `open` state and resumed when it returns to `open`. The hook diffs
|
|
192
|
+
* the polled value against the last committed one, so identical
|
|
193
|
+
* readings do not trigger React re-renders.
|
|
194
|
+
*/
|
|
195
|
+
type BufferedAmountPolling = false | true | "raf" | {
|
|
196
|
+
intervalMs: number;
|
|
197
|
+
};
|
|
171
198
|
interface UseWebSocketOptions<TIncoming = unknown, TOutgoing = TIncoming> {
|
|
172
199
|
url: UrlProvider;
|
|
173
200
|
protocols?: string | string[];
|
|
174
201
|
connect?: boolean;
|
|
175
202
|
binaryType?: BinaryType;
|
|
203
|
+
bufferedAmountPolling?: BufferedAmountPolling;
|
|
176
204
|
parseMessage?: MessageParser<TIncoming>;
|
|
177
205
|
serializeMessage?: MessageSerializer<TOutgoing>;
|
|
178
206
|
reconnect?: false | UseReconnectOptions;
|
|
@@ -274,4 +302,4 @@ declare class RealtimeErrorEvent extends Event {
|
|
|
274
302
|
constructor(type: string, init: RealtimeErrorEventInit);
|
|
275
303
|
}
|
|
276
304
|
|
|
277
|
-
export { type ConnectionGateReason, type ConnectionStateSnapshot, type HeartbeatAckMatcher, type HeartbeatBeatFn, type MessageParser, type MessageSerializer, type Milliseconds, type RealtimeConnectionStatus, RealtimeErrorEvent, type RealtimeErrorEventInit, type RealtimeErrorKind, type RealtimeTransport, type ReconnectAttempt, type ReconnectDelayContext, type ReconnectDelayStrategy, type ReconnectStatus, type ReconnectTrigger, type UrlProvider, type UseConnectionGateHook, type UseConnectionGateOptions, type UseConnectionGateResult, type UseEventSourceHook, type UseEventSourceOptions, type UseEventSourceResult, type UseHeartbeatHook, type UseHeartbeatOptions, type UseHeartbeatResult, type UseOnlineStatusHook, type UseOnlineStatusOptions, type UseOnlineStatusResult, type UsePageVisibilityHook, type UsePageVisibilityOptions, type UsePageVisibilityResult, type UseReconnectHook, type UseReconnectOptions, type UseReconnectResult, type UseWebSocketHeartbeatOptions, type UseWebSocketHook, type UseWebSocketOptions, type UseWebSocketResult, type WebSocketHeartbeatAction, useConnectionGate, useEventSource, useHeartbeat, useOnlineStatus, usePageVisibility, useReconnect, useWebSocket };
|
|
305
|
+
export { type BufferedAmountPolling, type ConnectionGateReason, type ConnectionStateSnapshot, type HeartbeatAckMatcher, type HeartbeatBeatFn, type MessageParser, type MessageSerializer, type Milliseconds, type RealtimeConnectionStatus, RealtimeErrorEvent, type RealtimeErrorEventInit, type RealtimeErrorKind, type RealtimeTransport, type ReconnectAttempt, type ReconnectDelayContext, type ReconnectDelayStrategy, type ReconnectStatus, type ReconnectTrigger, type UrlProvider, type UseConnectionGateHook, type UseConnectionGateOptions, type UseConnectionGateResult, type UseEventSourceHook, type UseEventSourceOptions, type UseEventSourceResult, type UseHeartbeatHook, type UseHeartbeatOptions, type UseHeartbeatResult, type UseOnlineStatusHook, type UseOnlineStatusOptions, type UseOnlineStatusResult, type UsePageVisibilityHook, type UsePageVisibilityOptions, type UsePageVisibilityResult, type UseReconnectHook, type UseReconnectOptions, type UseReconnectResult, type UseWebSocketHeartbeatOptions, type UseWebSocketHook, type UseWebSocketOptions, type UseWebSocketResult, type WebSocketHeartbeatAction, useConnectionGate, useEventSource, useHeartbeat, useOnlineStatus, usePageVisibility, useReconnect, useWebSocket };
|
package/dist/index.d.ts
CHANGED
|
@@ -168,11 +168,39 @@ interface UseWebSocketHeartbeatOptions<TOutgoing = unknown, TIncoming = TOutgoin
|
|
|
168
168
|
timeoutAction?: WebSocketHeartbeatAction;
|
|
169
169
|
errorAction?: WebSocketHeartbeatAction;
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Controls how the hook surfaces the live `WebSocket.bufferedAmount`
|
|
173
|
+
* value through `state.bufferedAmount`.
|
|
174
|
+
*
|
|
175
|
+
* The native `WebSocket` does not emit any event when buffered bytes
|
|
176
|
+
* drain to the network, so by default `state.bufferedAmount` is only
|
|
177
|
+
* refreshed when the consumer calls `send(...)`, when a message
|
|
178
|
+
* arrives, or when the socket transitions to `open`. For UIs that need
|
|
179
|
+
* to display real-time backpressure (e.g. an outbound queue meter,
|
|
180
|
+
* a "flushing..." indicator, or a flow-control gauge), enable polling.
|
|
181
|
+
*
|
|
182
|
+
* - `false` (default): no polling. `state.bufferedAmount` updates only
|
|
183
|
+
* on the natural lifecycle events listed above.
|
|
184
|
+
* - `true`: poll once every 100ms while the socket is `open`.
|
|
185
|
+
* - `"raf"`: poll on every animation frame while the socket is `open`.
|
|
186
|
+
* Recommended for visual gauges that are tied to a render loop.
|
|
187
|
+
* - `{ intervalMs: N }`: poll every `N` milliseconds. `N` must be a
|
|
188
|
+
* positive integer; values <= 0 disable polling.
|
|
189
|
+
*
|
|
190
|
+
* Polling is automatically suspended when the socket is not in the
|
|
191
|
+
* `open` state and resumed when it returns to `open`. The hook diffs
|
|
192
|
+
* the polled value against the last committed one, so identical
|
|
193
|
+
* readings do not trigger React re-renders.
|
|
194
|
+
*/
|
|
195
|
+
type BufferedAmountPolling = false | true | "raf" | {
|
|
196
|
+
intervalMs: number;
|
|
197
|
+
};
|
|
171
198
|
interface UseWebSocketOptions<TIncoming = unknown, TOutgoing = TIncoming> {
|
|
172
199
|
url: UrlProvider;
|
|
173
200
|
protocols?: string | string[];
|
|
174
201
|
connect?: boolean;
|
|
175
202
|
binaryType?: BinaryType;
|
|
203
|
+
bufferedAmountPolling?: BufferedAmountPolling;
|
|
176
204
|
parseMessage?: MessageParser<TIncoming>;
|
|
177
205
|
serializeMessage?: MessageSerializer<TOutgoing>;
|
|
178
206
|
reconnect?: false | UseReconnectOptions;
|
|
@@ -274,4 +302,4 @@ declare class RealtimeErrorEvent extends Event {
|
|
|
274
302
|
constructor(type: string, init: RealtimeErrorEventInit);
|
|
275
303
|
}
|
|
276
304
|
|
|
277
|
-
export { type ConnectionGateReason, type ConnectionStateSnapshot, type HeartbeatAckMatcher, type HeartbeatBeatFn, type MessageParser, type MessageSerializer, type Milliseconds, type RealtimeConnectionStatus, RealtimeErrorEvent, type RealtimeErrorEventInit, type RealtimeErrorKind, type RealtimeTransport, type ReconnectAttempt, type ReconnectDelayContext, type ReconnectDelayStrategy, type ReconnectStatus, type ReconnectTrigger, type UrlProvider, type UseConnectionGateHook, type UseConnectionGateOptions, type UseConnectionGateResult, type UseEventSourceHook, type UseEventSourceOptions, type UseEventSourceResult, type UseHeartbeatHook, type UseHeartbeatOptions, type UseHeartbeatResult, type UseOnlineStatusHook, type UseOnlineStatusOptions, type UseOnlineStatusResult, type UsePageVisibilityHook, type UsePageVisibilityOptions, type UsePageVisibilityResult, type UseReconnectHook, type UseReconnectOptions, type UseReconnectResult, type UseWebSocketHeartbeatOptions, type UseWebSocketHook, type UseWebSocketOptions, type UseWebSocketResult, type WebSocketHeartbeatAction, useConnectionGate, useEventSource, useHeartbeat, useOnlineStatus, usePageVisibility, useReconnect, useWebSocket };
|
|
305
|
+
export { type BufferedAmountPolling, type ConnectionGateReason, type ConnectionStateSnapshot, type HeartbeatAckMatcher, type HeartbeatBeatFn, type MessageParser, type MessageSerializer, type Milliseconds, type RealtimeConnectionStatus, RealtimeErrorEvent, type RealtimeErrorEventInit, type RealtimeErrorKind, type RealtimeTransport, type ReconnectAttempt, type ReconnectDelayContext, type ReconnectDelayStrategy, type ReconnectStatus, type ReconnectTrigger, type UrlProvider, type UseConnectionGateHook, type UseConnectionGateOptions, type UseConnectionGateResult, type UseEventSourceHook, type UseEventSourceOptions, type UseEventSourceResult, type UseHeartbeatHook, type UseHeartbeatOptions, type UseHeartbeatResult, type UseOnlineStatusHook, type UseOnlineStatusOptions, type UseOnlineStatusResult, type UsePageVisibilityHook, type UsePageVisibilityOptions, type UsePageVisibilityResult, type UseReconnectHook, type UseReconnectOptions, type UseReconnectResult, type UseWebSocketHeartbeatOptions, type UseWebSocketHook, type UseWebSocketOptions, type UseWebSocketResult, type WebSocketHeartbeatAction, useConnectionGate, useEventSource, useHeartbeat, useOnlineStatus, usePageVisibility, useReconnect, useWebSocket };
|
package/dist/index.js
CHANGED
|
@@ -1220,47 +1220,62 @@ var useWebSocket = (options) => {
|
|
|
1220
1220
|
if (socketRef.current !== null) {
|
|
1221
1221
|
return;
|
|
1222
1222
|
}
|
|
1223
|
-
const socket2 = new WebSocket(resolvedUrl, protocols);
|
|
1224
|
-
const socketEpoch = nextSocketEpochRef.current + 1;
|
|
1225
|
-
socketRef.current = socket2;
|
|
1226
|
-
socketKeyRef.current = nextSocketKey;
|
|
1227
|
-
activeSocketEpochRef.current = socketEpoch;
|
|
1228
|
-
closingSocketEpochRef.current = null;
|
|
1229
|
-
nextSocketEpochRef.current = socketEpoch;
|
|
1230
|
-
socket2.binaryType = options.binaryType ?? "blob";
|
|
1231
1223
|
commitState((current) => ({
|
|
1232
1224
|
...current,
|
|
1233
|
-
bufferedAmount:
|
|
1225
|
+
bufferedAmount: 0,
|
|
1234
1226
|
lastChangedAt: Date.now(),
|
|
1235
1227
|
status: reconnect.status === "running" || reconnect.status === "scheduled" ? "reconnecting" : "connecting"
|
|
1236
1228
|
}));
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
handleOpen(event, socket2);
|
|
1242
|
-
};
|
|
1243
|
-
const handleSocketMessage = (event) => {
|
|
1244
|
-
if (!isActiveSocketEvent(socketEpoch)) {
|
|
1229
|
+
let cancelled = false;
|
|
1230
|
+
let detachListeners = null;
|
|
1231
|
+
queueMicrotask(() => {
|
|
1232
|
+
if (cancelled) {
|
|
1245
1233
|
return;
|
|
1246
1234
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1235
|
+
const socket2 = new WebSocket(resolvedUrl, protocols);
|
|
1236
|
+
const socketEpoch = nextSocketEpochRef.current + 1;
|
|
1237
|
+
socketRef.current = socket2;
|
|
1238
|
+
socketKeyRef.current = nextSocketKey;
|
|
1239
|
+
activeSocketEpochRef.current = socketEpoch;
|
|
1240
|
+
closingSocketEpochRef.current = null;
|
|
1241
|
+
nextSocketEpochRef.current = socketEpoch;
|
|
1242
|
+
socket2.binaryType = options.binaryType ?? "blob";
|
|
1243
|
+
commitState((current) => ({
|
|
1244
|
+
...current,
|
|
1245
|
+
bufferedAmount: socket2.bufferedAmount
|
|
1246
|
+
}));
|
|
1247
|
+
const handleSocketOpen = (event) => {
|
|
1248
|
+
if (!isActiveSocketEvent(socketEpoch)) {
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
handleOpen(event, socket2);
|
|
1252
|
+
};
|
|
1253
|
+
const handleSocketMessage = (event) => {
|
|
1254
|
+
if (!isActiveSocketEvent(socketEpoch)) {
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
handleMessage(event);
|
|
1258
|
+
};
|
|
1259
|
+
const handleSocketError = (event) => {
|
|
1260
|
+
handleError(event, socketEpoch);
|
|
1261
|
+
};
|
|
1262
|
+
const handleSocketClose = (event) => {
|
|
1263
|
+
handleClose(event, socketEpoch);
|
|
1264
|
+
};
|
|
1265
|
+
socket2.addEventListener("open", handleSocketOpen);
|
|
1266
|
+
socket2.addEventListener("message", handleSocketMessage);
|
|
1267
|
+
socket2.addEventListener("error", handleSocketError);
|
|
1268
|
+
socket2.addEventListener("close", handleSocketClose);
|
|
1269
|
+
detachListeners = () => {
|
|
1270
|
+
socket2.removeEventListener("open", handleSocketOpen);
|
|
1271
|
+
socket2.removeEventListener("message", handleSocketMessage);
|
|
1272
|
+
socket2.removeEventListener("error", handleSocketError);
|
|
1273
|
+
socket2.removeEventListener("close", handleSocketClose);
|
|
1274
|
+
};
|
|
1275
|
+
});
|
|
1259
1276
|
return () => {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
socket2.removeEventListener("error", handleSocketError);
|
|
1263
|
-
socket2.removeEventListener("close", handleSocketClose);
|
|
1277
|
+
cancelled = true;
|
|
1278
|
+
detachListeners?.();
|
|
1264
1279
|
};
|
|
1265
1280
|
}, [
|
|
1266
1281
|
closeSocket,
|
|
@@ -1300,6 +1315,58 @@ var useWebSocket = (options) => {
|
|
|
1300
1315
|
stopHeartbeat();
|
|
1301
1316
|
}
|
|
1302
1317
|
}, [state.status, stopHeartbeat]);
|
|
1318
|
+
const rawBufferedAmountPolling = options.bufferedAmountPolling;
|
|
1319
|
+
const bufferedAmountPollingMode = useMemo(() => {
|
|
1320
|
+
if (rawBufferedAmountPolling === void 0 || rawBufferedAmountPolling === false) {
|
|
1321
|
+
return null;
|
|
1322
|
+
}
|
|
1323
|
+
if (rawBufferedAmountPolling === true) {
|
|
1324
|
+
return 100;
|
|
1325
|
+
}
|
|
1326
|
+
if (rawBufferedAmountPolling === "raf") {
|
|
1327
|
+
return "raf";
|
|
1328
|
+
}
|
|
1329
|
+
const intervalMs = rawBufferedAmountPolling.intervalMs;
|
|
1330
|
+
return Number.isFinite(intervalMs) && intervalMs > 0 ? intervalMs : null;
|
|
1331
|
+
}, [rawBufferedAmountPolling]);
|
|
1332
|
+
const pollBufferedAmount = useStableCallback(() => {
|
|
1333
|
+
const socket2 = socketRef.current;
|
|
1334
|
+
if (socket2 === null) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
const next = socket2.bufferedAmount;
|
|
1338
|
+
if (stateRef.current.bufferedAmount === next) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
commitState((current) => ({
|
|
1342
|
+
...current,
|
|
1343
|
+
bufferedAmount: next
|
|
1344
|
+
}));
|
|
1345
|
+
});
|
|
1346
|
+
useEffect(() => {
|
|
1347
|
+
if (bufferedAmountPollingMode === null) {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
if (state.status !== "open") {
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
if (bufferedAmountPollingMode === "raf") {
|
|
1354
|
+
if (typeof requestAnimationFrame !== "function") {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
let frame = requestAnimationFrame(function loop() {
|
|
1358
|
+
pollBufferedAmount();
|
|
1359
|
+
frame = requestAnimationFrame(loop);
|
|
1360
|
+
});
|
|
1361
|
+
return () => {
|
|
1362
|
+
cancelAnimationFrame(frame);
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
const intervalId = setInterval(pollBufferedAmount, bufferedAmountPollingMode);
|
|
1366
|
+
return () => {
|
|
1367
|
+
clearInterval(intervalId);
|
|
1368
|
+
};
|
|
1369
|
+
}, [bufferedAmountPollingMode, state.status, pollBufferedAmount]);
|
|
1303
1370
|
const status = (reconnect.status === "scheduled" || reconnect.status === "running") && state.status !== "open" ? "reconnecting" : state.status;
|
|
1304
1371
|
const snapshot = createConnectionStateSnapshot(status, {
|
|
1305
1372
|
isSupported: supported,
|
|
@@ -1571,55 +1638,66 @@ var useEventSource = (options) => {
|
|
|
1571
1638
|
if (eventSourceRef.current !== null) {
|
|
1572
1639
|
return;
|
|
1573
1640
|
}
|
|
1574
|
-
const source = new EventSource(resolvedUrl, {
|
|
1575
|
-
withCredentials: options.withCredentials ?? false
|
|
1576
|
-
});
|
|
1577
|
-
const sourceEpoch = nextEventSourceEpochRef.current + 1;
|
|
1578
|
-
eventSourceRef.current = source;
|
|
1579
|
-
eventSourceKeyRef.current = nextEventSourceKey;
|
|
1580
|
-
activeEventSourceEpochRef.current = sourceEpoch;
|
|
1581
|
-
nextEventSourceEpochRef.current = sourceEpoch;
|
|
1582
1641
|
commitState((current) => ({
|
|
1583
1642
|
...current,
|
|
1584
1643
|
lastChangedAt: Date.now(),
|
|
1585
1644
|
status: reconnect.status === "running" || reconnect.status === "scheduled" ? "reconnecting" : "connecting"
|
|
1586
1645
|
}));
|
|
1587
|
-
|
|
1588
|
-
|
|
1646
|
+
let cancelled = false;
|
|
1647
|
+
let detachListeners = null;
|
|
1648
|
+
queueMicrotask(() => {
|
|
1649
|
+
if (cancelled) {
|
|
1589
1650
|
return;
|
|
1590
1651
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
const handleSourceError = (event) => {
|
|
1601
|
-
handleError(event, source, sourceEpoch);
|
|
1602
|
-
};
|
|
1603
|
-
source.addEventListener("open", handleSourceOpen);
|
|
1604
|
-
source.addEventListener("message", handleSourceMessage);
|
|
1605
|
-
for (const eventName of namedEvents) {
|
|
1606
|
-
const handler = (event) => {
|
|
1652
|
+
const source = new EventSource(resolvedUrl, {
|
|
1653
|
+
withCredentials: options.withCredentials ?? false
|
|
1654
|
+
});
|
|
1655
|
+
const sourceEpoch = nextEventSourceEpochRef.current + 1;
|
|
1656
|
+
eventSourceRef.current = source;
|
|
1657
|
+
eventSourceKeyRef.current = nextEventSourceKey;
|
|
1658
|
+
activeEventSourceEpochRef.current = sourceEpoch;
|
|
1659
|
+
nextEventSourceEpochRef.current = sourceEpoch;
|
|
1660
|
+
const handleSourceOpen = (event) => {
|
|
1607
1661
|
if (!isActiveEventSourceEvent(sourceEpoch)) {
|
|
1608
1662
|
return;
|
|
1609
1663
|
}
|
|
1610
|
-
|
|
1664
|
+
handleOpen(event, source);
|
|
1611
1665
|
};
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1666
|
+
const handleSourceMessage = (event) => {
|
|
1667
|
+
if (!isActiveEventSourceEvent(sourceEpoch)) {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
commitParsedMessage("message", event, false);
|
|
1671
|
+
};
|
|
1672
|
+
const namedEventHandlers = /* @__PURE__ */ new Map();
|
|
1673
|
+
const handleSourceError = (event) => {
|
|
1674
|
+
handleError(event, source, sourceEpoch);
|
|
1675
|
+
};
|
|
1676
|
+
source.addEventListener("open", handleSourceOpen);
|
|
1677
|
+
source.addEventListener("message", handleSourceMessage);
|
|
1678
|
+
for (const eventName of namedEvents) {
|
|
1679
|
+
const handler = (event) => {
|
|
1680
|
+
if (!isActiveEventSourceEvent(sourceEpoch)) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
commitParsedMessage(eventName, event, true);
|
|
1684
|
+
};
|
|
1685
|
+
namedEventHandlers.set(eventName, handler);
|
|
1686
|
+
source.addEventListener(eventName, handler);
|
|
1621
1687
|
}
|
|
1622
|
-
source.
|
|
1688
|
+
source.addEventListener("error", handleSourceError);
|
|
1689
|
+
detachListeners = () => {
|
|
1690
|
+
source.removeEventListener("open", handleSourceOpen);
|
|
1691
|
+
source.removeEventListener("message", handleSourceMessage);
|
|
1692
|
+
for (const [eventName, handler] of namedEventHandlers) {
|
|
1693
|
+
source.removeEventListener(eventName, handler);
|
|
1694
|
+
}
|
|
1695
|
+
source.removeEventListener("error", handleSourceError);
|
|
1696
|
+
};
|
|
1697
|
+
});
|
|
1698
|
+
return () => {
|
|
1699
|
+
cancelled = true;
|
|
1700
|
+
detachListeners?.();
|
|
1623
1701
|
};
|
|
1624
1702
|
}, [
|
|
1625
1703
|
closeEventSource,
|