Files
NomadArch/packages/ui/src/lib/server-events.ts
Gemini AI b448d11991 fix: restore complete source code and fix launchers
- Copy complete source code packages from original CodeNomad project
- Add root package.json with npm workspace configuration
- Include electron-app, server, ui, tauri-app, and opencode-config packages
- Fix Launch-Windows.bat and Launch-Dev-Windows.bat to work with correct npm scripts
- Fix Launch-Unix.sh to work with correct npm scripts
- Launchers now correctly call npm run dev:electron which launches Electron app
2025-12-23 12:57:55 +04:00

67 lines
1.9 KiB
TypeScript

import type { WorkspaceEventPayload, WorkspaceEventType } from "../../../server/src/api-types"
import { serverApi } from "./api-client"
import { getLogger } from "./logger"
const RETRY_BASE_DELAY = 1000
const RETRY_MAX_DELAY = 10000
const log = getLogger("sse")
function logSse(message: string, context?: Record<string, unknown>) {
if (context) {
log.info(message, context)
return
}
log.info(message)
}
class ServerEvents {
private handlers = new Map<WorkspaceEventType | "*", Set<(event: WorkspaceEventPayload) => void>>()
private source: EventSource | null = null
private retryDelay = RETRY_BASE_DELAY
constructor() {
this.connect()
}
private connect() {
if (this.source) {
this.source.close()
}
logSse("Connecting to backend events stream")
this.source = serverApi.connectEvents((event) => this.dispatch(event), () => this.scheduleReconnect())
this.source.onopen = () => {
logSse("Events stream connected")
this.retryDelay = RETRY_BASE_DELAY
}
}
private scheduleReconnect() {
if (this.source) {
this.source.close()
this.source = null
}
logSse("Events stream disconnected, scheduling reconnect", { delayMs: this.retryDelay })
setTimeout(() => {
this.retryDelay = Math.min(this.retryDelay * 2, RETRY_MAX_DELAY)
this.connect()
}, this.retryDelay)
}
private dispatch(event: WorkspaceEventPayload) {
logSse(`event ${event.type}`)
this.handlers.get("*")?.forEach((handler) => handler(event))
this.handlers.get(event.type)?.forEach((handler) => handler(event))
}
on(type: WorkspaceEventType | "*", handler: (event: WorkspaceEventPayload) => void): () => void {
if (!this.handlers.has(type)) {
this.handlers.set(type, new Set())
}
const bucket = this.handlers.get(type)!
bucket.add(handler)
return () => bucket.delete(handler)
}
}
export const serverEvents = new ServerEvents()