<NME> index.ts
<BEF> declare var console;

const logger = console;
const INIT_ACTION = "@ngrx/store/init";

const repeat = (str, times) => (new Array(times + 1)).join(str);
const pad = (num, maxLength) => repeat(`0`, maxLength - num.toString().length) + num;
const formatTime = (time) => `@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`;
const timer = typeof performance !== `undefined` && typeof performance.now === `function` ? performance : Date;

const getLogLevel = (level, action, payload, type) => {
    switch (typeof level) {
        case `object`:
            return typeof level[type] === `function` ? level[type](...payload) : level[type];
        case `function`:
            return level(action);
        default:
            return level;
    }
};

const printBuffer = options => logBuffer => {
    const {actionTransformer, collapsed, colors, timestamp, duration, level} = options;
    logBuffer.forEach((logEntry, key) => {
        const { started, startedTime, action, error } = logEntry;
        const prevState = logEntry.prevState.nextState ? logEntry.prevState.nextState : '(Empty)';
        let { took, nextState } = logEntry;
        const nextEntry = logBuffer[key + 1];
        if (nextEntry) {
            nextState = nextEntry.prevState;
            took = nextEntry.started - started;
        }

        const formattedAction = actionTransformer(action);
        const isCollapsed = (typeof collapsed === `function`) ? collapsed(() => nextState, action) : collapsed;

        const formattedTime = formatTime(startedTime);
        const titleCSS = colors.title ? `color: ${colors.title(formattedAction)};` : null;
        const title = `action ${timestamp ? formattedTime : ``} ${formattedAction.type} ${duration ? `(in ${took.toFixed(2)} ms)` : ``}`;

        try {
            if (isCollapsed) {
                if (colors.title) logger.groupCollapsed(`%c ${title}`, titleCSS);
                else logger.groupCollapsed(title);
            } else {
                if (colors.title) logger.group(`%c ${title}`, titleCSS);
                else logger.group(title);
            }
        } catch (e) {
            logger.log(title);
        }

        const prevStateLevel = getLogLevel(level, formattedAction, [prevState], `prevState`);
        const actionLevel = getLogLevel(level, formattedAction, [formattedAction], `action`);
        const errorLevel = getLogLevel(level, formattedAction, [error, prevState], `error`);
        const nextStateLevel = getLogLevel(level, formattedAction, [nextState], `nextState`);

        if (prevStateLevel) {
            if (colors.prevState) logger[prevStateLevel](`%c prev state`, `color: ${colors.prevState(prevState)}; font-weight: bold`, prevState);
            else logger[prevStateLevel](`prev state`, prevState);
        }

        if (actionLevel) {
            if (colors.action) logger[actionLevel](`%c action`, `color: ${colors.action(formattedAction)}; font-weight: bold`, formattedAction);
            else logger[actionLevel](`action`, formattedAction);
        }

        if (error && errorLevel) {
            if (colors.error) logger[errorLevel](`%c error`, `color: ${colors.error(error, prevState)}; font-weight: bold`, error);
            else logger[errorLevel](`error`, error);
        }

        if (nextStateLevel) {
            if (colors.nextState) logger[nextStateLevel](`%c next state`, `color: ${colors.nextState(nextState)}; font-weight: bold`, nextState);
            else logger[nextStateLevel](`next state`, nextState);
        }

        try {
            logger.groupEnd();
        } catch (e) {
            logger.log(`—— log end ——`);
        }
    });
    logBuffer.length = 0;
};

const isAllowed = (action, filter) => {
    if (!filter) {
        return true;
    }
    if (filter.whitelist && filter.whitelist.length) {
        return filter.whitelist.indexOf(action.type) !== -1;
    }
    return filter.blacklist && filter.blacklist.indexOf(action.type) === -1;
};

