react-realtime-hooks 1.4.2 → 2.0.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 CHANGED
@@ -88,7 +88,6 @@ export function NotificationsPanel() {
88
88
  parseMessage: (event) => JSON.parse(String(event.data)) as IncomingMessage,
89
89
  reconnect: {
90
90
  initialDelayMs: 1_000,
91
- maxAttempts: null,
92
91
  },
93
92
  heartbeat: {
94
93
  intervalMs: 10_000,
@@ -239,7 +238,6 @@ export function ChatSocket() {
239
238
  parseMessage: (event) => JSON.parse(String(event.data)) as IncomingMessage,
240
239
  reconnect: {
241
240
  initialDelayMs: 1_000,
242
- maxAttempts: null,
243
241
  },
244
242
  heartbeat: {
245
243
  intervalMs: 10_000,
@@ -393,6 +391,8 @@ export function GatedNotifications() {
393
391
  initialDelayMs: 1_000,
394
392
  maxAttempts: null,
395
393
  },
394
+ // ^ pass `null` explicitly to opt back into unlimited reconnect attempts;
395
+ // the default in 2.0 caps retries at 10.
396
396
  url: "ws://localhost:8080/notifications",
397
397
  });
398
398
 
@@ -508,7 +508,7 @@ retry loop.
508
508
  | `maxDelayMs` | `number` | `30000` | Delay cap |
509
509
  | `backoffFactor` | `number` | `2` | Exponential multiplier |
510
510
  | `jitterRatio` | `number` | `0.2` | Randomized variance ratio |
511
- | `maxAttempts` | `number \| null` | `null` | Max attempts, `null` means unlimited |
511
+ | `maxAttempts` | `number \| null` | `10` | Max attempts before `"stopped"`; pass `null` for unlimited |
512
512
  | `getDelayMs` | `ReconnectDelayStrategy` | `undefined` | Custom delay strategy |
513
513
  | `resetOnSuccess` | `boolean` | `true` | Resets attempt count after success |
514
514
  | `onSchedule` | `(attempt) => void` | `undefined` | Called when an attempt is scheduled |
@@ -540,7 +540,7 @@ retry loop.
540
540
  | -------------- | --------------------------------------------------- | ----------- | ------------------------------------------- |
541
541
  | `enabled` | `boolean` | `true` | Enables the heartbeat loop |
542
542
  | `intervalMs` | `number` | Required | Beat interval |
543
- | `timeoutMs` | `number` | `undefined` | Timeout before `hasTimedOut` becomes `true` |
543
+ | `timeoutMs` | `number \| null` | `10_000` | Timeout in ms before `hasTimedOut` becomes `true`; pass `null` to disable |
544
544
  | `message` | `TOutgoing \| (() => TOutgoing)` | `undefined` | Optional heartbeat payload |
545
545
  | `beat` | `() => void \| boolean \| Promise<void \| boolean>` | `undefined` | Custom beat side effect |
546
546
  | `matchesAck` | `(message) => boolean` | `undefined` | Ack matcher |
@@ -694,6 +694,12 @@ Run the local playground:
694
694
  npm run demo
695
695
  ```
696
696
 
697
+ ## Migrating from 1.x
698
+
699
+ Two defaults change in 2.0 (`reconnect.maxAttempts` → `10`,
700
+ `heartbeat.timeoutMs` → `10_000`). See [MIGRATING.md](./MIGRATING.md) for the
701
+ exact diff and how to restore 1.x behaviour.
702
+
697
703
  ## Contributing
698
704
 
699
705
  Development and release workflow live in [CONTRIBUTING.md](./CONTRIBUTING.md).
package/dist/index.cjs CHANGED
@@ -315,6 +315,7 @@ var DEFAULT_RECONNECT_OPTIONS = {
315
315
  enabled: true,
316
316
  initialDelayMs: 1e3,
317
317
  jitterRatio: 0.2,
318
+ maxAttempts: 10,
318
319
  maxDelayMs: 3e4,
319
320
  resetOnSuccess: true
320
321
  };
@@ -366,7 +367,7 @@ var normalizeReconnectOptions = (options) => {
366
367
  jitterRatio: sanitizeJitterRatio(
367
368
  options?.jitterRatio ?? DEFAULT_RECONNECT_OPTIONS.jitterRatio
368
369
  ),
369
- maxAttempts: sanitizeMaxAttempts(options?.maxAttempts),
370
+ maxAttempts: options?.maxAttempts === void 0 ? DEFAULT_RECONNECT_OPTIONS.maxAttempts : sanitizeMaxAttempts(options.maxAttempts),
370
371
  maxDelayMs,
371
372
  resetOnSuccess: options?.resetOnSuccess ?? DEFAULT_RECONNECT_OPTIONS.resetOnSuccess
372
373
  };
@@ -584,6 +585,7 @@ var useReconnect = (options = {}) => {
584
585
  status: state.status
585
586
  };
586
587
  };
588
+ var DEFAULT_HEARTBEAT_TIMEOUT_MS = 1e4;
587
589
  var createInitialState2 = (isRunning) => ({
588
590
  hasTimedOut: false,
589
591
  isRunning,
@@ -617,13 +619,14 @@ var useHeartbeat = (options) => {
617
619
  options.onTimeout?.();
618
620
  });
619
621
  const scheduleTimeout = useStableCallback(() => {
620
- if (options.timeoutMs === void 0) {
622
+ const timeoutMs = options.timeoutMs === void 0 ? DEFAULT_HEARTBEAT_TIMEOUT_MS : options.timeoutMs;
623
+ if (timeoutMs === null) {
621
624
  timeoutRef.current.cancel();
622
625
  return;
623
626
  }
624
627
  timeoutRef.current.schedule(() => {
625
628
  handleTimeout();
626
- }, options.timeoutMs);
629
+ }, timeoutMs);
627
630
  });
628
631
  const handleBeatSuccess = useStableCallback((performedAt) => {
629
632
  commitState((current) => ({
@@ -942,8 +945,9 @@ var useWebSocket = (options) => {
942
945
  const nextSocketEpochRef = react.useRef(0);
943
946
  const controller = useWebSocketController();
944
947
  const [openNonce, setOpenNonce] = react.useState(0);
948
+ const initialStatus = !supported || resolvedUrl === null ? "closed" : connect ? "connecting" : "idle";
945
949
  const [state, setState] = react.useState(
946
- () => createInitialState4(connect ? "connecting" : "idle")
950
+ () => createInitialState4(initialStatus)
947
951
  );
948
952
  const stateRef = react.useRef(state);
949
953
  react.useInsertionEffect(() => {
@@ -985,7 +989,7 @@ var useWebSocket = (options) => {
985
989
  startOnMount: false
986
990
  };
987
991
  if (heartbeatConfig !== null && heartbeatConfig.timeoutMs !== void 0) {
988
- heartbeatHookOptions.timeoutMs = heartbeatConfig.timeoutMs;
992
+ heartbeatHookOptions.timeoutMs = heartbeatConfig.timeoutMs ?? null;
989
993
  }
990
994
  if (heartbeatConfig !== null && heartbeatConfig.matchesAck !== void 0) {
991
995
  heartbeatHookOptions.matchesAck = heartbeatConfig.matchesAck;
@@ -1517,8 +1521,9 @@ var useEventSource = (options) => {
1517
1521
  const suppressReconnectRef = react.useRef(false);
1518
1522
  const terminalErrorRef = react.useRef(null);
1519
1523
  const [openNonce, setOpenNonce] = react.useState(0);
1524
+ const initialStatus = !supported || resolvedUrl === null ? "closed" : connect ? "connecting" : "idle";
1520
1525
  const [state, setState] = react.useState(
1521
- () => createInitialState5(connect ? "connecting" : "idle")
1526
+ () => createInitialState5(initialStatus)
1522
1527
  );
1523
1528
  const stateRef = react.useRef(state);
1524
1529
  react.useInsertionEffect(() => {