@xh/hoist 74.0.0-SNAPSHOT.1748890930922 → 74.0.0-SNAPSHOT.1749050851202
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
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
### 🐞 Bug Fixes
|
|
15
15
|
* Improved `ViewManagerModel.settleTime` by delegating to individual `PersistenceProviders`.
|
|
16
16
|
* Fixed bug where grid column state could become unintentionally dirty when columns were hidden.
|
|
17
|
+
* Improved `WebsocketService` heartbeat detection to auto-reconnect when the socket reports as open
|
|
18
|
+
and heartbeats can be sent, but no heartbeat acknowledgements are being received from the server.
|
|
17
19
|
|
|
18
20
|
## v73.0.1 - 2025-05-19
|
|
19
21
|
|
|
@@ -56,7 +56,7 @@ export interface DateInputProps extends HoistProps, LayoutProps, HoistInputProps
|
|
|
56
56
|
*/
|
|
57
57
|
maxDate?: Date | LocalDate;
|
|
58
58
|
/**
|
|
59
|
-
*
|
|
59
|
+
* Minimum (inclusive) valid date that can be entered by the user via the calendar picker or
|
|
60
60
|
* keyboard. Will reset any out-of-bounds manually entered input to `null`.
|
|
61
61
|
*
|
|
62
62
|
* See note re. validation on maxDate, above.
|
|
@@ -45,6 +45,8 @@ export declare class WebSocketService extends HoistService {
|
|
|
45
45
|
private _timer;
|
|
46
46
|
private _socket;
|
|
47
47
|
private _subsByTopic;
|
|
48
|
+
private _lastHeartbeatSent;
|
|
49
|
+
private _lastHeartbeatReceived;
|
|
48
50
|
constructor();
|
|
49
51
|
initAsync(): Promise<void>;
|
|
50
52
|
/**
|
|
@@ -70,7 +72,9 @@ export declare class WebSocketService extends HoistService {
|
|
|
70
72
|
getFormattedTelemetry(): PlainObject;
|
|
71
73
|
private connect;
|
|
72
74
|
private disconnect;
|
|
75
|
+
private reconnect;
|
|
73
76
|
private heartbeatOrReconnect;
|
|
77
|
+
private get heartbeatWasUnacknowledged();
|
|
74
78
|
private onServerInstanceChange;
|
|
75
79
|
onOpen(ev: any): void;
|
|
76
80
|
onClose(ev: any): void;
|
|
@@ -86,7 +86,7 @@ export interface DateInputProps extends HoistProps, LayoutProps, HoistInputProps
|
|
|
86
86
|
maxDate?: Date | LocalDate;
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
|
-
*
|
|
89
|
+
* Minimum (inclusive) valid date that can be entered by the user via the calendar picker or
|
|
90
90
|
* keyboard. Will reset any out-of-bounds manually entered input to `null`.
|
|
91
91
|
*
|
|
92
92
|
* See note re. validation on maxDate, above.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "74.0.0-SNAPSHOT.
|
|
3
|
+
"version": "74.0.0-SNAPSHOT.1749050851202",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
package/svc/WebSocketService.ts
CHANGED
|
@@ -70,6 +70,9 @@ export class WebSocketService extends HoistService {
|
|
|
70
70
|
private _socket: WebSocket;
|
|
71
71
|
private _subsByTopic: Record<string, WebSocketSubscription[]> = {};
|
|
72
72
|
|
|
73
|
+
private _lastHeartbeatSent: number = null;
|
|
74
|
+
private _lastHeartbeatReceived: number = null;
|
|
75
|
+
|
|
73
76
|
constructor() {
|
|
74
77
|
super();
|
|
75
78
|
makeObservable(this);
|
|
@@ -177,6 +180,10 @@ export class WebSocketService extends HoistService {
|
|
|
177
180
|
if (s === this._socket) this.onMessage(data);
|
|
178
181
|
};
|
|
179
182
|
this._socket = s;
|
|
183
|
+
|
|
184
|
+
// Reset heartbeat tracking - any prior values no longer relevant.
|
|
185
|
+
this._lastHeartbeatReceived = null;
|
|
186
|
+
this._lastHeartbeatSent = null;
|
|
180
187
|
} catch (e) {
|
|
181
188
|
this.logError('Failure creating WebSocket', e);
|
|
182
189
|
}
|
|
@@ -192,24 +199,41 @@ export class WebSocketService extends HoistService {
|
|
|
192
199
|
this.updateConnectedStatus();
|
|
193
200
|
}
|
|
194
201
|
|
|
202
|
+
private reconnect() {
|
|
203
|
+
this.disconnect();
|
|
204
|
+
this.connect();
|
|
205
|
+
}
|
|
206
|
+
|
|
195
207
|
private heartbeatOrReconnect() {
|
|
196
208
|
this.updateConnectedStatus();
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.logWarn(
|
|
209
|
+
|
|
210
|
+
// If there is a problem, attempt to reconnect and come back on the next cycle.
|
|
211
|
+
const {connected, heartbeatWasUnacknowledged} = this;
|
|
212
|
+
if (!connected || heartbeatWasUnacknowledged) {
|
|
213
|
+
this.logWarn(
|
|
214
|
+
`Heartbeat found ${!connected ? 'websocket not connected' : 'last heartbeat not acknowledged'} - attempting to reconnect...`
|
|
215
|
+
);
|
|
202
216
|
this.noteTelemetryEvent('heartbeatReconnectAttempt');
|
|
203
|
-
this.
|
|
204
|
-
|
|
217
|
+
this.reconnect();
|
|
218
|
+
return;
|
|
205
219
|
}
|
|
220
|
+
|
|
221
|
+
// If all looks OK, send a heartbeat message.
|
|
222
|
+
this.sendMessage({topic: this.HEARTBEAT_TOPIC, data: 'ping'});
|
|
223
|
+
this.noteTelemetryEvent('heartbeatSent');
|
|
224
|
+
this._lastHeartbeatSent = Date.now();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// We expect the server to respond immediately to every heartbeat. There will be a tiny window
|
|
228
|
+
// while the message is round-tripping, but that's not material to our check on HEARTBEAT_INTERVAL.
|
|
229
|
+
private get heartbeatWasUnacknowledged() {
|
|
230
|
+
return this._lastHeartbeatSent > this._lastHeartbeatReceived;
|
|
206
231
|
}
|
|
207
232
|
|
|
208
233
|
private onServerInstanceChange() {
|
|
209
234
|
this.logWarn('Server instance changed - attempting to connect to new instance.');
|
|
210
235
|
this.noteTelemetryEvent('instanceChangeReconnectAttempt');
|
|
211
|
-
this.
|
|
212
|
-
this.connect();
|
|
236
|
+
this.reconnect();
|
|
213
237
|
}
|
|
214
238
|
|
|
215
239
|
//------------------------
|
|
@@ -256,6 +280,7 @@ export class WebSocketService extends HoistService {
|
|
|
256
280
|
XH.clientHealthService.sendReportAsync();
|
|
257
281
|
break;
|
|
258
282
|
case this.HEARTBEAT_TOPIC:
|
|
283
|
+
this._lastHeartbeatReceived = Date.now();
|
|
259
284
|
this.noteTelemetryEvent('heartbeatReceived');
|
|
260
285
|
break;
|
|
261
286
|
}
|