@metamask/core-backend 2.0.0 → 3.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/CHANGELOG.md +49 -1
- package/dist/AccountActivityService.cjs +37 -19
- package/dist/AccountActivityService.cjs.map +1 -1
- package/dist/AccountActivityService.d.cts +4 -1
- package/dist/AccountActivityService.d.cts.map +1 -1
- package/dist/AccountActivityService.d.mts +4 -1
- package/dist/AccountActivityService.d.mts.map +1 -1
- package/dist/AccountActivityService.mjs +37 -19
- package/dist/AccountActivityService.mjs.map +1 -1
- package/dist/BackendWebSocketService-method-action-types.cjs.map +1 -1
- package/dist/BackendWebSocketService-method-action-types.d.cts +21 -1
- package/dist/BackendWebSocketService-method-action-types.d.cts.map +1 -1
- package/dist/BackendWebSocketService-method-action-types.d.mts +21 -1
- package/dist/BackendWebSocketService-method-action-types.d.mts.map +1 -1
- package/dist/BackendWebSocketService-method-action-types.mjs.map +1 -1
- package/dist/BackendWebSocketService.cjs +121 -45
- package/dist/BackendWebSocketService.cjs.map +1 -1
- package/dist/BackendWebSocketService.d.cts +17 -2
- package/dist/BackendWebSocketService.d.cts.map +1 -1
- package/dist/BackendWebSocketService.d.mts +17 -2
- package/dist/BackendWebSocketService.d.mts.map +1 -1
- package/dist/BackendWebSocketService.mjs +121 -45
- package/dist/BackendWebSocketService.mjs.map +1 -1
- package/package.json +2 -2
|
@@ -9,7 +9,8 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _BackendWebSocketService_instances, _BackendWebSocketService_messenger, _BackendWebSocketService_options, _BackendWebSocketService_isEnabled, _BackendWebSocketService_trace, _BackendWebSocketService_ws, _BackendWebSocketService_state, _BackendWebSocketService_reconnectAttempts, _BackendWebSocketService_reconnectTimer, _BackendWebSocketService_connectionTimeout, _BackendWebSocketService_connectionPromise, _BackendWebSocketService_pendingRequests, _BackendWebSocketService_connectedAt, _BackendWebSocketService_manualDisconnect, _BackendWebSocketService_subscriptions, _BackendWebSocketService_channelCallbacks, _BackendWebSocketService_subscribeEvents, _BackendWebSocketService_buildAuthenticatedUrl, _BackendWebSocketService_establishConnection, _BackendWebSocketService_handleMessage, _BackendWebSocketService_isServerResponse, _BackendWebSocketService_isSubscriptionNotification, _BackendWebSocketService_isChannelMessage, _BackendWebSocketService_handleServerResponse, _BackendWebSocketService_handleChannelMessage, _BackendWebSocketService_handleSubscriptionNotification, _BackendWebSocketService_parseMessage, _BackendWebSocketService_handleClose, _BackendWebSocketService_handleError, _BackendWebSocketService_scheduleReconnect, _BackendWebSocketService_clearTimers, _BackendWebSocketService_clearPendingRequests, _BackendWebSocketService_clearSubscriptions, _BackendWebSocketService_setState;
|
|
12
|
+
var _BackendWebSocketService_instances, _BackendWebSocketService_messenger, _BackendWebSocketService_options, _BackendWebSocketService_isEnabled, _BackendWebSocketService_trace, _BackendWebSocketService_ws, _BackendWebSocketService_state, _BackendWebSocketService_reconnectAttempts, _BackendWebSocketService_reconnectTimer, _BackendWebSocketService_connectionTimeout, _BackendWebSocketService_stableConnectionTimer, _BackendWebSocketService_connectionPromise, _BackendWebSocketService_pendingRequests, _BackendWebSocketService_connectedAt, _BackendWebSocketService_manualDisconnect, _BackendWebSocketService_subscriptions, _BackendWebSocketService_channelCallbacks, _BackendWebSocketService_backoff, _BackendWebSocketService_subscribeEvents, _BackendWebSocketService_buildAuthenticatedUrl, _BackendWebSocketService_establishConnection, _BackendWebSocketService_handleMessage, _BackendWebSocketService_isServerResponse, _BackendWebSocketService_isSubscriptionNotification, _BackendWebSocketService_isChannelMessage, _BackendWebSocketService_handleServerResponse, _BackendWebSocketService_handleChannelMessage, _BackendWebSocketService_handleSubscriptionNotification, _BackendWebSocketService_parseMessage, _BackendWebSocketService_handleClose, _BackendWebSocketService_handleError, _BackendWebSocketService_scheduleReconnect, _BackendWebSocketService_newBackoff, _BackendWebSocketService_clearTimers, _BackendWebSocketService_clearPendingRequests, _BackendWebSocketService_clearSubscriptions, _BackendWebSocketService_setState;
|
|
13
|
+
import { ExponentialBackoff } from "@metamask/controller-utils";
|
|
13
14
|
import { getErrorMessage } from "@metamask/utils";
|
|
14
15
|
import { v4 as uuidV4 } from "uuid";
|
|
15
16
|
import { projectLogger, createModuleLogger } from "./logger.mjs";
|
|
@@ -18,6 +19,7 @@ const log = createModuleLogger(projectLogger, SERVICE_NAME);
|
|
|
18
19
|
const MESSENGER_EXPOSED_METHODS = [
|
|
19
20
|
'connect',
|
|
20
21
|
'disconnect',
|
|
22
|
+
'forceReconnection',
|
|
21
23
|
'sendMessage',
|
|
22
24
|
'sendRequest',
|
|
23
25
|
'subscribe',
|
|
@@ -148,6 +150,7 @@ export class BackendWebSocketService {
|
|
|
148
150
|
_BackendWebSocketService_reconnectAttempts.set(this, 0);
|
|
149
151
|
_BackendWebSocketService_reconnectTimer.set(this, null);
|
|
150
152
|
_BackendWebSocketService_connectionTimeout.set(this, null);
|
|
153
|
+
_BackendWebSocketService_stableConnectionTimer.set(this, null);
|
|
151
154
|
// Track the current connection promise to handle concurrent connection attempts
|
|
152
155
|
_BackendWebSocketService_connectionPromise.set(this, null);
|
|
153
156
|
_BackendWebSocketService_pendingRequests.set(this, new Map());
|
|
@@ -162,6 +165,8 @@ export class BackendWebSocketService {
|
|
|
162
165
|
// Key: channel name (serves as unique identifier)
|
|
163
166
|
// Value: ChannelCallback configuration
|
|
164
167
|
_BackendWebSocketService_channelCallbacks.set(this, new Map());
|
|
168
|
+
// Backoff instance for reconnection delays (reset on stable connection)
|
|
169
|
+
_BackendWebSocketService_backoff.set(this, void 0);
|
|
165
170
|
__classPrivateFieldSet(this, _BackendWebSocketService_messenger, options.messenger, "f");
|
|
166
171
|
__classPrivateFieldSet(this, _BackendWebSocketService_isEnabled, options.isEnabled, "f");
|
|
167
172
|
// Default to no-op trace function to keep core platform-agnostic
|
|
@@ -175,6 +180,8 @@ export class BackendWebSocketService {
|
|
|
175
180
|
maxReconnectDelay: options.maxReconnectDelay ?? 5000,
|
|
176
181
|
requestTimeout: options.requestTimeout ?? 30000,
|
|
177
182
|
}, "f");
|
|
183
|
+
// Initialize backoff for reconnection delays
|
|
184
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
178
185
|
// Subscribe to authentication and keyring controller events
|
|
179
186
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_subscribeEvents).call(this);
|
|
180
187
|
// Register action handlers using the method actions pattern
|
|
@@ -212,38 +219,50 @@ export class BackendWebSocketService {
|
|
|
212
219
|
return;
|
|
213
220
|
}
|
|
214
221
|
// If already connecting, wait for the existing connection attempt to complete
|
|
215
|
-
if (__classPrivateFieldGet(this,
|
|
222
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f")) {
|
|
216
223
|
await __classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f");
|
|
217
224
|
return;
|
|
218
225
|
}
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const token = await __classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").call('AuthenticationController:getBearerToken');
|
|
223
|
-
if (!token) {
|
|
224
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
bearerToken = token;
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
log('Failed to check authentication requirements', { error });
|
|
231
|
-
// Can't connect - schedule retry
|
|
232
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
226
|
+
// If a reconnect is already scheduled, defer to it to avoid bypassing exponential backoff
|
|
227
|
+
// This prevents rapid loops when server accepts then immediately closes connections
|
|
228
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
233
229
|
return;
|
|
234
230
|
}
|
|
235
|
-
|
|
236
|
-
//
|
|
237
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise,
|
|
231
|
+
// Create and store the connection promise IMMEDIATELY (before any async operations)
|
|
232
|
+
// This ensures subsequent connect() calls will wait for this promise instead of creating new connections
|
|
233
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, (async () => {
|
|
234
|
+
// Priority 2: Check authentication requirements (signed in)
|
|
235
|
+
let bearerToken;
|
|
236
|
+
try {
|
|
237
|
+
const token = await __classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").call('AuthenticationController:getBearerToken');
|
|
238
|
+
if (!token) {
|
|
239
|
+
throw new Error('Authentication required: user not signed in');
|
|
240
|
+
}
|
|
241
|
+
bearerToken = token;
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
log('Failed to check authentication requirements', { error });
|
|
245
|
+
throw error;
|
|
246
|
+
}
|
|
247
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTING);
|
|
248
|
+
// Establish the actual WebSocket connection
|
|
249
|
+
try {
|
|
250
|
+
await __classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_establishConnection).call(this, bearerToken);
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
const errorMessage = getErrorMessage(error);
|
|
254
|
+
log('Connection attempt failed', { errorMessage, error });
|
|
255
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.ERROR);
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
})(), "f");
|
|
238
259
|
try {
|
|
239
260
|
await __classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f");
|
|
240
261
|
}
|
|
241
|
-
catch
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m",
|
|
245
|
-
// Rethrow to propagate error to caller
|
|
246
|
-
throw error;
|
|
262
|
+
catch {
|
|
263
|
+
// Always schedule reconnect on any failure
|
|
264
|
+
// Exponential backoff will prevent aggressive retries
|
|
265
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
247
266
|
}
|
|
248
267
|
finally {
|
|
249
268
|
// Clear the connection promise when done (success or failure)
|
|
@@ -252,10 +271,8 @@ export class BackendWebSocketService {
|
|
|
252
271
|
}
|
|
253
272
|
/**
|
|
254
273
|
* Closes WebSocket connection
|
|
255
|
-
*
|
|
256
|
-
* @returns Promise that resolves when disconnection is complete
|
|
257
274
|
*/
|
|
258
|
-
|
|
275
|
+
disconnect() {
|
|
259
276
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED ||
|
|
260
277
|
__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTING) {
|
|
261
278
|
return;
|
|
@@ -267,11 +284,41 @@ export class BackendWebSocketService {
|
|
|
267
284
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error('WebSocket disconnected'));
|
|
268
285
|
// Clear any pending connection promise
|
|
269
286
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
287
|
+
// Reset reconnect attempts on manual disconnect
|
|
288
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
270
289
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f")) {
|
|
271
290
|
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(1000, 'Normal closure');
|
|
272
291
|
}
|
|
273
292
|
log('WebSocket manually disconnected');
|
|
274
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Forces a WebSocket reconnection to clean up subscription state
|
|
296
|
+
*
|
|
297
|
+
* This method is useful when subscription state may be out of sync and needs to be reset.
|
|
298
|
+
* It performs a controlled disconnect-then-reconnect sequence:
|
|
299
|
+
* - Disconnects cleanly to trigger subscription cleanup
|
|
300
|
+
* - Schedules reconnection with exponential backoff to prevent rapid loops
|
|
301
|
+
* - All subscriptions will be cleaned up automatically on disconnect
|
|
302
|
+
*
|
|
303
|
+
* Use cases:
|
|
304
|
+
* - Recovering from subscription/unsubscription issues
|
|
305
|
+
* - Cleaning up orphaned subscriptions
|
|
306
|
+
* - Forcing a fresh subscription state
|
|
307
|
+
*
|
|
308
|
+
* @returns Promise that resolves when disconnection is complete (reconnection is scheduled)
|
|
309
|
+
*/
|
|
310
|
+
async forceReconnection() {
|
|
311
|
+
// If a reconnect is already scheduled, don't force another one
|
|
312
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
313
|
+
log('Reconnect already scheduled, skipping force reconnection');
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
log('Forcing WebSocket reconnection to clean up subscription state');
|
|
317
|
+
// Perform controlled disconnect
|
|
318
|
+
this.disconnect();
|
|
319
|
+
// Schedule reconnection with exponential backoff
|
|
320
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
321
|
+
}
|
|
275
322
|
/**
|
|
276
323
|
* Sends a message through the WebSocket (fire-and-forget, no response expected)
|
|
277
324
|
*
|
|
@@ -615,7 +662,7 @@ export class BackendWebSocketService {
|
|
|
615
662
|
return subscription;
|
|
616
663
|
}
|
|
617
664
|
}
|
|
618
|
-
_BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_options = new WeakMap(), _BackendWebSocketService_isEnabled = new WeakMap(), _BackendWebSocketService_trace = new WeakMap(), _BackendWebSocketService_ws = new WeakMap(), _BackendWebSocketService_state = new WeakMap(), _BackendWebSocketService_reconnectAttempts = new WeakMap(), _BackendWebSocketService_reconnectTimer = new WeakMap(), _BackendWebSocketService_connectionTimeout = new WeakMap(), _BackendWebSocketService_connectionPromise = new WeakMap(), _BackendWebSocketService_pendingRequests = new WeakMap(), _BackendWebSocketService_connectedAt = new WeakMap(), _BackendWebSocketService_manualDisconnect = new WeakMap(), _BackendWebSocketService_subscriptions = new WeakMap(), _BackendWebSocketService_channelCallbacks = new WeakMap(), _BackendWebSocketService_instances = new WeakSet(), _BackendWebSocketService_subscribeEvents = function _BackendWebSocketService_subscribeEvents() {
|
|
665
|
+
_BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_options = new WeakMap(), _BackendWebSocketService_isEnabled = new WeakMap(), _BackendWebSocketService_trace = new WeakMap(), _BackendWebSocketService_ws = new WeakMap(), _BackendWebSocketService_state = new WeakMap(), _BackendWebSocketService_reconnectAttempts = new WeakMap(), _BackendWebSocketService_reconnectTimer = new WeakMap(), _BackendWebSocketService_connectionTimeout = new WeakMap(), _BackendWebSocketService_stableConnectionTimer = new WeakMap(), _BackendWebSocketService_connectionPromise = new WeakMap(), _BackendWebSocketService_pendingRequests = new WeakMap(), _BackendWebSocketService_connectedAt = new WeakMap(), _BackendWebSocketService_manualDisconnect = new WeakMap(), _BackendWebSocketService_subscriptions = new WeakMap(), _BackendWebSocketService_channelCallbacks = new WeakMap(), _BackendWebSocketService_backoff = new WeakMap(), _BackendWebSocketService_instances = new WeakSet(), _BackendWebSocketService_subscribeEvents = function _BackendWebSocketService_subscribeEvents() {
|
|
619
666
|
// Subscribe to authentication state changes (sign in/out)
|
|
620
667
|
__classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").subscribe('AuthenticationController:stateChange', (state) => {
|
|
621
668
|
if (state.isSignedIn) {
|
|
@@ -623,7 +670,6 @@ _BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_opt
|
|
|
623
670
|
this.connect();
|
|
624
671
|
}
|
|
625
672
|
else {
|
|
626
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
627
673
|
this.disconnect();
|
|
628
674
|
}
|
|
629
675
|
}, (state) => ({ isSignedIn: state.isSignedIn }));
|
|
@@ -634,7 +680,6 @@ _BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_opt
|
|
|
634
680
|
});
|
|
635
681
|
// Subscribe to wallet lock event
|
|
636
682
|
__classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").subscribe('KeyringController:lock', () => {
|
|
637
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
638
683
|
this.disconnect();
|
|
639
684
|
});
|
|
640
685
|
}, _BackendWebSocketService_buildAuthenticatedUrl = function _BackendWebSocketService_buildAuthenticatedUrl(bearerToken) {
|
|
@@ -683,8 +728,15 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
683
728
|
__classPrivateFieldSet(this, _BackendWebSocketService_ws, ws, "f");
|
|
684
729
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTED);
|
|
685
730
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, Date.now(), "f");
|
|
686
|
-
//
|
|
687
|
-
|
|
731
|
+
// Only reset after connection stays stable for a period (10 seconds)
|
|
732
|
+
// This prevents rapid reconnect loops when server accepts then immediately closes
|
|
733
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, setTimeout(() => {
|
|
734
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
735
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
736
|
+
// Create new backoff sequence for fresh start on next disconnect
|
|
737
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
738
|
+
log('Connection stable - reset reconnect attempts and backoff');
|
|
739
|
+
}, 10000), "f");
|
|
688
740
|
resolve();
|
|
689
741
|
});
|
|
690
742
|
};
|
|
@@ -781,13 +833,11 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
781
833
|
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
782
834
|
name: `${SERVICE_NAME} Channel Message`,
|
|
783
835
|
data: {
|
|
784
|
-
channel: message.channel,
|
|
785
836
|
latency_ms: latency,
|
|
786
837
|
event: message.event,
|
|
787
838
|
},
|
|
788
839
|
tags: {
|
|
789
840
|
service: SERVICE_NAME,
|
|
790
|
-
channel_type: message.channel,
|
|
791
841
|
},
|
|
792
842
|
}, () => {
|
|
793
843
|
// Direct lookup for exact channel match
|
|
@@ -804,7 +854,7 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
804
854
|
// Calculate notification latency: time from server sent to client received
|
|
805
855
|
const receivedAt = Date.now();
|
|
806
856
|
const latency = receivedAt - timestamp;
|
|
807
|
-
// Trace notification processing
|
|
857
|
+
// Trace notification processing wi th latency data
|
|
808
858
|
// Use stored channelType instead of parsing each time
|
|
809
859
|
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
810
860
|
name: `${SERVICE_NAME} Notification`,
|
|
@@ -828,7 +878,14 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
828
878
|
}, _BackendWebSocketService_handleClose = function _BackendWebSocketService_handleClose(event) {
|
|
829
879
|
// Calculate connection duration before we clear state
|
|
830
880
|
const connectionDuration = Date.now() - __classPrivateFieldGet(this, _BackendWebSocketService_connectedAt, "f");
|
|
831
|
-
__classPrivateFieldGet(this,
|
|
881
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f")) {
|
|
882
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
883
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
884
|
+
}
|
|
885
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f")) {
|
|
886
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f"));
|
|
887
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
888
|
+
}
|
|
832
889
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, 0, "f");
|
|
833
890
|
// Clear any pending connection promise
|
|
834
891
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
@@ -858,28 +915,43 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
858
915
|
}, () => {
|
|
859
916
|
// Empty trace callback - just measuring the event
|
|
860
917
|
});
|
|
861
|
-
// For any unexpected disconnects, attempt reconnection
|
|
862
|
-
// The manualDisconnect flag is the only gate - if it's false, we reconnect
|
|
863
918
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
864
919
|
}, _BackendWebSocketService_handleError = function _BackendWebSocketService_handleError(_error) {
|
|
865
920
|
// Placeholder for future error handling logic
|
|
866
921
|
}, _BackendWebSocketService_scheduleReconnect = function _BackendWebSocketService_scheduleReconnect() {
|
|
922
|
+
// If a reconnect is already scheduled, don't schedule another one
|
|
923
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
// Increment attempts BEFORE calculating delay so backoff grows properly
|
|
867
927
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f") + 1, "f");
|
|
868
|
-
|
|
869
|
-
const delay =
|
|
928
|
+
// Use Cockatiel's exponential backoff to get delay with jitter
|
|
929
|
+
const delay = __classPrivateFieldGet(this, _BackendWebSocketService_backoff, "f").duration;
|
|
930
|
+
// Progress to next backoff state for future reconnect attempts
|
|
931
|
+
// Pass attempt number as context (though ExponentialBackoff doesn't use it)
|
|
932
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_backoff, __classPrivateFieldGet(this, _BackendWebSocketService_backoff, "f").next({ attempt: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f") }), "f");
|
|
933
|
+
log('Scheduling reconnect', {
|
|
934
|
+
attempt: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f"),
|
|
935
|
+
delay_ms: delay,
|
|
936
|
+
});
|
|
870
937
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectTimer, setTimeout(() => {
|
|
871
938
|
// Clear timer reference first
|
|
872
939
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectTimer, null, "f");
|
|
873
940
|
// Check if connection is still enabled before reconnecting
|
|
874
941
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f") && !__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f").call(this)) {
|
|
875
942
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
943
|
+
// Create new backoff sequence when disabled
|
|
944
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
876
945
|
return;
|
|
877
946
|
}
|
|
878
|
-
//
|
|
879
|
-
this.connect()
|
|
880
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
881
|
-
});
|
|
947
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
948
|
+
this.connect();
|
|
882
949
|
}, delay), "f");
|
|
950
|
+
}, _BackendWebSocketService_newBackoff = function _BackendWebSocketService_newBackoff() {
|
|
951
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_backoff, new ExponentialBackoff({
|
|
952
|
+
initialDelay: __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").reconnectDelay,
|
|
953
|
+
maxDelay: __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").maxReconnectDelay,
|
|
954
|
+
}).next(), "f");
|
|
883
955
|
}, _BackendWebSocketService_clearTimers = function _BackendWebSocketService_clearTimers() {
|
|
884
956
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
885
957
|
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f"));
|
|
@@ -889,6 +961,10 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
889
961
|
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
890
962
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
891
963
|
}
|
|
964
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f")) {
|
|
965
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f"));
|
|
966
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
967
|
+
}
|
|
892
968
|
}, _BackendWebSocketService_clearPendingRequests = function _BackendWebSocketService_clearPendingRequests(error) {
|
|
893
969
|
for (const [, request] of __classPrivateFieldGet(this, _BackendWebSocketService_pendingRequests, "f")) {
|
|
894
970
|
clearTimeout(request.timeout);
|