From f3b4ccf04abfb7fb82d7116d385fccf0f6ad4e91 Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sat, 9 Aug 2025 19:10:50 +0200 Subject: [PATCH 01/10] feat: add queuing to event-clients --- examples/react/start/src/plugin.ts | 6 +++ packages/event-bus-client/src/plugin.ts | 71 ++++++++++++++++++++++++- packages/event-bus/src/client/client.ts | 16 ++++++ packages/event-bus/src/server/server.ts | 12 ++++- 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/examples/react/start/src/plugin.ts b/examples/react/start/src/plugin.ts index 18b3f2fc..11a36753 100644 --- a/examples/react/start/src/plugin.ts +++ b/examples/react/start/src/plugin.ts @@ -19,8 +19,14 @@ class QueryDevtoolsClient extends EventClient { constructor() { super({ pluginId: 'query-devtools', + debug: true, }) } } export const queryPlugin = new QueryDevtoolsClient() +// this should be queued and emitted when bus is available +queryPlugin.emit('test', { + title: 'Query Devtools', + description: 'A plugin for query debugging', +}) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index 192cb0dd..a83ad84d 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -23,7 +23,26 @@ export class EventClient< #pluginId: TPluginId #eventTarget: () => EventTarget #debug: boolean + #queuedEvents: Array> + #connected: boolean + #connectIntervalId: number | null + #connectEveryMs: number + #retryCount = 0 + #maxRetries = 5 + #connectFunction = () => { + if (this.#retryCount < this.#maxRetries) { + this.#retryCount++ + this.#eventTarget().dispatchEvent(new CustomEvent('tanstack-connect')) + return + } + this.#eventTarget().removeEventListener( + 'tanstack-connect', + this.#connectFunction, + ) + this.debugLog('Max retries reached, giving up on connection') + clearInterval(this.#connectIntervalId!) + } constructor({ pluginId, debug = false, @@ -35,6 +54,46 @@ export class EventClient< this.#eventTarget = this.getGlobalTarget this.#debug = debug this.debugLog(' Initializing event subscription for plugin', this.#pluginId) + this.#queuedEvents = [] + this.#connected = false + this.#connectIntervalId = null + this.#connectEveryMs = 600 + this.startConnectLoop() + } + + private startConnectLoop() { + if (this.#connectIntervalId !== null) return + this.debugLog(`Starting connect loop (every ${this.#connectEveryMs}ms)`) + const onConnected = () => { + this.debugLog('Connected to event bus') + this.#connected = true + this.debugLog('Emitting queued events', this.#queuedEvents) + this.#queuedEvents.forEach((event) => this.emitEventToBus(event)) + this.#queuedEvents = [] + this.stopConnectLoop() + this.#eventTarget().removeEventListener( + 'tanstack-connect-success', + onConnected, + ) + } + this.#eventTarget().addEventListener( + 'tanstack-connect-success', + onConnected, + ) + + this.#connectIntervalId = setInterval( + this.#connectFunction, + this.#connectEveryMs, + ) as unknown as number + } + + private stopConnectLoop() { + if (this.#connectIntervalId === null) { + return + } + clearInterval(this.#connectIntervalId) + this.#connectIntervalId = null + this.debugLog('Stopped connect loop') } private debugLog(...args: Array) { @@ -84,7 +143,17 @@ export class EventClient< eventSuffix: TSuffix, payload: TEventMap[`${TPluginId & string}:${TSuffix}`], ) { - this.emitEventToBus({ + // wait to connect to the bus + if (!this.#connected) { + this.debugLog('Bus not available, will be pushed as soon as connected') + return this.#queuedEvents.push({ + type: `${this.#pluginId}:${eventSuffix}`, + payload, + pluginId: this.#pluginId, + }) + } + // emit right now + return this.emitEventToBus({ type: `${this.#pluginId}:${eventSuffix}`, payload, pluginId: this.#pluginId, diff --git a/packages/event-bus/src/client/client.ts b/packages/event-bus/src/client/client.ts index 0695b781..393522ce 100644 --- a/packages/event-bus/src/client/client.ts +++ b/packages/event-bus/src/client/client.ts @@ -30,11 +30,18 @@ export class ClientEventBus { #eventTarget: EventTarget #debug: boolean #connectToServerBus: boolean + #dispatcher = (e: Event) => { const event = (e as CustomEvent).detail this.emitToServer(event) this.emitToClients(event) } + #connectFunction = () => { + this.debugLog( + 'Connection request made to event-bus, replying back with success', + ) + this.#eventTarget.dispatchEvent(new CustomEvent('tanstack-connect-success')) + } constructor({ port = 42069, debug = false, @@ -46,6 +53,7 @@ export class ClientEventBus { this.#socket = null this.#connectToServerBus = connectToServerBus this.#eventTarget = this.getGlobalTarget() + this.debugLog('Initializing client event bus') } @@ -91,6 +99,10 @@ export class ClientEventBus { 'tanstack-dispatch-event', this.#dispatcher, ) + this.#eventTarget.addEventListener( + 'tanstack-connect', + this.#connectFunction, + ) } stop() { this.debugLog('Stopping client event bus') @@ -101,6 +113,10 @@ export class ClientEventBus { 'tanstack-dispatch-event', this.#dispatcher, ) + this.#eventTarget.removeEventListener( + 'tanstack-connect', + this.#connectFunction, + ) this.#eventSource?.close() this.#socket?.close() this.#socket = null diff --git a/packages/event-bus/src/server/server.ts b/packages/event-bus/src/server/server.ts index 932381f5..719c94f6 100644 --- a/packages/event-bus/src/server/server.ts +++ b/packages/event-bus/src/server/server.ts @@ -33,7 +33,9 @@ export class ServerEventBus { this.debugLog('Dispatching event from dispatcher, forwarding', event) this.emit(event) } - + #connectFunction = () => { + this.#eventTarget.dispatchEvent(new CustomEvent('tanstack-connect-success')) + } constructor({ port = 42069, debug = false } = {}) { this.#port = port this.#eventTarget = globalThis.__EVENT_TARGET__ ?? new EventTarget() @@ -165,6 +167,10 @@ export class ServerEventBus { 'tanstack-dispatch-event', this.#dispatcher, ) + this.#eventTarget.addEventListener( + 'tanstack-connect', + this.#connectFunction, + ) this.handleNewConnection(wss) // Handle connection upgrade for WebSocket @@ -200,6 +206,10 @@ export class ServerEventBus { 'tanstack-dispatch-event', this.#dispatcher, ) + this.#eventTarget.removeEventListener( + 'tanstack-connect', + this.#connectFunction, + ) this.debugLog('[tanstack-devtools] All connections cleared') } } From e124870bdae66908b87b59ad21590656618f1577 Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sun, 10 Aug 2025 14:55:29 +0200 Subject: [PATCH 02/10] chore: fix tests --- packages/event-bus-client/src/plugin.ts | 62 ++++++++++--------- packages/event-bus-client/tests/index.test.ts | 30 ++++++--- pnpm-lock.yaml | 2 + 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index a83ad84d..e5c9ce93 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -15,10 +15,10 @@ type AllDevtoolsEvents> = { export class EventClient< TEventMap extends Record, TPluginId extends string = TEventMap extends Record - ? P extends `${infer Id}:${string}` - ? Id - : never - : never, + ? P extends `${infer Id}:${string}` + ? Id + : never + : never, > { #pluginId: TPluginId #eventTarget: () => EventTarget @@ -29,7 +29,18 @@ export class EventClient< #connectEveryMs: number #retryCount = 0 #maxRetries = 5 - + #onConnected = () => { + this.debugLog('Connected to event bus') + this.#connected = true + this.debugLog('Emitting queued events', this.#queuedEvents) + this.#queuedEvents.forEach((event) => this.emitEventToBus(event)) + this.#queuedEvents = [] + this.stopConnectLoop() + this.#eventTarget().removeEventListener( + 'tanstack-connect-success', + this.#onConnected, + ) + } #connectFunction = () => { if (this.#retryCount < this.#maxRetries) { this.#retryCount++ @@ -41,8 +52,9 @@ export class EventClient< this.#connectFunction, ) this.debugLog('Max retries reached, giving up on connection') - clearInterval(this.#connectIntervalId!) + this.stopConnectLoop() } + constructor({ pluginId, debug = false, @@ -58,28 +70,22 @@ export class EventClient< this.#connected = false this.#connectIntervalId = null this.#connectEveryMs = 600 + + this.#eventTarget().addEventListener( + 'tanstack-connect-success', + this.#onConnected, + ) + this.#connectFunction() this.startConnectLoop() } + onConnected(cb: () => void) { + this.#eventTarget().addEventListener('tanstack-connect-success', cb) + } + private startConnectLoop() { - if (this.#connectIntervalId !== null) return + if (this.#connectIntervalId !== null || this.#connected) return this.debugLog(`Starting connect loop (every ${this.#connectEveryMs}ms)`) - const onConnected = () => { - this.debugLog('Connected to event bus') - this.#connected = true - this.debugLog('Emitting queued events', this.#queuedEvents) - this.#queuedEvents.forEach((event) => this.emitEventToBus(event)) - this.#queuedEvents = [] - this.stopConnectLoop() - this.#eventTarget().removeEventListener( - 'tanstack-connect-success', - onConnected, - ) - } - this.#eventTarget().addEventListener( - 'tanstack-connect-success', - onConnected, - ) this.#connectIntervalId = setInterval( this.#connectFunction, @@ -107,7 +113,7 @@ export class EventClient< typeof globalThis !== 'undefined' && globalThis.__TANSTACK_EVENT_TARGET__ ) { - this.debugLog('Using global event target') + this.debugLog('Using global event target',) return globalThis.__TANSTACK_EVENT_TARGET__ } // CLient event target is the window object @@ -137,8 +143,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, payload: TEventMap[`${TPluginId & string}:${TSuffix}`], @@ -165,8 +171,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, cb: ( diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index 37eb501c..34472295 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -1,15 +1,14 @@ -import { describe, expect, it, vi } from 'vitest' -import { EventClient } from '../src' +import { describe, expect, it, vi, } from 'vitest' import { ClientEventBus } from '@tanstack/devtools-event-bus/client' +import { EventClient } from '../src' // start the client bus for testing new ClientEventBus().start() // client bus uses window to dispatch events const clientBusEmitTarget = window - describe('EventClient', () => { describe('debug config', () => { - it('should emit logs when debug set to true and have the correct plugin name', () => { + it('should emit logs when debug set to true and have the correct plugin name', async () => { const consoleSpy = vi.spyOn(console, 'log') new EventClient({ debug: true, @@ -35,7 +34,17 @@ describe('EventClient', () => { describe('getGlobalTarget', () => { it('if the global target is set it should re-use it for emitting/listening/removing of events', () => { const target = new EventTarget() - globalThis.__TANSTACK_EVENT_TARGET__ = target + const handleSuccessConnection = vi.fn() + target.addEventListener("tanstack-connect", () => { + target.dispatchEvent( + new CustomEvent("tanstack-connect-success") + ) + }) + globalThis.__TANSTACK_EVENT_TARGET__ = null + + vi.spyOn(globalThis, '__TANSTACK_EVENT_TARGET__', 'get').mockImplementation(() => { + return target + }) const client = new EventClient({ debug: false, pluginId: 'test', @@ -43,7 +52,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -55,9 +64,9 @@ describe('EventClient', () => { expect.any(String), expect.any(Function), ) - globalThis.__TANSTACK_EVENT_TARGET__ = null + vi.resetAllMocks() + target.removeEventListener("tanstack-connect", handleSuccessConnection) }) - it('should use the window object if the globalTarget is not set for emitting/listening/removing of events', () => { const target = window const client = new EventClient({ @@ -67,7 +76,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -80,6 +89,7 @@ describe('EventClient', () => { expect.any(Function), ) }) + }) describe('on', () => { @@ -90,7 +100,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => {}) + client.on('event', () => { }) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99a27403..22bec3af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -240,6 +240,8 @@ importers: specifier: ^4.2.4 version: 4.2.4 + examples/react/start/generated/prisma: {} + examples/solid/basic: dependencies: '@tanstack/solid-devtools': From 845bb838017a7350a177dca87abed42d90a4243c Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sun, 10 Aug 2025 14:55:59 +0200 Subject: [PATCH 03/10] chore: remove function --- packages/event-bus-client/src/plugin.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index e5c9ce93..9b0ab147 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -79,10 +79,6 @@ export class EventClient< this.startConnectLoop() } - onConnected(cb: () => void) { - this.#eventTarget().addEventListener('tanstack-connect-success', cb) - } - private startConnectLoop() { if (this.#connectIntervalId !== null || this.#connected) return this.debugLog(`Starting connect loop (every ${this.#connectEveryMs}ms)`) From 52df1b9891c39cb50c369507576a6ac934159ba8 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 10 Aug 2025 12:56:36 +0000 Subject: [PATCH 04/10] ci: apply automated fixes --- packages/event-bus-client/src/plugin.ts | 18 +++++++-------- packages/event-bus-client/tests/index.test.ts | 23 ++++++++++--------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index 9b0ab147..58ff9d26 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -15,10 +15,10 @@ type AllDevtoolsEvents> = { export class EventClient< TEventMap extends Record, TPluginId extends string = TEventMap extends Record - ? P extends `${infer Id}:${string}` - ? Id - : never - : never, + ? P extends `${infer Id}:${string}` + ? Id + : never + : never, > { #pluginId: TPluginId #eventTarget: () => EventTarget @@ -109,7 +109,7 @@ export class EventClient< typeof globalThis !== 'undefined' && globalThis.__TANSTACK_EVENT_TARGET__ ) { - this.debugLog('Using global event target',) + this.debugLog('Using global event target') return globalThis.__TANSTACK_EVENT_TARGET__ } // CLient event target is the window object @@ -139,8 +139,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, payload: TEventMap[`${TPluginId & string}:${TSuffix}`], @@ -167,8 +167,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, cb: ( diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index 34472295..6bb3fa27 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi, } from 'vitest' +import { describe, expect, it, vi } from 'vitest' import { ClientEventBus } from '@tanstack/devtools-event-bus/client' import { EventClient } from '../src' @@ -35,14 +35,16 @@ describe('EventClient', () => { it('if the global target is set it should re-use it for emitting/listening/removing of events', () => { const target = new EventTarget() const handleSuccessConnection = vi.fn() - target.addEventListener("tanstack-connect", () => { - target.dispatchEvent( - new CustomEvent("tanstack-connect-success") - ) + target.addEventListener('tanstack-connect', () => { + target.dispatchEvent(new CustomEvent('tanstack-connect-success')) }) globalThis.__TANSTACK_EVENT_TARGET__ = null - vi.spyOn(globalThis, '__TANSTACK_EVENT_TARGET__', 'get').mockImplementation(() => { + vi.spyOn( + globalThis, + '__TANSTACK_EVENT_TARGET__', + 'get', + ).mockImplementation(() => { return target }) const client = new EventClient({ @@ -52,7 +54,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -65,7 +67,7 @@ describe('EventClient', () => { expect.any(Function), ) vi.resetAllMocks() - target.removeEventListener("tanstack-connect", handleSuccessConnection) + target.removeEventListener('tanstack-connect', handleSuccessConnection) }) it('should use the window object if the globalTarget is not set for emitting/listening/removing of events', () => { const target = window @@ -76,7 +78,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -89,7 +91,6 @@ describe('EventClient', () => { expect.any(Function), ) }) - }) describe('on', () => { @@ -100,7 +101,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => { }) + client.on('event', () => {}) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), From f62bdf903591fad15cccab93290a95c194c99b51 Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sun, 10 Aug 2025 15:00:30 +0200 Subject: [PATCH 05/10] chore: remove function async --- .changeset/eleven-garlics-work.md | 6 ++++++ packages/event-bus-client/tests/index.test.ts | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .changeset/eleven-garlics-work.md diff --git a/.changeset/eleven-garlics-work.md b/.changeset/eleven-garlics-work.md new file mode 100644 index 00000000..8f6950c5 --- /dev/null +++ b/.changeset/eleven-garlics-work.md @@ -0,0 +1,6 @@ +--- +'@tanstack/devtools-event-client': patch +'@tanstack/devtools-event-bus': patch +--- + +add queued events to event bus diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index 6bb3fa27..dc7cb764 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -8,7 +8,7 @@ new ClientEventBus().start() const clientBusEmitTarget = window describe('EventClient', () => { describe('debug config', () => { - it('should emit logs when debug set to true and have the correct plugin name', async () => { + it('should emit logs when debug set to true and have the correct plugin name', () => { const consoleSpy = vi.spyOn(console, 'log') new EventClient({ debug: true, @@ -54,7 +54,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -78,7 +78,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -101,7 +101,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => {}) + client.on('event', () => { }) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), From 09132a016d1d64f160b539f1de9335c1c06fd0ab Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 10 Aug 2025 13:01:00 +0000 Subject: [PATCH 06/10] ci: apply automated fixes --- packages/event-bus-client/tests/index.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index dc7cb764..bb671115 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -54,7 +54,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -78,7 +78,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -101,7 +101,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => { }) + client.on('event', () => {}) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), From 6a548b2870f50763fba56956af8bffc3aee29a2f Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sun, 10 Aug 2025 15:02:22 +0200 Subject: [PATCH 07/10] chore: change reconnect in ms value --- packages/event-bus-client/src/plugin.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index 58ff9d26..db718d3d 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -15,10 +15,10 @@ type AllDevtoolsEvents> = { export class EventClient< TEventMap extends Record, TPluginId extends string = TEventMap extends Record - ? P extends `${infer Id}:${string}` - ? Id - : never - : never, + ? P extends `${infer Id}:${string}` + ? Id + : never + : never, > { #pluginId: TPluginId #eventTarget: () => EventTarget @@ -69,7 +69,7 @@ export class EventClient< this.#queuedEvents = [] this.#connected = false this.#connectIntervalId = null - this.#connectEveryMs = 600 + this.#connectEveryMs = 500 this.#eventTarget().addEventListener( 'tanstack-connect-success', @@ -139,8 +139,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, payload: TEventMap[`${TPluginId & string}:${TSuffix}`], @@ -167,8 +167,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, cb: ( From dbbe0f254769dadc1a3297131658672c4c4dc420 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 10 Aug 2025 13:02:54 +0000 Subject: [PATCH 08/10] ci: apply automated fixes --- packages/event-bus-client/src/plugin.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/event-bus-client/src/plugin.ts b/packages/event-bus-client/src/plugin.ts index db718d3d..d914a762 100644 --- a/packages/event-bus-client/src/plugin.ts +++ b/packages/event-bus-client/src/plugin.ts @@ -15,10 +15,10 @@ type AllDevtoolsEvents> = { export class EventClient< TEventMap extends Record, TPluginId extends string = TEventMap extends Record - ? P extends `${infer Id}:${string}` - ? Id - : never - : never, + ? P extends `${infer Id}:${string}` + ? Id + : never + : never, > { #pluginId: TPluginId #eventTarget: () => EventTarget @@ -139,8 +139,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, payload: TEventMap[`${TPluginId & string}:${TSuffix}`], @@ -167,8 +167,8 @@ export class EventClient< keyof TEventMap, `${TPluginId & string}:${string}` > extends `${TPluginId & string}:${infer S}` - ? S - : never, + ? S + : never, >( eventSuffix: TSuffix, cb: ( From 9e9ea34309f8e72b91c07bf7550b67b4bc02a4de Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sun, 10 Aug 2025 15:08:19 +0200 Subject: [PATCH 09/10] chore: add tests for new functionality --- packages/event-bus-client/tests/index.test.ts | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index bb671115..4737b8ef 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -3,7 +3,8 @@ import { ClientEventBus } from '@tanstack/devtools-event-bus/client' import { EventClient } from '../src' // start the client bus for testing -new ClientEventBus().start() +const bus = new ClientEventBus() +bus.start() // client bus uses window to dispatch events const clientBusEmitTarget = window describe('EventClient', () => { @@ -54,7 +55,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -78,7 +79,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => {}) + const cleanup = client.on('test:event', () => { }) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -101,7 +102,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => {}) + client.on('event', () => { }) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), @@ -194,6 +195,27 @@ describe('EventClient', () => { }) }) + describe("queued events", () => { + it("emits queued events when connected to the event bus", async () => { + bus.stop() + const client = new EventClient({ + debug: false, + pluginId: 'test', + }) + const eventHandler = vi.fn() + client.on('event', eventHandler) + client.emit('event', { foo: 'bar' }) + + bus.start() + // wait to connect to the bus + await new Promise(resolve => setTimeout(resolve, 500)) + expect(eventHandler).toHaveBeenCalledWith({ + type: 'test:event', + payload: { foo: 'bar' }, + pluginId: 'test', + }) + }) + }) describe('onAllPluginEvents', () => { it('should listen to all events that come from the plugin', () => { const client = new EventClient({ From 8a4bfae5fec56d22d71fcb83ee9dcdcae94e902e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 10 Aug 2025 13:09:00 +0000 Subject: [PATCH 10/10] ci: apply automated fixes --- packages/event-bus-client/tests/index.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/event-bus-client/tests/index.test.ts b/packages/event-bus-client/tests/index.test.ts index 4737b8ef..048ffa4a 100644 --- a/packages/event-bus-client/tests/index.test.ts +++ b/packages/event-bus-client/tests/index.test.ts @@ -55,7 +55,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -79,7 +79,7 @@ describe('EventClient', () => { const targetEmitSpy = vi.spyOn(target, 'dispatchEvent') const targetListenSpy = vi.spyOn(target, 'addEventListener') const targetRemoveSpy = vi.spyOn(target, 'removeEventListener') - const cleanup = client.on('test:event', () => { }) + const cleanup = client.on('test:event', () => {}) cleanup() client.emit('test:event', { foo: 'bar' }) expect(targetEmitSpy).toHaveBeenCalledWith(expect.any(Event)) @@ -102,7 +102,7 @@ describe('EventClient', () => { }) const eventBusSpy = vi.spyOn(clientBusEmitTarget, 'addEventListener') - client.on('event', () => { }) + client.on('event', () => {}) expect(eventBusSpy).toHaveBeenCalledWith( 'test:event', expect.any(Function), @@ -195,8 +195,8 @@ describe('EventClient', () => { }) }) - describe("queued events", () => { - it("emits queued events when connected to the event bus", async () => { + describe('queued events', () => { + it('emits queued events when connected to the event bus', async () => { bus.stop() const client = new EventClient({ debug: false, @@ -208,7 +208,7 @@ describe('EventClient', () => { bus.start() // wait to connect to the bus - await new Promise(resolve => setTimeout(resolve, 500)) + await new Promise((resolve) => setTimeout(resolve, 500)) expect(eventHandler).toHaveBeenCalledWith({ type: 'test:event', payload: { foo: 'bar' },