Skip to content
Snippets Groups Projects
index.js 6.29 MiB
Newer Older
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

const {
  BaseKonnector,
  log,
  addData,
  hydrateAndFilter,
  errors,
} = __webpack_require__(1)

const getAccountId = __webpack_require__(1244)

const moment = __webpack_require__(1245)
const rp = __webpack_require__(1379)
__webpack_require__(1383)

moment.locale('fr') // set the language
moment.tz.setDefault('Europe/Paris') // set the timezone

/*** Connector Constants ***/
const manualExecution = process.env.COZY_JOB_MANUAL_EXECUTION
const startDailyDate = manualExecution
  ? moment().subtract(12, 'month')
  : moment().subtract(32, 'month')
const startDailyDateString = startDailyDate.format('YYYY-MM-DD')
const startLoadDate = moment().subtract(7, 'day')
const startLoadDateString = startLoadDate.format('YYYY-MM-DD')
const endDate = moment()
const endDateString = endDate.format('YYYY-MM-DD')
const baseUrl = 'https://gw.prd.api.enedis.fr'
const dailyDataURL = `${baseUrl}/v4/metering_data/daily_consumption`
const loadCurveURL = `${baseUrl}/v4/metering_data/consumption_load_curve`

/**
 * The start function is run by the BaseKonnector instance only when it got all the account
 * information (fields). When you run this connector yourself in "standalone" mode or "dev" mode,
 * the account information come from ./konnector-dev-config.json file
 * cozyParameters are static parameters, independents from the account. Most often, it can be a
 * secret api key.
 * @param {Object}  fields
 * @param {string}  fields.access_token - access token
 * @param {string}  fields.refresh_token - refresh token
 * @param {Object}  cozyParameters - cozy parameters
 * @param {boolean} doRetry - whether we should use the refresh token or not
 */
async function start(fields, cozyParameters, doRetry = true) {
  log('info', 'Starting the enedis konnector')
  log('info', `Manual execution: ${manualExecution}`)
  const accountId = getAccountId()
  let usage_point_id = ''
  try {
    const { access_token } = fields
    if (
      this._account &&
      this._account.oauth_callback_results &&
      this._account.oauth_callback_results.usage_points_id
    ) {
      const usage_points_id = this._account.oauth_callback_results.usage_points_id.split(
        ','
      )
      usage_point_id = usage_points_id[0]
    } else if (fields.usage_point_id) {
      // In case of refresh token, we retrieve the usage point id from the fields
      usage_point_id = fields.usage_point_id
      log('error', 'no usage_point_id found')
      throw errors.USER_ACTION_NEEDED_OAUTH_OUTDATED
    }

    log('info', 'Fetching enedis daily data')
    const fetchedDailyData = await getDailyData(access_token, usage_point_id)
    log('info', 'Process enedis daily data')
    const processedDailyData = await processData(
      fetchedDailyData,
      'com.grandlyon.enedis.day',
      ['year', 'month', 'day']
    )
    log('info', 'Agregate enedis daily data for month and year')
    await agregateMonthAndYearData(processedDailyData)
    log('info', 'Process enedis load data')
    await startLoadDataProcess(access_token, usage_point_id)
  } catch (err) {
    if (err.statusCode === 403 || err.code === 403) {
      if (!fields.refresh_token) {
        log('info', 'no refresh token found')
        throw errors.USER_ACTION_NEEDED_OAUTH_OUTDATED
      } else if (doRetry) {
        log('info', 'asking refresh from the stack')
        let body
        try {
          body = await cozyClient.fetchJSON(
            'POST',
            `/accounts/enedisgrandlyon/${accountId}/refresh`
          )
        } catch (err) {
          log('info', `Error during refresh ${err.message}`)
          throw errors.USER_ACTION_NEEDED_OAUTH_OUTDATED
        }
        log('info', 'refresh response')
        log('info', JSON.stringify(body))
        fields.access_token = body.attributes.oauth.access_token
        fields.usage_point_id = usage_point_id
        return start(fields, cozyParameters, false)
      }
      log('error', `Error during authentication: ${err.message}`)
      throw errors.VENDOR_DOWN
    } else {
      log('error', 'caught an unexpected error')
      log('error', err.message)
    }
  }
}

