@metamask/core-backend 4.0.0 → 5.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 +33 -1
- package/README.md +1 -1
- package/dist/AccountActivityService.cjs +19 -7
- package/dist/AccountActivityService.cjs.map +1 -1
- package/dist/AccountActivityService.d.cts.map +1 -1
- package/dist/AccountActivityService.d.mts.map +1 -1
- package/dist/AccountActivityService.mjs +19 -7
- 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 +106 -20
- package/dist/BackendWebSocketService-method-action-types.d.cts.map +1 -1
- package/dist/BackendWebSocketService-method-action-types.d.mts +106 -20
- 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 +128 -174
- package/dist/BackendWebSocketService.cjs.map +1 -1
- package/dist/BackendWebSocketService.d.cts +4 -2
- package/dist/BackendWebSocketService.d.cts.map +1 -1
- package/dist/BackendWebSocketService.d.mts +4 -2
- package/dist/BackendWebSocketService.d.mts.map +1 -1
- package/dist/BackendWebSocketService.mjs +128 -174
- package/dist/BackendWebSocketService.mjs.map +1 -1
- package/package.json +11 -10
|
@@ -10,7 +10,7 @@ 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_stableConnectionTimer, _BackendWebSocketService_connectionPromise, _BackendWebSocketService_pendingRequests, _BackendWebSocketService_connectedAt,
|
|
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_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_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
16
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
@@ -19,6 +19,11 @@ const uuid_1 = require("uuid");
|
|
|
19
19
|
const logger_1 = require("./logger.cjs");
|
|
20
20
|
const SERVICE_NAME = 'BackendWebSocketService';
|
|
21
21
|
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, SERVICE_NAME);
|
|
22
|
+
// WebSocket close codes and reasons for internal operations
|
|
23
|
+
const MANUAL_DISCONNECT_CODE = 4999;
|
|
24
|
+
const MANUAL_DISCONNECT_REASON = 'Internal: Manual disconnect';
|
|
25
|
+
const FORCE_RECONNECT_CODE = 4998;
|
|
26
|
+
const FORCE_RECONNECT_REASON = 'Internal: Force reconnect';
|
|
22
27
|
const MESSENGER_EXPOSED_METHODS = [
|
|
23
28
|
'connect',
|
|
24
29
|
'disconnect',
|
|
@@ -92,8 +97,10 @@ var WebSocketState;
|
|
|
92
97
|
(function (WebSocketState) {
|
|
93
98
|
WebSocketState["CONNECTING"] = "connecting";
|
|
94
99
|
WebSocketState["CONNECTED"] = "connected";
|
|
100
|
+
/** @deprecated This value is no longer used internally and will be removed in a future major release */
|
|
95
101
|
WebSocketState["DISCONNECTING"] = "disconnecting";
|
|
96
102
|
WebSocketState["DISCONNECTED"] = "disconnected";
|
|
103
|
+
/** @deprecated TThis value is no longer used internally and will be removed in a future major release */
|
|
97
104
|
WebSocketState["ERROR"] = "error";
|
|
98
105
|
})(WebSocketState || (exports.WebSocketState = WebSocketState = {}));
|
|
99
106
|
/**
|
|
@@ -159,8 +166,6 @@ class BackendWebSocketService {
|
|
|
159
166
|
_BackendWebSocketService_connectionPromise.set(this, null);
|
|
160
167
|
_BackendWebSocketService_pendingRequests.set(this, new Map());
|
|
161
168
|
_BackendWebSocketService_connectedAt.set(this, 0);
|
|
162
|
-
// Track manual disconnects to prevent automatic reconnection
|
|
163
|
-
_BackendWebSocketService_manualDisconnect.set(this, false);
|
|
164
169
|
// Simplified subscription storage (single flat map)
|
|
165
170
|
// Key: subscription ID string (e.g., 'sub_abc123def456')
|
|
166
171
|
// Value: WebSocketSubscription object with channels, callback and metadata
|
|
@@ -180,8 +185,8 @@ class BackendWebSocketService {
|
|
|
180
185
|
__classPrivateFieldSet(this, _BackendWebSocketService_options, {
|
|
181
186
|
url: options.url,
|
|
182
187
|
timeout: options.timeout ?? 10000,
|
|
183
|
-
reconnectDelay: options.reconnectDelay ??
|
|
184
|
-
maxReconnectDelay: options.maxReconnectDelay ??
|
|
188
|
+
reconnectDelay: options.reconnectDelay ?? 10000,
|
|
189
|
+
maxReconnectDelay: options.maxReconnectDelay ?? 60000,
|
|
185
190
|
requestTimeout: options.requestTimeout ?? 30000,
|
|
186
191
|
}, "f");
|
|
187
192
|
// Initialize backoff for reconnection delays
|
|
@@ -208,8 +213,6 @@ class BackendWebSocketService {
|
|
|
208
213
|
* @returns Promise that resolves when connection is established
|
|
209
214
|
*/
|
|
210
215
|
async connect() {
|
|
211
|
-
// Reset manual disconnect flag when explicitly connecting
|
|
212
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_manualDisconnect, false, "f");
|
|
213
216
|
// Priority 1: Check if feature is enabled via callback (feature flag check)
|
|
214
217
|
// If feature is disabled, stop all connection attempts
|
|
215
218
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f") && !__classPrivateFieldGet(this, _BackendWebSocketService_isEnabled, "f").call(this)) {
|
|
@@ -248,17 +251,8 @@ class BackendWebSocketService {
|
|
|
248
251
|
log('Failed to check authentication requirements', { error });
|
|
249
252
|
throw error;
|
|
250
253
|
}
|
|
251
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTING);
|
|
252
254
|
// Establish the actual WebSocket connection
|
|
253
|
-
|
|
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
|
-
}
|
|
255
|
+
await __classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_establishConnection).call(this, bearerToken);
|
|
262
256
|
})(), "f");
|
|
263
257
|
try {
|
|
264
258
|
await __classPrivateFieldGet(this, _BackendWebSocketService_connectionPromise, "f");
|
|
@@ -277,22 +271,11 @@ class BackendWebSocketService {
|
|
|
277
271
|
* Closes WebSocket connection
|
|
278
272
|
*/
|
|
279
273
|
disconnect() {
|
|
280
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED ||
|
|
281
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTING) {
|
|
274
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED || !__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f")) {
|
|
282
275
|
return;
|
|
283
276
|
}
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.DISCONNECTING);
|
|
287
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearTimers).call(this);
|
|
288
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error('WebSocket disconnected'));
|
|
289
|
-
// Clear any pending connection promise
|
|
290
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
291
|
-
// Reset reconnect attempts on manual disconnect
|
|
292
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
293
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f")) {
|
|
294
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(1000, 'Normal closure');
|
|
295
|
-
}
|
|
277
|
+
// Close WebSocket with manual disconnect code and reason
|
|
278
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(MANUAL_DISCONNECT_CODE, MANUAL_DISCONNECT_REASON);
|
|
296
279
|
log('WebSocket manually disconnected');
|
|
297
280
|
}
|
|
298
281
|
/**
|
|
@@ -312,16 +295,15 @@ class BackendWebSocketService {
|
|
|
312
295
|
* @returns Promise that resolves when disconnection is complete (reconnection is scheduled)
|
|
313
296
|
*/
|
|
314
297
|
async forceReconnection() {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
298
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED || !__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f")) {
|
|
299
|
+
log('WebSocket already disconnected, scheduling reconnect');
|
|
300
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
318
301
|
return;
|
|
319
302
|
}
|
|
320
303
|
log('Forcing WebSocket reconnection to clean up subscription state');
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
304
|
+
// This ensures ws.onclose will schedule a reconnect (not treat it as manual disconnect)
|
|
305
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
306
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(FORCE_RECONNECT_CODE, FORCE_RECONNECT_REASON);
|
|
325
307
|
}
|
|
326
308
|
/**
|
|
327
309
|
* Sends a message through the WebSocket (fire-and-forget, no response expected)
|
|
@@ -563,17 +545,13 @@ class BackendWebSocketService {
|
|
|
563
545
|
* Called when service is being destroyed or app is terminating
|
|
564
546
|
*/
|
|
565
547
|
destroy() {
|
|
548
|
+
// Always clear timers first to prevent reconnection attempts after destruction
|
|
549
|
+
// This handles the case where destroy() is called while DISCONNECTED with a pending reconnect timer
|
|
566
550
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearTimers).call(this);
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error('Service cleanup'));
|
|
572
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f") && __classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").readyState === WebSocket.OPEN) {
|
|
573
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_ws, "f").close(1000, 'Service cleanup');
|
|
574
|
-
}
|
|
575
|
-
// Set state to disconnected immediately
|
|
576
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.DISCONNECTED);
|
|
551
|
+
// Reset reconnect attempts to prevent any future reconnection logic
|
|
552
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
553
|
+
// Disconnect the WebSocket if connected (will be no-op if already disconnected)
|
|
554
|
+
this.disconnect();
|
|
577
555
|
}
|
|
578
556
|
/**
|
|
579
557
|
* Create and manage a subscription with server-side registration (recommended for most use cases)
|
|
@@ -658,7 +636,7 @@ class BackendWebSocketService {
|
|
|
658
636
|
// Store subscription with subscription ID as key
|
|
659
637
|
__classPrivateFieldGet(this, _BackendWebSocketService_subscriptions, "f").set(subscriptionId, {
|
|
660
638
|
subscriptionId,
|
|
661
|
-
channels: [...channels],
|
|
639
|
+
channels: [...channels], // Store copy of channels
|
|
662
640
|
channelType,
|
|
663
641
|
callback,
|
|
664
642
|
unsubscribe,
|
|
@@ -667,7 +645,7 @@ class BackendWebSocketService {
|
|
|
667
645
|
}
|
|
668
646
|
}
|
|
669
647
|
exports.BackendWebSocketService = BackendWebSocketService;
|
|
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(),
|
|
648
|
+
_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_subscriptions = new WeakMap(), _BackendWebSocketService_channelCallbacks = new WeakMap(), _BackendWebSocketService_backoff = new WeakMap(), _BackendWebSocketService_instances = new WeakSet(), _BackendWebSocketService_subscribeEvents = function _BackendWebSocketService_subscribeEvents() {
|
|
671
649
|
// Subscribe to authentication state changes (sign in/out)
|
|
672
650
|
__classPrivateFieldGet(this, _BackendWebSocketService_messenger, "f").subscribe('AuthenticationController:stateChange', (state) => {
|
|
673
651
|
if (state.isSignedIn) {
|
|
@@ -702,34 +680,31 @@ _BackendWebSocketService_messenger = new WeakMap(), _BackendWebSocketService_opt
|
|
|
702
680
|
*/
|
|
703
681
|
async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
704
682
|
const wsUrl = __classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_buildAuthenticatedUrl).call(this, bearerToken);
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
},
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
service: SERVICE_NAME,
|
|
731
|
-
},
|
|
732
|
-
}, () => {
|
|
683
|
+
// Transition to CONNECTING state before creating WebSocket
|
|
684
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTING);
|
|
685
|
+
return __classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
686
|
+
name: `${SERVICE_NAME} Connection`,
|
|
687
|
+
data: {
|
|
688
|
+
reconnectAttempt: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f"),
|
|
689
|
+
},
|
|
690
|
+
tags: {
|
|
691
|
+
service: SERVICE_NAME,
|
|
692
|
+
},
|
|
693
|
+
}, () => {
|
|
694
|
+
return new Promise((resolve, reject) => {
|
|
695
|
+
const ws = new WebSocket(wsUrl);
|
|
696
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, setTimeout(() => {
|
|
697
|
+
log('WebSocket connection timeout - forcing close', {
|
|
698
|
+
timeout: __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").timeout,
|
|
699
|
+
});
|
|
700
|
+
// Close the WebSocket - onclose will handle rejection and state change
|
|
701
|
+
ws.close();
|
|
702
|
+
}, __classPrivateFieldGet(this, _BackendWebSocketService_options, "f").timeout), "f");
|
|
703
|
+
ws.onopen = () => {
|
|
704
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f")) {
|
|
705
|
+
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
706
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
707
|
+
}
|
|
733
708
|
__classPrivateFieldSet(this, _BackendWebSocketService_ws, ws, "f");
|
|
734
709
|
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.CONNECTED);
|
|
735
710
|
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, Date.now(), "f");
|
|
@@ -743,45 +718,79 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
743
718
|
log('Connection stable - reset reconnect attempts and backoff');
|
|
744
719
|
}, 10000), "f");
|
|
745
720
|
resolve();
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
};
|
|
757
|
-
ws.onclose = (event) => {
|
|
758
|
-
log('WebSocket onclose event triggered', {
|
|
759
|
-
code: event.code,
|
|
760
|
-
reason: event.reason,
|
|
761
|
-
wasClean: event.wasClean,
|
|
762
|
-
});
|
|
763
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.CONNECTING) {
|
|
764
|
-
// Handle connection-phase close events
|
|
765
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f")) {
|
|
766
|
-
clearTimeout(__classPrivateFieldGet(this, _BackendWebSocketService_connectionTimeout, "f"));
|
|
767
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectionTimeout, null, "f");
|
|
721
|
+
};
|
|
722
|
+
ws.onclose = (event) => {
|
|
723
|
+
log('WebSocket onclose event triggered', {
|
|
724
|
+
code: event.code,
|
|
725
|
+
reason: event.reason || getCloseReason(event.code),
|
|
726
|
+
wasClean: event.wasClean,
|
|
727
|
+
});
|
|
728
|
+
// Guard against duplicate close events
|
|
729
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.DISCONNECTED) {
|
|
730
|
+
return;
|
|
768
731
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
732
|
+
// Detect if this is a manual disconnect or service cleanup based on close code
|
|
733
|
+
const isManualDisconnect = event.code === MANUAL_DISCONNECT_CODE &&
|
|
734
|
+
event.reason === MANUAL_DISCONNECT_REASON;
|
|
735
|
+
// If connection hasn't been established yet, handle the connection promise
|
|
736
|
+
if (__classPrivateFieldGet(this, _BackendWebSocketService_state, "f") === WebSocketState.CONNECTING) {
|
|
737
|
+
if (isManualDisconnect) {
|
|
738
|
+
// Manual disconnect during connection - resolve to prevent reconnection
|
|
739
|
+
resolve();
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
// Failed connection attempt - reject to trigger reconnection
|
|
743
|
+
reject(new Error(`WebSocket connection closed during connection: ${event.code} ${event.reason}`));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// Calculate connection duration before we clear state (only if we were connected)
|
|
747
|
+
const connectionDuration_ms = __classPrivateFieldGet(this, _BackendWebSocketService_connectedAt, "f") > 0 ? Date.now() - __classPrivateFieldGet(this, _BackendWebSocketService_connectedAt, "f") : 0;
|
|
748
|
+
// Clear all timers
|
|
749
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearTimers).call(this);
|
|
750
|
+
// Clear WebSocket reference to allow garbage collection
|
|
751
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_ws, undefined, "f");
|
|
752
|
+
// Clear connection tracking
|
|
753
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
754
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, 0, "f");
|
|
755
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error(`WebSocket connection closed: ${event.code} ${event.reason || getCloseReason(event.code)}`));
|
|
756
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearSubscriptions).call(this);
|
|
757
|
+
// Update state to disconnected
|
|
758
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.DISCONNECTED);
|
|
759
|
+
// Check if this was a manual disconnect
|
|
760
|
+
if (isManualDisconnect) {
|
|
761
|
+
// Manual disconnect - reset attempts and don't reconnect
|
|
762
|
+
__classPrivateFieldSet(this, _BackendWebSocketService_reconnectAttempts, 0, "f");
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
// Unexpected disconnect - schedule reconnection
|
|
766
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
767
|
+
}
|
|
768
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
769
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
770
|
+
name: `${SERVICE_NAME} Disconnection`,
|
|
771
|
+
data: {
|
|
772
|
+
code: event.code,
|
|
773
|
+
reason: event.reason || getCloseReason(event.code),
|
|
774
|
+
wasClean: event.wasClean,
|
|
775
|
+
reconnectAttempts: __classPrivateFieldGet(this, _BackendWebSocketService_reconnectAttempts, "f"),
|
|
776
|
+
...(connectionDuration_ms > 0 && { connectionDuration_ms }),
|
|
777
|
+
},
|
|
778
|
+
tags: {
|
|
779
|
+
service: SERVICE_NAME,
|
|
780
|
+
},
|
|
781
|
+
});
|
|
782
|
+
};
|
|
783
|
+
// Set up message handler immediately - no need to wait for connection
|
|
784
|
+
ws.onmessage = (event) => {
|
|
785
|
+
try {
|
|
786
|
+
const message = __classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_parseMessage).call(this, event.data);
|
|
787
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_handleMessage).call(this, message);
|
|
788
|
+
}
|
|
789
|
+
catch {
|
|
790
|
+
// Silently ignore invalid JSON messages
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
});
|
|
785
794
|
});
|
|
786
795
|
}, _BackendWebSocketService_handleMessage = function _BackendWebSocketService_handleMessage(message) {
|
|
787
796
|
// Handle server responses (correlated with requests) first
|
|
@@ -831,23 +840,7 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
831
840
|
if (__classPrivateFieldGet(this, _BackendWebSocketService_channelCallbacks, "f").size === 0) {
|
|
832
841
|
return;
|
|
833
842
|
}
|
|
834
|
-
|
|
835
|
-
const receivedAt = Date.now();
|
|
836
|
-
const latency = receivedAt - message.timestamp;
|
|
837
|
-
// Trace channel message processing with latency data
|
|
838
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
839
|
-
name: `${SERVICE_NAME} Channel Message`,
|
|
840
|
-
data: {
|
|
841
|
-
latency_ms: latency,
|
|
842
|
-
event: message.event,
|
|
843
|
-
},
|
|
844
|
-
tags: {
|
|
845
|
-
service: SERVICE_NAME,
|
|
846
|
-
},
|
|
847
|
-
}, () => {
|
|
848
|
-
// Direct lookup for exact channel match
|
|
849
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_channelCallbacks, "f").get(message.channel)?.callback(message);
|
|
850
|
-
});
|
|
843
|
+
__classPrivateFieldGet(this, _BackendWebSocketService_channelCallbacks, "f").get(message.channel)?.callback(message);
|
|
851
844
|
}, _BackendWebSocketService_handleSubscriptionNotification = function _BackendWebSocketService_handleSubscriptionNotification(message) {
|
|
852
845
|
const { subscriptionId, timestamp, channel } = message;
|
|
853
846
|
// Only handle if subscriptionId is defined and not null (allows "0" as valid ID)
|
|
@@ -861,6 +854,8 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
861
854
|
const latency = receivedAt - timestamp;
|
|
862
855
|
// Trace notification processing wi th latency data
|
|
863
856
|
// Use stored channelType instead of parsing each time
|
|
857
|
+
// Promise result intentionally not awaited
|
|
858
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
864
859
|
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
865
860
|
name: `${SERVICE_NAME} Notification`,
|
|
866
861
|
data: {
|
|
@@ -880,47 +875,6 @@ async function _BackendWebSocketService_establishConnection(bearerToken) {
|
|
|
880
875
|
return false;
|
|
881
876
|
}, _BackendWebSocketService_parseMessage = function _BackendWebSocketService_parseMessage(data) {
|
|
882
877
|
return JSON.parse(data);
|
|
883
|
-
}, _BackendWebSocketService_handleClose = function _BackendWebSocketService_handleClose(event) {
|
|
884
|
-
// Calculate connection duration before we clear state
|
|
885
|
-
const connectionDuration = Date.now() - __classPrivateFieldGet(this, _BackendWebSocketService_connectedAt, "f");
|
|
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
|
-
}
|
|
894
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectedAt, 0, "f");
|
|
895
|
-
// Clear any pending connection promise
|
|
896
|
-
__classPrivateFieldSet(this, _BackendWebSocketService_connectionPromise, null, "f");
|
|
897
|
-
// Clear subscriptions and pending requests on any disconnect
|
|
898
|
-
// This ensures clean state for reconnection
|
|
899
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearPendingRequests).call(this, new Error('WebSocket connection closed'));
|
|
900
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_clearSubscriptions).call(this);
|
|
901
|
-
// Update state to disconnected
|
|
902
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_setState).call(this, WebSocketState.DISCONNECTED);
|
|
903
|
-
// Check if this was a manual disconnect
|
|
904
|
-
if (__classPrivateFieldGet(this, _BackendWebSocketService_manualDisconnect, "f")) {
|
|
905
|
-
// Manual disconnect - don't reconnect
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
// Trace unexpected disconnect with details
|
|
909
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_trace, "f").call(this, {
|
|
910
|
-
name: `${SERVICE_NAME} Disconnect`,
|
|
911
|
-
data: {
|
|
912
|
-
code: event.code,
|
|
913
|
-
reason: event.reason || getCloseReason(event.code),
|
|
914
|
-
connectionDuration_ms: connectionDuration,
|
|
915
|
-
},
|
|
916
|
-
tags: {
|
|
917
|
-
service: SERVICE_NAME,
|
|
918
|
-
disconnect_type: 'unexpected',
|
|
919
|
-
},
|
|
920
|
-
}, () => {
|
|
921
|
-
// Empty trace callback - just measuring the event
|
|
922
|
-
});
|
|
923
|
-
__classPrivateFieldGet(this, _BackendWebSocketService_instances, "m", _BackendWebSocketService_scheduleReconnect).call(this);
|
|
924
878
|
}, _BackendWebSocketService_handleError = function _BackendWebSocketService_handleError(_error) {
|
|
925
879
|
// Placeholder for future error handling logic
|
|
926
880
|
}, _BackendWebSocketService_scheduleReconnect = function _BackendWebSocketService_scheduleReconnect() {
|