diff --git a/packages/ui/src/sync/event-pipeline.ts b/packages/ui/src/sync/event-pipeline.ts index 70c0d21e..49220065 100644 --- a/packages/ui/src/sync/event-pipeline.ts +++ b/packages/ui/src/sync/event-pipeline.ts @@ -146,7 +146,6 @@ type DirectoryQueue = { export function createEventPipeline(input: EventPipelineInput) { const { sdk, onEvent, onReconnect, onDisconnect, routeDirectory, transport = "auto" } = input const abort = new AbortController() - let hasConnected = false let disconnected = false let lastEventId: string | undefined let wsFallbackUntil = 0 @@ -245,19 +244,13 @@ export function createEventPipeline(input: EventPipelineInput) { let heartbeat: ReturnType | undefined const markConnected = () => { - const wasDisconnected = disconnected disconnected = false - if (hasConnected) { - onReconnect?.() - return - } - hasConnected = true - // First successful connect, but an earlier attempt already fired onDisconnect - // (e.g. sidecar was not ready at launch). Consumer state is stuck at - // isConnected=false — fire onReconnect to unstick it. - if (wasDisconnected) { - onReconnect?.() - } + // Fire onReconnect on every successful connect — including the very + // first one. Consumer state (isConnected) starts at false and needs + // to be flipped positively; without this the send button throws + // "Connection lost" until something else (HTTP health check) happens + // to race a setState({isConnected: true}) through. + onReconnect?.() } const enqueueEvent = (directory: string, payload: Event) => {