import { Subject, BehaviorSubject, of, Observable, Observer, throwError } from 'rxjs' import { concatMap, map, catchError, filter, take } from 'rxjs/operators' export type Action = { action: () => T, notify: BehaviorSubject } export class ActionSerializer { private readonly sequentialActions = new Subject>() constructor () { this.sequentialActions.pipe( concatMap(({ action, notify }) => fromSync$(action).pipe( catchError(e => of(notify.next({ error: e }))), map(result => notify.next({ result })), )), catchError(e => of(console.error(`Action Serializer Exception`, e))), ).subscribe() } run$ (action: () => T): Observable { const notify = new BehaviorSubject(undefined) as BehaviorSubject this.sequentialActions.next({ action, notify }) return (notify as BehaviorSubject).pipe( filter(res => res !== undefined), take(1), concatMap((res: any) => res.error ? throwError(res.error) : of(res.result)), ) } } function fromSync$ (action: (s: S) => T, s: S): Observable function fromSync$ (action: () => T): Observable function fromSync$ (action: (s: S) => T, s?: S): Observable { return new Observable((subscriber: Observer) => { try { subscriber.next(action(s as S)) subscriber.complete() } catch (e) { subscriber.error(e) } }) }