UNPKG

ngrx-loading-state

Version:

NgRx Loading State consistently manages loading actions such as API fetches.

166 lines 28.1 kB
import { createEffect, ofType } from '@ngrx/effects'; import { createSelector, on } from '@ngrx/store'; import { catchError, groupBy, mergeMap, of, pipe } from 'rxjs'; import { cloneLoadingState, combineLoadingStates, getNewFailureState, getNewLoadState, getNewSuccessState } from '../loading-state/loading-state-functions'; /** * IdLoadingAction is similar to LoadingAction with the difference that it's parameterized on a user provided ID. * */ export class IdLoadingActions { constructor(options) { // Could have used createActionGroup() but the string literal typing of Source is giving me trouble. For now, // just separate types. this.idLoad = options.idLoad; this.idSuccess = options.idSuccess; this.idFailure = options.idFailure; } // ---------------------------------------------------------------------------- // Typing // ---------------------------------------------------------------------------- instanceOfIdLoad(action) { return action.type === this.idLoad.type; } instanceOfIdSuccess(action) { return action.type === this.idSuccess.type; } instanceOfIdFailure(action) { return action.type === this.idFailure.type; } // ------------------------------------------------------------------------------------------------ // Reducer // ------------------------------------------------------------------------------------------------ reducer(options) { const { onLoad, onSuccess, onFailure } = options || {}; return [ on(this.idLoad, (state, action) => { // Reducer must always create a new copy of the state. const newState = { ...state, idLoadingStates: this.setState(getNewLoadState, action, state.idLoadingStates) }; // The updated loadingStates is passed to the user code for maximum // flexibility in case the user wishes to change the loadingStates. return (onLoad ? onLoad(newState, action) : newState); }), on(this.idSuccess, (state, action) => { const newState = { ...state, idLoadingStates: this.setState(getNewSuccessState, action, state.idLoadingStates) }; return (onSuccess ? onSuccess(newState, action) : newState); }), on(this.idFailure, (state, action) => { const newState = { ...state, idLoadingStates: this.setState(getNewFailureState, action, state.idLoadingStates) }; return (onFailure ? onFailure(newState, action) : newState); }) ]; } catchError(id) { return catchError((error) => { return of( // AZ: Casting to "any" is less than ideal. But just can't figure out the complex typing here. this.idFailure({ id, error })); }); } // ---------------------------------------------------------------------------- // Selectors // ---------------------------------------------------------------------------- /** * Returns a map of selectors for loading, success, error, and the entire state. * The advantage of doing it in a bundle is that we can share the result of createStateSelector(), * if we separated into individual functions, each function might need to call createStateSelector() * to create a new instance of the selector. We can't cache any created selectors because will cause * memory leak since the cached references are always help in this class and hence does not get released. * @param selectLoadingStates Selector that returns the loadingStats of the feature slice. You can use createLoadingStatesSelector() * to create it. * @returns A collection of selectors * state: the LoadingState * loading: True if loading * success: True if last load was successful * error: LrError2 object if previous loading failed. * */ createIdSelectors(selectIdLoadingStates) { const selectIdLoadingStateMap = createSelector(selectIdLoadingStates, (idLoadingStates) => idLoadingStates[this.key]); const state = (id) => { return createSelector(selectIdLoadingStateMap, (idLoadingStateMap) => this.getIdLoadingState(idLoadingStateMap, id)); }; const loading = (id) => { return createSelector(state(id), (idLoadingState) => idLoadingState.loading); }; const success = (id) => { return createSelector(state(id), (idLoadingState) => idLoadingState.success); }; const error = (id) => { return createSelector(state(id), (idLoadingState) => idLoadingState.error); }; const combinedState = createSelector(selectIdLoadingStateMap, (idLoadingStateMap) => { return combineLoadingStates(idLoadingStateMap ? Object.values(idLoadingStateMap) : []); }); return { state, loading, success, error, combinedState }; } // ---------------------------------------------------------------------------- // Effects // ---------------------------------------------------------------------------- idLoadHandler(fetch) { return pipe(ofType(this.idLoad), (source) => { // Below is inspired by: https://github.com/nrwl/nx/blob/master/packages/angular/src/runtime/nx/data-persistence.ts#L75 const groupedFetches = source.pipe(groupBy((action) => { return action.id; // This will be used as the "group.key" })); return groupedFetches.pipe(mergeMap((group) => { return fetch(group, group.key); })); }); } createEffect(actions$, fetch) { return createEffect(() => { return actions$.pipe(this.idLoadHandler(fetch)); }); } // ---------------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------------- get key() { return this.idLoad.type; } getIdLoadingState(idLoadingStateMap, id) { if (id == null || id === '') { throw new Error('id parameter is null or empty string, this is almost always a logic bug.'); } // We should not be modifying the state without going via the reducer, hence // returning the immutable "init" object. return idLoadingStateMap?.[id]; } setState(getNewState, action, idLoadingStates) { const currentState = cloneLoadingState(idLoadingStates[this.key]?.[action.id]); const newState = getNewState(action, currentState); if (newState) { // Return new reference only when the state has changed. return { ...idLoadingStates, [this.key]: { ...idLoadingStates[this.key], [action.id]: { ...newState, isIdLoadingState: true, id: action.id } } }; } else { // No change in state, so no change in parent state. return idLoadingStates; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWQtbG9hZGluZy1zdGF0ZS1hY3Rpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmdyeC1sb2FkaW5nLXN0YXRlL3NyYy9saWIvaWQtbG9hZGluZy1zdGF0ZS9pZC1sb2FkaW5nLXN0YXRlLWFjdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFXLFlBQVksRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUQsT0FBTyxFQUFVLGNBQWMsRUFBd0MsRUFBRSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRS9GLE9BQU8sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBYyxFQUFFLEVBQUUsSUFBSSxFQUFpQixNQUFNLE1BQU0sQ0FBQztBQUMxRixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLG9CQUFvQixFQUNwQixrQkFBa0IsRUFDbEIsZUFBZSxFQUNmLGtCQUFrQixFQUNuQixNQUFNLDBDQUEwQyxDQUFDO0FBa0JsRDs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sZ0JBQWdCO0lBUzNCLFlBQVksT0FJWDtRQUNDLDZHQUE2RztRQUM3Ryx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQzdCLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFHLE9BQU8sQ0FBQyxTQUFTLENBQUM7SUFDckMsQ0FBQztJQUVELCtFQUErRTtJQUMvRSxTQUFTO0lBQ1QsK0VBQStFO0lBQy9FLGdCQUFnQixDQUNkLE1BQWM7UUFFZCxPQUFPLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUM7SUFDMUMsQ0FBQztJQUVELG1CQUFtQixDQUNqQixNQUFjO1FBRWQsT0FBTyxNQUFNLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxTQUFT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LENBQUMsQ0FBQztRQUMvRSxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsTUFBTSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBRW5ELElBQUksUUFBUSxFQUFFO1lBQ1osd0RBQXdEO1lBQ3hELE9BQU87Z0JBQ0wsR0FBRyxlQUFlO2dCQUNsQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRTtvQkFDVixHQUFHLGVBQWUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO29CQUM1QixDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLEdBQUcsUUFBUSxFQUFFLGdCQUFnQixFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLEVBQUUsRUFBRTtpQkFDcEU7YUFDRixDQUFDO1NBQ0g7YUFBTTtZQUNMLG9EQUFvRDtZQUNwRCxPQUFPLGVBQWUsQ0FBQztTQUN4QjtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEFjdGlvbnMsIGNyZWF0ZUVmZmVjdCwgb2ZUeXBlIH0gZnJvbSAnQG5ncngvZWZmZWN0cyc7XG5pbXBvcnQgeyBBY3Rpb24sIGNyZWF0ZVNlbGVjdG9yLCBEZWZhdWx0UHJvamVjdG9yRm4sIE1lbW9pemVkU2VsZWN0b3IsIG9uIH0gZnJvbSAnQG5ncngvc3RvcmUnO1xuaW1wb3J0IHsgVHlwZWRBY3Rpb24gfSBmcm9tICdAbmdyeC9zdG9yZS9zcmMvbW9kZWxzJztcbmltcG9ydCB7IGNhdGNoRXJyb3IsIGdyb3VwQnksIG1lcmdlTWFwLCBPYnNlcnZhYmxlLCBvZiwgcGlwZSwgVW5hcnlGdW5jdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHtcbiAgY2xvbmVMb2FkaW5nU3RhdGUsXG4gIGNvbWJpbmVMb2FkaW5nU3RhdGVzLFxuICBnZXROZXdGYWlsdXJlU3RhdGUsXG4gIGdldE5ld0xvYWRTdGF0ZSxcbiAgZ2V0TmV3U3VjY2Vzc1N0YXRlXG59IGZyb20gJy4uL2xvYWRpbmctc3RhdGUvbG9hZGluZy1zdGF0ZS1mdW5jdGlvbnMnO1xuaW1wb3J0IHtcbiAgQWN0aW9uRmFjdG9yeVJlc3VsdCxcbiAgTG9hZGluZ0FjdGlvbnNSZWR1Y2VyVHlwZXMsXG4gIExvYWRpbmdTdGF0ZSxcbiAgT25TdGF0ZVxufSBmcm9tICcuLi9sb2FkaW5nLXN0YXRlL2xvYWRpbmctc3RhdGUtdHlwZXMnO1xuaW1wb3J0IHtcbiAgSWQsXG4gIElkRmFpbHVyZUFjdGlvbixcbiAgSWRMb2FkQWN0aW9uLFxuICBJZExvYWRpbmdTdGF0ZSxcbiAgSWRMb2FkaW5nU3RhdGVNYXAsXG4gIElkTG9hZGluZ1N0YXRlcyxcbiAgSWRTdWNjZXNzQWN0aW9uLFxuICBXaXRoSWRMb2FkaW5nU3RhdGVzT25seVxufSBmcm9tICcuL2lkLWxvYWRpbmctc3RhdGUtdHlwZXMnO1xuXG4vKipcbiAqIElkTG9hZGluZ0FjdGlvbiBpcyBzaW1pbGFyIHRvIExvYWRpbmdBY3Rpb24gd2l0aCB0aGUgZGlmZmVyZW5jZSB0aGF0IGl0J3MgcGFyYW1ldGVyaXplZCBvbiBhIHVzZXIgcHJvdmlkZWQgSUQuXG4gKlxuICovXG5leHBvcnQgY2xhc3MgSWRMb2FkaW5nQWN0aW9uczxcbiAgTG9hZFBheWxvYWRUeXBlIGV4dGVuZHMgb2JqZWN0LFxuICBTdWNjZXNzUGF5bG9hZFR5cGUgZXh0ZW5kcyBvYmplY3QsXG4gIEZhaWx1cmVQYXlsb2FkVHlwZSBleHRlbmRzIG9iamVjdFxuPiB7XG4gIHJlYWRvbmx5IGlkTG9hZDogQWN0aW9uRmFjdG9yeVJlc3VsdDxJZExvYWRBY3Rpb24gJiBMb2FkUGF5bG9hZFR5cGU+O1xuICByZWFkb25seSBpZFN1Y2Nlc3M6IEFjdGlvbkZhY3RvcnlSZXN1bHQ8SWRTdWNjZXNzQWN0aW9uICYgU3VjY2Vzc1BheWxvYWRUeXBlPjtcbiAgcmVhZG9ubHkgaWRGYWlsdXJlOiBBY3Rpb25GYWN0b3J5UmVzdWx0PElkRmFpbHVyZUFjdGlvbiAmIEZhaWx1cmVQYXlsb2FkVHlwZT47XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczoge1xuICAgIGlkTG9hZDogQWN0aW9uRmFjdG9yeVJlc3VsdDxJZExvYWRBY3Rpb24gJiBMb2FkUGF5bG9hZFR5cGU+O1xuICAgIGlkU3VjY2VzczogQWN0aW9uRmFjdG9yeVJlc3VsdDxJZFN1Y2Nlc3NBY3Rpb24gJiBTdWNjZXNzUGF5bG9hZFR5cGU+O1xuICAgIGlkRmFpbHVyZTogQWN0aW9uRmFjdG9yeVJlc3VsdDxJZEZhaWx1cmVBY3Rpb24gJiBGYWlsdXJlUGF5bG9hZFR5cGU+O1xuICB9KSB7XG4gICAgLy8gQ291bGQgaGF2ZSB1c2VkIGNyZWF0ZUFjdGlvbkdyb3VwKCkgYnV0IHRoZSBzdHJpbmcgbGl0ZXJhbCB0eXBpbmcgb2YgU291cmNlIGlzIGdpdmluZyBtZSB0cm91YmxlLiBGb3Igbm93LFxuICAgIC8vIGp1c3Qgc2VwYXJhdGUgdHlwZXMuXG4gICAgdGhpcy5pZExvYWQgPSBvcHRpb25zLmlkTG9hZDtcbiAgICB0aGlzLmlkU3VjY2VzcyA9IG9wdGlvbnMuaWRTdWNjZXNzO1xuICAgIHRoaXMuaWRGYWlsdXJlID0gb3B0aW9ucy5pZEZhaWx1cmU7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIFR5cGluZ1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIGluc3RhbmNlT2ZJZExvYWQoXG4gICAgYWN0aW9uOiBBY3Rpb25cbiAgKTogYWN0aW9uIGlzIFJldHVyblR5cGU8QWN0aW9uRmFjdG9yeVJlc3VsdDxJZExvYWRBY3Rpb24gJiBMb2FkUGF5bG9hZFR5cGU+PiB7XG4gICAgcmV0dXJuIGFjdGlvbi50eXBlID09PSB0aGlzLmlkTG9hZC50eXBlO1xuICB9XG5cbiAgaW5zdGFuY2VPZklkU3VjY2VzcyhcbiAgICBhY3Rpb246IEFjdGlvblxuICApOiBhY3Rpb24gaXMgUmV0dXJuVHlwZTxBY3Rpb25GYWN0b3J5UmVzdWx0PElkU3VjY2Vzc0FjdGlvbiAmIFN1Y2Nlc3NQYXlsb2FkVHlwZT4+IHtcbiAgICByZXR1cm4gYWN0aW9uLnR5cGUgPT09IHRoaXMuaWRTdWNjZXNzLnR5cGU7XG4gIH1cblxuICBpbnN0YW5jZU9mSWRGYWlsdXJlKFxuICAgIGFjdGlvbjogQWN0aW9uXG4gICk6IGFjdGlvbiBpcyBSZXR1cm5UeXBlPEFjdGlvbkZhY3RvcnlSZXN1bHQ8SWRGYWlsdXJlQWN0aW9uICYgRmFpbHVyZVBheWxvYWRUeXBlPj4ge1xuICAgIHJldHVybiBhY3Rpb24udHlwZSA9PT0gdGhpcy5pZEZhaWx1cmUudHlwZTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBSZWR1Y2VyXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICByZWR1Y2VyPFN0YXRlIGV4dGVuZHMgV2l0aElkTG9hZGluZ1N0YXRlc09ubHk+KG9wdGlvbnM/OiB7XG4gICAgb25Mb2FkPzogKFxuICAgICAgc3RhdGU6IE9uU3RhdGU8U3RhdGU+LFxuICAgICAgYWN0aW9uOiBJZExvYWRBY3Rpb24gJiBMb2FkUGF5bG9hZFR5cGUgJiBUeXBlZEFjdGlvbjxzdHJpbmc+XG4gICAgKSA9PiBTdGF0ZTtcbiAgICBvblN1Y2Nlc3M/OiAoXG4gICAgICBzdGF0ZTogT25TdGF0ZTxTdGF0ZT4sXG4gICAgICBhY3Rpb246IElkU3VjY2Vzc0FjdGlvbiAmIFN1Y2Nlc3NQYXlsb2FkVHlwZSAmIFR5cGVkQWN0aW9uPHN0cmluZz5cbiAgICApID0+IFN0YXRlO1xuICAgIG9uRmFpbHVyZT86IChcbiAgICAgIHN0YXRlOiBPblN0YXRlPFN0YXRlPixcbiAgICAgIGFjdGlvbjogSWRGYWlsdXJlQWN0aW9uICYgRmFpbHVyZVBheWxvYWRUeXBlICYgVHlwZWRBY3Rpb248c3RyaW5nPlxuICAgICkgPT4gU3RhdGU7XG4gIH0pOiBbXG4gICAgTG9hZGluZ0FjdGlvbnNSZWR1Y2VyVHlwZXM8U3RhdGU+LFxuICAgIExvYWRpbmdBY3Rpb25zUmVkdWNlclR5cGVzPFN0YXRlPixcbiAgICBMb2FkaW5nQWN0aW9uc1JlZHVjZXJUeXBlczxTdGF0ZT5cbiAgXSB7XG4gICAgY29uc3QgeyBvbkxvYWQsIG9uU3VjY2Vzcywgb25GYWlsdXJlIH0gPSBvcHRpb25zIHx8IHt9O1xuICAgIHJldHVybiBbXG4gICAgICBvbih0aGlzLmlkTG9hZCwgKHN0YXRlLCBhY3Rpb24pID0+IHtcbiAgICAgICAgLy8gUmVkdWNlciBtdXN0IGFsd2F5cyBjcmVhdGUgYSBuZXcgY29weSBvZiB0aGUgc3RhdGUuXG4gICAgICAgIGNvbnN0IG5ld1N0YXRlID0ge1xuICAgICAgICAgIC4uLnN0YXRlLFxuICAgICAgICAgIGlkTG9hZGluZ1N0YXRlczogdGhpcy5zZXRTdGF0ZShnZXROZXdMb2FkU3RhdGUsIGFjdGlvbiwgc3RhdGUuaWRMb2FkaW5nU3RhdGVzKVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFRoZSB1cGRhdGVkIGxvYWRpbmdTdGF0ZXMgaXMgcGFzc2VkIHRvIHRoZSB1c2VyIGNvZGUgZm9yIG1heGltdW1cbiAgICAgICAgLy8gZmxleGliaWxpdHkgaW4gY2FzZSB0aGUgdXNlciB3aXNoZXMgdG8gY2hhbmdlIHRoZSBsb2FkaW5nU3RhdGVzLlxuICAgICAgICByZXR1cm4gKG9uTG9hZCA/IG9uTG9hZChuZXdTdGF0ZSwgYWN0aW9uKSA6IG5ld1N0YXRlKSBhcyBPblN0YXRlPFN0YXRlPjtcbiAgICAgIH0pLFxuICAgICAgb24odGhpcy5pZFN1Y2Nlc3MsIChzdGF0ZSwgYWN0aW9uKSA9PiB7XG4gICAgICAgIGNvbnN0IG5ld1N0YXRlID0ge1xuICAgICAgICAgIC4uLnN0YXRlLFxuICAgICAgICAgIGlkTG9hZGluZ1N0YXRlczogdGhpcy5zZXRTdGF0ZShnZXROZXdTdWNjZXNzU3RhdGUsIGFjdGlvbiwgc3RhdGUuaWRMb2FkaW5nU3RhdGVzKVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAob25TdWNjZXNzID8gb25TdWNjZXNzKG5ld1N0YXRlLCBhY3Rpb24pIDogbmV3U3RhdGUpIGFzIE9uU3RhdGU8U3RhdGU+O1xuICAgICAgfSksXG4gICAgICBvbih0aGlzLmlkRmFpbHVyZSwgKHN0YXRlLCBhY3Rpb24pID0+IHtcbiAgICAgICAgY29uc3QgbmV3U3RhdGUgPSB7XG4gICAgICAgICAgLi4uc3RhdGUsXG4gICAgICAgICAgaWRMb2FkaW5nU3RhdGVzOiB0aGlzLnNldFN0YXRlKGdldE5ld0ZhaWx1cmVTdGF0ZSwgYWN0aW9uLCBzdGF0ZS5pZExvYWRpbmdTdGF0ZXMpXG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIChvbkZhaWx1cmUgPyBvbkZhaWx1cmUobmV3U3RhdGUsIGFjdGlvbikgOiBuZXdTdGF0ZSkgYXMgT25TdGF0ZTxTdGF0ZT47XG4gICAgICB9KVxuICAgIF07XG4gIH1cblxuICBjYXRjaEVycm9yKGlkOiBJZCk6IFJldHVyblR5cGU8dHlwZW9mIGNhdGNoRXJyb3I+IHtcbiAgICByZXR1cm4gY2F0Y2hFcnJvcigoZXJyb3IpID0+IHtcbiAgICAgIHJldHVybiBvZihcbiAgICAgICAgLy8gQVo6IENhc3RpbmcgdG8gXCJhbnlcIiBpcyBsZXNzIHRoYW4gaWRlYWwuIEJ1dCBqdXN0IGNhbid0IGZpZ3VyZSBvdXQgdGhlIGNvbXBsZXggdHlwaW5nIGhlcmUuXG4gICAgICAgIHRoaXMuaWRGYWlsdXJlKHtcbiAgICAgICAgICBpZCxcbiAgICAgICAgICBlcnJvclxuICAgICAgICB9IGFzIGFueSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIFNlbGVjdG9yc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbWFwIG9mIHNlbGVjdG9ycyBmb3IgbG9hZGluZywgc3VjY2VzcywgZXJyb3IsIGFuZCB0aGUgZW50aXJlIHN0YXRlLlxuICAgKiBUaGUgYWR2YW50YWdlIG9mIGRvaW5nIGl0IGluIGEgYnVuZGxlIGlzIHRoYXQgd2UgY2FuIHNoYXJlIHRoZSByZXN1bHQgb2YgY3JlYXRlU3RhdGVTZWxlY3RvcigpLFxuICAgKiBpZiB3ZSBzZXBhcmF0ZWQgaW50byBpbmRpdmlkdWFsIGZ1bmN0aW9ucywgZWFjaCBmdW5jdGlvbiBtaWdodCBuZWVkIHRvIGNhbGwgY3JlYXRlU3RhdGVTZWxlY3RvcigpXG4gICAqIHRvIGNyZWF0ZSBhIG5ldyBpbnN0YW5jZSBvZiB0aGUgc2VsZWN0b3IuIFdlIGNhbid0IGNhY2hlIGFueSBjcmVhdGVkIHNlbGVjdG9ycyBiZWNhdXNlIHdpbGwgY2F1c2VcbiAgICogbWVtb3J5IGxlYWsgc2luY2UgdGhlIGNhY2hlZCByZWZlcmVuY2VzIGFyZSBhbHdheXMgaGVscCBpbiB0aGlzIGNsYXNzIGFuZCBoZW5jZSBkb2VzIG5vdCBnZXQgcmVsZWFzZWQuXG4gICAqIEBwYXJhbSBzZWxlY3RMb2FkaW5nU3RhdGVzIFNlbGVjdG9yIHRoYXQgcmV0dXJucyB0aGUgbG9hZGluZ1N0YXRzIG9mIHRoZSBmZWF0dXJlIHNsaWNlLiBZb3UgY2FuIHVzZSBjcmVhdGVMb2FkaW5nU3RhdGVzU2VsZWN0b3IoKVxuICAgKiAgIHRvIGNyZWF0ZSBpdC5cbiAgICogQHJldHVybnMgQSBjb2xsZWN0aW9uIG9mIHNlbGVjdG9yc1xuICAgKiAgIHN0YXRlOiB0aGUgTG9hZGluZ1N0YXRlXG4gICAqICAgbG9hZGluZzogVHJ1ZSBpZiBsb2FkaW5nXG4gICAqICAgc3VjY2VzczogVHJ1ZSBpZiBsYXN0IGxvYWQgd2FzIHN1Y2Nlc3NmdWxcbiAgICogICBlcnJvcjogTHJFcnJvcjIgb2JqZWN0IGlmIHByZXZpb3VzIGxvYWRpbmcgZmFpbGVkLlxuICAgKlxuICAgKi9cbiAgY3JlYXRlSWRTZWxlY3RvcnMoXG4gICAgc2VsZWN0SWRMb2FkaW5nU3RhdGVzOiBNZW1vaXplZFNlbGVjdG9yPFxuICAgICAgb2JqZWN0LFxuICAgICAgSWRMb2FkaW5nU3RhdGVzLFxuICAgICAgRGVmYXVsdFByb2plY3RvckZuPElkTG9hZGluZ1N0YXRlcz5cbiAgICA+XG4gICk6IHtcbiAgICBzdGF0ZTogKGlkOiBJZCkgPT4gTWVtb2l6ZWRTZWxlY3RvcjxvYmplY3QsIElkTG9hZGluZ1N0YXRlLCBEZWZhdWx0UHJvamVjdG9yRm48SWRMb2FkaW5nU3RhdGU+PjtcbiAgICBsb2FkaW5nOiAoaWQ6IElkKSA9PiBNZW1vaXplZFNlbGVjdG9yPG9iamVjdCwgYm9vbGVhbiwgRGVmYXVsdFByb2plY3RvckZuPGJvb2xlYW4+PjtcbiAgICBzdWNjZXNzOiAoaWQ6IElkKSA9PiBNZW1vaXplZFNlbGVjdG9yPG9iamVjdCwgYm9vbGVhbiwgRGVmYXVsdFByb2plY3RvckZuPGJvb2xlYW4+PjtcbiAgICBlcnJvcjogKGlkOiBJZCkgPT4gTWVtb2l6ZWRTZWxlY3RvcjxvYmplY3QsIGFueSwgRGVmYXVsdFByb2plY3RvckZuPGFueT4+O1xuICAgIGNvbWJpbmVkU3RhdGU6IE1lbW9pemVkU2VsZWN0b3I8b2JqZWN0LCBhbnksIERlZmF1bHRQcm9qZWN0b3JGbjxhbnk+PjtcbiAgfSB7XG4gICAgY29uc3Qgc2VsZWN0SWRMb2FkaW5nU3RhdGVNYXAgPSBjcmVhdGVTZWxlY3RvcihcbiAgICAgIHNlbGVjdElkTG9hZGluZ1N0YXRlcyxcbiAgICAgIChpZExvYWRpbmdTdGF0ZXMpID0+IGlkTG9hZGluZ1N0YXRlc1t0aGlzLmtleV1cbiAgICApO1xuXG4gICAgY29uc3Qgc3RhdGUgPSAoXG4gICAgICBpZDogSWRcbiAgICApOiBNZW1vaXplZFNlbGVjdG9yPG9iamVjdCwgSWRMb2FkaW5nU3RhdGUsIERlZmF1bHRQcm9qZWN0b3JGbjxJZExvYWRpbmdTdGF0ZT4+ID0+IHtcbiAgICAgIHJldHVybiBjcmVhdGVTZWxlY3RvcihzZWxlY3RJZExvYWRpbmdTdGF0ZU1hcCwgKGlkTG9hZGluZ1N0YXRlTWFwKSA9PlxuICAgICAgICB0aGlzLmdldElkTG9hZGluZ1N0YXRlKGlkTG9hZGluZ1N0YXRlTWFwLCBpZClcbiAgICAgICk7XG4gICAgfTtcblxuICAgIGNvbnN0IGxvYWRpbmcgPSAoaWQ6IElkKSA9PiB7XG4gICAgICByZXR1cm4gY3JlYXRlU2VsZWN0b3Ioc3RhdGUoaWQpLCAoaWRMb2FkaW5nU3RhdGUpID0+IGlkTG9hZGluZ1N0YXRlLmxvYWRpbmcpO1xuICAgIH07XG4gICAgY29uc3Qgc3VjY2VzcyA9IChpZDogSWQpID0+IHtcbiAgICAgIHJldHVybiBjcmVhdGVTZWxlY3RvcihzdGF0ZShpZCksIChpZExvYWRpbmdTdGF0ZSkgPT4gaWRMb2FkaW5nU3RhdGUuc3VjY2Vzcyk7XG4gICAgfTtcbiAgICBjb25zdCBlcnJvciA9IChpZDogSWQpID0+IHtcbiAgICAgIHJldHVybiBjcmVhdGVTZWxlY3RvcihzdGF0ZShpZCksIChpZExvYWRpbmdTdGF0ZSkgPT4gaWRMb2FkaW5nU3RhdGUuZXJyb3IpO1xuICAgIH07XG5cbiAgICBjb25zdCBjb21iaW5lZFN0YXRlID0gY3JlYXRlU2VsZWN0b3Ioc2VsZWN0SWRMb2FkaW5nU3RhdGVNYXAsIChpZExvYWRpbmdTdGF0ZU1hcCkgPT4ge1xuICAgICAgcmV0dXJuIGNvbWJpbmVMb2FkaW5nU3RhdGVzKGlkTG9hZGluZ1N0YXRlTWFwID8gT2JqZWN0LnZhbHVlcyhpZExvYWRpbmdTdGF0ZU1hcCkgOiBbXSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3RhdGUsXG4gICAgICBsb2FkaW5nLFxuICAgICAgc3VjY2VzcyxcbiAgICAgIGVycm9yLFxuICAgICAgY29tYmluZWRTdGF0ZVxuICAgIH07XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIEVmZmVjdHNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBpZExvYWRIYW5kbGVyKFxuICAgIGZldGNoOiAoXG4gICAgICBpZEFjdGlvbnMkOiBPYnNlcnZhYmxlPElkTG9hZEFjdGlvbiAmIExvYWRQYXlsb2FkVHlwZSAmIFR5cGVkQWN0aW9uPHN0cmluZz4+LFxuICAgICAgaWQ6IElkXG4gICAgKSA9PiBPYnNlcnZhYmxlPEFjdGlvbj5cbiAgKTogVW5hcnlGdW5jdGlvbjxPYnNlcnZhYmxlPEFjdGlvbj4sIE9ic2VydmFibGU8QWN0aW9uPj4ge1xuICAgIHJldHVybiBwaXBlKG9mVHlwZSh0aGlzLmlkTG9hZCksIChzb3VyY2UpOiBPYnNlcnZhYmxlPEFjdGlvbj4gPT4ge1xuICAgICAgLy8gQmVsb3cgaXMgaW5zcGlyZWQgYnk6IGh0dHBzOi8vZ2l0aHViLmNvbS9ucndsL254L2Jsb2IvbWFzdGVyL3BhY2thZ2VzL2FuZ3VsYXIvc3JjL3J1bnRpbWUvbngvZGF0YS1wZXJzaXN0ZW5jZS50cyNMNzVcbiAgICAgIGNvbnN0IGdyb3VwZWRGZXRjaGVzID0gc291cmNlLnBpcGUoXG4gICAgICAgIGdyb3VwQnkoKGFjdGlvbikgPT4ge1xuICAgICAgICAgIHJldHVybiBhY3Rpb24uaWQ7IC8vIFRoaXMgd2lsbCBiZSB1c2VkIGFzIHRoZSBcImdyb3VwLmtleVwiXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgICAgcmV0dXJuIGdyb3VwZWRGZXRjaGVzLnBpcGUoXG4gICAgICAgIG1lcmdlTWFwKChncm91cCkgPT4ge1xuICAgICAgICAgIHJldHVybiBmZXRjaChncm91cCwgZ3JvdXAua2V5KTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICBjcmVhdGVFZmZlY3QoXG4gICAgYWN0aW9ucyQ6IEFjdGlvbnMsXG4gICAgZmV0Y2g6IChcbiAgICAgIGlkQWN0aW9ucyQ6IE9ic2VydmFibGU8SWRMb2FkQWN0aW9uICYgTG9hZFBheWxvYWRUeXBlICYgVHlwZWRBY3Rpb248c3RyaW5nPj4sXG4gICAgICBpZDogSWRcbiAgICApID0+IE9ic2VydmFibGU8QWN0aW9uPlxuICApIHtcbiAgICByZXR1cm4gY3JlYXRlRWZmZWN0KCgpID0+IHtcbiAgICAgIHJldHVybiBhY3Rpb25zJC5waXBlKHRoaXMuaWRMb2FkSGFuZGxlcihmZXRjaCkpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBIZWxwZXJzXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgcHJpdmF0ZSBnZXQga2V5KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuaWRMb2FkLnR5cGU7XG4gIH1cblxuICBwcml2YXRlIGdldElkTG9hZGluZ1N0YXRlKFxuICAgIGlkTG9hZGluZ1N0YXRlTWFwOiBSZWFkb25seTxJZExvYWRpbmdTdGF0ZU1hcD4sXG4gICAgaWQ6IElkXG4gICk6IFJlYWRvbmx5PElkTG9hZGluZ1N0YXRlPiB7XG4gICAgaWYgKGlkID09IG51bGwgfHwgaWQgPT09ICcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2lkIHBhcmFtZXRlciBpcyBudWxsIG9yIGVtcHR5IHN0cmluZywgdGhpcyBpcyBhbG1vc3QgYWx3YXlzIGEgbG9naWMgYnVnLicpO1xuICAgIH1cbiAgICAvLyBXZSBzaG91bGQgbm90IGJlIG1vZGlmeWluZyB0aGUgc3RhdGUgd2l0aG91dCBnb2luZyB2aWEgdGhlIHJlZHVjZXIsIGhlbmNlXG4gICAgLy8gcmV0dXJuaW5nIHRoZSBpbW11dGFibGUgXCJpbml0XCIgb2JqZWN0LlxuICAgIHJldHVybiBpZExvYWRpbmdTdGF0ZU1hcD8uW2lkXTtcbiAgfVxuXG4gIHByaXZhdGUgc2V0U3RhdGUoXG4gICAgZ2V0TmV3U3RhdGU6IChcbiAgICAgIGFjdGlvbjogQWN0aW9uICYgKElkTG9hZEFjdGlvbiB8IElkU3VjY2Vzc0FjdGlvbiB8IElkRmFpbHVyZUFjdGlvbiksXG4gICAgICBvbGRMb2FkaW5nU3RhdGU6IFJlYWRvbmx5PExvYWRpbmdTdGF0ZT5cbiAgICApID0+IFJlYWRvbmx5PExvYWRpbmdTdGF0ZT4gfCBudWxsLFxuICAgIGFjdGlvbjogQWN0aW9uICYgKElkTG9hZEFjdGlvbiB8IElkU3VjY2Vzc0FjdGlvbiB8IElkRmFpbHVyZUFjdGlvbiksXG4gICAgaWRMb2FkaW5nU3RhdGVzOiBSZWFkb25seTxJZExvYWRpbmdTdGF0ZXM+XG4gICk6IFJlYWRvbmx5PElkTG9hZGluZ1N0YXRlcz4ge1xuICAgIGNvbnN0IGN1cnJlbnRTdGF0ZSA9IGNsb25lTG9hZGluZ1N0YXRlKGlkTG9hZGluZ1N0YXRlc1t0aGlzLmtleV0/LlthY3Rpb24uaWRdKTtcbiAgICBjb25zdCBuZXdTdGF0ZSA9IGdldE5ld1N0YXRlKGFjdGlvbiwgY3VycmVudFN0YXRlKTtcblxuICAgIGlmIChuZXdTdGF0ZSkge1xuICAgICAgLy8gUmV0dXJuIG5ldyByZWZlcmVuY2Ugb25seSB3aGVuIHRoZSBzdGF0ZSBoYXMgY2hhbmdlZC5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLmlkTG9hZGluZ1N0YXRlcyxcbiAgICAgICAgW3RoaXMua2V5XToge1xuICAgICAgICAgIC4uLmlkTG9hZGluZ1N0YXRlc1t0aGlzLmtleV0sXG4gICAgICAgICAgW2FjdGlvbi5pZF06IHsgLi4ubmV3U3RhdGUsIGlzSWRMb2FkaW5nU3RhdGU6IHRydWUsIGlkOiBhY3Rpb24uaWQgfVxuICAgICAgICB9XG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBObyBjaGFuZ2UgaW4gc3RhdGUsIHNvIG5vIGNoYW5nZSBpbiBwYXJlbnQgc3RhdGUuXG4gICAgICByZXR1cm4gaWRMb2FkaW5nU3RhdGVzO1xuICAgIH1cbiAgfVxufVxuIl19