@chromahq/react 1.0.23 → 1.0.24

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.d.ts CHANGED
@@ -76,7 +76,19 @@ interface ConnectionStatusResult {
76
76
  reconnect: (() => void) | undefined;
77
77
  /** Any connection error */
78
78
  error: Error | null | undefined;
79
+ /** Whether the system is fully ready (bridge connected + optional store ready) */
80
+ isReady: boolean;
81
+ /** Whether the system is loading (bridge connecting/reconnecting OR store not ready) */
82
+ isLoading: boolean;
79
83
  }
80
- declare const useConnectionStatus: () => ConnectionStatusResult;
84
+ interface StoreReadyMethods {
85
+ onReady: (callback: () => void) => () => void;
86
+ isReady: () => boolean;
87
+ }
88
+ /**
89
+ * Hook to get unified connection status
90
+ * @param store Optional store to include in readiness check
91
+ */
92
+ declare const useConnectionStatus: (store?: StoreReadyMethods) => ConnectionStatusResult;
81
93
 
82
94
  export { BridgeProvider, useBridge, useBridgeQuery, useConnectionStatus };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext } from 'react';
2
+ import { createContext, useState, useRef, useEffect, useCallback, useMemo, useContext, useSyncExternalStore } from 'react';
3
3
 
4
4
  const BRIDGE_ENABLE_LOGS = true;
5
5
  const CONFIG = {
@@ -46,6 +46,7 @@ function createBridgeInstance(deps) {
46
46
  messageIdRef,
47
47
  isConnectedRef,
48
48
  consecutiveTimeoutsRef,
49
+ reconnectionGracePeriodRef,
49
50
  defaultTimeout,
50
51
  onReconnectNeeded
51
52
  } = deps;
@@ -66,11 +67,15 @@ function createBridgeInstance(deps) {
66
67
  const timeout = setTimeout(() => {
67
68
  if (!pendingRequestsRef.current.has(id)) return;
68
69
  pendingRequestsRef.current.delete(id);
69
- consecutiveTimeoutsRef.current++;
70
+ if (!reconnectionGracePeriodRef.current) {
71
+ consecutiveTimeoutsRef.current++;
72
+ }
70
73
  {
71
- console.warn(`[Bridge] Request timed out: ${key} (${timeoutDuration}ms)`);
74
+ console.warn(
75
+ `[Bridge] Request timed out: ${key} (${timeoutDuration}ms)${reconnectionGracePeriodRef.current ? " [grace period]" : ""}`
76
+ );
72
77
  }
73
- if (consecutiveTimeoutsRef.current >= CONFIG.CONSECUTIVE_FAILURE_THRESHOLD) {
78
+ if (!reconnectionGracePeriodRef.current && consecutiveTimeoutsRef.current >= CONFIG.CONSECUTIVE_FAILURE_THRESHOLD) {
74
79
  {
75
80
  console.warn(
76
81
  `[Bridge] ${consecutiveTimeoutsRef.current} consecutive timeouts, reconnecting...`
@@ -230,6 +235,7 @@ const BridgeProvider = ({
230
235
  const errorCheckIntervalRef = useRef(null);
231
236
  const consecutivePingFailuresRef = useRef(0);
232
237
  const consecutiveTimeoutsRef = useRef(0);
238
+ const reconnectionGracePeriodRef = useRef(false);
233
239
  const pendingRequestsRef = useRef(/* @__PURE__ */ new Map());
234
240
  const eventListenersRef = useRef(/* @__PURE__ */ new Map());
235
241
  const messageIdRef = useRef(0);
@@ -471,6 +477,7 @@ const BridgeProvider = ({
471
477
  messageIdRef,
472
478
  isConnectedRef,
473
479
  consecutiveTimeoutsRef,
480
+ reconnectionGracePeriodRef,
474
481
  defaultTimeout,
475
482
  onReconnectNeeded: triggerReconnect
476
483
  });
@@ -483,6 +490,13 @@ const BridgeProvider = ({
483
490
  swRestartRetryCountRef.current = 0;
484
491
  consecutiveTimeoutsRef.current = 0;
485
492
  isConnectingRef.current = false;
493
+ reconnectionGracePeriodRef.current = true;
494
+ setTimeout(() => {
495
+ reconnectionGracePeriodRef.current = false;
496
+ if (BRIDGE_ENABLE_LOGS) {
497
+ console.log("[Bridge] Grace period ended, timeout monitoring active");
498
+ }
499
+ }, 3e3);
486
500
  eventListenersRef.current.get("bridge:connected")?.forEach((handler) => {
487
501
  try {
488
502
  handler({ timestamp: Date.now() });
@@ -701,14 +715,26 @@ function useBridgeMutation(key, options = {}) {
701
715
  return { mutate, data, loading, error, reset };
702
716
  }
703
717
 
704
- const useConnectionStatus = () => {
718
+ const useConnectionStatus = (store) => {
705
719
  const context = useContext(BridgeContext);
720
+ const storeReady = useSyncExternalStore(
721
+ store?.onReady ?? (() => () => {
722
+ }),
723
+ store?.isReady ?? (() => true),
724
+ () => false
725
+ // Server-side fallback
726
+ );
727
+ const bridgeConnected = context?.status === "connected";
728
+ const isReady = bridgeConnected && storeReady;
729
+ const isLoading = !isReady && (context?.status === "connecting" || context?.status === "reconnecting" || bridgeConnected && !storeReady);
706
730
  return {
707
731
  status: context?.status,
708
- isConnected: context?.status === "connected",
732
+ isConnected: bridgeConnected,
709
733
  isServiceWorkerAlive: context?.isServiceWorkerAlive ?? false,
710
734
  reconnect: context?.reconnect,
711
- error: context?.error
735
+ error: context?.error,
736
+ isReady,
737
+ isLoading
712
738
  };
713
739
  };
714
740
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromahq/react",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "description": "React bindings for the Chroma Chrome extension framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",