Skip to content

Instantly share code, notes, and snippets.

@jsphbtst
Last active January 17, 2024 04:48
Show Gist options
  • Save jsphbtst/c9666513fca41902467e8e059d552493 to your computer and use it in GitHub Desktop.
Save jsphbtst/c9666513fca41902467e8e059d552493 to your computer and use it in GitHub Desktop.
Client Fetch-Based SSE Listener
class FetchEventSource {
private url: string
private headers: HeadersInit
private controller: AbortController
private reader?: ReadableStreamDefaultReader<Uint8Array>
constructor(url: string, headers: HeadersInit) {
this.url = url
this.headers = headers
this.controller = new AbortController()
}
async connect(): Promise<void> {
try {
const response = await fetch(this.url, {
signal: this.controller.signal,
headers: {
...this.headers,
Accept: 'text/event-stream'
}
})
if (response.body === null) {
throw new Error('Response body is null')
}
this.reader = response.body.getReader()
} catch (error: unknown) {
const message = error instanceof Error ? error.message : 'Error establishing connection'
throw new Error(message)
}
}
async listen(callback: (data: string) => void): Promise<void> {
if (!this.reader) {
throw new Error('Reader not initialized')
}
try {
// eslint-disable-next-line no-constant-condition
while (true) {
const { value, done } = await this.reader.read()
if (done) {
break
}
const text = new TextDecoder().decode(value)
callback(text)
}
} catch (error: unknown) {
const message =
error instanceof Error && error.name !== 'AbortError'
? error.message
: 'Error reading the stream'
throw new Error(message)
}
}
close(): void {
this.controller.abort()
this.reader?.cancel()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment