UNPKG

ngx-sse-client

Version:

A simple SSE (Server Sent Events) client for Angular applications.

1 lines 17 kB
{"version":3,"file":"ngx-sse-client.mjs","sources":["../../../projects/ngx-sse-client/src/lib/sse-options.interface.ts","../../../projects/ngx-sse-client/src/lib/sse-request-options.interface.ts","../../../projects/ngx-sse-client/src/lib/sse-client-subscriber.ts","../../../projects/ngx-sse-client/src/lib/sse-client.service.ts","../../../projects/ngx-sse-client/src/public-api.ts","../../../projects/ngx-sse-client/src/ngx-sse-client.ts"],"sourcesContent":["export interface SseOptions {\n /**\n * `true` to automatically reconnect when the request is closed by an request\n * error (including timeout errors) or completed.\n *\n * In this case, to close the connection is necessary to unsubscribe manually.\n *\n * @default `true`\n */\n keepAlive: boolean;\n\n /**\n * Delay before reconnecting with the server, this is only useful when\n * `keepAlive` is `true`.\n *\n * @default `5000`\n */\n reconnectionDelay: number;\n\n /**\n * Defines the response type.\n *\n * When set to `event` a `MessageEvent` will be returned with the data and a\n * default `Event` with type error in case of erros.\n *\n * When set to `text` only the message data will be returned. In this case no\n * errors will be returned, only the data from successful requests.\n *\n * @default `text`\n */\n responseType: 'event' | 'text';\n}\n\nexport const defaultSseOptions: SseOptions = { keepAlive: true, reconnectionDelay: 3_000, responseType: 'event' };\n","import { HttpContext, HttpHeaders, HttpParams } from '@angular/common/http';\n\nexport interface SseRequestOptions {\n body?: any;\n headers?: HttpHeaders | { [header: string]: string | string[] };\n params?: HttpParams | { [param: string]: string | string[] };\n context?: HttpContext;\n withCredentials?: boolean;\n}\n\nexport const defaultRequestOptions = { observe: 'events', reportProgress: true, responseType: 'text' };\n","import { HttpClient, HttpDownloadProgressEvent, HttpErrorResponse, HttpEvent, HttpEventType, HttpResponse } from '@angular/common/http';\nimport { Observable, Subscriber, Subscription } from 'rxjs';\nimport { delay, repeatWhen, retryWhen, takeWhile, tap } from 'rxjs/operators';\n\nimport { SseErrorEvent } from './sse-error-event.interface';\nimport { SseOptions } from './sse-options.interface';\n\nexport class SseClientSubscriber {\n private static readonly SEPARATOR = ':';\n\n private progress = 0;\n private chunk = '';\n\n constructor(private httpClient: HttpClient, private sseOptions: SseOptions, private httpClientOptions: any, private url: string, private method: string) { }\n\n public createObservable(): Observable<string | Event> {\n return new Observable<string | Event>((observer) => {\n const subscription = this.subscribeStreamRequest(this.url, this.sseOptions, this.httpClientOptions, this.method, observer);\n return () => subscription.unsubscribe();\n });\n }\n\n private subscribeStreamRequest(url: string, options: SseOptions, requestOptions: any, method: string, observer: Subscriber<string | Event>): Subscription {\n return this.httpClient\n .request<string>(method, url, requestOptions)\n .pipe(repeatWhen((completed) => this.repeatWhen(completed, options.keepAlive, options.reconnectionDelay)))\n .pipe(retryWhen((error) => this.retryWhen(error, options.keepAlive, options.reconnectionDelay, observer)))\n .subscribe((event) => this.parseStreamEvent(event, observer));\n }\n\n private repeatWhen(completed: Observable<any>, keepAlive: boolean, reconnectionDelay: number): Observable<any> {\n return completed.pipe(takeWhile(() => keepAlive)).pipe(delay(reconnectionDelay));\n }\n\n private retryWhen(attempts: Observable<any>, keepAlive: boolean, reconnectionDelay: number, observer: Subscriber<string | Event>): Observable<any> {\n return attempts\n .pipe(tap((error) => this.threatRequestError(error, observer)))\n .pipe(takeWhile(() => keepAlive))\n .pipe(delay(reconnectionDelay));\n }\n\n private threatRequestError(event: HttpErrorResponse, observer: Subscriber<string | Event>): void {\n this.dispatchStreamData(this.errorEvent(event), observer);\n\n if (!this.isValidStatus(event.status)) {\n observer.error(event);\n }\n }\n\n private isValidStatus(status: number): boolean {\n return status !== undefined && status !== null && status <= 299;\n }\n\n private parseStreamEvent(event: HttpEvent<string>, observer: Subscriber<string>): void {\n if (event.type === HttpEventType.Sent) {\n this.progress = 0;\n return;\n }\n\n if (event.type === HttpEventType.DownloadProgress) {\n this.onStreamProgress((event as HttpDownloadProgressEvent).partialText as string, observer);\n return;\n }\n\n if (event.type === HttpEventType.Response) {\n this.onStreamCompleted(event as HttpResponse<string>, observer);\n return;\n }\n }\n\n private onStreamProgress(data: string, observer: Subscriber<string>): void {\n data = data.substring(this.progress);\n this.progress += data.length;\n data.split(/(\\r\\n|\\r|\\n){2}/g).forEach((part) => this.parseEventData(part, observer));\n }\n\n private onStreamCompleted(response: HttpResponse<string>, observer: Subscriber<string>): void {\n this.onStreamProgress(response.body as string, observer);\n this.dispatchStreamData(this.parseEventChunk(this.chunk), observer);\n\n this.chunk = '';\n this.progress = 0;\n\n if (this.sseOptions.keepAlive) {\n const message = `Server response ended, will reconnect in ${this.sseOptions.reconnectionDelay}ms`;\n this.dispatchStreamData(this.errorEvent({ status: 1, message }), observer);\n } else {\n observer.complete();\n }\n }\n\n private parseEventData(part: string, observer: Subscriber<string>) {\n if (part.trim().length === 0) {\n this.dispatchStreamData(this.parseEventChunk(this.chunk), observer);\n this.chunk = '';\n } else {\n this.chunk += part;\n }\n }\n\n private parseEventChunk(chunk: string): MessageEvent | undefined {\n if (!chunk || chunk.length === 0) return;\n\n const chunkEvent: ChunkEvent = { id: undefined, data: '', event: 'message' };\n chunk.split(/\\n|\\r\\n|\\r/).forEach((line) => this.parseChunkLine(line.trim(), chunkEvent));\n\n return this.messageEvent(chunkEvent.event, { lastEventId: chunkEvent.id, data: chunkEvent.data });\n }\n\n private parseChunkLine(line: string, event: ChunkEvent) {\n const index = line.indexOf(SseClientSubscriber.SEPARATOR);\n if (index <= 0) return;\n\n const field = line.substring(0, index);\n if (Object.keys(event).findIndex((key: string) => key === field) === -1) return;\n\n let data = line.substring(index + 1).replace(/^\\s/, '');\n if (field === 'data') data = event.data + data;\n\n event[field] = data;\n }\n\n private dispatchStreamData(event: Event | undefined, observer: Subscriber<unknown>): void {\n if (!this.validEvent(event)) return;\n\n if (this.sseOptions.responseType === 'event') {\n observer.next(event);\n } else {\n observer.next((event as MessageEvent).data);\n }\n }\n\n private validEvent(event: Event | undefined): boolean {\n if (!event) return false;\n if (event.type === 'error' && this.sseOptions.responseType !== 'event') return false;\n if (event.type !== 'error' && (!(event as MessageEvent).data || !(event as MessageEvent).data.length)) return false;\n return true;\n }\n\n private messageEvent(type: string, options: MessageEventInit): MessageEvent {\n return new MessageEvent(type, options);\n }\n\n private errorEvent(error?: any): Event {\n let eventData: Partial<SseErrorEvent> | undefined;\n\n if (error && error.status > 0) {\n eventData = { error, message: error.message };\n\n if (!this.isValidStatus(error.status)) {\n eventData['status'] = error.status;\n eventData['statusText'] = error.statusText;\n }\n }\n\n return new ErrorEvent('error', eventData);\n }\n}\n\ntype ChunkEvent = { id: string | undefined; data: string; event: 'message';[key: string]: any };\n\n","import { HttpClient } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable } from 'rxjs';\n\nimport { defaultSseOptions, SseOptions } from './sse-options.interface';\nimport { defaultRequestOptions, SseRequestOptions } from './sse-request-options.interface';\n\nimport { SseClientSubscriber } from './sse-client-subscriber';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SseClient {\n constructor(private httpClient: HttpClient) { }\n\n /**\n * Constructs a request which listen to the SSE and interprets the data as\n * events and returns the full event stream.\n *\n * @param url the endpoint URL.\n * @param options an object of `SseOption`\n * @param requestOptions the HTTP options to send with the request.\n * @param method the HTTP method\n *\n * @returns an observable of all events for the request, with the response body of type `Event`.\n */\n public stream(url: string, options?: { keepAlive?: boolean; reconnectionDelay?: number; responseType?: 'event' }, requestOptions?: SseRequestOptions, method?: string): Observable<Event>;\n\n /**\n * Constructs a request which listen to the SSE and interprets the data as a\n * string text and returns the full event stream.\n *\n * @param url the endpoint URL.\n * @param options an object of `SseOption`\n * @param requestOptions the HTTP options to send with the request.\n * @param method the HTTP method\n *\n * @returns an observable of all events for the request, with the response body of type string.\n */\n public stream(url: string, options?: { keepAlive?: boolean; reconnectionDelay?: number; responseType?: 'text' }, requestOptions?: SseRequestOptions, method?: string): Observable<string>;\n\n public stream(url: string, options?: Partial<SseOptions>, requestOptions?: Partial<SseRequestOptions>, method = 'GET'): Observable<string | Event> {\n var sseOptions: SseOptions = Object.assign({}, defaultSseOptions, options);\n var httpClientOptions: any = Object.assign({}, requestOptions as any, defaultRequestOptions);\n\n return new SseClientSubscriber(this.httpClient, sseOptions, httpClientOptions, url, method).createObservable();\n }\n}\n","/*\n * Public API Surface of ngx-sse-client\n */\nexport * from './lib/sse-client.service';\nexport * from './lib/sse-error-event.interface';\nexport * from './lib/sse-options.interface';\nexport * from './lib/sse-request-options.interface';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}