{"version":3,"file":"ngrx-router-store-data-persistence.mjs","sources":["../../../../modules/router-store/data-persistence/src/operators.ts","../../../../modules/router-store/data-persistence/src/ngrx-router-store-data-persistence.ts"],"sourcesContent":["import type { Type } from '@angular/core';\nimport type {\n  ActivatedRouteSnapshot,\n  RouterStateSnapshot,\n} from '@angular/router';\nimport type { RouterNavigationAction } from '@ngrx/router-store';\nimport { ROUTER_NAVIGATION } from '@ngrx/router-store';\nimport type { Action } from '@ngrx/store';\nimport type { Observable } from 'rxjs';\nimport { isObservable, of } from 'rxjs';\nimport {\n  catchError,\n  concatMap,\n  filter,\n  groupBy,\n  map,\n  mergeMap,\n  switchMap,\n} from 'rxjs/operators';\n\nexport interface PessimisticUpdateOpts<T extends Array<unknown>, A> {\n  run(a: A, ...slices: [...T]): Observable<Action> | Action | void;\n  onError(a: A, e: any): Observable<any> | any;\n}\n\nexport interface OptimisticUpdateOpts<T extends Array<unknown>, A> {\n  run(a: A, ...slices: [...T]): Observable<Action> | Action | void;\n  undoAction(a: A, e: any): Observable<Action> | Action;\n}\n\nexport interface FetchOpts<T extends Array<unknown>, A> {\n  id?(a: A, ...slices: [...T]): any;\n  run(a: A, ...slices: [...T]): Observable<Action> | Action | void;\n  onError?(a: A, e: any): Observable<any> | any;\n}\n\nexport interface HandleNavigationOpts<T extends Array<unknown>> {\n  run(\n    a: ActivatedRouteSnapshot,\n    ...slices: [...T]\n  ): Observable<Action> | Action | void;\n  onError?(a: ActivatedRouteSnapshot, e: any): Observable<any> | any;\n}\n\nexport type ActionOrActionWithStates<T extends Array<unknown>, A> =\n  | A\n  | [A, ...T];\nexport type ActionOrActionWithState<T, A> = ActionOrActionWithStates<[T], A>;\nexport type ActionStatesStream<T extends Array<unknown>, A> = Observable<\n  ActionOrActionWithStates<T, A>\n>;\nexport type ActionStateStream<T, A> = Observable<\n  ActionOrActionWithStates<[T], A>\n>;\n\n/**\n * @description\n * Handles pessimistic updates (updating the server first).\n *\n * Updating the server, when implemented naively, suffers from race conditions and poor error handling.\n *\n * `pessimisticUpdate` addresses these problems. It runs all fetches in order, which removes race conditions\n * and forces the developer to handle errors.\n *\n * @usageNotes\n *\n * ```typescript\n * @Injectable()\n * class TodoEffects {\n *   updateTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       ofType('UPDATE_TODO'),\n *       pessimisticUpdate({\n *         // provides an action\n *         run: (action: UpdateTodo) => {\n *           // update the backend first, and then dispatch an action that will\n *           // update the client side\n *           return this.backend.updateTodo(action.todo.id, action.todo).pipe(\n *             map((updated) => ({\n *               type: 'UPDATE_TODO_SUCCESS',\n *               todo: updated,\n *             }))\n *           );\n *         },\n *         onError: (action: UpdateTodo, error: any) => {\n *           // we don't need to undo the changes on the client side.\n *           // we can dispatch an error, or simply log the error here and return `null`\n *           return null;\n *         },\n *       })\n *     )\n *   );\n *\n *   constructor(private actions$: Actions, private backend: Backend) {}\n * }\n * ```\n *\n * Note that if you don't return a new action from the run callback, you must set the dispatch property\n * of the effect to false, like this:\n *\n * ```typescript\n * class TodoEffects {\n *   updateTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       //...\n *     ), { dispatch: false }\n *   );\n * }\n * ```\n *\n * @param opts\n */\nexport function pessimisticUpdate<T extends Array<unknown>, A extends Action>(\n  opts: PessimisticUpdateOpts<T, A>\n) {\n  return (source: ActionStatesStream<T, A>): Observable<Action> => {\n    return source.pipe(\n      mapActionAndState(),\n      concatMap(runWithErrorHandling(opts.run, opts.onError))\n    );\n  };\n}\n\n/**\n *\n * @description\n *\n * Handles optimistic updates (updating the client first).\n *\n * It runs all fetches in order, which removes race conditions and forces the developer to handle errors.\n *\n * When using `optimisticUpdate`, in case of a failure, the developer has already updated the state locally,\n * so the developer must provide an undo action.\n *\n * The error handling must be done in the callback, or by means of the undo action.\n *\n * @usageNotes\n *\n * ```typescript\n * @Injectable()\n * class TodoEffects {\n *   updateTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       ofType('UPDATE_TODO'),\n *       optimisticUpdate({\n *         // provides an action\n *         run: (action: UpdateTodo) => {\n *           return this.backend.updateTodo(action.todo.id, action.todo).pipe(\n *             mapTo({\n *               type: 'UPDATE_TODO_SUCCESS',\n *             })\n *           );\n *         },\n *         undoAction: (action: UpdateTodo, error: any) => {\n *           // dispatch an undo action to undo the changes in the client state\n *           return {\n *             type: 'UNDO_TODO_UPDATE',\n *             todo: action.todo,\n *           };\n *         },\n *       })\n *     )\n *   );\n *\n *   constructor(private actions$: Actions, private backend: Backend) {}\n * }\n * ```\n *\n * Note that if you don't return a new action from the run callback, you must set the dispatch property\n * of the effect to false, like this:\n *\n * ```typescript\n * class TodoEffects {\n *   updateTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       //...\n *     ), { dispatch: false }\n *   );\n * }\n * ```\n *\n * @param opts\n */\nexport function optimisticUpdate<T extends Array<unknown>, A extends Action>(\n  opts: OptimisticUpdateOpts<T, A>\n) {\n  return (source: ActionStatesStream<T, A>): Observable<Action> => {\n    return source.pipe(\n      mapActionAndState(),\n      concatMap(runWithErrorHandling(opts.run, opts.undoAction))\n    );\n  };\n}\n\n/**\n *\n * @description\n *\n * Handles data fetching.\n *\n * Data fetching implemented naively suffers from race conditions and poor error handling.\n *\n * `fetch` addresses these problems. It runs all fetches in order, which removes race conditions\n * and forces the developer to handle errors.\n *\n * @usageNotes\n *\n * ```typescript\n * @Injectable()\n * class TodoEffects {\n *   loadTodos$ = createEffect(() =>\n *     this.actions$.pipe(\n *       ofType('GET_TODOS'),\n *       fetch({\n *         // provides an action\n *         run: (a: GetTodos) => {\n *           return this.backend.getAll().pipe(\n *             map((response) => ({\n *               type: 'TODOS',\n *               todos: response.todos,\n *             }))\n *           );\n *         },\n *         onError: (action: GetTodos, error: any) => {\n *           // dispatch an undo action to undo the changes in the client state\n *           return null;\n *         },\n *       })\n *     )\n *   );\n *\n *   constructor(private actions$: Actions, private backend: Backend) {}\n * }\n * ```\n *\n * This is correct, but because it set the concurrency to 1, it may not be performant.\n *\n * To fix that, you can provide the `id` function, like this:\n *\n * ```typescript\n * @Injectable()\n * class TodoEffects {\n *   loadTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       ofType('GET_TODO'),\n *       fetch({\n *         id: (todo: GetTodo) => {\n *           return todo.id;\n *         },\n *         // provides an action\n *         run: (todo: GetTodo) => {\n *           return this.backend.getTodo(todo.id).map((response) => ({\n *             type: 'LOAD_TODO_SUCCESS',\n *             todo: response.todo,\n *           }));\n *         },\n *         onError: (action: GetTodo, error: any) => {\n *           // dispatch an undo action to undo the changes in the client state\n *           return null;\n *         },\n *       })\n *     )\n *   );\n *\n *   constructor(private actions$: Actions, private backend: Backend) {}\n * }\n * ```\n *\n * With this setup, the requests for Todo 1 will run concurrently with the requests for Todo 2.\n *\n * In addition, if there are multiple requests for Todo 1 scheduled, it will only run the last one.\n *\n * @param opts\n */\nexport function fetch<T extends Array<unknown>, A extends Action>(\n  opts: FetchOpts<T, A>\n) {\n  return (source: ActionStatesStream<T, A>): Observable<Action> => {\n    if (opts.id) {\n      const groupedFetches = source.pipe(\n        mapActionAndState(),\n        groupBy(([action, ...store]) => {\n          return opts.id(action, ...store);\n        })\n      );\n\n      return groupedFetches.pipe(\n        mergeMap((pairs) =>\n          pairs.pipe(switchMap(runWithErrorHandling(opts.run, opts.onError)))\n        )\n      );\n    }\n\n    return source.pipe(\n      mapActionAndState(),\n      concatMap(runWithErrorHandling(opts.run, opts.onError))\n    );\n  };\n}\n\n/**\n * @description\n *\n * Handles data fetching as part of router navigation.\n *\n * Data fetching implemented naively suffers from race conditions and poor error handling.\n *\n * `navigation` addresses these problems.\n *\n * It checks if an activated router state contains the passed in component type, and, if it does, runs the `run`\n * callback. It provides the activated snapshot associated with the component and the current state. And it only runs\n * the last request.\n *\n * @usageNotes\n *\n * ```typescript\n * @Injectable()\n * class TodoEffects {\n *   loadTodo$ = createEffect(() =>\n *     this.actions$.pipe(\n *       // listens for the routerNavigation action from @ngrx/router-store\n *       navigation(TodoComponent, {\n *         run: (activatedRouteSnapshot: ActivatedRouteSnapshot) => {\n *           return this.backend\n *             .fetchTodo(activatedRouteSnapshot.params['id'])\n *             .pipe(\n *               map((todo) => ({\n *                 type: 'LOAD_TODO_SUCCESS',\n *                 todo: todo,\n *               }))\n *             );\n *         },\n *         onError: (\n *           activatedRouteSnapshot: ActivatedRouteSnapshot,\n *           error: any\n *         ) => {\n *           // we can log and error here and return null\n *           // we can also navigate back\n *           return null;\n *         },\n *       })\n *     )\n *   );\n *\n *   constructor(private actions$: Actions, private backend: Backend) {}\n * }\n * ```\n *\n * @param component\n * @param opts\n */\nexport function navigation<T extends Array<unknown>, A extends Action>(\n  component: Type<any>,\n  opts: HandleNavigationOpts<T>\n) {\n  return (source: ActionStatesStream<T, A>) => {\n    const nav = source.pipe(\n      mapActionAndState(),\n      filter(([action]) => isStateSnapshot(action)),\n      map(([action, ...slices]) => {\n        if (!isStateSnapshot(action)) {\n          // Because of the above filter we'll never get here,\n          // but this properly type narrows `action`\n          // @ts-ignore\n          return;\n        }\n\n        return [\n          findSnapshot(component, action.payload.routerState.root),\n          ...slices,\n        ] as [ActivatedRouteSnapshot, ...T];\n      }),\n      filter(([snapshot]) => !!snapshot)\n    );\n\n    return nav.pipe(switchMap(runWithErrorHandling(opts.run, opts.onError)));\n  };\n}\n\nfunction isStateSnapshot(\n  action: any\n): action is RouterNavigationAction<RouterStateSnapshot> {\n  return action.type === ROUTER_NAVIGATION;\n}\n\nfunction runWithErrorHandling<T extends Array<unknown>, A, R>(\n  run: (a: A, ...slices: [...T]) => Observable<R> | R | void,\n  onError: any\n) {\n  return ([action, ...slices]: [A, ...T]): Observable<R> => {\n    try {\n      const r = wrapIntoObservable(run(action, ...slices));\n      return r.pipe(catchError((e) => wrapIntoObservable(onError(action, e))));\n    } catch (e) {\n      return wrapIntoObservable(onError(action, e));\n    }\n  };\n}\n\n/**\n * @whatItDoes maps Observable<Action | [Action, State]> to\n * Observable<[Action, State]>\n */\nfunction mapActionAndState<T extends Array<unknown>, A>() {\n  return (source: Observable<ActionOrActionWithStates<T, A>>) => {\n    return source.pipe(\n      map((value) => normalizeActionAndState(value) as [A, ...T])\n    );\n  };\n}\n\n/**\n * @whatItDoes Normalizes either a bare action or an array of action and slices\n * into an array of action and slices (or undefined)\n */\nfunction normalizeActionAndState<T extends Array<unknown>, A>(\n  args: ActionOrActionWithStates<T, A>\n): [A, ...T] {\n  let action: A, slices: T;\n\n  if (args instanceof Array) {\n    [action, ...slices] = args;\n  } else {\n    slices = [] as T;\n    action = args;\n  }\n\n  return [action, ...slices];\n}\n\nfunction findSnapshot(\n  component: Type<any>,\n  s: ActivatedRouteSnapshot\n): ActivatedRouteSnapshot {\n  if (s.routeConfig && s.routeConfig.component === component) {\n    return s;\n  }\n  for (const c of s.children) {\n    const ss = findSnapshot(component, c);\n    if (ss) {\n      return ss;\n    }\n  }\n  return null;\n}\n\nfunction wrapIntoObservable<O>(obj: Observable<O> | O | void): Observable<O> {\n  if (isObservable(obj)) {\n    return obj;\n  } else if (!obj) {\n    return of();\n  } else {\n    return of(obj as O);\n  }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}