Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions projects/kit/src/lib/realtime/kit-realtime-connection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ describe('KitRealtimeConnection', () => {
connection.stop();
});

it('requests a REST resync when the initial socket connection is fully established', async () => {
const connection = new TestConnection();
const reconnected = vi.fn();
connection.reconnected$.subscribe(reconnected);
await connection.openForTest();

connection.sockets[0].open();

expect(reconnected).toHaveBeenCalledOnce();
connection.stop();
});

it('emits resync after a partial multi-target connection failure recovers', async () => {
vi.useFakeTimers();
const connection = new TestConnection();
Expand Down
15 changes: 2 additions & 13 deletions projects/kit/src/lib/realtime/kit-realtime-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,14 @@ export abstract class KitRealtimeConnection<TEvent extends KitRealtimeEvent> {
#reconnectTimer: ReturnType<typeof setTimeout> | null = null;
#pingTimer: ReturnType<typeof setInterval> | null = null;
#reconnectAttempt = 0;
#hasOpened = false;
#needsResync = false;
#isAppActive = true;
#isNetworkConnected = true;
#lifecycleRegistration: Promise<void> | null = null;
#lifecycleGeneration = 0;

/** All parsed events received by this connection. */
readonly events$: Observable<KitClientRealtimeEvent<TEvent>> = this.#events$.asObservable();
/** Emits once after every fully restored connection cycle, prompting consumers to resync via REST. */
/** Emits after every fully established connection cycle, including the first, prompting a REST resync. */
readonly reconnected$: Observable<void> = this.#reconnected$.asObservable();

/** Override timing/protocol defaults in specialized clients or tests. */
Expand Down Expand Up @@ -254,8 +252,6 @@ export abstract class KitRealtimeConnection<TEvent extends KitRealtimeEvent> {

/** Reset resync and backoff history when the owning session ends. */
protected resetConnectionState(): void {
this.#hasOpened = false;
this.#needsResync = false;
this.#reconnectAttempt = 0;
}

Expand Down Expand Up @@ -302,11 +298,7 @@ export abstract class KitRealtimeConnection<TEvent extends KitRealtimeEvent> {
return;
}
this.#opening = false;
if (this.#hasOpened || this.#needsResync) {
this.#reconnected$.next();
}
this.#hasOpened = true;
this.#needsResync = false;
this.#reconnected$.next();
};
socket.onmessage = ({ data }) => {
if (generation !== this.#generation || typeof data !== 'string') {
Expand Down Expand Up @@ -341,9 +333,6 @@ export abstract class KitRealtimeConnection<TEvent extends KitRealtimeEvent> {
if (generation !== this.#generation) {
return;
}
if ([...this.#sockets].some((socket) => socket.readyState === WebSocket.OPEN)) {
this.#needsResync = true;
}
this.#closeSockets();
void this.handleConnectionFailure()
.catch(() => undefined)
Expand Down