@steve31415/baselib 3.19.0 → 3.19.1

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.
@@ -116,6 +116,7 @@ export declare class SyncClient<B, C extends EventBody, S extends EventBody, Sum
116
116
  private countdownTimer;
117
117
  private pingTimer;
118
118
  private watchdogTimer;
119
+ private socketCreatedAt;
119
120
  private rolloverTimer;
120
121
  private escalateTimer;
121
122
  private escalateArmedAt;
@@ -154,6 +155,9 @@ export declare class SyncClient<B, C extends EventBody, S extends EventBody, Sum
154
155
  subscribe(listener: (state: SyncClientState) => void): () => void;
155
156
  private installRuntimeListeners;
156
157
  private wakeConnection;
158
+ /** Drops the current socket, if any, without treating it as an outage, and
159
+ * connects at once. */
160
+ private replaceSocket;
157
161
  private connect;
158
162
  private connectNow;
159
163
  private scheduleReconnect;
@@ -15,6 +15,7 @@ const GAP_BUFFER_MAX = 1_000;
15
15
  const RECONCILE_MOVED_MAX_REFETCHES = 3;
16
16
  const CLOSE_NO_USER = 4403;
17
17
  const PROBE_AFTER_ATTEMPTS = 2;
18
+ const SOCKET_CONNECTING = 0;
18
19
  const SOCKET_OPEN = 1;
19
20
  class LifecycleAbort {
20
21
  reason;
@@ -45,6 +46,7 @@ export class SyncClient {
45
46
  countdownTimer = null;
46
47
  pingTimer = null;
47
48
  watchdogTimer = null;
49
+ socketCreatedAt = 0;
48
50
  rolloverTimer = null;
49
51
  escalateTimer = null;
50
52
  escalateArmedAt = 0;
@@ -207,14 +209,7 @@ export class SyncClient {
207
209
  if (this.halted || this.disposed)
208
210
  return;
209
211
  this.options.logger.info('sync reconnect for traffic build');
210
- const previous = this.socket;
211
- this.socket = null;
212
- this.clearConnectionTimers();
213
- if (previous) {
214
- previous.close();
215
- this.detachSocket(previous);
216
- }
217
- this.connectNow();
212
+ this.replaceSocket();
218
213
  }
219
214
  state() {
220
215
  return this.currentState;
@@ -232,11 +227,33 @@ export class SyncClient {
232
227
  wakeConnection() {
233
228
  if (this.halted || this.disposed)
234
229
  return;
235
- if (this.socket !== null) {
236
- if (this.socket.readyState === SOCKET_OPEN)
237
- this.sendConnect();
230
+ const socket = this.socket;
231
+ if (socket?.readyState === SOCKET_OPEN) {
232
+ this.sendConnect();
238
233
  return;
239
234
  }
235
+ // A handshake still inside its watchdog window may just be slow: leave
236
+ // it. One past that window began before the page was frozen (a
237
+ // backgrounded phone tab) and its watchdog never ran; a socket already
238
+ // closing is gone too. Waiting on either routes the returning user
239
+ // through the watchdog's close and a full backoff step (16-30 s of
240
+ // "Reconnecting…" observed on reader, 2026-09-24).
241
+ if (socket?.readyState === SOCKET_CONNECTING &&
242
+ this.options.runtime.now() - this.socketCreatedAt < CONNECT_WATCHDOG_MS) {
243
+ return;
244
+ }
245
+ this.replaceSocket();
246
+ }
247
+ /** Drops the current socket, if any, without treating it as an outage, and
248
+ * connects at once. */
249
+ replaceSocket() {
250
+ const previous = this.socket;
251
+ this.socket = null;
252
+ this.clearConnectionTimers();
253
+ if (previous) {
254
+ previous.close();
255
+ this.detachSocket(previous);
256
+ }
240
257
  this.connectNow();
241
258
  }
242
259
  connect() {
@@ -256,6 +273,7 @@ export class SyncClient {
256
273
  return;
257
274
  }
258
275
  this.socket = socket;
276
+ this.socketCreatedAt = this.options.runtime.now();
259
277
  this.watchdogTimer = this.options.runtime.setTimeout(() => {
260
278
  if (socket.readyState !== SOCKET_OPEN)
261
279
  socket.close();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steve31415/baselib",
3
- "version": "3.19.0",
3
+ "version": "3.19.1",
4
4
  "description": "Plasticine new-world shared platform library: logging, auth, service-to-service auth, db, HTTP, sync, app updates",
5
5
  "type": "module",
6
6
  "license": "MIT",