{ "version": 3, "sources": ["libs/rx-utils/src/lib/subscription-list.ts", "libs/rx-utils/work-state/src/manual-start-work-state-map.ts", "libs/rx-utils/work-state/src/observable-work-state-map.ts", "libs/rx-utils/work-state/src/switching-work-state.ts", "libs/rx-utils/work-state/observable/src/helpers.ts"], "sourcesContent": ["import { Observable, Subscription } from 'rxjs';\n\nexport class SubscriptionList {\n static new(): SubscriptionList {\n return new SubscriptionList();\n }\n\n static fromList(list: Subscription[]): SubscriptionList {\n return new SubscriptionList(Array.from(list));\n }\n\n private constructor(private readonly subscriptions: Subscription[] = []) {}\n\n destroy(): void {\n this.subscriptions.forEach((s) => s.unsubscribe());\n }\n\n add(inputs: Observable, subscriptionFunction?: (T: any) => void): void {\n this.subscriptions.push(inputs.subscribe(subscriptionFunction));\n }\n\n addSub(subscription: Subscription): void {\n this.subscriptions.push(subscription);\n }\n\n asList(): Subscription[] {\n return Array.from(this.subscriptions);\n }\n\n addAll(...subs: Subscription[]): void {\n this.subscriptions.push(...subs);\n }\n}\n", "import { Observable, ReplaySubject, Subject } from 'rxjs';\nimport { distinctUntilChanged, filter, map, scan, share, shareReplay, startWith } from 'rxjs/operators';\nimport { WorkStateMap } from './work-state-map';\n\ninterface State {\n id: ID;\n isExpired: boolean;\n}\n\ninterface Status {\n id: ID;\n isSuccess: boolean;\n}\n\ninterface Result {\n id: ID;\n result: RESULT;\n}\n\nfunction getById(obs: Observable>, id: ID): Observable {\n return obs.pipe(\n filter((allResults) => allResults.has(id)),\n map((filteredResults) => filteredResults.get(id) as RESULT),\n ) as Observable;\n}\n\n/*\n * A WorkStateMap where individual units of work are started by explicitly\n * invoking the `startWork` function.\n */\nexport class ManualStartWorkStateMap implements WorkStateMap {\n private loading$$: Subject> = new ReplaySubject(1);\n public readonly loading$: Observable>;\n private readonly status$$: Subject> = new Subject();\n public readonly success$: Observable>;\n public readonly successEvents$: Observable>;\n private results$$: Subject> = new Subject();\n private resultsMap$$: Subject> = new ReplaySubject(1);\n public readonly results$: Observable> = this.resultsMap$$.pipe(shareReplay(1));\n\n constructor(private readonly logErrors = true) {\n this.loading$ = this.loading$$.asObservable().pipe(\n scan, Map>((prevVal, newVal) => {\n if (newVal.isExpired) {\n prevVal.delete(newVal.id);\n } else {\n prevVal.set(newVal.id, undefined);\n }\n return prevVal;\n }, new Map()),\n shareReplay(1),\n );\n this.results$$\n .asObservable()\n .pipe(\n scan, Map>((prevVal, newVal) => {\n prevVal.set(newVal.id, newVal.result);\n return prevVal;\n }, new Map()),\n )\n .subscribe(this.resultsMap$$);\n this.successEvents$ = this.status$$.asObservable().pipe(\n scan, Map>((prevMap, status) => {\n prevMap.set(status.id, status.isSuccess);\n return prevMap;\n }, new Map()),\n share(),\n );\n const successSink = new ReplaySubject>(1);\n this.successEvents$.subscribe(successSink);\n this.success$ = successSink.asObservable();\n }\n\n isLoading$(someId: ID): Observable {\n return this.loading$.pipe(\n map((allWork) => allWork.has(someId)),\n startWith(false),\n distinctUntilChanged(),\n );\n }\n\n startWork(\n id: ID,\n work: (onFinish: (result: RESULT) => void, onFailure: () => void) => void,\n fallbackResult?: RESULT,\n ): void {\n this.loading$$.next({\n id: id,\n isExpired: false,\n });\n const onSuccess = (result: RESULT) => {\n this.handleSuccess(id, result);\n };\n const onFail = () => {\n this.handleFailure(id, fallbackResult);\n };\n\n const safeWork = () => {\n try {\n work(onSuccess, onFail);\n } catch (e) {\n if (this.logErrors) {\n console.error(e);\n }\n onFail();\n }\n };\n\n safeWork();\n }\n\n private handleSuccess(id: ID, result: RESULT): void {\n this.loading$$.next({\n id: id,\n isExpired: true,\n });\n this.status$$.next({\n id: id,\n isSuccess: true,\n });\n this.results$$.next({\n id: id,\n result: result,\n });\n }\n\n private handleFailure(id: ID, fallbackResult?: RESULT): void {\n this.loading$$.next({\n id: id,\n isExpired: true,\n });\n this.status$$.next({\n id: id,\n isSuccess: false,\n });\n if (this.fallbackResultIsProvided(fallbackResult)) {\n this.results$$.next({\n id: id,\n result: fallbackResult as RESULT,\n });\n }\n }\n\n private fallbackResultIsProvided(result?: RESULT): boolean {\n // TODO: Support null results, too.\n return result !== null && result !== undefined;\n }\n\n isSuccess$(someId: ID): Observable {\n return getById(this.success$, someId).pipe(distinctUntilChanged());\n }\n\n successEvent$(someId: ID): Observable {\n return getById(this.successEvents$, someId);\n }\n\n getWorkResults$(someId: ID): Observable {\n return getById(this.results$, someId).pipe(distinctUntilChanged(), shareReplay(1));\n }\n}\n", "import { Observable } from 'rxjs';\nimport { take } from 'rxjs/operators';\nimport { ManualStartWorkStateMap } from './manual-start-work-state-map';\nimport { WorkStateMap } from './work-state-map';\n\n/**\n * WorkStateMap which allows observables to be supplied as the work. The WSM will\n * attempt to resolve a single result form the observable. If it succeeds, the\n * map will use its results and update accordingly. Likewise, if it fails it\n * will update its statuses.\n *\n * To start work, provide a promise like:\n * ```typescript\n * const wsm = new ObservableWorkStateMap();\n * wsm.startWork('foo', myObservable$);\n * ```\n */\nexport class ObservableWorkStateMap implements WorkStateMap {\n private delegate = new ManualStartWorkStateMap(this.logErrors);\n\n constructor(private readonly logErrors = true) {}\n\n startWork(someId: ID, work: Observable, fallbackValue?: RESULT): void {\n this.delegate.startWork(\n someId,\n (onFinish, onFailure) => {\n work.pipe(take(1)).subscribe(onFinish, (err) => {\n if (this.logErrors) {\n console.error(err);\n }\n onFailure();\n });\n },\n fallbackValue,\n );\n }\n\n getWorkResults$(someId: ID): Observable {\n return this.delegate.getWorkResults$(someId);\n }\n\n isLoading$(someId: ID): Observable {\n return this.delegate.isLoading$(someId);\n }\n\n isSuccess$(someId: ID): Observable {\n return this.delegate.isSuccess$(someId);\n }\n\n successEvent$(someId: ID): Observable {\n return this.delegate.successEvent$(someId);\n }\n}\n", "import { EMPTY, merge, Observable, ReplaySubject, Subject, Subscription } from 'rxjs';\nimport { catchError, distinctUntilChanged, mapTo, share, shareReplay, startWith, switchMap } from 'rxjs/operators';\nimport { WorkStates } from './work-states';\n\nexport class SwitchingWorkState implements WorkStates {\n readonly workResults$: Observable;\n readonly isLoading$: Observable;\n readonly isSuccess$: Observable;\n private readonly successEvents$$ = new Subject();\n readonly successEvents$: Observable = this.successEvents$$.pipe(share());\n private readonly inputs$$ = new ReplaySubject(1);\n readonly subscriptions: Subscription[] = [];\n\n constructor(private inputHandler: (i: INPUT) => Observable, logErrors = true) {\n const errors$ = new ReplaySubject(1);\n if (logErrors) {\n this.subscriptions.push(errors$.subscribe(console.error));\n }\n this.workResults$ = this.inputs$$.pipe(\n switchMap((i: INPUT) =>\n this.inputHandler(i).pipe(\n catchError((err) => {\n errors$.next(err);\n return EMPTY;\n }),\n ),\n ),\n shareReplay({ refCount: true, bufferSize: 1 }),\n );\n this.isLoading$ = merge(\n errors$.pipe(mapTo(false)),\n this.inputs$$.pipe(mapTo(true)),\n this.workResults$.pipe(mapTo(false)),\n ).pipe(startWith(false), distinctUntilChanged());\n const uniqueSuccess$ = merge(this.workResults$.pipe(mapTo(true)), errors$.pipe(mapTo(false)));\n this.isSuccess$ = uniqueSuccess$.pipe(distinctUntilChanged());\n this.subscriptions.push(uniqueSuccess$.subscribe(this.successEvents$$));\n }\n\n updateInputHandler(inputHandler: (i: INPUT) => Observable): void {\n this.inputHandler = inputHandler;\n }\n\n startWork(param: INPUT): void {\n this.inputs$$.next(param);\n }\n\n destroy(): void {\n this.subscriptions.forEach((s) => s.unsubscribe());\n }\n}\n", "import { Observable, race, SchedulerLike, of } from 'rxjs';\nimport { delay, share, switchMap } from 'rxjs/operators';\n\nexport interface ObservableWorkMap {\n startWork(someId: I, work: Observable): void;\n getWorkResults$(someId: I): Observable;\n}\n\n/**\n * Will execute the given work when there is no value in the given WorkStateMap\n * for the given ID.\n */\nexport function startWorkIfInitial(\n workId: I,\n stateMap: ObservableWorkMap,\n work: () => Observable,\n scheduler?: SchedulerLike,\n): Observable {\n const o = workIfInitial$(workId, stateMap, work, scheduler);\n o.subscribe();\n return o;\n}\n\n/**\n * Will execute the given work when the following conditions are true:\n * - There is no value in the given WorkStateMap for the given ID\n * - A subscriber has been added to the observable returned from this function\n */\nexport function startWorkIfNeededForSubscriber(\n workID: I,\n stateMap: ObservableWorkMap,\n work: () => Observable,\n scheduler?: SchedulerLike,\n): Observable {\n return of('').pipe(\n switchMap(() => {\n // SwitchMap causes this work to only happen after a subscriber is added\n return workIfInitial$(workID, stateMap, work, scheduler);\n }),\n );\n}\n\nfunction workIfInitial$(\n workId: I,\n stateMap: ObservableWorkMap,\n work: () => Observable,\n scheduler?: SchedulerLike,\n): Observable {\n const workWithDelay: Observable = of(workId).pipe(\n delay(10, scheduler),\n switchMap((id: I) => {\n stateMap.startWork(id, work());\n return stateMap.getWorkResults$(workId);\n }),\n share(),\n );\n return race(workWithDelay, stateMap.getWorkResults$(workId));\n}\n\n// This function can be called to immediate store a result in a work state map.\n// Useful if you have already run the work, but just want to publish the result\n// to anyone who is subscribed to the given stateMap's workResults.\nexport function applyFinishedWork(stateMap: ObservableWorkMap, id: ID, result: RESULT): void {\n stateMap.startWork(id, of(result));\n}\n"], "mappings": "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", "names": ["SubscriptionList", "new", "fromList", "list", "Array", "from", "constructor", "subscriptions", "destroy", "forEach", "s", "unsubscribe", "add", "inputs", "subscriptionFunction", "push", "subscribe", "addSub", "subscription", "asList", "addAll", "subs", "getById", "obs", "id", "pipe", "filter", "allResults", "has", "map", "filteredResults", "get", "ManualStartWorkStateMap", "constructor", "logErrors", "loading$$", "ReplaySubject", "status$$", "Subject", "results$$", "resultsMap$$", "results$", "shareReplay", "loading$", "asObservable", "scan", "prevVal", "newVal", "isExpired", "delete", "set", "undefined", "Map", "result", "subscribe", "successEvents$", "prevMap", "status", "isSuccess", "share", "successSink", "success$", "isLoading$", "someId", "allWork", "startWith", "distinctUntilChanged", "startWork", "work", "fallbackResult", "next", "onSuccess", "handleSuccess", "onFail", "handleFailure", "safeWork", "e", "console", "error", "fallbackResultIsProvided", "isSuccess$", "successEvent$", "getWorkResults$", "ObservableWorkStateMap", "constructor", "logErrors", "delegate", "ManualStartWorkStateMap", "startWork", "someId", "work", "fallbackValue", "onFinish", "onFailure", "pipe", "take", "subscribe", "err", "console", "error", "getWorkResults$", "isLoading$", "isSuccess$", "successEvent$", "SwitchingWorkState", "constructor", "inputHandler", "logErrors", "successEvents$$", "Subject", "successEvents$", "pipe", "share", "inputs$$", "ReplaySubject", "subscriptions", "errors$", "push", "subscribe", "console", "error", "workResults$", "switchMap", "i", "catchError", "err", "next", "EMPTY", "shareReplay", "refCount", "bufferSize", "isLoading$", "merge", "mapTo", "startWith", "distinctUntilChanged", "uniqueSuccess$", "isSuccess$", "updateInputHandler", "startWork", "param", "destroy", "forEach", "s", "unsubscribe", "startWorkIfNeededForSubscriber", "workID", "stateMap", "work", "scheduler", "of", "pipe", "switchMap", "workIfInitial$", "workId", "workWithDelay", "delay", "id", "startWork", "getWorkResults$", "share", "race", "applyFinishedWork", "result"] }