@catalyst-cloud/sdk 0.5.0 → 0.7.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/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/live-sync-client.d.ts +162 -9
- package/dist/live-sync-client.d.ts.map +1 -1
- package/dist/live-sync-client.js +497 -41
- package/dist/live-sync-client.js.map +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js.map +1 -1
- package/dist/otel.d.ts +14 -0
- package/dist/otel.d.ts.map +1 -1
- package/dist/otel.js +9 -0
- package/dist/otel.js.map +1 -1
- package/dist/replica/catalyst-replica.d.ts +39 -1
- package/dist/replica/catalyst-replica.d.ts.map +1 -1
- package/dist/replica/catalyst-replica.js +202 -69
- package/dist/replica/catalyst-replica.js.map +1 -1
- package/dist/types.d.ts +17 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { LiveSyncClient, buildConnectUrl, parseFrame, toWsOrigin, type AuthStrategy, type LiveSyncClientOptions, type LiveSyncStatus, type LogLevel, type WebSocketLike, type WebSocketFactory, } from "./live-sync-client.js";
|
|
2
|
-
export { ENTITY_NAMES, CHANGE_OPS, PING_FRAME, PONG_FRAME, type AccountId, type EntityName, type ChangeOp, type ChangeFrame, type ResyncFrame, type SyncFrame, type PongFrame, type ServerFrame, } from "./types.js";
|
|
3
|
-
export { DEFAULT_SCOPE_NAME, CATALYST_ATTR, REPLICA_METRIC, REPLICA_LOG, REPLICA_SPAN, REPLICA_STATUS_CODE, type ReplicaApplyResult, type TelemetryConfig, } from "./otel.js";
|
|
2
|
+
export { ENTITY_NAMES, CHANGE_OPS, PING_FRAME, PONG_FRAME, type AccountId, type EntityName, type ChangeOp, type ChangeFrame, type ResyncFrame, type SyncFrame, type PongFrame, type HeadFrame, type ServerFrame, } from "./types.js";
|
|
3
|
+
export { DEFAULT_SCOPE_NAME, CATALYST_ATTR, REPLICA_METRIC, REPLICA_LOG, REPLICA_SPAN, REPLICA_STATUS_CODE, type ReplicaApplyResult, type ReplicaGapEvent, type TelemetryConfig, } from "./otel.js";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,UAAU,EACV,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,EACV,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,UAAU,EACV,UAAU,EACV,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AAKpB,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,uBAAuB;AACvB,EAAE;AACF,+EAA+E;AAE/E,OAAO,EACL,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,GAOX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,UAAU,EACV,UAAU,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,sGAAsG;AACtG,mGAAmG;AACnG,uBAAuB;AACvB,EAAE;AACF,+EAA+E;AAE/E,OAAO,EACL,cAAc,EACd,eAAe,EACf,UAAU,EACV,UAAU,GAOX,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,UAAU,EACV,UAAU,GAUX,MAAM,YAAY,CAAC;AAEpB,sGAAsG;AACtG,qGAAqG;AACrG,qGAAqG;AACrG,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,GAIpB,MAAM,WAAW,CAAC"}
|
|
@@ -58,7 +58,11 @@ export interface LiveSyncClientOptions {
|
|
|
58
58
|
* Re-seed the consumer's store from a full snapshot and resolve to the FRESH cursor. Called on a
|
|
59
59
|
* `{type:"resync"}` underflow frame and (optionally) before the first connect. The host pulls
|
|
60
60
|
* /snapshot into bun:sqlite; the browser re-runs its OPFS seed(). The client closes the socket
|
|
61
|
-
* before calling this so no live frame interleaves with the seed.
|
|
61
|
+
* before calling this so no live frame interleaves with the seed. The await is bounded by
|
|
62
|
+
* {@link reseedTimeoutMs} (CTC-281) — a hanging reseed is abandoned (its late settle discarded)
|
|
63
|
+
* and the client re-enters the backoff path, so this callback can never wedge the transport; still,
|
|
64
|
+
* bound your own I/O (as the replica's seedFromSnapshot does) so a dead fetch fails fast, not at
|
|
65
|
+
* the backstop.
|
|
62
66
|
*/
|
|
63
67
|
reseed: () => Promise<number>;
|
|
64
68
|
/**
|
|
@@ -93,6 +97,40 @@ export interface LiveSyncClientOptions {
|
|
|
93
97
|
* socket half-open and force-reconnecting through the normal backoff path. Default `15_000`.
|
|
94
98
|
*/
|
|
95
99
|
pongTimeoutMs?: number;
|
|
100
|
+
/**
|
|
101
|
+
* Connect/open deadline (CTC-281): how long (ms) after constructing a socket to wait for `onopen`
|
|
102
|
+
* before treating the attempt as failed (tear the socket down, status "reconnecting", backoff
|
|
103
|
+
* reconnect). Without it, a TCP-connect or HTTP-upgrade stall that never fires open/close/error
|
|
104
|
+
* (undici sets no upgrade deadline; injected impls are trusted blindly) wedges the client in
|
|
105
|
+
* "connecting" with ZERO pending timers — restart-only. Default `20_000`; `0` disables.
|
|
106
|
+
*/
|
|
107
|
+
openTimeoutMs?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Re-seed deadline (CTC-281): how long (ms) to wait for the injected {@link reseed} callback to
|
|
110
|
+
* settle before abandoning the attempt (status "reconnecting", backoff reconnect; the abandoned
|
|
111
|
+
* reseed's late settle is discarded). While resyncing the client holds NO socket and suppresses
|
|
112
|
+
* scheduleReconnect, so an unbounded reseed hang was a zero-timer restart-only wedge — the exact
|
|
113
|
+
* ticket-ask-3 state. A TOTAL-duration backstop, deliberately generous: the replica's
|
|
114
|
+
* seedFromSnapshot already fails fast on a dead stream via its own IDLE abort
|
|
115
|
+
* (`snapshotIdleTimeoutMs`); this bound exists for reseed impls with no bound of their own (e.g. a
|
|
116
|
+
* browser OPFS seed over a default fetch). Raise it if a legitimate full seed can stream longer.
|
|
117
|
+
* Default `600_000` (10 min); `0` disables.
|
|
118
|
+
*/
|
|
119
|
+
reseedTimeoutMs?: number;
|
|
120
|
+
/**
|
|
121
|
+
* Gap detection (CTL-1402): how long (ms) to wait for a `{type:"sync"}` gap re-request to finish
|
|
122
|
+
* redelivering the detected hole before retrying (or, once {@link gapRetryLimit} re-requests have
|
|
123
|
+
* been spent, escalating to the full re-seed path). Default `10_000`; set `0` to never time out
|
|
124
|
+
* (the gap then heals only via the replay itself or the next reconnect — not recommended).
|
|
125
|
+
*/
|
|
126
|
+
gapTimeoutMs?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Gap detection (CTL-1402): total `{type:"sync"}` re-requests to spend on one gap before escalating
|
|
129
|
+
* to the resync/re-seed path. Default `3`. Escalation — never silent acceptance — is deliberate: a
|
|
130
|
+
* gap the replay cannot close (evicted rows, or seqs that never existed) must end in a /snapshot
|
|
131
|
+
* re-seed, not a sealed hole.
|
|
132
|
+
*/
|
|
133
|
+
gapRetryLimit?: number;
|
|
96
134
|
/** Injectable WebSocket factory (tests / a node polyfill). Defaults to `globalThis.WebSocket`. */
|
|
97
135
|
wsFactory?: WebSocketFactory;
|
|
98
136
|
/** Optional structured logger; defaults to console. */
|
|
@@ -137,6 +175,10 @@ export declare class LiveSyncClient {
|
|
|
137
175
|
private readonly maxBackoffMs;
|
|
138
176
|
private readonly pingIntervalMs;
|
|
139
177
|
private readonly pongTimeoutMs;
|
|
178
|
+
private readonly openTimeoutMs;
|
|
179
|
+
private readonly reseedTimeoutMs;
|
|
180
|
+
private readonly gapTimeoutMs;
|
|
181
|
+
private readonly gapRetryLimit;
|
|
140
182
|
private readonly wsFactory;
|
|
141
183
|
private readonly log;
|
|
142
184
|
private readonly telemetryConfig;
|
|
@@ -150,6 +192,20 @@ export declare class LiveSyncClient {
|
|
|
150
192
|
private telemetry;
|
|
151
193
|
/** The in-flight connect-attempt span (ended OK on open, ERROR on construct-fail / close-before-open). */
|
|
152
194
|
private connectSpan;
|
|
195
|
+
/** Transport high-water: the highest seq DELIVERED to onChange — the contiguity baseline. Re-seeded
|
|
196
|
+
* from getCursor() on every (re)open (the durable cursor never advanced past an undelivered frame,
|
|
197
|
+
* so the on-open `{type:"sync"}` replay covers any previously-pending hole). `-1` = no baseline yet
|
|
198
|
+
* (fresh cursor / cursorless store) — gap checks are suspended until a baseline exists. */
|
|
199
|
+
private deliveredSeq;
|
|
200
|
+
/** The gap currently being re-requested, or null when the stream is contiguous. `seqFrom..seqTo` is
|
|
201
|
+
* the detected hole (fixed at detection); `retries` counts the sync re-requests spent on it. */
|
|
202
|
+
private gap;
|
|
203
|
+
private gapTimer;
|
|
204
|
+
/** Epoch ms of the last inbound CHANGE frame (live or replayed, delivered or gap-dropped). Unlike
|
|
205
|
+
* {@link lastFrameAt} this ignores pongs, so it only moves when the feed actually pushes data. */
|
|
206
|
+
private _lastChangeFrameAt;
|
|
207
|
+
/** The `catalyst.replica.gaps` counter (no-op until telemetry resolves in start()). */
|
|
208
|
+
private gapCounter;
|
|
153
209
|
/** Epoch ms of the last inbound frame (any bytes: change, pong, even malformed). Null before the
|
|
154
210
|
* first frame. Public via {@link lastFrameAt} — the per-frame timestamp the catalyst daemon's
|
|
155
211
|
* stall classifier lacked (it can now distinguish a quiet feed from a dead socket). Client-lifetime. */
|
|
@@ -161,11 +217,34 @@ export declare class LiveSyncClient {
|
|
|
161
217
|
private pingSentAt;
|
|
162
218
|
/** Client-lifetime: consecutive opened-then-never-ponged connections. Reset to 0 by ANY pong. */
|
|
163
219
|
private probeFailures;
|
|
164
|
-
/** Client-lifetime: after PROBE_FAILURE_LIMIT never-ponged connections
|
|
165
|
-
* (an old server without auto-pong)
|
|
166
|
-
|
|
220
|
+
/** Client-lifetime until a pong: after PROBE_FAILURE_LIMIT never-ponged connections the watchdog
|
|
221
|
+
* DEGRADES to a {@link DEGRADED_PROBE_MULTIPLIER}x-slower re-probe (an old server without auto-pong)
|
|
222
|
+
* — it never turns off outright, so detection is never a restart-only casualty (CTC-281). Only
|
|
223
|
+
* reachable while pong capability is UNPROVEN ({@link pongEverObserved}); the first pong clears it. */
|
|
224
|
+
private watchdogDegraded;
|
|
225
|
+
/** Client-lifetime pong latch (CTC-281): has ANY connection EVER answered a ping? Once true, the
|
|
226
|
+
* server's auto-pong capability is PROVEN for good — a later never-ponged connection is a liveness
|
|
227
|
+
* failure (the incident's open-but-silent socket), never feature-detect evidence, so the watchdog
|
|
228
|
+
* can no longer even degrade itself. PER-PROCESS by design — which is exactly why the degrade must
|
|
229
|
+
* be soft (see {@link DEGRADED_PROBE_MULTIPLIER}): a restart mid-incident resets this latch. */
|
|
230
|
+
private pongEverObserved;
|
|
167
231
|
private pingTimer;
|
|
168
232
|
private pongDeadline;
|
|
233
|
+
/** Per-CONNECTION connect/open deadline (CTC-281): armed when the socket is constructed, cleared on
|
|
234
|
+
* open/close/teardown. The only timer pending between openSocket() and onopen — the guarantee that
|
|
235
|
+
* a never-firing ws impl cannot leave the client wedged in "connecting" with nothing scheduled. */
|
|
236
|
+
private connectTimer;
|
|
237
|
+
/** Per-CONNECTION onerror→onclose fallback (CTC-281): armed by onerror, fires forceReconnect once
|
|
238
|
+
* if the impl never follows error with close (undici #3697/#3546). Cleared on open/close/teardown. */
|
|
239
|
+
private errorFallbackTimer;
|
|
240
|
+
/** Per-CONNECTION: has THIS socket fired onopen? The connect-deadline's late-timer guard (a
|
|
241
|
+
* throttled background tab can fire the deadline after onopen already ran and cleared it). */
|
|
242
|
+
private socketOpened;
|
|
243
|
+
/** The pending reseed deadline (CTC-281) — the timer that makes "resyncing" (no socket, reconnect
|
|
244
|
+
* suppressed) a bounded state instead of a restart-only wedge. Cleared when the reseed settles in
|
|
245
|
+
* time and by stop() (ask 4: stop() leaves NOTHING pending). At most one reseed is ever in flight
|
|
246
|
+
* (`resyncing` guards the resync path; the boot seed runs before any socket exists). */
|
|
247
|
+
private reseedTimer;
|
|
169
248
|
constructor(opts: LiveSyncClientOptions);
|
|
170
249
|
/**
|
|
171
250
|
* Start the client: seed first if the consumer has no cursor, then open the live socket and keep it
|
|
@@ -188,6 +267,62 @@ export declare class LiveSyncClient {
|
|
|
188
267
|
/** Ask the service to replay everything after our durable cursor. */
|
|
189
268
|
private sendSync;
|
|
190
269
|
private handleFrame;
|
|
270
|
+
/**
|
|
271
|
+
* A change frame arrived BEYOND the contiguous next seq: every frame in `(deliveredSeq, frame.seq)`
|
|
272
|
+
* was silently dropped by the at-most-once live push. The frame is NOT applied and the baseline is
|
|
273
|
+
* NOT advanced past the hole — the mirror's change_log is durable, so the client re-requests the
|
|
274
|
+
* gap with the same `{type:"sync", after}` control frame it sends on every (re)connect, and the
|
|
275
|
+
* mirror replays the missing rows as ordinary change frames through the same apply path. While a
|
|
276
|
+
* re-request is in flight, further beyond-the-gap frames (in-flight live pushes the replay will
|
|
277
|
+
* cover) are dropped the same way WITHOUT sending another sync — one request per gap episode.
|
|
278
|
+
*/
|
|
279
|
+
private onGapFrame;
|
|
280
|
+
/**
|
|
281
|
+
* An end-of-pass head nudge (CTL-1402): `{type:"head", seq:N}` reports the mirror's current feed
|
|
282
|
+
* head after a reconcile pass whose change_log rows were never individually broadcast. If N sits
|
|
283
|
+
* beyond our contiguous baseline and no gap episode is pending, start one exactly as a beyond-gap
|
|
284
|
+
* change frame would — the hole is `deliveredSeq+1..N` (N itself is a real, un-broadcast row, so —
|
|
285
|
+
* unlike a change frame's trigger seq — it IS part of the hole) — and re-request it with the same
|
|
286
|
+
* bounded retry/escalation machinery and telemetry. The head frame is never applied and never
|
|
287
|
+
* advances a cursor. A head at/below the baseline is a no-op (already caught up); a head arriving
|
|
288
|
+
* while a gap is already pending is ignored (the in-flight replay already covers up to the head).
|
|
289
|
+
*/
|
|
290
|
+
private onHeadFrame;
|
|
291
|
+
/** Send (or re-send) the gap re-request from the current baseline and arm the heal deadline. */
|
|
292
|
+
private sendGapRequest;
|
|
293
|
+
/** (Re)arm the gap heal deadline. Armed when a re-request is sent AND refreshed on every frame of
|
|
294
|
+
* heal progress (the delivery path), so the deadline measures "no PROGRESS for gapTimeoutMs" rather
|
|
295
|
+
* than "not fully healed within gapTimeoutMs". `gapTimeoutMs === 0` disables it (heals only via the
|
|
296
|
+
* replay itself or the next reconnect). Only ever called with a gap episode pending. */
|
|
297
|
+
private armGapDeadline;
|
|
298
|
+
/** The heal deadline elapsed with the hole still open: retry within budget, else escalate to the
|
|
299
|
+
* full re-seed path. Escalation — never silent acceptance — is what keeps a drop from becoming a
|
|
300
|
+
* permanent hole one level up. */
|
|
301
|
+
private onGapTimeout;
|
|
302
|
+
/** The replay redelivered the whole detected hole (deliveredSeq reached seqTo contiguously). */
|
|
303
|
+
private onGapHealed;
|
|
304
|
+
/** Emit the gap lifecycle signal: a structured `catalyst.replica.gap` log line (the fleet's primary,
|
|
305
|
+
* Loki-materialized channel — same convention as `catalyst.replica.apply`) + a `result`-style
|
|
306
|
+
* low-cardinality bump of the `catalyst.replica.gaps` counter. seq_from/seq_to/size ride the log
|
|
307
|
+
* line as VALUES, never labels. Levels: `detected` and `healed` log at INFO — a gap is the
|
|
308
|
+
* steady-state path (every reconcile pass punches one that heals via re-request), so ALERTING MUST
|
|
309
|
+
* KEY ON `escalated` ONLY (logged at ERROR); a gap that heals is routine and boring. */
|
|
310
|
+
private recordGap;
|
|
311
|
+
private clearGapTimer;
|
|
312
|
+
/** Drop all gap state (pending hole + timer) — on (re)open and on the resync/re-seed path, both of
|
|
313
|
+
* which re-request/rebuild from the durable cursor and so supersede any pending re-request. */
|
|
314
|
+
private clearGapState;
|
|
315
|
+
private clearReseedTimer;
|
|
316
|
+
/**
|
|
317
|
+
* Run the injected reseed() bounded by {@link LiveSyncClientOptions.reseedTimeoutMs} (CTC-281).
|
|
318
|
+
* The injected callback is a trust boundary like the ws impl: while it runs there is NO socket and
|
|
319
|
+
* scheduleReconnect is suppressed, so an unbounded await here was the last zero-timer wedge — the
|
|
320
|
+
* deadline below is the pending timer that upholds the header invariant for the "resyncing" state.
|
|
321
|
+
* On timeout the attempt is ABANDONED, not cancelled (the callback owns its own I/O bounds — the
|
|
322
|
+
* replica's seedFromSnapshot aborts its fetch itself): a late settle is discarded via the `settled`
|
|
323
|
+
* latch, and a late REJECTION is swallowed so it can never surface as an unhandled rejection.
|
|
324
|
+
*/
|
|
325
|
+
private boundedReseed;
|
|
191
326
|
/**
|
|
192
327
|
* Cursor underflow: the deltas we need were evicted from the service's retained change buffer. Close the socket
|
|
193
328
|
* (so no live frame interleaves with the re-seed), re-seed via the injected callback, then reconnect
|
|
@@ -199,11 +334,20 @@ export declare class LiveSyncClient {
|
|
|
199
334
|
* Any inbound bytes prove the socket is alive; the catalyst daemon's stall classifier reads this to
|
|
200
335
|
* tell a quiet feed from a half-open socket (the per-frame timestamp it previously lacked). */
|
|
201
336
|
get lastFrameAt(): number | null;
|
|
337
|
+
/** Epoch ms of the last inbound CHANGE frame (live or replayed; delivered OR gap-dropped), or null
|
|
338
|
+
* before the first. Unlike {@link lastFrameAt} — which any bytes stamp, INCLUDING the mirror's
|
|
339
|
+
* watchdog auto-pongs — this only moves when the feed actually pushes data. Pairing the two lets a
|
|
340
|
+
* stall supervisor separate the three states CTL-1402 conflated: dead socket (both stale),
|
|
341
|
+
* healthy-but-unpushed socket (lastFrameAt fresh via pongs, lastChangeFrameAt stale while the
|
|
342
|
+
* mirror head advances), and a genuinely quiet feed (same signature, distinguished server-side). */
|
|
343
|
+
get lastChangeFrameAt(): number | null;
|
|
202
344
|
/** Any inbound frame: stamp liveness, cancel a pending pong deadline (it was answered), and postpone
|
|
203
345
|
* the next ping so a busy stream never sends one. Runs synchronously in onmessage before parsing. */
|
|
204
346
|
private onInboundFrame;
|
|
205
|
-
/** (Re)arm the idle-ping timer. No-op when the watchdog is
|
|
206
|
-
*
|
|
347
|
+
/** (Re)arm the idle-ping timer. No-op when the watchdog is off or there is no live socket, so it is
|
|
348
|
+
* safe to call on every frame. A setTimeout chain (not setInterval): each frame resets it. A
|
|
349
|
+
* DEGRADED watchdog still arms — at {@link DEGRADED_PROBE_MULTIPLIER}x the interval — so detection
|
|
350
|
+
* is never permanently off (CTC-281): every live socket always has a probe pending. */
|
|
207
351
|
private armPing;
|
|
208
352
|
/** The feed has been idle for a full interval: send one liveness ping and start the pong deadline. A
|
|
209
353
|
* synchronous send throw means the socket is already dead — treat it as an unanswered probe now. */
|
|
@@ -213,9 +357,16 @@ export declare class LiveSyncClient {
|
|
|
213
357
|
* is proven — re-arm and move on (detection latency grows; correctness holds). Otherwise: half-open. */
|
|
214
358
|
private onPongDeadline;
|
|
215
359
|
/** A ping went unanswered (deadline elapsed or the send threw). If this connection had already proven
|
|
216
|
-
* pong capability it is a genuine liveness timeout
|
|
217
|
-
*
|
|
218
|
-
* server
|
|
360
|
+
* pong capability it is a genuine liveness timeout. If pong capability was proven EARLIER in this
|
|
361
|
+
* client's lifetime (CTC-281), a never-ponged connection is the incident signature — a half-open
|
|
362
|
+
* socket against a server we KNOW auto-pongs — so it too is a liveness failure and must NEVER count
|
|
363
|
+
* toward the feature-detect (during the Jul 17-23 windows, 3 such sockets permanently disabled
|
|
364
|
+
* detection). Only while capability is UNPROVEN does the failure count toward the DEGRADE — after
|
|
365
|
+
* PROBE_FAILURE_LIMIT never-ponged connections the watchdog backs its probes off to
|
|
366
|
+
* DEGRADED_PROBE_MULTIPLIER x pingIntervalMs (an old server without auto-pong costs one bounded
|
|
367
|
+
* reconnect per degraded window; a mid-incident restart — per-process latch reset — still detects
|
|
368
|
+
* the next half-open within one degraded window, never restart-only; CTC-281). Every path
|
|
369
|
+
* force-reconnects through the existing backoff. */
|
|
219
370
|
private onProbeUnanswered;
|
|
220
371
|
/** Tear the socket down and reconnect through the normal backoff. closeSocket detaches handlers (so
|
|
221
372
|
* onclose won't also fire) and clears the liveness timers, so we schedule the reopen ourselves. */
|
|
@@ -223,6 +374,8 @@ export declare class LiveSyncClient {
|
|
|
223
374
|
private clearPingTimer;
|
|
224
375
|
private clearPongDeadline;
|
|
225
376
|
private clearLivenessTimers;
|
|
377
|
+
/** Clear the per-connection connect/open deadline + onerror→onclose fallback (CTC-281). */
|
|
378
|
+
private clearConnectTimers;
|
|
226
379
|
}
|
|
227
380
|
/** Parse a WS frame (string or ArrayBuffer) into a known server frame, or null for anything malformed. */
|
|
228
381
|
export declare function parseFrame(data: unknown): ServerFrame | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-sync-client.d.ts","sourceRoot":"","sources":["../src/live-sync-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"live-sync-client.d.ts","sourceRoot":"","sources":["../src/live-sync-client.ts"],"names":[],"mappings":"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"}
|