text: import { InjectionToken, Injectable, Inject, ErrorHandler, NgModule } from '@angular/core';
  import { ActionsSubject, UPDATE, INIT, ReducerObservable, ScannedActionsSubject, INITIAL_STATE, StateObservable, ReducerManagerDispatcher } from '@ngrx/store';
  import { EMPTY, Observable, of, merge, queueScheduler, ReplaySubject } from 'rxjs';
  import { share, filter, map, concatMap, timeout, debounceTime, catchError, take, takeUntil, switchMap, skip, observeOn, withLatestFrom, scan } from 'rxjs/operators';
  
  import * as ɵngcc0 from '@angular/core';
  import * as ɵngcc1 from '@ngrx/store';
  class StoreDevtoolsConfig {
      constructor() {
          this.maxAge = false;
      }
  }
  const STORE_DEVTOOLS_CONFIG = new InjectionToken('@ngrx/store-devtools Options');
  const INITIAL_OPTIONS = new InjectionToken('@ngrx/store-devtools Initial Config');
  function noMonitor() {
      return null;
  }
  const DEFAULT_NAME = 'NgRx Store DevTools';
  function createConfig(_options) {
      const DEFAULT_OPTIONS = {
          maxAge: false,
          monitor: noMonitor,
          actionSanitizer: undefined,
          stateSanitizer: undefined,
          name: DEFAULT_NAME,
          serialize: false,
          logOnly: false,
          // Add all features explicitly. This prevent buggy behavior for
          // options like "lock" which might otherwise not show up.
          features: {
              pause: true,
              lock: true,
              persist: true,
              export: true,
              import: 'custom',
              jump: true,
              skip: true,
              reorder: true,
              dispatch: true,
              test: true,
          },
      };
      let options = typeof _options === 'function' ? _options() : _options;
      const logOnly = options.logOnly
          ? { pause: true, export: true, test: true }
          : false;
      const features = options.features || logOnly || DEFAULT_OPTIONS.features;
      const config = Object.assign({}, DEFAULT_OPTIONS, { features }, options);
      if (config.maxAge && config.maxAge < 2) {
          throw new Error(`Devtools 'maxAge' cannot be less than 2, got ${config.maxAge}`);
      }
      return config;
  }
  
  const PERFORM_ACTION = 'PERFORM_ACTION';
  const REFRESH = 'REFRESH';
  const RESET = 'RESET';
  const ROLLBACK = 'ROLLBACK';
  const COMMIT = 'COMMIT';
  const SWEEP = 'SWEEP';
  const TOGGLE_ACTION = 'TOGGLE_ACTION';
  const SET_ACTIONS_ACTIVE = 'SET_ACTIONS_ACTIVE';
  const JUMP_TO_STATE = 'JUMP_TO_STATE';
  const JUMP_TO_ACTION = 'JUMP_TO_ACTION';
  const IMPORT_STATE = 'IMPORT_STATE';
  const LOCK_CHANGES = 'LOCK_CHANGES';
  const PAUSE_RECORDING = 'PAUSE_RECORDING';
  class PerformAction {
      constructor(action, timestamp) {
          this.action = action;
          this.timestamp = timestamp;
          this.type = PERFORM_ACTION;
          if (typeof action.type === 'undefined') {
              throw new Error('Actions may not have an undefined "type" property. ' +
                  'Have you misspelled a constant?');
          }
      }
  }
  class Refresh {
      constructor() {
          this.type = REFRESH;
      }
  }
  class Reset {
      constructor(timestamp) {
          this.timestamp = timestamp;
          this.type = RESET;
      }
  }
  class Rollback {
      constructor(timestamp) {
          this.timestamp = timestamp;
          this.type = ROLLBACK;
      }
  }
  class Commit {
      constructor(timestamp) {
          this.timestamp = timestamp;
          this.type = COMMIT;
      }
  }
  class Sweep {
      constructor() {
          this.type = SWEEP;
      }
  }
  class ToggleAction {
      constructor(id) {
          this.id = id;
          this.type = TOGGLE_ACTION;
      }
  }
  class SetActionsActive {
      constructor(start, end, active = true) {
          this.start = start;
          this.end = end;
          this.active = active;
          this.type = SET_ACTIONS_ACTIVE;
      }
  }
  class JumpToState {
      constructor(index) {
          this.index = index;
          this.type = JUMP_TO_STATE;
      }
  }
  class JumpToAction {
      constructor(actionId) {
          this.actionId = actionId;
          this.type = JUMP_TO_ACTION;
      }
  }
  class ImportState {
      constructor(nextLiftedState) {
          this.nextLiftedState = nextLiftedState;
          this.type = IMPORT_STATE;
      }
  }
  class LockChanges {
      constructor(status) {
          this.status = status;
          this.type = LOCK_CHANGES;
      }
  }
  class PauseRecording {
      constructor(status) {
          this.status = status;
          this.type = PAUSE_RECORDING;
      }
  }
  
  class DevtoolsDispatcher extends ActionsSubject {
  }
  DevtoolsDispatcher.ɵfac = function DevtoolsDispatcher_Factory(t) { return ɵDevtoolsDispatcher_BaseFactory(t || DevtoolsDispatcher); };
  DevtoolsDispatcher.ɵprov = ɵngcc0.ɵɵdefineInjectable({ token: DevtoolsDispatcher, factory: DevtoolsDispatcher.ɵfac });
  const ɵDevtoolsDispatcher_BaseFactory = /*@__PURE__*/ ɵngcc0.ɵɵgetInheritedFactory(DevtoolsDispatcher);
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(DevtoolsDispatcher, [{
          type: Injectable
      }], null, null); })();
  
  function difference(first, second) {
      return first.filter((item) => second.indexOf(item) < 0);
  }
  /**
   * Provides an app's view into the state of the lifted store.
   */
  function unliftState(liftedState) {
      const { computedStates, currentStateIndex } = liftedState;
      // At start up NgRx dispatches init actions,
      // When these init actions are being filtered out by the predicate or safe/block list options
      // we don't have a complete computed states yet.
      // At this point it could happen that we're out of bounds, when this happens we fall back to the last known state
      if (currentStateIndex >= computedStates.length) {
          const { state } = computedStates[computedStates.length - 1];
          return state;
      }
      const { state } = computedStates[currentStateIndex];
      return state;
  }
  function unliftAction(liftedState) {
      return liftedState.actionsById[liftedState.nextActionId - 1];
  }
  /**
   * Lifts an app's action into an action on the lifted store.
   */
  function liftAction(action) {
      return new PerformAction(action, +Date.now());
  }
  /**
   * Sanitizes given actions with given function.
   */
  function sanitizeActions(actionSanitizer, actions) {
      return Object.keys(actions).reduce((sanitizedActions, actionIdx) => {
          const idx = Number(actionIdx);
          sanitizedActions[idx] = sanitizeAction(actionSanitizer, actions[idx], idx);
          return sanitizedActions;
      }, {});
  }
  /**
   * Sanitizes given action with given function.
   */
  function sanitizeAction(actionSanitizer, action, actionIdx) {
      return Object.assign(Object.assign({}, action), { action: actionSanitizer(action.action, actionIdx) });
  }
  /**
   * Sanitizes given states with given function.
   */
  function sanitizeStates(stateSanitizer, states) {
      return states.map((computedState, idx) => ({
          state: sanitizeState(stateSanitizer, computedState.state, idx),
          error: computedState.error,
      }));
  }
  /**
   * Sanitizes given state with given function.
   */
  function sanitizeState(stateSanitizer, state, stateIdx) {
      return stateSanitizer(state, stateIdx);
  }
  /**
   * Read the config and tell if actions should be filtered
   */
  function shouldFilterActions(config) {
      return config.predicate || config.actionsSafelist || config.actionsBlocklist;
  }
  /**
   * Return a full filtered lifted state
   */
  function filterLiftedState(liftedState, predicate, safelist, blocklist) {
      const filteredStagedActionIds = [];
      const filteredActionsById = {};
      const filteredComputedStates = [];
      liftedState.stagedActionIds.forEach((id, idx) => {
          const liftedAction = liftedState.actionsById[id];
          if (!liftedAction)
              return;
          if (idx &&
              isActionFiltered(liftedState.computedStates[idx], liftedAction, predicate, safelist, blocklist)) {
              return;
          }
          filteredActionsById[id] = liftedAction;
          filteredStagedActionIds.push(id);
          filteredComputedStates.push(liftedState.computedStates[idx]);
      });
      return Object.assign(Object.assign({}, liftedState), { stagedActionIds: filteredStagedActionIds, actionsById: filteredActionsById, computedStates: filteredComputedStates });
  }
  /**
   * Return true is the action should be ignored
   */
  function isActionFiltered(state, action, predicate, safelist, blockedlist) {
      const predicateMatch = predicate && !predicate(state, action.action);
      const safelistMatch = safelist &&
          !action.action.type.match(safelist.map((s) => escapeRegExp(s)).join('|'));
      const blocklistMatch = blockedlist &&
          action.action.type.match(blockedlist.map((s) => escapeRegExp(s)).join('|'));
      return predicateMatch || safelistMatch || blocklistMatch;
  }
  /**
   * Return string with escaped RegExp special characters
   * https://stackoverflow.com/a/6969486/1337347
   */
  function escapeRegExp(s) {
      return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  }
  
  const ExtensionActionTypes = {
      START: 'START',
      DISPATCH: 'DISPATCH',
      STOP: 'STOP',
      ACTION: 'ACTION',
  };
  const REDUX_DEVTOOLS_EXTENSION = new InjectionToken('@ngrx/store-devtools Redux Devtools Extension');
  class DevtoolsExtension {
      constructor(devtoolsExtension, config, dispatcher) {
          this.config = config;
          this.dispatcher = dispatcher;
          this.devtoolsExtension = devtoolsExtension;
          this.createActionStreams();
      }
      notify(action, state) {
          if (!this.devtoolsExtension) {
              return;
          }
          // Check to see if the action requires a full update of the liftedState.
          // If it is a simple action generated by the user's app and the recording
          // is not locked/paused, only send the action and the current state (fast).
          //
          // A full liftedState update (slow: serializes the entire liftedState) is
          // only required when:
          //   a) redux-devtools-extension fires the @@Init action (ignored by
          //      @ngrx/store-devtools)
          //   b) an action is generated by an @ngrx module (e.g. @ngrx/effects/init
          //      or @ngrx/store/update-reducers)
          //   c) the state has been recomputed due to time-traveling
          //   d) any action that is not a PerformAction to err on the side of
          //      caution.
          if (action.type === PERFORM_ACTION) {
              if (state.isLocked || state.isPaused) {
                  return;
              }
              const currentState = unliftState(state);
              if (shouldFilterActions(this.config) &&
                  isActionFiltered(currentState, action, this.config.predicate, this.config.actionsSafelist, this.config.actionsBlocklist)) {
                  return;
              }
              const sanitizedState = this.config.stateSanitizer
                  ? sanitizeState(this.config.stateSanitizer, currentState, state.currentStateIndex)
                  : currentState;
              const sanitizedAction = this.config.actionSanitizer
                  ? sanitizeAction(this.config.actionSanitizer, action, state.nextActionId)
                  : action;
              this.sendToReduxDevtools(() => this.extensionConnection.send(sanitizedAction, sanitizedState));
          }
          else {
              // Requires full state update
              const sanitizedLiftedState = Object.assign(Object.assign({}, state), { stagedActionIds: state.stagedActionIds, actionsById: this.config.actionSanitizer
                      ? sanitizeActions(this.config.actionSanitizer, state.actionsById)
                      : state.actionsById, computedStates: this.config.stateSanitizer
                      ? sanitizeStates(this.config.stateSanitizer, state.computedStates)
                      : state.computedStates });
              this.sendToReduxDevtools(() => this.devtoolsExtension.send(null, sanitizedLiftedState, this.getExtensionConfig(this.config)));
          }
      }
      createChangesObservable() {
          if (!this.devtoolsExtension) {
              return EMPTY;
          }
          return new Observable((subscriber) => {
              const connection = this.devtoolsExtension.connect(this.getExtensionConfig(this.config));
              this.extensionConnection = connection;
              connection.init();
              connection.subscribe((change) => subscriber.next(change));
              return connection.unsubscribe;
          });
      }
      createActionStreams() {
          // Listens to all changes
          const changes$ = this.createChangesObservable().pipe(share());
          // Listen for the start action
          const start$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.START));
          // Listen for the stop action
          const stop$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.STOP));
          // Listen for lifted actions
          const liftedActions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.DISPATCH), map((change) => this.unwrapAction(change.payload)), concatMap((action) => {
              if (action.type === IMPORT_STATE) {
                  // State imports may happen in two situations:
                  // 1. Explicitly by user
                  // 2. User activated the "persist state accross reloads" option
                  //    and now the state is imported during reload.
                  // Because of option 2, we need to give possible
                  // lazy loaded reducers time to instantiate.
                  // As soon as there is no UPDATE action within 1 second,
                  // it is assumed that all reducers are loaded.
                  return this.dispatcher.pipe(filter((action) => action.type === UPDATE), timeout(1000), debounceTime(1000), map(() => action), catchError(() => of(action)), take(1));
              }
              else {
                  return of(action);
              }
          }));
          // Listen for unlifted actions
          const actions$ = changes$.pipe(filter((change) => change.type === ExtensionActionTypes.ACTION), map((change) => this.unwrapAction(change.payload)));
          const actionsUntilStop$ = actions$.pipe(takeUntil(stop$));
          const liftedUntilStop$ = liftedActions$.pipe(takeUntil(stop$));
          this.start$ = start$.pipe(takeUntil(stop$));
          // Only take the action sources between the start/stop events
          this.actions$ = this.start$.pipe(switchMap(() => actionsUntilStop$));
          this.liftedActions$ = this.start$.pipe(switchMap(() => liftedUntilStop$));
      }
      unwrapAction(action) {
          return typeof action === 'string' ? eval(`(${action})`) : action;
      }
      getExtensionConfig(config) {
          const extensionOptions = {
              name: config.name,
              features: config.features,
              serialize: config.serialize,
          };
          if (config.maxAge !== false /* support === 0 */) {
              extensionOptions.maxAge = config.maxAge;
          }
          return extensionOptions;
      }
      sendToReduxDevtools(send) {
          try {
              send();
          }
          catch (err) {
              console.warn('@ngrx/store-devtools: something went wrong inside the redux devtools', err);
          }
      }
  }
  DevtoolsExtension.ɵfac = function DevtoolsExtension_Factory(t) { return new (t || DevtoolsExtension)(ɵngcc0.ɵɵinject(REDUX_DEVTOOLS_EXTENSION), ɵngcc0.ɵɵinject(STORE_DEVTOOLS_CONFIG), ɵngcc0.ɵɵinject(DevtoolsDispatcher)); };
  DevtoolsExtension.ɵprov = ɵngcc0.ɵɵdefineInjectable({ token: DevtoolsExtension, factory: DevtoolsExtension.ɵfac });
  /** @nocollapse */
  DevtoolsExtension.ctorParameters = () => [
      { type: undefined, decorators: [{ type: Inject, args: [REDUX_DEVTOOLS_EXTENSION,] }] },
      { type: StoreDevtoolsConfig, decorators: [{ type: Inject, args: [STORE_DEVTOOLS_CONFIG,] }] },
      { type: DevtoolsDispatcher }
  ];
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(DevtoolsExtension, [{
          type: Injectable
      }], function () { return [{ type: undefined, decorators: [{
                  type: Inject,
                  args: [REDUX_DEVTOOLS_EXTENSION]
              }] }, { type: StoreDevtoolsConfig, decorators: [{
                  type: Inject,
                  args: [STORE_DEVTOOLS_CONFIG]
              }] }, { type: DevtoolsDispatcher }]; }, null); })();
  
  const INIT_ACTION = { type: INIT };
  const RECOMPUTE = '@ngrx/store-devtools/recompute';
  const RECOMPUTE_ACTION = { type: RECOMPUTE };
  /**
   * Computes the next entry in the log by applying an action.
   */
  function computeNextEntry(reducer, action, state, error, errorHandler) {
      if (error) {
          return {
              state,
              error: 'Interrupted by an error up the chain',
          };
      }
      let nextState = state;
      let nextError;
      try {
          nextState = reducer(state, action);
      }
      catch (err) {
          nextError = err.toString();
          errorHandler.handleError(err);
      }
      return {
          state: nextState,
          error: nextError,
      };
  }
  /**
   * Runs the reducer on invalidated actions to get a fresh computation log.
   */
  function recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, errorHandler, isPaused) {
      // Optimization: exit early and return the same reference
      // if we know nothing could have changed.
      if (minInvalidatedStateIndex >= computedStates.length &&
          computedStates.length === stagedActionIds.length) {
          return computedStates;
      }
      const nextComputedStates = computedStates.slice(0, minInvalidatedStateIndex);
      // If the recording is paused, recompute all states up until the pause state,
      // else recompute all states.
      const lastIncludedActionId = stagedActionIds.length - (isPaused ? 1 : 0);
      for (let i = minInvalidatedStateIndex; i < lastIncludedActionId; i++) {
          const actionId = stagedActionIds[i];
          const action = actionsById[actionId].action;
          const previousEntry = nextComputedStates[i - 1];
          const previousState = previousEntry ? previousEntry.state : committedState;
          const previousError = previousEntry ? previousEntry.error : undefined;
          const shouldSkip = skippedActionIds.indexOf(actionId) > -1;
          const entry = shouldSkip
              ? previousEntry
              : computeNextEntry(reducer, action, previousState, previousError, errorHandler);
          nextComputedStates.push(entry);
      }
      // If the recording is paused, the last state will not be recomputed,
      // because it's essentially not part of the state history.
      if (isPaused) {
          nextComputedStates.push(computedStates[computedStates.length - 1]);
      }
      return nextComputedStates;
  }
  function liftInitialState(initialCommittedState, monitorReducer) {
      return {
          monitorState: monitorReducer(undefined, {}),
          nextActionId: 1,
          actionsById: { 0: liftAction(INIT_ACTION) },
          stagedActionIds: [0],
          skippedActionIds: [],
          committedState: initialCommittedState,
          currentStateIndex: 0,
          computedStates: [],
          isLocked: false,
          isPaused: false,
      };
  }
  /**
   * Creates a history state reducer from an app's reducer.
   */
  function liftReducerWith(initialCommittedState, initialLiftedState, errorHandler, monitorReducer, options = {}) {
      /**
       * Manages how the history actions modify the history state.
       */
      return (reducer) => (liftedState, liftedAction) => {
          let { monitorState, actionsById, nextActionId, stagedActionIds, skippedActionIds, committedState, currentStateIndex, computedStates, isLocked, isPaused, } = liftedState || initialLiftedState;
          if (!liftedState) {
              // Prevent mutating initialLiftedState
              actionsById = Object.create(actionsById);
          }
          function commitExcessActions(n) {
              // Auto-commits n-number of excess actions.
              let excess = n;
              let idsToDelete = stagedActionIds.slice(1, excess + 1);
              for (let i = 0; i < idsToDelete.length; i++) {
                  if (computedStates[i + 1].error) {
                      // Stop if error is found. Commit actions up to error.
                      excess = i;
                      idsToDelete = stagedActionIds.slice(1, excess + 1);
                      break;
                  }
                  else {
                      delete actionsById[idsToDelete[i]];
                  }
              }
              skippedActionIds = skippedActionIds.filter((id) => idsToDelete.indexOf(id) === -1);
              stagedActionIds = [0, ...stagedActionIds.slice(excess + 1)];
              committedState = computedStates[excess].state;
              computedStates = computedStates.slice(excess);
              currentStateIndex =
                  currentStateIndex > excess ? currentStateIndex - excess : 0;
          }
          function commitChanges() {
              // Consider the last committed state the new starting point.
              // Squash any staged actions into a single committed state.
              actionsById = { 0: liftAction(INIT_ACTION) };
              nextActionId = 1;
              stagedActionIds = [0];
              skippedActionIds = [];
              committedState = computedStates[currentStateIndex].state;
              currentStateIndex = 0;
              computedStates = [];
          }
          // By default, aggressively recompute every state whatever happens.
          // This has O(n) performance, so we'll override this to a sensible
          // value whenever we feel like we don't have to recompute the states.
          let minInvalidatedStateIndex = 0;
          switch (liftedAction.type) {
              case LOCK_CHANGES: {
                  isLocked = liftedAction.status;
                  minInvalidatedStateIndex = Infinity;
                  break;
              }
              case PAUSE_RECORDING: {
                  isPaused = liftedAction.status;
                  if (isPaused) {
                      // Add a pause action to signal the devtools-user the recording is paused.
                      // The corresponding state will be overwritten on each update to always contain
                      // the latest state (see Actions.PERFORM_ACTION).
                      stagedActionIds = [...stagedActionIds, nextActionId];
                      actionsById[nextActionId] = new PerformAction({
                          type: '@ngrx/devtools/pause',
                      }, +Date.now());
                      nextActionId++;
                      minInvalidatedStateIndex = stagedActionIds.length - 1;
                      computedStates = computedStates.concat(computedStates[computedStates.length - 1]);
                      if (currentStateIndex === stagedActionIds.length - 2) {
                          currentStateIndex++;
                      }
                      minInvalidatedStateIndex = Infinity;
                  }
                  else {
                      commitChanges();
                  }
                  break;
              }
              case RESET: {
                  // Get back to the state the store was created with.
                  actionsById = { 0: liftAction(INIT_ACTION) };
                  nextActionId = 1;
                  stagedActionIds = [0];
                  skippedActionIds = [];
                  committedState = initialCommittedState;
                  currentStateIndex = 0;
                  computedStates = [];
                  break;
              }
              case COMMIT: {
                  commitChanges();
                  break;
              }
              case ROLLBACK: {
                  // Forget about any staged actions.
                  // Start again from the last committed state.
                  actionsById = { 0: liftAction(INIT_ACTION) };
                  nextActionId = 1;
                  stagedActionIds = [0];
                  skippedActionIds = [];
                  currentStateIndex = 0;
                  computedStates = [];
                  break;
              }
              case TOGGLE_ACTION: {
                  // Toggle whether an action with given ID is skipped.
                  // Being skipped means it is a no-op during the computation.
                  const { id: actionId } = liftedAction;
                  const index = skippedActionIds.indexOf(actionId);
                  if (index === -1) {
                      skippedActionIds = [actionId, ...skippedActionIds];
                  }
                  else {
                      skippedActionIds = skippedActionIds.filter((id) => id !== actionId);
                  }
                  // Optimization: we know history before this action hasn't changed
                  minInvalidatedStateIndex = stagedActionIds.indexOf(actionId);
                  break;
              }
              case SET_ACTIONS_ACTIVE: {
                  // Toggle whether an action with given ID is skipped.
                  // Being skipped means it is a no-op during the computation.
                  const { start, end, active } = liftedAction;
                  const actionIds = [];
                  for (let i = start; i < end; i++)
                      actionIds.push(i);
                  if (active) {
                      skippedActionIds = difference(skippedActionIds, actionIds);
                  }
                  else {
                      skippedActionIds = [...skippedActionIds, ...actionIds];
                  }
                  // Optimization: we know history before this action hasn't changed
                  minInvalidatedStateIndex = stagedActionIds.indexOf(start);
                  break;
              }
              case JUMP_TO_STATE: {
                  // Without recomputing anything, move the pointer that tell us
                  // which state is considered the current one. Useful for sliders.
                  currentStateIndex = liftedAction.index;
                  // Optimization: we know the history has not changed.
                  minInvalidatedStateIndex = Infinity;
                  break;
              }
              case JUMP_TO_ACTION: {
                  // Jumps to a corresponding state to a specific action.
                  // Useful when filtering actions.
                  const index = stagedActionIds.indexOf(liftedAction.actionId);
                  if (index !== -1)
                      currentStateIndex = index;
                  minInvalidatedStateIndex = Infinity;
                  break;
              }
              case SWEEP: {
                  // Forget any actions that are currently being skipped.
                  stagedActionIds = difference(stagedActionIds, skippedActionIds);
                  skippedActionIds = [];
                  currentStateIndex = Math.min(currentStateIndex, stagedActionIds.length - 1);
                  break;
              }
              case PERFORM_ACTION: {
                  // Ignore action and return state as is if recording is locked
                  if (isLocked) {
                      return liftedState || initialLiftedState;
                  }
                  if (isPaused ||
                      (liftedState &&
                          isActionFiltered(liftedState.computedStates[currentStateIndex], liftedAction, options.predicate, options.actionsSafelist, options.actionsBlocklist))) {
                      // If recording is paused or if the action should be ignored, overwrite the last state
                      // (corresponds to the pause action) and keep everything else as is.
                      // This way, the app gets the new current state while the devtools
                      // do not record another action.
                      const lastState = computedStates[computedStates.length - 1];
                      computedStates = [
                          ...computedStates.slice(0, -1),
                          computeNextEntry(reducer, liftedAction.action, lastState.state, lastState.error, errorHandler),
                      ];
                      minInvalidatedStateIndex = Infinity;
                      break;
                  }
                  // Auto-commit as new actions come in.
                  if (options.maxAge && stagedActionIds.length === options.maxAge) {
                      commitExcessActions(1);
                  }
                  if (currentStateIndex === stagedActionIds.length - 1) {
                      currentStateIndex++;
                  }
                  const actionId = nextActionId++;
                  // Mutation! This is the hottest path, and we optimize on purpose.
                  // It is safe because we set a new key in a cache dictionary.
                  actionsById[actionId] = liftedAction;
                  stagedActionIds = [...stagedActionIds, actionId];
                  // Optimization: we know that only the new action needs computing.
                  minInvalidatedStateIndex = stagedActionIds.length - 1;
                  break;
              }
              case IMPORT_STATE: {
                  // Completely replace everything.
                  ({
                      monitorState,
                      actionsById,
                      nextActionId,
                      stagedActionIds,
                      skippedActionIds,
                      committedState,
                      currentStateIndex,
                      computedStates,
                      isLocked,
                      isPaused,
                  } = liftedAction.nextLiftedState);
                  break;
              }
              case INIT: {
                  // Always recompute states on hot reload and init.
                  minInvalidatedStateIndex = 0;
                  if (options.maxAge && stagedActionIds.length > options.maxAge) {
                      // States must be recomputed before committing excess.
                      computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, errorHandler, isPaused);
                      commitExcessActions(stagedActionIds.length - options.maxAge);
                      // Avoid double computation.
                      minInvalidatedStateIndex = Infinity;
                  }
                  break;
              }
              case UPDATE: {
                  const stateHasErrors = computedStates.filter((state) => state.error).length > 0;
                  if (stateHasErrors) {
                      // Recompute all states
                      minInvalidatedStateIndex = 0;
                      if (options.maxAge && stagedActionIds.length > options.maxAge) {
                          // States must be recomputed before committing excess.
                          computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, errorHandler, isPaused);
                          commitExcessActions(stagedActionIds.length - options.maxAge);
                          // Avoid double computation.
                          minInvalidatedStateIndex = Infinity;
                      }
                  }
                  else {
                      // If not paused/locked, add a new action to signal devtools-user
                      // that there was a reducer update.
                      if (!isPaused && !isLocked) {
                          if (currentStateIndex === stagedActionIds.length - 1) {
                              currentStateIndex++;
                          }
                          // Add a new action to only recompute state
                          const actionId = nextActionId++;
                          actionsById[actionId] = new PerformAction(liftedAction, +Date.now());
                          stagedActionIds = [...stagedActionIds, actionId];
                          minInvalidatedStateIndex = stagedActionIds.length - 1;
                          computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, errorHandler, isPaused);
                      }
                      // Recompute state history with latest reducer and update action
                      computedStates = computedStates.map((cmp) => (Object.assign(Object.assign({}, cmp), { state: reducer(cmp.state, RECOMPUTE_ACTION) })));
                      currentStateIndex = stagedActionIds.length - 1;
                      if (options.maxAge && stagedActionIds.length > options.maxAge) {
                          commitExcessActions(stagedActionIds.length - options.maxAge);
                      }
                      // Avoid double computation.
                      minInvalidatedStateIndex = Infinity;
                  }
                  break;
              }
              default: {
                  // If the action is not recognized, it's a monitor action.
                  // Optimization: a monitor action can't change history.
                  minInvalidatedStateIndex = Infinity;
                  break;
              }
          }
          computedStates = recomputeStates(computedStates, minInvalidatedStateIndex, reducer, committedState, actionsById, stagedActionIds, skippedActionIds, errorHandler, isPaused);
          monitorState = monitorReducer(monitorState, liftedAction);
          return {
              monitorState,
              actionsById,
              nextActionId,
              stagedActionIds,
              skippedActionIds,
              committedState,
              currentStateIndex,
              computedStates,
              isLocked,
              isPaused,
          };
      };
  }
  
  class StoreDevtools {
      constructor(dispatcher, actions$, reducers$, extension, scannedActions, errorHandler, initialState, config) {
          const liftedInitialState = liftInitialState(initialState, config.monitor);
          const liftReducer = liftReducerWith(initialState, liftedInitialState, errorHandler, config.monitor, config);
          const liftedAction$ = merge(merge(actions$.asObservable().pipe(skip(1)), extension.actions$).pipe(map(liftAction)), dispatcher, extension.liftedActions$).pipe(observeOn(queueScheduler));
          const liftedReducer$ = reducers$.pipe(map(liftReducer));
          const liftedStateSubject = new ReplaySubject(1);
          const liftedStateSubscription = liftedAction$
              .pipe(withLatestFrom(liftedReducer$), scan(({ state: liftedState }, [action, reducer]) => {
              let reducedLiftedState = reducer(liftedState, action);
              // On full state update
              // If we have actions filters, we must filter completely our lifted state to be sync with the extension
              if (action.type !== PERFORM_ACTION && shouldFilterActions(config)) {
                  reducedLiftedState = filterLiftedState(reducedLiftedState, config.predicate, config.actionsSafelist, config.actionsBlocklist);
              }
              // Extension should be sent the sanitized lifted state
              extension.notify(action, reducedLiftedState);
              return { state: reducedLiftedState, action };
          }, { state: liftedInitialState, action: null }))
              .subscribe(({ state, action }) => {
              liftedStateSubject.next(state);
              if (action.type === PERFORM_ACTION) {
                  const unliftedAction = action.action;
                  scannedActions.next(unliftedAction);
              }
          });
          const extensionStartSubscription = extension.start$.subscribe(() => {
              this.refresh();
          });
          const liftedState$ = liftedStateSubject.asObservable();
          const state$ = liftedState$.pipe(map(unliftState));
          this.extensionStartSubscription = extensionStartSubscription;
          this.stateSubscription = liftedStateSubscription;
          this.dispatcher = dispatcher;
          this.liftedState = liftedState$;
          this.state = state$;
      }
      dispatch(action) {
          this.dispatcher.next(action);
      }
      next(action) {
          this.dispatcher.next(action);
      }
      error(error) { }
      complete() { }
      performAction(action) {
          this.dispatch(new PerformAction(action, +Date.now()));
      }
      refresh() {
          this.dispatch(new Refresh());
      }
      reset() {
          this.dispatch(new Reset(+Date.now()));
      }
      rollback() {
          this.dispatch(new Rollback(+Date.now()));
      }
      commit() {
          this.dispatch(new Commit(+Date.now()));
      }
      sweep() {
          this.dispatch(new Sweep());
      }
      toggleAction(id) {
          this.dispatch(new ToggleAction(id));
      }
      jumpToAction(actionId) {
          this.dispatch(new JumpToAction(actionId));
      }
      jumpToState(index) {
          this.dispatch(new JumpToState(index));
      }
      importState(nextLiftedState) {
          this.dispatch(new ImportState(nextLiftedState));
      }
      lockChanges(status) {
          this.dispatch(new LockChanges(status));
      }
      pauseRecording(status) {
          this.dispatch(new PauseRecording(status));
      }
  }
  StoreDevtools.ɵfac = function StoreDevtools_Factory(t) { return new (t || StoreDevtools)(ɵngcc0.ɵɵinject(DevtoolsDispatcher), ɵngcc0.ɵɵinject(ɵngcc1.ActionsSubject), ɵngcc0.ɵɵinject(ɵngcc1.ReducerObservable), ɵngcc0.ɵɵinject(DevtoolsExtension), ɵngcc0.ɵɵinject(ɵngcc1.ScannedActionsSubject), ɵngcc0.ɵɵinject(ɵngcc0.ErrorHandler), ɵngcc0.ɵɵinject(INITIAL_STATE), ɵngcc0.ɵɵinject(STORE_DEVTOOLS_CONFIG)); };
  StoreDevtools.ɵprov = ɵngcc0.ɵɵdefineInjectable({ token: StoreDevtools, factory: StoreDevtools.ɵfac });
  /** @nocollapse */
  StoreDevtools.ctorParameters = () => [
      { type: DevtoolsDispatcher },
      { type: ActionsSubject },
      { type: ReducerObservable },
      { type: DevtoolsExtension },
      { type: ScannedActionsSubject },
      { type: ErrorHandler },
      { type: undefined, decorators: [{ type: Inject, args: [INITIAL_STATE,] }] },
      { type: StoreDevtoolsConfig, decorators: [{ type: Inject, args: [STORE_DEVTOOLS_CONFIG,] }] }
  ];
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(StoreDevtools, [{
          type: Injectable
      }], function () { return [{ type: DevtoolsDispatcher }, { type: ɵngcc1.ActionsSubject }, { type: ɵngcc1.ReducerObservable }, { type: DevtoolsExtension }, { type: ɵngcc1.ScannedActionsSubject }, { type: ɵngcc0.ErrorHandler }, { type: undefined, decorators: [{
                  type: Inject,
                  args: [INITIAL_STATE]
              }] }, { type: StoreDevtoolsConfig, decorators: [{
                  type: Inject,
                  args: [STORE_DEVTOOLS_CONFIG]
              }] }]; }, null); })();
  
  const IS_EXTENSION_OR_MONITOR_PRESENT = new InjectionToken('@ngrx/store-devtools Is Devtools Extension or Monitor Present');
  function createIsExtensionOrMonitorPresent(extension, config) {
      return Boolean(extension) || config.monitor !== noMonitor;
  }
  function createReduxDevtoolsExtension() {
      const extensionKey = '__REDUX_DEVTOOLS_EXTENSION__';
      if (typeof window === 'object' &&
          typeof window[extensionKey] !== 'undefined') {
          return window[extensionKey];
      }
      else {
          return null;
      }
  }
  function createStateObservable(devtools) {
      return devtools.state;
  }
  class StoreDevtoolsModule {
      static instrument(options = {}) {
          return {
              ngModule: StoreDevtoolsModule,
              providers: [
                  DevtoolsExtension,
                  DevtoolsDispatcher,
                  StoreDevtools,
                  {
                      provide: INITIAL_OPTIONS,
                      useValue: options,
                  },
                  {
                      provide: IS_EXTENSION_OR_MONITOR_PRESENT,
                      deps: [REDUX_DEVTOOLS_EXTENSION, STORE_DEVTOOLS_CONFIG],
                      useFactory: createIsExtensionOrMonitorPresent,
                  },
                  {
                      provide: REDUX_DEVTOOLS_EXTENSION,
                      useFactory: createReduxDevtoolsExtension,
                  },
                  {
                      provide: STORE_DEVTOOLS_CONFIG,
                      deps: [INITIAL_OPTIONS],
                      useFactory: createConfig,
                  },
                  {
                      provide: StateObservable,
                      deps: [StoreDevtools],
                      useFactory: createStateObservable,
                  },
                  {
                      provide: ReducerManagerDispatcher,
                      useExisting: DevtoolsDispatcher,
                  },
              ],
          };
      }
  }
  StoreDevtoolsModule.ɵfac = function StoreDevtoolsModule_Factory(t) { return new (t || StoreDevtoolsModule)(); };
  StoreDevtoolsModule.ɵmod = ɵngcc0.ɵɵdefineNgModule({ type: StoreDevtoolsModule });
  StoreDevtoolsModule.ɵinj = ɵngcc0.ɵɵdefineInjector({});
  (function () { (typeof ngDevMode === "undefined" || ngDevMode) && ɵngcc0.ɵsetClassMetadata(StoreDevtoolsModule, [{
          type: NgModule,
          args: [{}]
      }], null, null); })();
  
  /**
   * DO NOT EDIT
   *
   * This file is automatically generated at build
   */
  
  /**
   * Generated bundle index. Do not edit.
   */
  
  export { INITIAL_OPTIONS, RECOMPUTE, StoreDevtools, StoreDevtoolsConfig, StoreDevtoolsModule, IS_EXTENSION_OR_MONITOR_PRESENT as ɵa, createIsExtensionOrMonitorPresent as ɵb, createReduxDevtoolsExtension as ɵc, createStateObservable as ɵd, STORE_DEVTOOLS_CONFIG as ɵe, noMonitor as ɵf, createConfig as ɵg, REDUX_DEVTOOLS_EXTENSION as ɵh, DevtoolsExtension as ɵi, DevtoolsDispatcher as ɵj };
  
  //# sourceMappingURL=ngrx-store-devtools.js.map