export const storeLogger = (opts: LoggerOptions = {}) => (reducer: Function) => {
    let log = {};
    const ua = typeof window !== 'undefined' && window.navigator.userAgent ? window.navigator.userAgent : '';
    let ms_ie = false;
    //fix for action display in IE
    const old_ie = ua.indexOf('MSIE ');
    const new_ie = ua.indexOf('Trident/');

    if ((old_ie > -1) || (new_ie > -1)) {
        ms_ie = true;
    }

    let colors: LoggerColorsOption;
    if (ms_ie) {
        // Setting colors functions to null when it's an IE browser.
        colors = {
            title: null,
            prevState: null,
            action: null,
            nextState: null,
            error: null,
        }
    } else {
        colors = {
            title: null,
            prevState: () => '#9E9E9E',
            action: () => '#03A9F4',
            nextState: () => '#4CAF50',
            error: () => '#F20404',
        }
    }

    const defaults: LoggerOptions = {
        level: 'log',
        collapsed: false,
        duration: true,
        timestamp: true,
        stateTransformer: state => state,
        actionTransformer: actn => actn,
        filter: {
            whitelist: [],
            blacklist: []
        },
        colors: colors
    };

    const options = Object.assign({}, defaults, opts);
    const {stateTransformer} = options;
    const buffer = printBuffer(options);

    return function(state, action) {
        let preLog = {
            started: timer.now(),
            startedTime: new Date(),
            prevState: stateTransformer(log),
            action
        };

        let nextState = reducer(state, action);

        let postLog = {
            took: timer.now() - preLog.started,
            nextState: stateTransformer(nextState)
        };
        log = Object.assign({}, preLog, postLog);
        //ignore init action fired by store and devtools
        if(action.type !== INIT_ACTION && isAllowed(action, options.filter)) {
            buffer([log]);
        }

        return nextState;
    }
};

export interface LoggerOptions {
    /**
     * 'log' | 'console' | 'warn' | 'error' | 'info'. Default: 'log'
     */
    level?: any;
    /**
     * Should log group be collapsed? default: false
     */
    collapsed?: boolean;
    /**
     * Print duration with action? default: true
     */
    duration?: boolean;
    /**
     * Print timestamp with action? default: true
     */
    timestamp?: boolean;
    filter?: LoggerFilterOption;
    /**
     * Transform state before print default: state => state
     */
    stateTransformer?: (state: Object) => Object;
    /**
     * Transform action before print default: actn => actn
     */
    actionTransformer?: (actn: Object) => Object;
    colors?: LoggerColorsOption;
};

export interface LoggerFilterOption {
    /**
     * Only print actions included in this list - has priority over blacklist
     */
    whitelist?: string[];
    /**
     * Only print actions that are NOT included in this list
     */
    blacklist?: string[];
}

export interface LoggerColorsOption {
    title: (action: Object) => string;
    prevState: (prevState: Object) => string;
    action: (action: Object) => string;
    nextState: (nextState: Object) => string;
    error: (error: any, prevState: Object) => string;
}

<MSG> chore: bump version

<DFF> @@ -1,217 +1,288 @@
 declare var console;
 
 const logger = console;
-const INIT_ACTION = "@ngrx/store/init";
+const INIT_ACTION = '@ngrx/store/init';
 
