@adventurelabs/scout-core 1.0.55 → 1.0.57
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/hooks/useScoutDbListener.js +83 -19
- package/package.json +3 -3
|
@@ -6,6 +6,12 @@ export function useScoutDbListener(scoutSupabase) {
|
|
|
6
6
|
const supabase = useRef(null);
|
|
7
7
|
const channels = useRef([]);
|
|
8
8
|
const dispatch = useAppDispatch();
|
|
9
|
+
const reconnectTimeoutRef = useRef(null);
|
|
10
|
+
const reconnectAttemptsRef = useRef(0);
|
|
11
|
+
const maxReconnectAttempts = 10;
|
|
12
|
+
const baseDelay = 1000; // 1 second
|
|
13
|
+
const maxDelay = 5000; // 5 seconds
|
|
14
|
+
const lastChannelIdRef = useRef(null);
|
|
9
15
|
function handleTagInserts(payload) {
|
|
10
16
|
console.log("[DB Listener] Tag INSERT received:", payload.new);
|
|
11
17
|
dispatch(addTag(payload.new));
|
|
@@ -71,15 +77,25 @@ export function useScoutDbListener(scoutSupabase) {
|
|
|
71
77
|
function handleConnectivityUpdates(payload) {
|
|
72
78
|
console.log("[DB Listener] Connectivity UPDATE received:", payload.new);
|
|
73
79
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
// Clean up all channels
|
|
81
|
+
const cleanupChannels = () => {
|
|
82
|
+
channels.current.forEach((channel) => {
|
|
83
|
+
if (channel) {
|
|
84
|
+
scoutSupabase.removeChannel(channel);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
channels.current = [];
|
|
88
|
+
};
|
|
89
|
+
// Setup channel with event handlers
|
|
90
|
+
const setupChannel = () => {
|
|
91
|
+
if (!scoutSupabase)
|
|
92
|
+
return null;
|
|
93
|
+
const channelId = `scout_realtime_${Date.now()}_${Math.random()
|
|
94
|
+
.toString(36)
|
|
95
|
+
.substr(2, 9)}`;
|
|
96
|
+
const mainChannel = scoutSupabase.channel(channelId);
|
|
97
|
+
lastChannelIdRef.current = channelId;
|
|
98
|
+
console.log(`[DB Listener] Creating channel: ${channelId}`);
|
|
83
99
|
// Subscribe to all events
|
|
84
100
|
mainChannel
|
|
85
101
|
.on("postgres_changes", { event: "INSERT", schema: "public", table: "plans" }, handlePlanInserts)
|
|
@@ -101,27 +117,75 @@ export function useScoutDbListener(scoutSupabase) {
|
|
|
101
117
|
console.log("[DB Listener] Subscription status:", status);
|
|
102
118
|
if (status === "SUBSCRIBED") {
|
|
103
119
|
console.log("[DB Listener] ✅ Successfully subscribed to real-time updates");
|
|
120
|
+
reconnectAttemptsRef.current = 0; // Reset reconnect attempts on successful connection
|
|
104
121
|
}
|
|
105
122
|
else if (status === "CHANNEL_ERROR") {
|
|
106
|
-
console.
|
|
123
|
+
console.warn("[DB Listener] ❌ Channel error occurred. Reconnecting...");
|
|
124
|
+
handleReconnect();
|
|
107
125
|
}
|
|
108
126
|
else if (status === "TIMED_OUT") {
|
|
109
|
-
console.
|
|
127
|
+
console.warn("[DB Listener] ⏰ Subscription timed out. Reconnecting...");
|
|
128
|
+
handleReconnect();
|
|
110
129
|
}
|
|
111
130
|
else if (status === "CLOSED") {
|
|
112
|
-
console.log(
|
|
131
|
+
console.log(`[DB Listener] 🔒 Channel closed: ${lastChannelIdRef.current}`);
|
|
132
|
+
// Only reconnect if this isn't an immediate closure after subscription
|
|
133
|
+
if (reconnectAttemptsRef.current > 0) {
|
|
134
|
+
console.log("[DB Listener] Reconnecting...");
|
|
135
|
+
handleReconnect();
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
console.log("[DB Listener] Channel closed immediately after subscription, not reconnecting");
|
|
139
|
+
}
|
|
113
140
|
}
|
|
114
141
|
});
|
|
115
|
-
|
|
142
|
+
return mainChannel;
|
|
143
|
+
};
|
|
144
|
+
// Handle reconnection with exponential backoff
|
|
145
|
+
const handleReconnect = () => {
|
|
146
|
+
if (reconnectAttemptsRef.current >= maxReconnectAttempts) {
|
|
147
|
+
console.error("[DB Listener] 🚫 Max reconnection attempts reached");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
// Clear any existing timeout
|
|
151
|
+
if (reconnectTimeoutRef.current) {
|
|
152
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
153
|
+
}
|
|
154
|
+
const delay = Math.min(baseDelay * (reconnectAttemptsRef.current + 1), maxDelay);
|
|
155
|
+
console.log(`[DB Listener] 🔄 Attempting reconnection in ${delay}ms (attempt ${reconnectAttemptsRef.current + 1}/${maxReconnectAttempts})`);
|
|
156
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
157
|
+
reconnectAttemptsRef.current++;
|
|
158
|
+
cleanupChannels();
|
|
159
|
+
const newChannel = setupChannel();
|
|
160
|
+
if (newChannel) {
|
|
161
|
+
channels.current.push(newChannel);
|
|
162
|
+
}
|
|
163
|
+
}, delay);
|
|
164
|
+
};
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (!scoutSupabase) {
|
|
167
|
+
console.error("[DB Listener] No Supabase client available");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
supabase.current = scoutSupabase;
|
|
171
|
+
// Initial channel setup
|
|
172
|
+
const mainChannel = setupChannel();
|
|
173
|
+
if (mainChannel) {
|
|
174
|
+
channels.current.push(mainChannel);
|
|
175
|
+
}
|
|
116
176
|
// Cleanup function
|
|
117
177
|
return () => {
|
|
118
178
|
console.log("[DB Listener] 🧹 Cleaning up channels");
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
179
|
+
// Clear any pending reconnection attempts
|
|
180
|
+
if (reconnectTimeoutRef.current) {
|
|
181
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
182
|
+
reconnectTimeoutRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
// Reset reconnect attempts and channel tracking
|
|
185
|
+
reconnectAttemptsRef.current = 0;
|
|
186
|
+
lastChannelIdRef.current = null;
|
|
187
|
+
// Clean up channels
|
|
188
|
+
cleanupChannels();
|
|
125
189
|
};
|
|
126
190
|
}, [scoutSupabase, dispatch]);
|
|
127
191
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adventurelabs/scout-core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"description": "Core utilities and helpers for Adventure Labs Scout applications",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"typescript": "^5.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@supabase/supabase-js": "^2.
|
|
48
|
-
"@supabase/ssr": "^0.
|
|
47
|
+
"@supabase/supabase-js": "^2.53.6",
|
|
48
|
+
"@supabase/ssr": "^0.6.1",
|
|
49
49
|
"@reduxjs/toolkit": "^2.0.0",
|
|
50
50
|
"zustand": "^4.0.0"
|
|
51
51
|
}
|