@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
|
@@ -10,9 +10,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
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;
|
|
13
|
+
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;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.BackendWebSocketService = exports.WebSocketEventType = exports.WebSocketState = exports.getCloseReason = void 0;
|
|
16
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
16
17
|
const utils_1 = require("@metamask/utils");
|
|
17
18
|
const uuid_1 = require("uuid");
|
|
18
19
|
const logger_1 = require("./logger.cjs");
|
|
@@ -21,6 +22,7 @@ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, SERVICE_NAM
|
|
|
21
22
|
const MESSENGER_EXPOSED_METHODS = [
|
|
22
23
|
'connect',
|
|
23
24
|
'disconnect',
|
|
25
|
+
'forceReconnection',
|
|
24
26
|
'sendMessage',
|
|
25
27
|
'sendRequest',
|
|
26
28
|
'subscribe',
|
|
@@ -152,6 +154,7 @@ class BackendWebSocketService {
|
|
|
152
154
|
_BackendWebSocketService_reconnectAttempts.set(this, 0);
|
|
153
155
|
_BackendWebSocketService_reconnectTimer.set(this, null);
|
|
154
156
|
_BackendWebSocketService_connectionTimeout.set(this, null);
|
|
157
|
+
_BackendWebSocketService_stableConnectionTimer.set(this, null);
|
|
155
158
|
// Track the current connection promise to handle concurrent connection attempts
|
|
156
159
|
_BackendWebSocketService_connectionPromise.set(this, null);
|
|
157
160
|
_BackendWebSocketService_pendingRequests.set(this, new Map());
|
|
@@ -166,6 +169,8 @@ class BackendWebSocketService {
|
|
|
166
169
|
// Key: channel name (serves as unique identifier)
|
|
167
170
|
// Value: ChannelCallback configuration
|
|
168
171
|
_BackendWebSocketService_channelCallbacks.set(this, new Map());
|
|
172
|
+
// Backoff instance for reconnection delays (reset on stable connection)
|
|
173
|
+
_BackendWebSocketService_backoff.set(this, void 0);
|
|
169
174
|
__classPrivateFieldSet(this, _BackendWebSocketService_messenger, options.messenger, "f");
|
|
170
175
|
__classPrivateFieldSet(this, _BackendWebSocketService_isEnabled, options.isEnabled, "f");
|
|
171
176
|
// Default to no-op trace function to keep core platform-agnostic
|
|
@@ -179,6 +184,8 @@ class BackendWebSocketService {
|
|
|
179
184
|
maxReconnectDelay: options.maxReconnectDelay ?? 5000,
|
|
180
185
|
requestTimeout: options.requestTimeout ?? 30000,
|
|
181
186
|
}, "f");
|
|
187
|
+
// Initialize backoff for reconnection delays
|
|
188
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
182
189
|
// Subscribe to authentication and keyring controller events
|
|
183
190
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_subscribeEvents).call(this);
|
|
184
191
|
// Register action handlers using the method actions pattern
|
|
@@ -216,38 +223,50 @@ class BackendWebSocketService {
|
|
|
216
223
|
return;
|
|
217
224
|
}
|
|
218
225
|
// If already connecting, wait for the existing connection attempt to complete
|
|
219
|
-
if (__classPrivateFieldGet(this,
|
|
226
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f")) {
|
|
220
227
|
await __classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f");
|
|
221
228
|
return;
|
|
222
229
|
}
|
|
223
|
-
//
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const token = await __classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").call('AuthenticationController:getBearerToken');
|
|
227
|
-
if (!token) {
|
|
228
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
bearerToken = token;
|
|
232
|
-
}
|
|
233
|
-
catch (error) {
|
|
234
|
-
log('Failed to check authentication requirements', { error });
|
|
235
|
-
// Can't connect - schedule retry
|
|
236
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
230
|
+
// If a reconnect is already scheduled, defer to it to avoid bypassing exponential backoff
|
|
231
|
+
// This prevents rapid loops when server accepts then immediately closes connections
|
|
232
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
237
233
|
return;
|
|
238
234
|
}
|
|
239
|
-
|
|
240
|
-
//
|
|
241
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise,
|
|
235
|
+
// Create and store the connection promise IMMEDIATELY (before any async operations)
|
|
236
|
+
// This ensures subsequent connect() calls will wait for this promise instead of creating new connections
|
|
237
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, (async () => {
|
|
238
|
+
// Priority 2: Check authentication requirements (signed in)
|
|
239
|
+
let bearerToken;
|
|
240
|
+
try {
|
|
241
|
+
const token = await __classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").call('AuthenticationController:getBearerToken');
|
|
242
|
+
if (!token) {
|
|
243
|
+
throw new Error('Authentication required: user not signed in');
|
|
244
|
+
}
|
|
245
|
+
bearerToken = token;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
log('Failed to check authentication requirements', { error });
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTING);
|
|
252
|
+
// Establish the actual WebSocket connection
|
|
253
|
+
try {
|
|
254
|
+
await __classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_establishConnection).call(this, bearerToken);
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
const errorMessage = (0, utils_1.getErrorMessage)(error);
|
|
258
|
+
log('Connection attempt failed', { errorMessage, error });
|
|
259
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.ERROR);
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
})(), "f");
|
|
242
263
|
try {
|
|
243
264
|
await __classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f");
|
|
244
265
|
}
|
|
245
|
-
catch
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m",
|
|
249
|
-
// Rethrow to propagate error to caller
|
|
250
|
-
throw error;
|
|
266
|
+
catch {
|
|
267
|
+
// Always schedule reconnect on any failure
|
|
268
|
+
// Exponential backoff will prevent aggressive retries
|
|
269
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
251
270
|
}
|
|
252
271
|
finally {
|
|
253
272
|
// Clear the connection promise when done (success or failure)
|
|
@@ -256,10 +275,8 @@ class BackendWebSocketService {
|
|
|
256
275
|
}
|
|
257
276
|
/**
|
|
258
277
|
* Closes WebSocket connection
|
|
259
|
-
*
|
|
260
|
-
* @returns Promise that resolves when disconnection is complete
|
|
261
278
|
*/
|
|
262
|
-
|
|
279
|
+
disconnect() {
|
|
263
280
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED ||
|
|
264
281
|
__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTING) {
|
|
265
282
|
return;
|
|
@@ -271,11 +288,41 @@ class BackendWebSocketService {
|
|
|
271
288
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error('WebSocket disconnected'));
|
|
272
289
|
// Clear any pending connection promise
|
|
273
290
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
291
|
+
// Reset reconnect attempts on manual disconnect
|
|
292
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
274
293
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f")) {
|
|
275
294
|
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(1000, 'Normal closure');
|
|
276
295
|
}
|
|
277
296
|
log('WebSocket manually disconnected');
|
|
278
297
|
}
|
|
298
|
+
/**
|
|
299
|
+
* Forces a WebSocket reconnection to clean up subscription state
|
|
300
|
+
*
|
|
301
|
+
* This method is useful when subscription state may be out of sync and needs to be reset.
|
|
302
|
+
* It performs a controlled disconnect-then-reconnect sequence:
|
|
303
|
+
* - Disconnects cleanly to trigger subscription cleanup
|
|
304
|
+
* - Schedules reconnection with exponential backoff to prevent rapid loops
|
|
305
|
+
* - All subscriptions will be cleaned up automatically on disconnect
|
|
306
|
+
*
|
|
307
|
+
* Use cases:
|
|
308
|
+
* - Recovering from subscription/unsubscription issues
|
|
309
|
+
* - Cleaning up orphaned subscriptions
|
|
310
|
+
* - Forcing a fresh subscription state
|
|
311
|
+
*
|
|
312
|
+
* @returns Promise that resolves when disconnection is complete (reconnection is scheduled)
|
|
313
|
+
*/
|
|
314
|
+
async forceReconnection() {
|
|
315
|
+
// If a reconnect is already scheduled, don't force another one
|
|
316
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
317
|
+
log('Reconnect already scheduled, skipping force reconnection');
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
log('Forcing WebSocket reconnection to clean up subscription state');
|
|
321
|
+
// Perform controlled disconnect
|
|
322
|
+
this.disconnect();
|
|
323
|
+
// Schedule reconnection with exponential backoff
|
|
324
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
325
|
+
}
|
|
279
326
|
/**
|
|
280
327
|
* Sends a message through the WebSocket (fire-and-forget, no response expected)
|
|
281
328
|
*
|
|
@@ -620,7 +667,7 @@ class BackendWebSocketService {
|
|
|
620
667
|
}
|
|
621
668
|
}
|
|
622
669
|
exports.BackendWebSocketService = BackendWebSocketService;
|
|
623
|
-
_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() {
|
|
670
|
+
_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() {
|
|
624
671
|
// Subscribe to authentication state changes (sign in/out)
|
|
625
672
|
__classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").subscribe('AuthenticationController:stateChange', (state) => {
|
|
626
673
|
if (state.isSignedIn) {
|
|
@@ -628,7 +675,6 @@ _BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_opt
|
|
|
628
675
|
this.connect();
|
|
629
676
|
}
|
|
630
677
|
else {
|
|
631
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
632
678
|
this.disconnect();
|
|
633
679
|
}
|
|
634
680
|
}, (state) => ({ isSignedIn: state.isSignedIn }));
|
|
@@ -639,7 +685,6 @@ _BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_opt
|
|
|
639
685
|
});
|
|
640
686
|
// Subscribe to wallet lock event
|
|
641
687
|
__classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").subscribe('KeyringController:lock', () => {
|
|
642
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
643
688
|
this.disconnect();
|
|
644
689
|
});
|
|
645
690
|
}, _BackendWebSocketService_buildAuthenticatedUrl = function _BackendWebSocketService_buildAuthenticatedUrl(bearerToken) {
|
|
@@ -688,8 +733,15 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
688
733
|
__classPrivateFieldSet(this, _BackendWebSocketService_ws, ws, "f");
|
|
689
734
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTED);
|
|
690
735
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, Date.now(), "f");
|
|
691
|
-
//
|
|
692
|
-
|
|
736
|
+
// Only reset after connection stays stable for a period (10 seconds)
|
|
737
|
+
// This prevents rapid reconnect loops when server accepts then immediately closes
|
|
738
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, setTimeout(() => {
|
|
739
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
740
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
741
|
+
// Create new backoff sequence for fresh start on next disconnect
|
|
742
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
743
|
+
log('Connection stable - reset reconnect attempts and backoff');
|
|
744
|
+
}, 10000), "f");
|
|
693
745
|
resolve();
|
|
694
746
|
});
|
|
695
747
|
};
|
|
@@ -786,13 +838,11 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
786
838
|
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
787
839
|
name: `${SERVICE_NAME} Channel Message`,
|
|
788
840
|
data: {
|
|
789
|
-
channel: message.channel,
|
|
790
841
|
latency_ms: latency,
|
|
791
842
|
event: message.event,
|
|
792
843
|
},
|
|
793
844
|
tags: {
|
|
794
845
|
service: SERVICE_NAME,
|
|
795
|
-
channel_type: message.channel,
|
|
796
846
|
},
|
|
797
847
|
}, () => {
|
|
798
848
|
// Direct lookup for exact channel match
|
|
@@ -809,7 +859,7 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
809
859
|
// Calculate notification latency: time from server sent to client received
|
|
810
860
|
const receivedAt = Date.now();
|
|
811
861
|
const latency = receivedAt - timestamp;
|
|
812
|
-
// Trace notification processing
|
|
862
|
+
// Trace notification processing wi th latency data
|
|
813
863
|
// Use stored channelType instead of parsing each time
|
|
814
864
|
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
815
865
|
name: `${SERVICE_NAME} Notification`,
|
|
@@ -833,7 +883,14 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
833
883
|
}, _BackendWebSocketService_handleClose = function _BackendWebSocketService_handleClose(event) {
|
|
834
884
|
// Calculate connection duration before we clear state
|
|
835
885
|
const connectionDuration = Date.now() - __classPrivateFieldGet(this, _BackendWebSocketService_connectedAt, "f");
|
|
836
|
-
__classPrivateFieldGet(this,
|
|
886
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f")) {
|
|
887
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
888
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
889
|
+
}
|
|
890
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f")) {
|
|
891
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f"));
|
|
892
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
893
|
+
}
|
|
837
894
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, 0, "f");
|
|
838
895
|
// Clear any pending connection promise
|
|
839
896
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
@@ -863,28 +920,43 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
863
920
|
}, () => {
|
|
864
921
|
// Empty trace callback - just measuring the event
|
|
865
922
|
});
|
|
866
|
-
// For any unexpected disconnects, attempt reconnection
|
|
867
|
-
// The manualDisconnect flag is the only gate - if it's false, we reconnect
|
|
868
923
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
869
924
|
}, _BackendWebSocketService_handleError = function _BackendWebSocketService_handleError(_error) {
|
|
870
925
|
// Placeholder for future error handling logic
|
|
871
926
|
}, _BackendWebSocketService_scheduleReconnect = function _BackendWebSocketService_scheduleReconnect() {
|
|
927
|
+
// If a reconnect is already scheduled, don't schedule another one
|
|
928
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
// Increment attempts BEFORE calculating delay so backoff grows properly
|
|
872
932
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f") + 1, "f");
|
|
873
|
-
|
|
874
|
-
const delay =
|
|
933
|
+
// Use Cockatiel's exponential backoff to get delay with jitter
|
|
934
|
+
const delay = __classPrivateFieldGet(this, _BackendWebSocketService_backoff, "f").duration;
|
|
935
|
+
// Progress to next backoff state for future reconnect attempts
|
|
936
|
+
// Pass attempt number as context (though ExponentialBackoff doesn't use it)
|
|
937
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_backoff, __classPrivateFieldGet(this, _BackendWebSocketService_backoff, "f").next({ attempt: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f") }), "f");
|
|
938
|
+
log('Scheduling reconnect', {
|
|
939
|
+
attempt: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f"),
|
|
940
|
+
delay_ms: delay,
|
|
941
|
+
});
|
|
875
942
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectTimer, setTimeout(() => {
|
|
876
943
|
// Clear timer reference first
|
|
877
944
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectTimer, null, "f");
|
|
878
945
|
// Check if connection is still enabled before reconnecting
|
|
879
946
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f") && !__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f").call(this)) {
|
|
880
947
|
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
948
|
+
// Create new backoff sequence when disabled
|
|
949
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_newBackoff).call(this);
|
|
881
950
|
return;
|
|
882
951
|
}
|
|
883
|
-
//
|
|
884
|
-
this.connect()
|
|
885
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
886
|
-
});
|
|
952
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
953
|
+
this.connect();
|
|
887
954
|
}, delay), "f");
|
|
955
|
+
}, _BackendWebSocketService_newBackoff = function _BackendWebSocketService_newBackoff() {
|
|
956
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_backoff, new controller_utils_1.ExponentialBackoff({
|
|
957
|
+
initialDelay: __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").reconnectDelay,
|
|
958
|
+
maxDelay: __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").maxReconnectDelay,
|
|
959
|
+
}).next(), "f");
|
|
888
960
|
}, _BackendWebSocketService_clearTimers = function _BackendWebSocketService_clearTimers() {
|
|
889
961
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f")) {
|
|
890
962
|
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_reconnectTimer, "f"));
|
|
@@ -894,6 +966,10 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
894
966
|
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
895
967
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
896
968
|
}
|
|
969
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f")) {
|
|
970
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_stableConnectionTimer, "f"));
|
|
971
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_stableConnectionTimer, null, "f");
|
|
972
|
+
}
|
|
897
973
|
}, _BackendWebSocketService_clearPendingRequests = function _BackendWebSocketService_clearPendingRequests(error) {
|
|
898
974
|
for (const [, request] of __classPrivateFieldGet(this, _BackendWebSocketService_pendingRequests, "f")) {
|
|
899
975
|
clearTimeout(request.timeout);
|