/**
 * Retrieve data from the API
 * Format: { value: "Wh", "date": "YYYY-MM-DD" }
 */
async function getDailyData(token, usagePointID) {
  const dataRequest = {
    method: 'GET',
    uri:
      startDailyDateString +
      '&usage_point_id=' +
      usagePointID,
    headers: {
      Accept: 'application/json',
      Authorization: 'Bearer ' + token,
    },
  }
  const response = await rp(dataRequest)
  return response
}

/**
 * Check if history is loaded
 * If not, call several time the api to retrieve 1 month of history for load data
 * If yes only call once the api
 */
async function startLoadDataProcess(token, usagePointID) {
  log('info', 'Check consent for user')
  const isConsent = await checkConsentForLoadCurve(
    token,
    usagePointID,
    startLoadDateString,
    log('info', 'Check history')
    const isHistory = await isHistoryLoaded('com.grandlyon.enedis.minute')
    log('info', `isHistory: ${isHistory}`)
    if (isHistory || manualExecution) {
      log('info', 'launch process without history')
      await launchLoadDataProcess(
        token,
        usagePointID,
        startLoadDateString,
        endDateString
    } else {
      log('info', 'launch process with history')
      for (var i = 0; i < 4; i++) {
        const increamentedStartDate = moment(startLoadDate)
        const incrementedEndDate = moment(endDate)
        const increamentedStartDateString = increamentedStartDate
          .subtract(7 * i, 'day')
          .format('YYYY-MM-DD')
        const incrementedEndDateString = incrementedEndDate
          .subtract(7 * i, 'day')
          .format('YYYY-MM-DD')
        await launchLoadDataProcess(
          token,
          usagePointID,
          increamentedStartDateString,
          incrementedEndDateString
        )
      }
 * Request API and check return code
 * Return true or false
async function checkConsentForLoadCurve(
  const dataRequest = {
    method: 'GET',
    uri:
      '&usage_point_id=' +
      usagePointID,
    headers: {
      Accept: 'application/json',
      Authorization: 'Bearer ' + token,
    },
    log('info', 'Consent found for load curve')
  } catch (err) {
    if (
      (err.statusCode === 400 || err.code === 400) &&
      err.message.search('ADAM-ERR0075') > 0
    ) {
      log('info', 'No consent for load curve')
      return false
    } else if (err.statusCode === 403 || err.code === 403) {
      log('info', 'No consent for load curve')
/**
 * Function checking if the history is loaded
 */
async function isHistoryLoaded(doctype) {
  log('debug', doctype, 'Retrieve data')
  const result = await cozyClient.data.findAll(doctype)
  if (result && result.length > 0) {
    const filtered = result.filter(function(el) {
      const elDate = moment({
        year: el.year,
        month: el.month,
        day: el.day,
        minute: el.minute,
      })
      return elDate.isBefore(startLoadDate)
    })
    if (filtered.length > 0) {
      return true
/**
 * Launch process to handle load data
 */
async function launchLoadDataProcess(
  token,
  usagePointID,
  _startLoadDate,
  _endDate
) {
  log('info', 'Fetching enedis load data')
  const fetchedLoadData = await getLoadData(
    token,
    usagePointID,
    _startLoadDate,
    _endDate
  )
  if (fetchedLoadData && fetchedLoadData.length > 0) {
    log('info', 'Process enedis load data')
    const processedLoadData = await processData(
      fetchedLoadData,
      'com.grandlyon.enedis.minute',
      ['year', 'month', 'day', 'hour', 'minute']
    )
    // log('info', 'Agregate enedis load data for hour')
    // await agregateHourlyData(processedLoadData)
  } else {
    log('info', 'No consent or data for load curve')
  }
}

/**
 * Retrieve data from the API
 * Format: { value: "W", "date": "YYYY-MM-DD hh:mm:ss" }
 */
async function getLoadData(token, usagePointID, _startDate, _endDate) {
  const dataRequest = {
    method: 'GET',
    uri:
      _startDate +
      '&end=' +
      _endDate +
      '&usage_point_id=' +
      usagePointID,
    headers: {
      Accept: 'application/json',
      Authorization: 'Bearer ' + token,
    },
  }
  const response = await rp(dataRequest)
  return response
}

/**
 * Parse data
 * Remove existing data from DB using hydrateAndFilter
 * Store filtered data
 * Return the list of filtered data
 */
async function processData(data, doctype, filterKeys) {
  const parsedData = JSON.parse(data)
  const intervalData = parsedData.meter_reading.interval_reading
  const formatedData = await formateData(intervalData, doctype)
  // Remove data for existing days into the DB
  const filteredData = await hydrateAndFilter(formatedData, doctype, {
  })
  // Store new day data
  await storeData(filteredData, doctype, filterKeys)
  return filteredData
}

/**
 * Agregate data from daily data to monthly and yearly data
 */
async function agregateMonthAndYearData(data) {
  // Sum year and month values into object with year or year-month as keys
  if (data && data.length > 0) {
    let monthData = {}
    let yearData = {}
    data.forEach(element => {
      element.year + '-' + element.month in monthData
        ? (monthData[element.year + '-' + element.month] += element.load)
        : (monthData[element.year + '-' + element.month] = element.load)
      element.year in yearData
        ? (yearData[element.year] += element.load)
        : (yearData[element.year] = element.load)
    })
    // Agregation for Month data
    const agregatedMonthData = await buildAgregatedData(
      monthData,
      'com.grandlyon.enedis.month'
    )
    await storeData(agregatedMonthData, 'com.grandlyon.enedis.month', [
      'year',
    ])
    // Agregation for Year data
    const agregatedYearData = await buildAgregatedData(
      yearData,
      'com.grandlyon.enedis.year'
    )
    await storeData(agregatedYearData, 'com.grandlyon.enedis.year', ['year'])
  }
}

/**
 * Agregate data from load data (every 30 min) to Hourly data
 */
async function agregateHourlyData(data) {
  // Sum year and month values into object with year or year-month as keys
  if (data && data.length > 0) {
    let hourData = {}
    data.forEach(element => {
      let key =
        element.year +
        '-' +
        element.month +
        '-' +
        element.day +
        '-' +
        element.hour
      key in hourData
        ? (hourData[key] += element.load)
        : (hourData[key] = element.load)
    })
    // Agregation for Month data
    const agregatedMonthData = await buildAgregatedData(
      hourData,
      'com.grandlyon.enedis.hour'
    )
    await storeData(agregatedMonthData, 'com.grandlyon.enedis.hour', [
      'year',
      'month',
      'day',
    ])
  }
}

/**
 * Save data in the right doctype db and prevent duplicated keys
 */
async function storeData(data, doctype, filterKeys) {
  log('debug', doctype, 'Store into')
  const filteredDocuments = await hydrateAndFilter(data, doctype, {
  })
  return await addData(filteredDocuments, doctype)
}

/**
 * Format data for DB storage
 * Remove bad data
 */
async function formateData(data, doctype) {
  log('info', 'Formating data')
  return data.map(record => {
    let date = moment(record.date, 'YYYY/MM/DD h:mm:ss')
    if (record.value != -2) {
      const load =
        doctype === 'com.grandlyon.enedis.minute'
          ? record.value / 2
          : record.value
      if (doctype === 'com.grandlyon.enedis.minute') {
        date = date.subtract(30, 'minute')
      }
      return {
        load: parseFloat(load / 1000),
        year: parseInt(date.format('YYYY')),
        month: parseInt(date.format('M')),
        day: parseInt(date.format('D')),
        hour: parseInt(date.format('H')),
        minute: parseInt(date.format('m')),
      }
    }
  })
}

/**
 * Retrieve and remove old data for a specific doctype
 * Return an Array of agregated data
 */
async function buildAgregatedData(data, doctype) {
  let agregatedData = []
  for (let [key, value] of Object.entries(data)) {
    const data = await buildDataFromKey(doctype, key, value)
    const oldValue = await resetInProgressAggregatedData(data, doctype)
    data.load += oldValue
    agregatedData.push(data)
  }
  return agregatedData
}

/**
 * Format an entry for DB storage
 * using key and value
 * For year doctype: key = "YYYY"
 * For month doctype: key = "YYYY-MM"
 */
async function buildDataFromKey(doctype, key, value) {
  let year, month, day, hour
  if (doctype === 'com.grandlyon.enedis.year') {
    year = key
    month = 1
    day = 0
    hour = 0
  } else if (doctype === 'com.grandlyon.enedis.month') {
    const split = key.split('-')
    year = split[0]
    month = split[1]
    day = 0
    hour = 0
  } else {
    const split = key.split('-')
    year = split[0]
    month = split[1]
    day = split[2]
    hour = split[3]
  }
  return {
    load: Math.round(value * 10000) / 10000,
    year: parseInt(year),
    month: parseInt(month),
    day: parseInt(day),
    hour: parseInt(hour),
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
  }
}

/**
 * Function handling special case.
 * The temporary aggregated data need to be remove in order for the most recent one te be saved.
 * ex for com.grandlyon.enedis.year :
 * { load: 76.712, year: 2020, ... } need to be replace by
 * { load: 82.212, year: 2020, ... } after enedis data reprocess
 */
async function resetInProgressAggregatedData(data, doctype) {
  // /!\ Warning: cannot use mongo queries because not supported for dev by cozy-konnectors-libs
  log('debug', doctype, 'Remove aggregated data for')
  const result = await cozyClient.data.findAll(doctype)
  if (result && result.length > 0) {
    // Filter data to remove
    var filtered = []
    if (doctype === 'com.grandlyon.enedis.year') {
      // Yearly case
      filtered = result.filter(function(el) {
        return el.year == data.year
      })
    } else if (doctype === 'com.grandlyon.enedis.month') {
      // Monthly case
      filtered = result.filter(function(el) {
        return el.year == data.year && el.month == data.month
      })
    } else {
      // Hourly case
      filtered = result.filter(function(el) {
        return (
          el.year == data.year &&
          el.month == data.month &&
          el.day == data.day &&
          el.hour == data.hour
        )
      })
    }
    // Remove data
    let sum = 0.0
    for (const doc of filtered) {
      sum += doc.load
      log('debug', doc, 'Removing this entry for ' + doctype)
      await cozyClient.data.delete(doctype, doc)
    }
    return sum
  }
  return 0.0
}

module.exports = new BaseKonnector(start)


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

const log = __webpack_require__(2).namespace('cozy-konnector-libs');

const requestFactory = __webpack_require__(22);

const hydrateAndFilter = __webpack_require__(611);

const categorization = __webpack_require__(1115);

module.exports = {
  BaseKonnector: __webpack_require__(1170),
  CookieKonnector: __webpack_require__(1237),
  cozyClient: __webpack_require__(617),
  errors: __webpack_require__(1176),
  log,
  saveFiles: __webpack_require__(1172),
  saveBills: __webpack_require__(1171),
  saveIdentity: __webpack_require__(1203),
  linkBankOperations: __webpack_require__(1181),
  addData: __webpack_require__(1180),
  hydrateAndFilter,
  htmlToPDF: __webpack_require__(1238).htmlToPDF,
  createCozyPDFDocument: __webpack_require__(1238).createCozyPDFDocument,
  filterData: deprecate(hydrateAndFilter, 'Use hydrateAndFilter now. filterData will be removed in cozy-konnector-libs@4'),
  updateOrCreate: __webpack_require__(1202),
  request: deprecate(requestFactory, 'Use requestFactory instead of request. It will be removed in cozy-konnector-libs@4'),
  requestFactory,
  retry: __webpack_require__(1173),
  wrapIfSentrySetUp: __webpack_require__(1204).wrapIfSentrySetUp,
  Document: __webpack_require__(1239),
  signin: __webpack_require__(1199),
  submitForm: __webpack_require__(1199),
  scrape: __webpack_require__(1241),
  mkdirp: __webpack_require__(1175),
  normalizeFilename: __webpack_require__(1242),
  utils: __webpack_require__(616),
  solveCaptcha: __webpack_require__(1243),
  createCategorizer: categorization.createCategorizer,
  categorize: categorization.categorize,
  manifest: __webpack_require__(1059)
};

function deprecate(wrapped, message) {
  return function () {
    log('warn', message);
    return wrapped.apply(this, arguments);
  };
}

/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

const { filterLevel, filterSecrets } = __webpack_require__(3)
const Secret = __webpack_require__(4)
const { LOG_LEVEL } = process.env
let level = LOG_LEVEL || 'debug'
const format = __webpack_require__(5)
const filters = [filterLevel, filterSecrets]

const filterOut = function() {
  for (const filter of filters) {
    if (filter.apply(null, arguments) === false) {
      return true
    }
  }
  return false
}

/**
 * Use it to log messages in your konnector. Typical types are
 *
 * - `debug`
 * - `warning`
 * - `info`
 * - `error`
 * - `ok`
 *
 *
 * @example
 *
 * They will be colored in development mode. In production mode, those logs are formatted in JSON to be interpreted by the stack and possibly sent to the client. `error` will stop the konnector.
 *
 * ```js
 * logger = log('my-namespace')
 * logger('debug', '365 bills')
 * // my-namespace : debug : 365 bills
 * logger('info', 'Page fetched')
 * // my-namespace : info : Page fetched
 * ```
 * @param  {string} type
 * @param  {string} message
 * @param  {string} label
 * @param  {string} namespace
 */
function log(type, message, label, namespace) {
  if (filterOut(level, type, message, label, namespace)) {
    return
  }
  // eslint-disable-next-line no-console
  console.log(format(type, message, label, namespace))
}

log.addFilter = function(filter) {
  return filters.push(filter)
}

log.setLevel = function(lvl) {
  level = lvl
}

// Short-hands
const methods = ['debug', 'info', 'warn', 'error', 'ok', 'critical']
methods.forEach(level => {
  log[level] = function(message, label, namespace) {
    return log(level, message, label, namespace)
  }
})

module.exports = log

log.setNoRetry = obj => {
  if (obj) obj.no_retry = true
  else obj = { no_retry: true }
  return obj.no_retry
}
log.Secret = Secret
log.namespace = function(namespace) {
  return function(type, message, label, ns = namespace) {
    log(type, message, label, ns)
  }
}


/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

const levels = {
  secret: 0,
  debug: 10,
  info: 20,
  warn: 30,
  error: 40,
  ok: 50,
  critical: 50
}

const Secret = __webpack_require__(4)

const filterSecrets = function(level, type, message) {
  if (type !== 'secret' && message instanceof Secret) {
    throw new Error('You should log a secret with log.secret')
  }
}

const filterLevel = function(level, type) {
  return levels[type] >= levels[level]
}

module.exports = {
  filterSecrets,
  filterLevel
}


/***/ }),
/* 4 */
/***/ (function(module, exports) {

const Secret = function(data) {
  Object.assign(this, data)
  return this
}

Secret.prototype.toString = function() {
  throw new Error('Cannot convert Secret to string')
}

module.exports = Secret


/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

const prodFormat = __webpack_require__(6)
const devFormat = __webpack_require__(8)

switch ("none") {
  case 'production':
    module.exports = prodFormat
    break
  case 'development':
    module.exports = devFormat
    break
  case 'standalone':
    module.exports = devFormat
    break
  case 'test':
    module.exports = devFormat
    break
  default:
    module.exports = prodFormat
}


/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

const stringify = __webpack_require__(7)

const LOG_LENGTH_LIMIT = 64 * 1024 - 1

function prodFormat(type, message, label, namespace) {
  const log = { time: new Date(), type, label, namespace }

  if (typeof message === 'object') {
    if (message && message.no_retry) {
      log.no_retry = message.no_retry
    }
    if (message && message.message) {
      log.message = message.message
    }
  } else {
    log.message = message
  }

  // properly display error messages
  if (log.message && log.message.stack) {
    log.message = log.message.stack
  }

  // cut the string to avoid a fail in the stack
  let result = log
  try {
    result = stringify(log).substr(0, LOG_LENGTH_LIMIT)
  } catch (err) {
    // eslint-disable-next-line no-console
    console.log(err.message, 'cozy-logger: Failed to convert message to JSON')
  }
  return result
}

module.exports = prodFormat


/***/ }),
/* 7 */
/***/ (function(module, exports) {

exports = module.exports = stringify
exports.getSerialize = serializer

function stringify(obj, replacer, spaces, cycleReplacer) {
  return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces)
}

function serializer(replacer, cycleReplacer) {
  var stack = [], keys = []

  if (cycleReplacer == null) cycleReplacer = function(key, value) {
    if (stack[0] === value) return "[Circular ~]"
    return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]"
  }

  return function(key, value) {
    if (stack.length > 0) {
      var thisPos = stack.indexOf(this)
      ~thisPos ? stack.splice(thisPos + 1) : stack.push(this)
      ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key)
      if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value)
    }
    else stack.push(value)

    return replacer == null ? value : replacer.call(this, key, value)
  }
}


/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {

const util = __webpack_require__(9)
const chalk = __webpack_require__(10)

if (util && util.inspect && util.inspect.defaultOptions) {
  util.inspect.defaultOptions.maxArrayLength = null
  util.inspect.defaultOptions.depth = 2
  util.inspect.defaultOptions.colors = true
}

const type2color = {
  debug: 'cyan',
  warn: 'yellow',
  info: 'blue',
  error: 'red',
  ok: 'green',
  secret: 'red',
  critical: 'red'
}

function devFormat(type, message, label, namespace) {
  let formatmessage = message

  if (typeof formatmessage !== 'string') {
    formatmessage = util.inspect(formatmessage)
  }

  let formatlabel = label ? ` : "${label}" ` : ''
  let formatnamespace = namespace ? chalk.magenta(`${namespace}: `) : ''

  let color = type2color[type]
  let formattype = color ? chalk[color](type) : type

  return `${formatnamespace}${formattype}${formatlabel} : ${formatmessage}`
}

module.exports = devFormat


/***/ }),
/* 9 */
/***/ (function(module, exports) {

module.exports = require("util");

/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

const escapeStringRegexp = __webpack_require__(11);
const ansiStyles = __webpack_require__(12);
const stdoutColor = __webpack_require__(18).stdout;

const template = __webpack_require__(21);

const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm');

// `supportsColor.level` → `ansiStyles.color[name]` mapping
const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];

// `color-convert` models to exclude from the Chalk API due to conflicts and such
const skipModels = new Set(['gray']);

const styles = Object.create(null);

function applyOptions(obj, options) {
	options = options || {};

	// Detect level if not set manually
	const scLevel = stdoutColor ? stdoutColor.level : 0;
	obj.level = options.level === undefined ? scLevel : options.level;
	obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
}

function Chalk(options) {
	// We check for this.template here since calling `chalk.constructor()`
	// by itself will have a `this` of a previously constructed chalk object
	if (!this || !(this instanceof Chalk) || this.template) {
		const chalk = {};
		applyOptions(chalk, options);

		chalk.template = function () {
			const args = [].slice.call(arguments);
			return chalkTag.apply(null, [chalk.template].concat(args));
		};