This commit is contained in:
darenhsu
2022-07-17 13:16:16 +08:00
parent 84759556ff
commit befd344ab0
28070 changed files with 4008428 additions and 1 deletions
+118
View File
@@ -0,0 +1,118 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [3.1.7] - 2019-04-23
### Fixed
- Fixed default export to resolve TS2309
- Updated dependencies to fix build error
- Added missing CHANGELOG entries (versions 3.0.1 until today)
## [3.1.6] - 2019-04-21
### Fixed
- Fixed export of `IAxiosRetryConfig`
## [3.1.5] - 2019-04-20
### Fixed
- Fixed TS definitions
## [3.1.4] - 2019-04-18
### Fixed
- Fixed TS definitions
### Added
- Added note in README related to compatibility issue with `axios 0.19.0`
- Updated LICENSE
## [3.1.2] - 2019-01-24
### Added
- TravisCI build status badge in README
- Update `index.d.ts` with missing functions
## [3.1.1] - 2018-06-13
### Fixed
- Do not run `requestTransform` again after retry
### Added
- Explicit return type on `axiosRetry`
- Prettier
## [3.1.0] - 2018-04-26
### Fixed
- Export `isRetryableError` for CommonJS
### Added
- Added additional param `shouldResetTimeout`
## [3.0.2] - 2018-02-09
### Added
- Now `isRetryableError` method is accessible.
- Added `delayStrategy` option to be able to have exponential backoff for successive retries.
## [3.0.1] - 2017-08-16
### Fixed
- Fixed first request time not being taken into account in timeout across retries.
- Fixed negative timeouts being passed to XHR (browsers), causing that no timeout was applied.
- Fixed safe methods and idempotent errors not being retried on unknown network errors.
## [3.0.0] - 2017-08-13
### Changed
- Retried errors on idempotent requests (5xx with get, head, options, put and delete) by default,
along with safe network errors.
- Moved some hard-coded conditions to the default `retryCondition` function so users can define a
custom function that overwrites them. The conditions that verify that the error is not a timeout or
an unsafe network error have been moved to `isNetworkError`.
### Added
- Added additional pre-defined retry conditions: `isSafeRequestError`, `isIdempotentRequestError`.
## [2.0.1] - 2017-06-19
### Fixed
- Removed dependency from the `package.json` file.
## [2.0.0] - 2017-06-15
### Changed
- Now the configured timeout in Axios is not for each retry request but for the whole request lifecycle.
## [1.3.1] - 2017-06-19
### Fixed
- Removed dependency from the `package.json` file.
## [1.3.0] - 2017-06-15
### Added
- Allowed per-request configuration using the `axios-retry` namespace.
+13
View File
@@ -0,0 +1,13 @@
Copyright 2019 Softonic International S.A.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+87
View File
@@ -0,0 +1,87 @@
# axios-retry
[![Build Status](https://travis-ci.org/softonic/axios-retry.svg?branch=master)](https://travis-ci.org/softonic/axios-retry)
Axios plugin that intercepts failed requests and retries them whenever possible.
## Installation
```bash
npm install axios-retry
```
### Note
Not working with `axios 0.19.0`. For details see the [bug](https://github.com/axios/axios/issues/2203). [`axios 0.19.1`](https://github.com/axios/axios/releases/tag/0.19.1) has fixed this bug.
## Usage
```js
// CommonJS
// const axiosRetry = require('axios-retry');
// ES6
import axiosRetry from 'axios-retry';
axiosRetry(axios, { retries: 3 });
axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
.then(result => {
result.data; // 'ok'
});
// Exponential back-off retry delay between requests
axiosRetry(axios, { retryDelay: axiosRetry.exponentialDelay});
// Custom retry delay
axiosRetry(axios, { retryDelay: (retryCount) => {
return retryCount * 1000;
}});
// Works with custom axios instances
const client = axios.create({ baseURL: 'http://example.com' });
axiosRetry(client, { retries: 3 });
client.get('/test') // The first request fails and the second returns 'ok'
.then(result => {
result.data; // 'ok'
});
// Allows request-specific configuration
client
.get('/test', {
'axios-retry': {
retries: 0
}
})
.catch(error => { // The first request fails
error !== undefined
});
```
**Note:** Unless `shouldResetTimeout` is set, the plugin interprets the request timeout as a global value, so it is not used for each retry but for the whole request lifecycle.
## Options
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| retries | `Number` | `3` | The number of times to retry before failing. |
| retryCondition | `Function` | `isNetworkOrIdempotentRequestError` | A callback to further control if a request should be retried. By default, it retries if it is a network error or a 5xx error on an idempotent request (GET, HEAD, OPTIONS, PUT or DELETE). |
| shouldResetTimeout | `Boolean` | false | Defines if the timeout should be reset between retries |
| retryDelay | `Function` | `function noDelay() { return 0; }` | A callback to further control the delay between retried requests. By default there is no delay between retries. Another option is exponentialDelay ([Exponential Backoff](https://developers.google.com/analytics/devguides/reporting/core/v3/errors#backoff)). The function is passed `retryCount` and `error`. |
## Testing
Clone the repository and execute:
```bash
npm test
```
## Contribute
1. Fork it: `git clone https://github.com/softonic/axios-retry.git`
2. Create your feature branch: `git checkout -b feature/my-new-feature`
3. Commit your changes: `git commit -am 'Added some feature'`
4. Check the build: `npm run build`
4. Push to the branch: `git push origin my-new-feature`
5. Submit a pull request :D
+228
View File
@@ -0,0 +1,228 @@
import isRetryAllowed from 'is-retry-allowed';
const namespace = 'axios-retry';
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkError(error) {
return (
!error.response &&
Boolean(error.code) && // Prevents retrying cancelled requests
error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests
isRetryAllowed(error)
); // Prevents retrying unsafe errors
}
const SAFE_HTTP_METHODS = ['get', 'head', 'options'];
const IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
/**
* @param {Error} error
* @return {boolean}
*/
export function isRetryableError(error) {
return (
error.code !== 'ECONNABORTED' &&
(!error.response || (error.response.status >= 500 && error.response.status <= 599))
);
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isSafeRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isIdempotentRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkOrIdempotentRequestError(error) {
return isNetworkError(error) || isIdempotentRequestError(error);
}
/**
* @return {number} - delay in milliseconds, always 0
*/
function noDelay() {
return 0;
}
/**
* @param {number} [retryNumber=0]
* @return {number} - delay in milliseconds
*/
export function exponentialDelay(retryNumber = 0) {
const delay = Math.pow(2, retryNumber) * 100;
const randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
return delay + randomSum;
}
/**
* Initializes and returns the retry state for the given request/config
* @param {AxiosRequestConfig} config
* @return {Object}
*/
function getCurrentState(config) {
const currentState = config[namespace] || {};
currentState.retryCount = currentState.retryCount || 0;
config[namespace] = currentState;
return currentState;
}
/**
* Returns the axios-retry options for the current request
* @param {AxiosRequestConfig} config
* @param {AxiosRetryConfig} defaultOptions
* @return {AxiosRetryConfig}
*/
function getRequestOptions(config, defaultOptions) {
return Object.assign({}, defaultOptions, config[namespace]);
}
/**
* @param {Axios} axios
* @param {AxiosRequestConfig} config
*/
function fixConfig(axios, config) {
if (axios.defaults.agent === config.agent) {
delete config.agent;
}
if (axios.defaults.httpAgent === config.httpAgent) {
delete config.httpAgent;
}
if (axios.defaults.httpsAgent === config.httpsAgent) {
delete config.httpsAgent;
}
}
/**
* Adds response interceptors to an axios instance to retry requests failed due to network issues
*
* @example
*
* import axios from 'axios';
*
* axiosRetry(axios, { retries: 3 });
*
* axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Exponential back-off retry delay between requests
* axiosRetry(axios, { retryDelay : axiosRetry.exponentialDelay});
*
* // Custom retry delay
* axiosRetry(axios, { retryDelay : (retryCount) => {
* return retryCount * 1000;
* }});
*
* // Also works with custom axios instances
* const client = axios.create({ baseURL: 'http://example.com' });
* axiosRetry(client, { retries: 3 });
*
* client.get('/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Allows request-specific configuration
* client
* .get('/test', {
* 'axios-retry': {
* retries: 0
* }
* })
* .catch(error => { // The first request fails
* error !== undefined
* });
*
* @param {Axios} axios An axios instance (the axios object or one created from axios.create)
* @param {Object} [defaultOptions]
* @param {number} [defaultOptions.retries=3] Number of retries
* @param {boolean} [defaultOptions.shouldResetTimeout=false]
* Defines if the timeout should be reset between retries
* @param {Function} [defaultOptions.retryCondition=isNetworkOrIdempotentRequestError]
* A function to determine if the error can be retried
* @param {Function} [defaultOptions.retryDelay=noDelay]
* A function to determine the delay between retry requests
*/
export default function axiosRetry(axios, defaultOptions) {
axios.interceptors.request.use(config => {
const currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
return config;
});
axios.interceptors.response.use(null, error => {
const config = error.config;
// If we have no information to retry the request
if (!config) {
return Promise.reject(error);
}
const {
retries = 3,
retryCondition = isNetworkOrIdempotentRequestError,
retryDelay = noDelay,
shouldResetTimeout = false
} = getRequestOptions(config, defaultOptions);
const currentState = getCurrentState(config);
const shouldRetry = retryCondition(error) && currentState.retryCount < retries;
if (shouldRetry) {
currentState.retryCount += 1;
const delay = retryDelay(currentState.retryCount, error);
// Axios fails merging this configuration to the default configuration because it has an issue
// with circular structures: https://github.com/mzabriskie/axios/issues/370
fixConfig(axios, config);
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
const lastRequestDuration = Date.now() - currentState.lastRequestTime;
// Minimum 1ms timeout (passing 0 or less to XHR means no timeout)
config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1);
}
config.transformRequest = [data => data];
return new Promise(resolve => setTimeout(() => resolve(axios(config)), delay));
}
return Promise.reject(error);
});
}
// Compatibility with CommonJS
axiosRetry.isNetworkError = isNetworkError;
axiosRetry.isSafeRequestError = isSafeRequestError;
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
axiosRetry.exponentialDelay = exponentialDelay;
axiosRetry.isRetryableError = isRetryableError;
+60
View File
@@ -0,0 +1,60 @@
import * as axios from 'axios'
interface IAxiosRetry {
(
axios: axios.AxiosStatic | axios.AxiosInstance,
axiosRetryConfig?: IAxiosRetry.IAxiosRetryConfig
): void;
isNetworkError(error: Error): boolean;
isRetryableError(error: Error): boolean;
isSafeRequestError(error: Error): boolean;
isIdempotentRequestError(error: Error): boolean;
isNetworkOrIdempotentRequestError(error: Error): boolean;
exponentialDelay(retryNumber: number): number;
}
export function isNetworkError(error: Error): boolean;
export function isRetryableError(error: Error): boolean;
export function isSafeRequestError(error: Error): boolean;
export function isIdempotentRequestError(error: Error): boolean;
export function isNetworkOrIdempotentRequestError(error: Error): boolean;
export function exponentialDelay(retryNumber: number): number;
declare namespace IAxiosRetry {
export interface IAxiosRetryConfig {
/**
* The number of times to retry before failing
* default: 3
*
* @type {number}
*/
retries?: number,
/**
* Defines if the timeout should be reset between retries
* default: false
*
* @type {boolean}
*/
shouldResetTimeout?: boolean,
/**
* A callback to further control if a request should be retried. By default, it retries if the result did not have a response.
* default: error => !error.response
*
* @type {Function}
*/
retryCondition?: (error: axios.AxiosError) => boolean,
/**
* A callback to further control the delay between retry requests. By default there is no delay.
*
* @type {Function}
*/
retryDelay?: (retryCount: number, error: axios.AxiosError) => number
}
}
declare const axiosRetry: IAxiosRetry;
export type IAxiosRetryConfig = IAxiosRetry.IAxiosRetryConfig;
export default axiosRetry;
+1
View File
@@ -0,0 +1 @@
module.exports = require('./lib/index').default;
+251
View File
@@ -0,0 +1,251 @@
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isNetworkError = isNetworkError;
exports.isRetryableError = isRetryableError;
exports.isSafeRequestError = isSafeRequestError;
exports.isIdempotentRequestError = isIdempotentRequestError;
exports.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
exports.exponentialDelay = exponentialDelay;
exports.default = axiosRetry;
var _isRetryAllowed = require('is-retry-allowed');
var _isRetryAllowed2 = _interopRequireDefault(_isRetryAllowed);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var namespace = 'axios-retry';
/**
* @param {Error} error
* @return {boolean}
*/
function isNetworkError(error) {
return !error.response && Boolean(error.code) && // Prevents retrying cancelled requests
error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests
(0, _isRetryAllowed2.default)(error); // Prevents retrying unsafe errors
}
var SAFE_HTTP_METHODS = ['get', 'head', 'options'];
var IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
/**
* @param {Error} error
* @return {boolean}
*/
function isRetryableError(error) {
return error.code !== 'ECONNABORTED' && (!error.response || error.response.status >= 500 && error.response.status <= 599);
}
/**
* @param {Error} error
* @return {boolean}
*/
function isSafeRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
function isIdempotentRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
function isNetworkOrIdempotentRequestError(error) {
return isNetworkError(error) || isIdempotentRequestError(error);
}
/**
* @return {number} - delay in milliseconds, always 0
*/
function noDelay() {
return 0;
}
/**
* @param {number} [retryNumber=0]
* @return {number} - delay in milliseconds
*/
function exponentialDelay() {
var retryNumber = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var delay = Math.pow(2, retryNumber) * 100;
var randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
return delay + randomSum;
}
/**
* Initializes and returns the retry state for the given request/config
* @param {AxiosRequestConfig} config
* @return {Object}
*/
function getCurrentState(config) {
var currentState = config[namespace] || {};
currentState.retryCount = currentState.retryCount || 0;
config[namespace] = currentState;
return currentState;
}
/**
* Returns the axios-retry options for the current request
* @param {AxiosRequestConfig} config
* @param {AxiosRetryConfig} defaultOptions
* @return {AxiosRetryConfig}
*/
function getRequestOptions(config, defaultOptions) {
return Object.assign({}, defaultOptions, config[namespace]);
}
/**
* @param {Axios} axios
* @param {AxiosRequestConfig} config
*/
function fixConfig(axios, config) {
if (axios.defaults.agent === config.agent) {
delete config.agent;
}
if (axios.defaults.httpAgent === config.httpAgent) {
delete config.httpAgent;
}
if (axios.defaults.httpsAgent === config.httpsAgent) {
delete config.httpsAgent;
}
}
/**
* Adds response interceptors to an axios instance to retry requests failed due to network issues
*
* @example
*
* import axios from 'axios';
*
* axiosRetry(axios, { retries: 3 });
*
* axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Exponential back-off retry delay between requests
* axiosRetry(axios, { retryDelay : axiosRetry.exponentialDelay});
*
* // Custom retry delay
* axiosRetry(axios, { retryDelay : (retryCount) => {
* return retryCount * 1000;
* }});
*
* // Also works with custom axios instances
* const client = axios.create({ baseURL: 'http://example.com' });
* axiosRetry(client, { retries: 3 });
*
* client.get('/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Allows request-specific configuration
* client
* .get('/test', {
* 'axios-retry': {
* retries: 0
* }
* })
* .catch(error => { // The first request fails
* error !== undefined
* });
*
* @param {Axios} axios An axios instance (the axios object or one created from axios.create)
* @param {Object} [defaultOptions]
* @param {number} [defaultOptions.retries=3] Number of retries
* @param {boolean} [defaultOptions.shouldResetTimeout=false]
* Defines if the timeout should be reset between retries
* @param {Function} [defaultOptions.retryCondition=isNetworkOrIdempotentRequestError]
* A function to determine if the error can be retried
* @param {Function} [defaultOptions.retryDelay=noDelay]
* A function to determine the delay between retry requests
*/
function axiosRetry(axios, defaultOptions) {
axios.interceptors.request.use(function (config) {
var currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
return config;
});
axios.interceptors.response.use(null, function (error) {
var config = error.config;
// If we have no information to retry the request
if (!config) {
return Promise.reject(error);
}
var _getRequestOptions = getRequestOptions(config, defaultOptions),
_getRequestOptions$re = _getRequestOptions.retries,
retries = _getRequestOptions$re === undefined ? 3 : _getRequestOptions$re,
_getRequestOptions$re2 = _getRequestOptions.retryCondition,
retryCondition = _getRequestOptions$re2 === undefined ? isNetworkOrIdempotentRequestError : _getRequestOptions$re2,
_getRequestOptions$re3 = _getRequestOptions.retryDelay,
retryDelay = _getRequestOptions$re3 === undefined ? noDelay : _getRequestOptions$re3,
_getRequestOptions$sh = _getRequestOptions.shouldResetTimeout,
shouldResetTimeout = _getRequestOptions$sh === undefined ? false : _getRequestOptions$sh;
var currentState = getCurrentState(config);
var shouldRetry = retryCondition(error) && currentState.retryCount < retries;
if (shouldRetry) {
currentState.retryCount += 1;
var delay = retryDelay(currentState.retryCount, error);
// Axios fails merging this configuration to the default configuration because it has an issue
// with circular structures: https://github.com/mzabriskie/axios/issues/370
fixConfig(axios, config);
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
var lastRequestDuration = Date.now() - currentState.lastRequestTime;
// Minimum 1ms timeout (passing 0 or less to XHR means no timeout)
config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1);
}
config.transformRequest = [function (data) {
return data;
}];
return new Promise(function (resolve) {
return setTimeout(function () {
return resolve(axios(config));
}, delay);
});
}
return Promise.reject(error);
});
}
// Compatibility with CommonJS
axiosRetry.isNetworkError = isNetworkError;
axiosRetry.isSafeRequestError = isSafeRequestError;
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
axiosRetry.exponentialDelay = exponentialDelay;
axiosRetry.isRetryableError = isRetryableError;
//# sourceMappingURL=index.js.map
+1
View File
File diff suppressed because one or more lines are too long
+92
View File
@@ -0,0 +1,92 @@
{
"_args": [
[
"axios-retry@3.1.8",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
]
],
"_from": "axios-retry@3.1.8",
"_id": "axios-retry@3.1.8",
"_inBundle": false,
"_integrity": "sha512-yPw5Y4Bg6Dgmhm35KaJFtlh23s1TecW0HsUerK4/IS1UKl0gtN2aJqdEKtVomiOS/bDo5w4P3sqgki/M10eF8Q==",
"_location": "/axios-retry",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "axios-retry@3.1.8",
"name": "axios-retry",
"escapedName": "axios-retry",
"rawSpec": "3.1.8",
"saveSpec": null,
"fetchSpec": "3.1.8"
},
"_requiredBy": [
"/@nuxtjs/axios"
],
"_resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.8.tgz",
"_spec": "3.1.8",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"author": {
"name": "Rubén Norte",
"email": "ruben.norte@softonic.com"
},
"bugs": {
"url": "https://github.com/softonic/axios-retry/issues"
},
"dependencies": {
"is-retry-allowed": "^1.1.0"
},
"description": "Axios plugin that intercepts failed requests and retries them whenever posible.",
"devDependencies": {
"axios": "^0.15.2",
"babel-cli": "^6.10.1",
"babel-preset-es2015": "^6.9.0",
"babel-register": "^6.9.0",
"eslint": "^4.4.1",
"eslint-config-airbnb-base": "^11.3.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jasmine": "^1.8.1",
"eslint-plugin-prettier": "^2.6.0",
"husky": "^0.14.3",
"jasmine": "^2.4.1",
"lint-staged": "^7.1.2",
"nock": "^8.0.0",
"prettier": "^1.12.1"
},
"files": [
"es",
"lib",
"index.js",
"index.d.ts"
],
"homepage": "https://github.com/softonic/axios-retry",
"license": "Apache-2.0",
"lint-staged": {
"*.+(js|jsx|scss)": [
"prettier --write",
"git add"
]
},
"main": "index.js",
"name": "axios-retry",
"repository": {
"type": "git",
"url": "git+https://github.com/softonic/axios-retry.git"
},
"scripts": {
"build": "rm -rf lib && babel es -d lib --source-maps",
"lint": "eslint es/**/*.js spec/**/*.spec.js",
"postrelease": "npm run push && npm publish",
"prebuild": "npm run test",
"precommit": "lint-staged",
"prerelease": "npm run build",
"pretest": "npm run lint",
"push": "git push origin master && git push origin --tags",
"release": "npm version -m \"New version: %s\"",
"test": "jasmine"
},
"typings": "./index.d.ts",
"version": "3.1.8"
}