-const repeat = (str, times) => (new Array(times + 1)).join(str);
-const pad = (num, maxLength) => repeat(`0`, maxLength - num.toString().length) + num;
-const formatTime = (time) => `@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`;
-const timer = typeof performance !== `undefined` && typeof performance.now === `function` ? performance : Date;
+const repeat = (str, times) => new Array(times + 1).join(str);
+const pad = (num, maxLength) =>
+  repeat(`0`, maxLength - num.toString().length) + num;
+const formatTime = time =>
+  `@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(
+    time.getSeconds(),
+    2
+  )}.${pad(time.getMilliseconds(), 3)}`;
+const timer =
+  typeof performance !== `undefined` && typeof performance.now === `function`
+    ? performance
+    : Date;
 
 const getLogLevel = (level, action, payload, type) => {
-    switch (typeof level) {
-        case `object`:
-            return typeof level[type] === `function` ? level[type](...payload) : level[type];
-        case `function`:
-            return level(action);
-        default:
-            return level;
-    }
+  switch (typeof level) {
+    case `object`:
+      return typeof level[type] === `function`
+        ? level[type](...payload)
+        : level[type];
+    case `function`:
+      return level(action);
+    default:
+      return level;
+  }
 };
 
 const printBuffer = options => logBuffer => {
-    const {actionTransformer, collapsed, colors, timestamp, duration, level} = options;
-    logBuffer.forEach((logEntry, key) => {
-        const { started, startedTime, action, error } = logEntry;
-        const prevState = logEntry.prevState.nextState ? logEntry.prevState.nextState : '(Empty)';
-        let { took, nextState } = logEntry;
-        const nextEntry = logBuffer[key + 1];
-        if (nextEntry) {
-            nextState = nextEntry.prevState;
-            took = nextEntry.started - started;
-        }
-
-        const formattedAction = actionTransformer(action);
-        const isCollapsed = (typeof collapsed === `function`) ? collapsed(() => nextState, action) : collapsed;
-
-        const formattedTime = formatTime(startedTime);
-        const titleCSS = colors.title ? `color: ${colors.title(formattedAction)};` : null;
-        const title = `action ${timestamp ? formattedTime : ``} ${formattedAction.type} ${duration ? `(in ${took.toFixed(2)} ms)` : ``}`;
-
-        try {
-            if (isCollapsed) {
-                if (colors.title) logger.groupCollapsed(`%c ${title}`, titleCSS);
-                else logger.groupCollapsed(title);
-            } else {
-                if (colors.title) logger.group(`%c ${title}`, titleCSS);
-                else logger.group(title);
-            }
-        } catch (e) {
-            logger.log(title);
-        }
-
-        const prevStateLevel = getLogLevel(level, formattedAction, [prevState], `prevState`);
-        const actionLevel = getLogLevel(level, formattedAction, [formattedAction], `action`);
-        const errorLevel = getLogLevel(level, formattedAction, [error, prevState], `error`);
-        const nextStateLevel = getLogLevel(level, formattedAction, [nextState], `nextState`);
-
-        if (prevStateLevel) {
-            if (colors.prevState) logger[prevStateLevel](`%c prev state`, `color: ${colors.prevState(prevState)}; font-weight: bold`, prevState);
-            else logger[prevStateLevel](`prev state`, prevState);
-        }
-
-        if (actionLevel) {
-            if (colors.action) logger[actionLevel](`%c action`, `color: ${colors.action(formattedAction)}; font-weight: bold`, formattedAction);
-            else logger[actionLevel](`action`, formattedAction);
-        }
-
-        if (error && errorLevel) {
-            if (colors.error) logger[errorLevel](`%c error`, `color: ${colors.error(error, prevState)}; font-weight: bold`, error);
-            else logger[errorLevel](`error`, error);
-        }
-
-        if (nextStateLevel) {
-            if (colors.nextState) logger[nextStateLevel](`%c next state`, `color: ${colors.nextState(nextState)}; font-weight: bold`, nextState);
-            else logger[nextStateLevel](`next state`, nextState);
-        }
-
-        try {
-            logger.groupEnd();
-        } catch (e) {
-            logger.log(`—— log end ——`);
-        }
-    });
-    logBuffer.length = 0;
-};
+  const {
+    actionTransformer,
+    collapsed,
+    colors,
+    timestamp,
+    duration,
+    level
+  } = options;
+  logBuffer.forEach((logEntry, key) => {
+    const { started, startedTime, action, error } = logEntry;
+    const prevState = logEntry.prevState.nextState
+      ? logEntry.prevState.nextState
+      : '(Empty)';
+    let { took, nextState } = logEntry;
+    const nextEntry = logBuffer[key + 1];
+    if (nextEntry) {
+      nextState = nextEntry.prevState;
+      took = nextEntry.started - started;
+    }
 
-const isAllowed = (action, filter) => {
-    if (!filter) {
-        return true;
+    const formattedAction = actionTransformer(action);
+    const isCollapsed =
+      typeof collapsed === `function`
+        ? collapsed(() => nextState, action)
+        : collapsed;
+
+    const formattedTime = formatTime(startedTime);
+    const titleCSS = colors.title
+      ? `color: ${colors.title(formattedAction)};`
+      : null;
+    const title = `action ${timestamp ? formattedTime : ``} ${
+      formattedAction.type
+    } ${duration ? `(in ${took.toFixed(2)} ms)` : ``}`;
+
+    try {
+      if (isCollapsed) {
+        if (colors.title) logger.groupCollapsed(`%c ${title}`, titleCSS);
+        else logger.groupCollapsed(title);
+      } else {
+        if (colors.title) logger.group(`%c ${title}`, titleCSS);
+        else logger.group(title);
+      }
+    } catch (e) {
+      logger.log(title);
+    }
+
+    const prevStateLevel = getLogLevel(
+      level,
+      formattedAction,
+      [prevState],
+      `prevState`
+    );
+    const actionLevel = getLogLevel(
+      level,
+      formattedAction,
+      [formattedAction],
+      `action`
+    );
+    const errorLevel = getLogLevel(
+      level,
+      formattedAction,
+      [error, prevState],
+      `error`
+    );
+    const nextStateLevel = getLogLevel(
+      level,
+      formattedAction,
+      [nextState],
+      `nextState`
+    );
+
+    if (prevStateLevel) {
+      if (colors.prevState)
+        logger[prevStateLevel](
+          `%c prev state`,
+          `color: ${colors.prevState(prevState)}; font-weight: bold`,
+          prevState
+        );
+      else logger[prevStateLevel](`prev state`, prevState);
     }
-    if (filter.whitelist && filter.whitelist.length) {
-        return filter.whitelist.indexOf(action.type) !== -1;
+
+    if (actionLevel) {
+      if (colors.action)
+        logger[actionLevel](
+          `%c action`,
+          `color: ${colors.action(formattedAction)}; font-weight: bold`,
+          formattedAction
+        );
+      else logger[actionLevel](`action`, formattedAction);
     }
-    return filter.blacklist && filter.blacklist.indexOf(action.type) === -1;
-};
 
-export const storeLogger = (opts: LoggerOptions = {}) => (reducer: Function) => {
-    let log = {};
-    const ua = typeof window !== 'undefined' && window.navigator.userAgent ? window.navigator.userAgent : '';
-    let ms_ie = false;
-    //fix for action display in IE
-    const old_ie = ua.indexOf('MSIE ');
-    const new_ie = ua.indexOf('Trident/');
+    if (error && errorLevel) {
+      if (colors.error)
+        logger[errorLevel](
+          `%c error`,
+          `color: ${colors.error(error, prevState)}; font-weight: bold`,
+          error
+        );
+      else logger[errorLevel](`error`, error);
+    }
 
-    if ((old_ie > -1) || (new_ie > -1)) {
-        ms_ie = true;
+    if (nextStateLevel) {
+      if (colors.nextState)
+        logger[nextStateLevel](
+          `%c next state`,
+          `color: ${colors.nextState(nextState)}; font-weight: bold`,
+          nextState
+        );
+      else logger[nextStateLevel](`next state`, nextState);
     }
 
-    let colors: LoggerColorsOption;
-    if (ms_ie) {
-        // Setting colors functions to null when it's an IE browser.
-        colors = {
-            title: null,
-            prevState: null,
-            action: null,
-            nextState: null,
-            error: null,
-        }
-    } else {
-        colors = {
-            title: null,
-            prevState: () => '#9E9E9E',
-            action: () => '#03A9F4',
-            nextState: () => '#4CAF50',
-            error: () => '#F20404',
-        }
+    try {
+      logger.groupEnd();
+    } catch (e) {
+      logger.log(`—— log end ——`);
     }
+  });
+  logBuffer.length = 0;
+};
+
+const isAllowed = (action, filter) => {
+  if (!filter) {
+    return true;
+  }
+  if (filter.whitelist && filter.whitelist.length) {
+    return filter.whitelist.indexOf(action.type) !== -1;
+  }
+  return filter.blacklist && filter.blacklist.indexOf(action.type) === -1;
+};
+
+export const storeLogger = (opts: LoggerOptions = {}) => (
+  reducer: Function
+) => {
+  let log = {};
+  const ua =
+    typeof window !== 'undefined' && window.navigator.userAgent
+      ? window.navigator.userAgent
+      : '';
+  let ms_ie = false;
+  //fix for action display in IE
+  const old_ie = ua.indexOf('MSIE ');
+  const new_ie = ua.indexOf('Trident/');
+
+  if (old_ie > -1 || new_ie > -1) {
+    ms_ie = true;
+  }
+
+  let colors: LoggerColorsOption;
+  if (ms_ie) {
+    // Setting colors functions to null when it's an IE browser.
+    colors = {
+      title: null,
+      prevState: null,
+      action: null,
+      nextState: null,
+      error: null
+    };
+  } else {
+    colors = {
+      title: null,
+      prevState: () => '#9E9E9E',
+      action: () => '#03A9F4',
+      nextState: () => '#4CAF50',
+      error: () => '#F20404'
+    };
+  }
 
-    const defaults: LoggerOptions = {
-        level: 'log',
-        collapsed: false,
-        duration: true,
-        timestamp: true,
-        stateTransformer: state => state,
-        actionTransformer: actn => actn,
-        filter: {
-            whitelist: [],
-            blacklist: []
-        },
-        colors: colors
+  const defaults: LoggerOptions = {
+    level: 'log',
+    collapsed: false,
+    duration: true,
+    timestamp: true,
+    stateTransformer: state => state,
+    actionTransformer: actn => actn,
+    filter: {
+      whitelist: [],
+      blacklist: []
+    },
+    colors: colors
+  };
+
+  const options = Object.assign({}, defaults, opts);
+  const { stateTransformer } = options;
+  const buffer = printBuffer(options);
+
+  return function(state, action) {
+    let preLog = {
+      started: timer.now(),
+      startedTime: new Date(),
+      prevState: stateTransformer(log),
+      action
     };
 
-    const options = Object.assign({}, defaults, opts);
-    const {stateTransformer} = options;
-    const buffer = printBuffer(options);
-
-    return function(state, action) {
-        let preLog = {
-            started: timer.now(),
-            startedTime: new Date(),
-            prevState: stateTransformer(log),
-            action
-        };
-
-        let nextState = reducer(state, action);
-
-        let postLog = {
-            took: timer.now() - preLog.started,
-            nextState: stateTransformer(nextState)
-        };
-        log = Object.assign({}, preLog, postLog);
-        //ignore init action fired by store and devtools
-        if(action.type !== INIT_ACTION && isAllowed(action, options.filter)) {
-            buffer([log]);
-        }
-
-        return nextState;
+    let nextState = reducer(state, action);
+
+    let postLog = {
+      took: timer.now() - preLog.started,
+      nextState: stateTransformer(nextState)
+    };
+    log = Object.assign({}, preLog, postLog);
+    //ignore init action fired by store and devtools
+    if (action.type !== INIT_ACTION && isAllowed(action, options.filter)) {
+      buffer([log]);
     }
+
+    return nextState;
+  };
 };
 
 export interface LoggerOptions {
-    /**
-     * 'log' | 'console' | 'warn' | 'error' | 'info'. Default: 'log'
-     */
-    level?: any;
-    /**
-     * Should log group be collapsed? default: false
-     */
-    collapsed?: boolean;
-    /**
-     * Print duration with action? default: true
-     */
-    duration?: boolean;
-    /**
-     * Print timestamp with action? default: true
-     */
-    timestamp?: boolean;
-    filter?: LoggerFilterOption;
-    /**
-     * Transform state before print default: state => state
-     */
-    stateTransformer?: (state: Object) => Object;
-    /**
-     * Transform action before print default: actn => actn
-     */
-    actionTransformer?: (actn: Object) => Object;
-    colors?: LoggerColorsOption;
-};
+  /**
+   * 'log' | 'console' | 'warn' | 'error' | 'info'. Default: 'log'
+   */
+  level?: any;
+  /**
+   * Should log group be collapsed? default: false
+   */
+  collapsed?: boolean;
+  /**
+   * Print duration with action? default: true
+   */
+  duration?: boolean;
+  /**
+   * Print timestamp with action? default: true
+   */
+  timestamp?: boolean;
+  filter?: LoggerFilterOption;
+  /**
+   * Transform state before print default: state => state
+   */
+  stateTransformer?: (state: Object) => Object;
+  /**
+   * Transform action before print default: actn => actn
+   */
+  actionTransformer?: (actn: Object) => Object;
+  colors?: LoggerColorsOption;
+}
 
 export interface LoggerFilterOption {
-    /**
-     * Only print actions included in this list - has priority over blacklist
-     */
-    whitelist?: string[];
-    /**
-     * Only print actions that are NOT included in this list
-     */
-    blacklist?: string[];
+  /**
+   * Only print actions included in this list - has priority over blacklist
+   */
+  whitelist?: string[];
+  /**
+   * Only print actions that are NOT included in this list
+   */
+  blacklist?: string[];
 }
 
 export interface LoggerColorsOption {
-    title: (action: Object) => string;
-    prevState: (prevState: Object) => string;
-    action: (action: Object) => string;
-    nextState: (nextState: Object) => string;
-    error: (error: any, prevState: Object) => string;
+  title: (action: Object) => string;
+  prevState: (prevState: Object) => string;
+  action: (action: Object) => string;
+  nextState: (nextState: Object) => string;
+  error: (error: any, prevState: Object) => string;
 }

chore: bump version