@autofleet/node-common 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +26 -0
- package/.eslintrc.json +0 -3
- package/README.md +1 -1
- package/index.js +6 -3
- package/logger/example.js +4 -5
- package/logger/index.js +37 -50
- package/logger/index.test.js +38 -92
- package/network/index.js +53 -23
- package/network/index.test.js +57 -20
- package/package.json +3 -3
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
jobs:
|
|
3
|
+
test:
|
|
4
|
+
docker:
|
|
5
|
+
- image: circleci/node:8.9.4
|
|
6
|
+
steps:
|
|
7
|
+
- checkout
|
|
8
|
+
- restore_cache:
|
|
9
|
+
keys:
|
|
10
|
+
- v1-dependencies-{{ checksum "package.json" }}
|
|
11
|
+
# fallback to using the latest cache if no exact match is found
|
|
12
|
+
- v1-dependencies-
|
|
13
|
+
- run: npm i
|
|
14
|
+
- save_cache:
|
|
15
|
+
paths:
|
|
16
|
+
- node_modules
|
|
17
|
+
key: v1-dependencies-{{ checksum "package.json" }}
|
|
18
|
+
- run: npm run coverage
|
|
19
|
+
- run: rm -rf ./coverage
|
|
20
|
+
- run: npm run linter
|
|
21
|
+
|
|
22
|
+
workflows:
|
|
23
|
+
version: 2
|
|
24
|
+
build_and_test:
|
|
25
|
+
jobs:
|
|
26
|
+
- test
|
package/.eslintrc.json
CHANGED
package/README.md
CHANGED
package/index.js
CHANGED
package/logger/example.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const logger = require('./index')(
|
|
1
|
+
const logger = require('./index')();
|
|
2
2
|
|
|
3
|
-
logger.info('it is working')
|
|
4
|
-
logger.error('errors displayed in logs/error.log')
|
|
5
|
-
logger.debug('debug with object', { a: 5 })
|
|
6
|
-
logger.debug('debug with 2 objects', { 1: { a: 5 }, 2: { b: 2 } })
|
|
3
|
+
logger.info('it is working');
|
|
4
|
+
logger.error('errors displayed in logs/error.log');
|
|
5
|
+
logger.debug('debug with object', { a: 5 });
|
package/logger/index.js
CHANGED
|
@@ -1,64 +1,51 @@
|
|
|
1
|
-
const
|
|
1
|
+
const winston = require('winston');
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { createLogger } = winston;
|
|
4
|
+
require('dotenv').config();
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const { env } = process;
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const infoEnvNmaes = [
|
|
9
|
+
'production',
|
|
10
|
+
'staging',
|
|
11
|
+
'test',
|
|
12
|
+
];
|
|
8
13
|
|
|
9
14
|
const getLevel = (logLevel) => {
|
|
10
|
-
if (logLevel) return logLevel
|
|
11
|
-
if (env.LOG_LEVEL) return env.LOG_LEVEL
|
|
12
|
-
if (env.NODE_ENV
|
|
13
|
-
|
|
14
|
-
return '
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (env.USE_LOG_FILES === 'true') {
|
|
21
|
-
transporters = transporters.concat([
|
|
22
|
-
new transports.File({ filename: 'logs/error.log', level: 'error' }),
|
|
23
|
-
new transports.File({ filename: 'logs/all.log' }),
|
|
24
|
-
])
|
|
15
|
+
if (logLevel) return logLevel;
|
|
16
|
+
if (env.LOG_LEVEL) return env.LOG_LEVEL;
|
|
17
|
+
if (infoEnvNmaes.includes(env.NODE_ENV)) return 'info';
|
|
18
|
+
if (env.NODE_ENV === 'development') return 'debug';
|
|
19
|
+
return 'debug';
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const getFormat = () => {
|
|
23
|
+
if (env.NODE_ENV === 'producation') {
|
|
24
|
+
return winston.format.json();
|
|
25
25
|
}
|
|
26
|
-
return transporters
|
|
27
|
-
}
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
delete info.message
|
|
36
|
-
delete info.timestamp
|
|
37
|
-
const params = JSON.stringify(info, null, 2)
|
|
38
|
-
return `${level}: ${message} ${timestamp} \n ${params} \n *****************`
|
|
39
|
-
})
|
|
27
|
+
return winston.format.combine(
|
|
28
|
+
winston.format.splat(),
|
|
29
|
+
winston.format.colorize(),
|
|
30
|
+
winston.format.simple(),
|
|
31
|
+
);
|
|
32
|
+
};
|
|
40
33
|
|
|
34
|
+
const createLoggerInstance = (level, transports) => {
|
|
41
35
|
const logger = createLogger({
|
|
42
|
-
format: combine(
|
|
43
|
-
format.colorize(),
|
|
44
|
-
// format.json(),
|
|
45
|
-
format.simple(),
|
|
46
|
-
// prettyPrint(),
|
|
47
|
-
timestamp(),
|
|
48
|
-
customFormat,
|
|
49
|
-
),
|
|
50
36
|
level,
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
format: getFormat(),
|
|
38
|
+
transports: [new winston.transports.Console()],
|
|
39
|
+
exceptionHandlers: transports,
|
|
40
|
+
exitOnError: false,
|
|
41
|
+
});
|
|
53
42
|
|
|
54
|
-
return logger
|
|
55
|
-
}
|
|
43
|
+
return logger;
|
|
44
|
+
};
|
|
56
45
|
|
|
57
46
|
const getLogger = (logLevel) => {
|
|
58
|
-
const level = getLevel(logLevel)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
module.exports = getLogger
|
|
47
|
+
const level = getLevel(logLevel);
|
|
48
|
+
return createLoggerInstance(level);
|
|
49
|
+
};
|
|
64
50
|
|
|
51
|
+
module.exports = getLogger;
|
package/logger/index.test.js
CHANGED
|
@@ -1,108 +1,54 @@
|
|
|
1
|
-
const Logger = require('./index')
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const wait = require('wait-promise')
|
|
1
|
+
const Logger = require('./index');
|
|
4
2
|
|
|
5
|
-
const { env } = process
|
|
6
|
-
|
|
7
|
-
const deleteLogFile = (filePath) => {
|
|
8
|
-
const dir = 'logs'
|
|
9
|
-
if (!fs.existsSync(dir)) {
|
|
10
|
-
fs.mkdirSync(dir)
|
|
11
|
-
}
|
|
12
|
-
if (fs.existsSync(filePath)) {
|
|
13
|
-
fs.unlinkSync(filePath)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const waitForFileToHaveContent = (filePath => wait.limit(30).until(() => {
|
|
18
|
-
if (fs.existsSync(filePath)) {
|
|
19
|
-
const content = fs.readFileSync(filePath, 'utf8')
|
|
20
|
-
return content !== ''
|
|
21
|
-
}
|
|
22
|
-
return false
|
|
23
|
-
}))
|
|
3
|
+
const { env } = process;
|
|
24
4
|
|
|
25
5
|
describe('Logger', () => {
|
|
26
6
|
it('it`s default level is info', () => {
|
|
27
|
-
env.NODE_ENV = ''
|
|
28
|
-
const logger = Logger()
|
|
29
|
-
expect(logger).toBeDefined()
|
|
30
|
-
expect(logger.level).toBe('
|
|
31
|
-
})
|
|
7
|
+
env.NODE_ENV = '';
|
|
8
|
+
const logger = Logger();
|
|
9
|
+
expect(logger).toBeDefined();
|
|
10
|
+
expect(logger.level).toBe('debug');
|
|
11
|
+
});
|
|
32
12
|
|
|
33
13
|
it('its default develpment level is debug', () => {
|
|
34
|
-
env.NODE_ENV = 'development'
|
|
35
|
-
const logger = Logger()
|
|
36
|
-
expect(logger.level).toBe('debug')
|
|
37
|
-
})
|
|
14
|
+
env.NODE_ENV = 'development';
|
|
15
|
+
const logger = Logger();
|
|
16
|
+
expect(logger.level).toBe('debug');
|
|
17
|
+
});
|
|
38
18
|
|
|
39
19
|
it('its default test level is info', () => {
|
|
40
|
-
env.NODE_ENV = 'test'
|
|
41
|
-
const logger = Logger()
|
|
42
|
-
expect(logger.level).toBe('info')
|
|
43
|
-
})
|
|
20
|
+
env.NODE_ENV = 'test';
|
|
21
|
+
const logger = Logger();
|
|
22
|
+
expect(logger.level).toBe('info');
|
|
23
|
+
});
|
|
44
24
|
|
|
45
25
|
it('its default production level is info', () => {
|
|
46
|
-
env.NODE_ENV = 'production'
|
|
47
|
-
const logger = Logger()
|
|
48
|
-
expect(logger.level).toBe('info')
|
|
49
|
-
})
|
|
26
|
+
env.NODE_ENV = 'production';
|
|
27
|
+
const logger = Logger();
|
|
28
|
+
expect(logger.level).toBe('info');
|
|
29
|
+
});
|
|
50
30
|
|
|
51
31
|
it('its level can be override by LOG_LEVEL env variable', () => {
|
|
52
|
-
env.NODE_ENV = 'development'
|
|
53
|
-
env.LOG_LEVEL = 'warn'
|
|
54
|
-
const logger = Logger()
|
|
55
|
-
expect(logger.level).toBe('warn')
|
|
56
|
-
})
|
|
32
|
+
env.NODE_ENV = 'development';
|
|
33
|
+
env.LOG_LEVEL = 'warn';
|
|
34
|
+
const logger = Logger();
|
|
35
|
+
expect(logger.level).toBe('warn');
|
|
36
|
+
});
|
|
57
37
|
|
|
58
38
|
it('its level can be override by function variable', () => {
|
|
59
|
-
env.NODE_ENV = 'production'
|
|
60
|
-
env.LOG_LEVEL = 'warn'
|
|
61
|
-
const logger = Logger('silly')
|
|
62
|
-
expect(logger.level).toBe('silly')
|
|
63
|
-
})
|
|
39
|
+
env.NODE_ENV = 'production';
|
|
40
|
+
env.LOG_LEVEL = 'warn';
|
|
41
|
+
const logger = Logger('silly');
|
|
42
|
+
expect(logger.level).toBe('silly');
|
|
43
|
+
});
|
|
64
44
|
|
|
65
45
|
it('its has functions for each level', () => {
|
|
66
|
-
const logger = Logger()
|
|
67
|
-
expect(logger.error).toBeFunction()
|
|
68
|
-
expect(logger.warn).toBeFunction()
|
|
69
|
-
expect(logger.info).toBeFunction()
|
|
70
|
-
expect(logger.verbose).toBeFunction()
|
|
71
|
-
expect(logger.debug).toBeFunction()
|
|
72
|
-
expect(logger.silly).toBeFunction()
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('it can have general file transporters', async () => {
|
|
76
|
-
env.USE_LOG_FILES = 'true'
|
|
77
|
-
const allPath = 'logs/all.log'
|
|
78
|
-
deleteLogFile(allPath)
|
|
79
|
-
|
|
80
|
-
const logger = Logger()
|
|
81
|
-
const errorText = 'this is error'
|
|
82
|
-
logger.error(errorText)
|
|
83
|
-
|
|
84
|
-
await waitForFileToHaveContent(allPath)
|
|
85
|
-
|
|
86
|
-
expect(fs.existsSync(allPath)).toBe(true)
|
|
87
|
-
|
|
88
|
-
const contents = fs.readFileSync(allPath, 'utf8')
|
|
89
|
-
expect(contents).toBe(`error: ${errorText}\n`)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('it can have general file transporters', async () => {
|
|
93
|
-
env.USE_LOG_FILES = 'true'
|
|
94
|
-
const errorPath = 'logs/error.log'
|
|
95
|
-
deleteLogFile(errorPath)
|
|
96
|
-
|
|
97
|
-
expect(fs.existsSync(errorPath)).toBe(false)
|
|
98
|
-
|
|
99
|
-
const logger = Logger()
|
|
100
|
-
const errorText = 'this is error'
|
|
101
|
-
logger.error(errorText)
|
|
102
|
-
|
|
103
|
-
await waitForFileToHaveContent(errorPath)
|
|
104
|
-
|
|
105
|
-
const contents = fs.readFileSync(errorPath, 'utf8')
|
|
106
|
-
expect(contents).toBe(`error: ${errorText}\n`)
|
|
107
|
-
})
|
|
108
|
-
})
|
|
46
|
+
const logger = Logger();
|
|
47
|
+
expect(logger.error).toBeFunction();
|
|
48
|
+
expect(logger.warn).toBeFunction();
|
|
49
|
+
expect(logger.info).toBeFunction();
|
|
50
|
+
expect(logger.verbose).toBeFunction();
|
|
51
|
+
expect(logger.debug).toBeFunction();
|
|
52
|
+
expect(logger.silly).toBeFunction();
|
|
53
|
+
});
|
|
54
|
+
});
|
package/network/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
const axios = require('axios')
|
|
2
|
-
const
|
|
3
|
-
require('
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const axiosRetry = require('axios-retry');
|
|
3
|
+
const Logger = require('../logger');
|
|
4
|
+
const httpAdapter = require('axios/lib/adapters/http');
|
|
5
|
+
require('dotenv').config();
|
|
4
6
|
/**
|
|
5
7
|
* Add support for nock testing
|
|
6
8
|
* see s://github.com/axios/axios/issues/305
|
|
7
9
|
*/
|
|
8
10
|
if (process.env.NODE_ENV === 'test') {
|
|
9
|
-
axios.defaults.adapter = httpAdapter
|
|
11
|
+
axios.defaults.adapter = httpAdapter;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
const HTTPMethods = [
|
|
@@ -17,36 +19,65 @@ const HTTPMethods = [
|
|
|
17
19
|
'put',
|
|
18
20
|
'patch',
|
|
19
21
|
'options',
|
|
20
|
-
]
|
|
22
|
+
];
|
|
21
23
|
|
|
22
24
|
const defaultSettings = {
|
|
23
25
|
timeout: 2500,
|
|
24
26
|
headers: { 'X-AF-AUTH': 'ANYONE' },
|
|
25
|
-
}
|
|
27
|
+
};
|
|
26
28
|
|
|
27
29
|
module.exports = class Network {
|
|
28
30
|
constructor(settings = {}) {
|
|
29
|
-
this.settings = Object.assign(defaultSettings, settings)
|
|
30
|
-
this.
|
|
31
|
-
|
|
32
|
-
this.
|
|
31
|
+
this.settings = Object.assign({}, defaultSettings, settings);
|
|
32
|
+
this.createBaseUrl();
|
|
33
|
+
|
|
34
|
+
this.axios = axios.create(this.settings);
|
|
35
|
+
this.addRetry(settings);
|
|
36
|
+
this.buildClassHttpMethods();
|
|
37
|
+
this.addLogs();
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
addRetry(settings) {
|
|
41
|
+
axiosRetry(this.axios, {
|
|
42
|
+
retries: 0,
|
|
43
|
+
retryDelay: axiosRetry.exponentialDelay,
|
|
44
|
+
...settings,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
addLogs() {
|
|
49
|
+
const logger = Logger();
|
|
50
|
+
this.axios.interceptors.request.use((request) => {
|
|
51
|
+
logger.info(`Start Request: [${request.method.toUpperCase()}] ${request.baseURL} ${request.url}`, {
|
|
52
|
+
headers: request.headers,
|
|
53
|
+
query: request.query,
|
|
54
|
+
body: request.body,
|
|
55
|
+
});
|
|
56
|
+
return request;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.axios.interceptors.response.use((response) => {
|
|
60
|
+
logger.info(`Finish Request: [${response.config.method.toUpperCase()} ${response.config.url}`);
|
|
61
|
+
return response;
|
|
62
|
+
}, (response) => {
|
|
63
|
+
logger.error(`Faild Request: [${response.config.method.toUpperCase()}] ${response.config.url}`);
|
|
64
|
+
return response;
|
|
65
|
+
});
|
|
39
66
|
}
|
|
40
67
|
|
|
41
68
|
createBaseUrl() {
|
|
42
|
-
|
|
69
|
+
if (!this.settings.serviceUrl && !this.settings.serviceName) {
|
|
70
|
+
throw new Error('At least one of the settings Missing serviceUrl or serviceName');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { settings } = this;
|
|
43
74
|
if (settings.serviceUrl) {
|
|
44
|
-
settings.baseURL = settings.serviceUrl
|
|
75
|
+
settings.baseURL = settings.serviceUrl;
|
|
45
76
|
} else if (settings.serviceName) {
|
|
46
|
-
const envServiceHostName = `${settings.serviceName}_SERVICE_HOST
|
|
47
|
-
settings.baseURL = `http://${process.env[envServiceHostName]}
|
|
77
|
+
const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;
|
|
78
|
+
settings.baseURL = `http://${process.env[envServiceHostName]}`;
|
|
48
79
|
if (!settings.baseURL) {
|
|
49
|
-
throw new Error(`Missing environment variable: ${envServiceHostName}`)
|
|
80
|
+
throw new Error(`Missing environment variable: ${envServiceHostName}`);
|
|
50
81
|
}
|
|
51
82
|
}
|
|
52
83
|
}
|
|
@@ -55,9 +86,8 @@ module.exports = class Network {
|
|
|
55
86
|
* Build class methods that wrap axios methods
|
|
56
87
|
*/
|
|
57
88
|
buildClassHttpMethods() {
|
|
58
|
-
this.axios = axios.create(this.settings)
|
|
59
89
|
HTTPMethods.forEach((method) => {
|
|
60
|
-
this[method] = (...args) => this.axios[method](...args)
|
|
61
|
-
})
|
|
90
|
+
this[method] = (...args) => this.axios[method](...args);
|
|
91
|
+
});
|
|
62
92
|
}
|
|
63
|
-
}
|
|
93
|
+
};
|
package/network/index.test.js
CHANGED
|
@@ -1,31 +1,68 @@
|
|
|
1
|
-
const nock = require('nock')
|
|
2
|
-
const Network = require('./index')
|
|
1
|
+
const nock = require('nock');
|
|
2
|
+
const Network = require('./index');
|
|
3
3
|
|
|
4
4
|
nock('http://www.google.com')
|
|
5
5
|
.get('/resource')
|
|
6
|
-
.reply(200, { one: 1 })
|
|
6
|
+
.reply(200, { one: 1 });
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
nock('https://www.apple.com')
|
|
10
10
|
.get('/resource')
|
|
11
|
-
.reply(200, { two: 2 })
|
|
11
|
+
.reply(200, { two: 2 });
|
|
12
12
|
|
|
13
13
|
describe('Network', () => {
|
|
14
14
|
it('Making requests by service name from ENV', async () => {
|
|
15
|
-
process.env.TEST_SERVICE_HOST = 'www.google.com'
|
|
16
|
-
const n = new Network({ serviceName: 'TEST' })
|
|
17
|
-
const response = await n.get('/resource')
|
|
18
|
-
expect(response).toBeDefined()
|
|
19
|
-
expect(response.data).toBeDefined()
|
|
20
|
-
expect(response.data.one).toBe(1)
|
|
21
|
-
})
|
|
15
|
+
process.env.TEST_SERVICE_HOST = 'www.google.com';
|
|
16
|
+
const n = new Network({ serviceName: 'TEST' });
|
|
17
|
+
const response = await n.get('/resource');
|
|
18
|
+
expect(response).toBeDefined();
|
|
19
|
+
expect(response.data).toBeDefined();
|
|
20
|
+
expect(response.data.one).toBe(1);
|
|
21
|
+
});
|
|
22
22
|
|
|
23
|
-
it('Making requests by service name from
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
expect(response).toBeDefined()
|
|
28
|
-
expect(response.data).
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
it('Making requests by service name from url', async () => {
|
|
24
|
+
const n = new Network({ serviceUrl: 'https://www.apple.com' });
|
|
25
|
+
const response = await n.get('/resource');
|
|
26
|
+
expect(response).toBeDefined();
|
|
27
|
+
expect(response.data).toBeDefined();
|
|
28
|
+
expect(response.data.two).toBe(2);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('Getting 404', async () => {
|
|
32
|
+
const n = new Network({ serviceUrl: 'https://www.apple.com' });
|
|
33
|
+
const response = await n.get('/resource', {
|
|
34
|
+
query: {
|
|
35
|
+
a: 'b',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
expect(response).toBeDefined();
|
|
39
|
+
expect(response.data).not.toBeDefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('Retry 1 time', async () => {
|
|
43
|
+
nock('https://www.apple2.com')
|
|
44
|
+
.get('/resource')
|
|
45
|
+
.once()
|
|
46
|
+
.reply(500);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
nock('https://www.apple2.com')
|
|
50
|
+
.get('/resource')
|
|
51
|
+
.once()
|
|
52
|
+
.reply(200, { two: 2 });
|
|
53
|
+
|
|
54
|
+
const n = new Network({ serviceUrl: 'https://www.apple2.com' });
|
|
55
|
+
const response = await n.get('/resource', {
|
|
56
|
+
query: {
|
|
57
|
+
a: 'b',
|
|
58
|
+
},
|
|
59
|
+
'axios-retry': {
|
|
60
|
+
retries: 1,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
expect(response).toBeDefined();
|
|
65
|
+
expect(response.data).toBeDefined();
|
|
66
|
+
expect(response.data.two).toBe(2);
|
|
67
|
+
});
|
|
68
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/node-common",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"coverage": "jest --coverage --forceExit --runInBand",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"homepage": "https://gitlab.com/AutoFleet/node-common#README",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"axios": "^0.18.0",
|
|
26
|
+
"axios-retry": "^3.1.0",
|
|
26
27
|
"dotenv": "^5.0.1",
|
|
27
28
|
"jest": "^22.4.3",
|
|
28
|
-
"
|
|
29
|
-
"winston": "^3.0.0-rc5"
|
|
29
|
+
"winston": "^3.0.0-rc4"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"eslint": "^4.19.1",
|