follow-redirects 1.2.6 → 1.5.0
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.
Potentially problematic release.
This version of follow-redirects might be problematic. Click here for more details.
- package/README.md +23 -1
- package/http.js +1 -1
- package/https.js +1 -1
- package/index.js +254 -211
- package/package.json +10 -13
package/README.md
CHANGED
@@ -5,7 +5,6 @@ Drop-in replacement for Nodes `http` and `https` that automatically follows redi
|
|
5
5
|
[](https://www.npmjs.com/package/follow-redirects)
|
6
6
|
[](https://travis-ci.org/olalonde/follow-redirects)
|
7
7
|
[](https://coveralls.io/r/olalonde/follow-redirects?branch=master)
|
8
|
-
[](https://codeclimate.com/github/olalonde/follow-redirects)
|
9
8
|
[](https://david-dm.org/olalonde/follow-redirects)
|
10
9
|
[](https://david-dm.org/olalonde/follow-redirects#info=devDependencies)
|
11
10
|
|
@@ -48,12 +47,15 @@ Global options are set directly on the `follow-redirects` module:
|
|
48
47
|
```javascript
|
49
48
|
var followRedirects = require('follow-redirects');
|
50
49
|
followRedirects.maxRedirects = 10;
|
50
|
+
followRedirects.maxBodyLength = 20 * 1024 * 1024; // 20 MB
|
51
51
|
```
|
52
52
|
|
53
53
|
The following global options are supported:
|
54
54
|
|
55
55
|
- `maxRedirects` (default: `21`) – sets the maximum number of allowed redirects; if exceeded, an error will be emitted.
|
56
56
|
|
57
|
+
- `maxBodyLength` (default: 10MB) – sets the maximum size of the request body; if exceeded, an error will be emitted.
|
58
|
+
|
57
59
|
|
58
60
|
### Per-request options
|
59
61
|
Per-request options are set by passing an `options` object:
|
@@ -73,8 +75,28 @@ the following per-request options are supported:
|
|
73
75
|
|
74
76
|
- `maxRedirects` (default: `21`) – sets the maximum number of allowed redirects; if exceeded, an error will be emitted.
|
75
77
|
|
78
|
+
- `maxBodyLength` (default: 10MB) – sets the maximum size of the request body; if exceeded, an error will be emitted.
|
79
|
+
|
76
80
|
- `agents` (default: `undefined`) – sets the `agent` option per protocol, since HTTP and HTTPS use different agents. Example value: `{ http: new http.Agent(), https: new https.Agent() }`
|
77
81
|
|
82
|
+
- `trackRedirects` (default: `false`) – whether to store the redirected response details into the `redirects` array on the response object.
|
83
|
+
|
84
|
+
|
85
|
+
### Advanced usage
|
86
|
+
By default, `follow-redirects` will use the Node.js default implementations
|
87
|
+
of [`http`](https://nodejs.org/api/http.html)
|
88
|
+
and [`https`](https://nodejs.org/api/https.html).
|
89
|
+
To enable features such as caching and/or intermediate request tracking,
|
90
|
+
you might instead want to wrap `follow-redirects` around custom protocol implementations:
|
91
|
+
|
92
|
+
```javascript
|
93
|
+
var followRedirects = require('follow-redirects').wrap({
|
94
|
+
http: require('your-custom-http'),
|
95
|
+
https: require('your-custom-https'),
|
96
|
+
});
|
97
|
+
```
|
98
|
+
|
99
|
+
Such custom protocols only need an implementation of the `request` method.
|
78
100
|
|
79
101
|
## Browserify Usage
|
80
102
|
|
package/http.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
module.exports = require(
|
1
|
+
module.exports = require("./").http;
|
package/https.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
module.exports = require(
|
1
|
+
module.exports = require("./").https;
|
package/index.js
CHANGED
@@ -1,238 +1,281 @@
|
|
1
|
-
|
2
|
-
var
|
3
|
-
var
|
4
|
-
var
|
5
|
-
var
|
6
|
-
var
|
7
|
-
|
8
|
-
|
9
|
-
var nativeProtocols = {'http:': http, 'https:': https};
|
10
|
-
var schemes = {};
|
11
|
-
var exports = module.exports = {
|
12
|
-
maxRedirects: 21
|
13
|
-
};
|
1
|
+
var url = require("url");
|
2
|
+
var http = require("http");
|
3
|
+
var https = require("https");
|
4
|
+
var assert = require("assert");
|
5
|
+
var Writable = require("stream").Writable;
|
6
|
+
var debug = require("debug")("follow-redirects");
|
7
|
+
|
14
8
|
// RFC7231§4.2.1: Of the request methods defined by this specification,
|
15
9
|
// the GET, HEAD, OPTIONS, and TRACE methods are defined to be safe.
|
16
|
-
var
|
10
|
+
var SAFE_METHODS = { GET: true, HEAD: true, OPTIONS: true, TRACE: true };
|
17
11
|
|
18
12
|
// Create handlers that pass events from native requests
|
19
13
|
var eventHandlers = Object.create(null);
|
20
|
-
[
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
["abort", "aborted", "error", "socket", "timeout"].forEach(function (event) {
|
15
|
+
eventHandlers[event] = function (arg) {
|
16
|
+
this._redirectable.emit(event, arg);
|
17
|
+
};
|
24
18
|
});
|
25
19
|
|
26
20
|
// An HTTP(S) request that can be redirected
|
27
21
|
function RedirectableRequest(options, responseCallback) {
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
22
|
+
// Initialize the request
|
23
|
+
Writable.call(this);
|
24
|
+
options.headers = options.headers || {};
|
25
|
+
this._options = options;
|
26
|
+
this._redirectCount = 0;
|
27
|
+
this._redirects = [];
|
28
|
+
this._requestBodyLength = 0;
|
29
|
+
this._requestBodyBuffers = [];
|
30
|
+
|
31
|
+
// Attach a callback if passed
|
32
|
+
if (responseCallback) {
|
33
|
+
this.on("response", responseCallback);
|
34
|
+
}
|
35
|
+
|
36
|
+
// React to responses of native requests
|
37
|
+
var self = this;
|
38
|
+
this._onNativeResponse = function (response) {
|
39
|
+
self._processResponse(response);
|
40
|
+
};
|
41
|
+
|
42
|
+
// Complete the URL object when necessary
|
43
|
+
if (!options.pathname && options.path) {
|
44
|
+
var searchPos = options.path.indexOf("?");
|
45
|
+
if (searchPos < 0) {
|
46
|
+
options.pathname = options.path;
|
47
|
+
}
|
48
|
+
else {
|
49
|
+
options.pathname = options.path.substring(0, searchPos);
|
50
|
+
options.search = options.path.substring(searchPos);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
// Perform the first request
|
55
|
+
this._performRequest();
|
58
56
|
}
|
59
57
|
RedirectableRequest.prototype = Object.create(Writable.prototype);
|
60
58
|
|
61
|
-
//
|
62
|
-
RedirectableRequest.prototype.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
// Set up event handlers
|
77
|
-
request._redirectable = this;
|
78
|
-
for (var event in eventHandlers) {
|
79
|
-
/* istanbul ignore else */
|
80
|
-
if (event) {
|
81
|
-
request.on(event, eventHandlers[event]);
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
// End a redirected request
|
86
|
-
// (The first request must be ended explicitly with RedirectableRequest#end)
|
87
|
-
if (this._isRedirect) {
|
88
|
-
// If the request doesn't have en entity, end directly.
|
89
|
-
var bufferedWrites = this._bufferedWrites;
|
90
|
-
if (bufferedWrites.length === 0) {
|
91
|
-
request.end();
|
92
|
-
// Otherwise, write the request entity and end afterwards.
|
93
|
-
} else {
|
94
|
-
var i = 0;
|
95
|
-
(function writeNext() {
|
96
|
-
if (i < bufferedWrites.length) {
|
97
|
-
var bufferedWrite = bufferedWrites[i++];
|
98
|
-
request.write(bufferedWrite.data, bufferedWrite.encoding, writeNext);
|
99
|
-
} else {
|
100
|
-
request.end();
|
101
|
-
}
|
102
|
-
})();
|
103
|
-
}
|
104
|
-
}
|
59
|
+
// Writes buffered data to the current native request
|
60
|
+
RedirectableRequest.prototype.write = function (data, encoding, callback) {
|
61
|
+
if (!(typeof data === "string" || typeof data === "object" && ("length" in data))) {
|
62
|
+
throw new Error("data should be a string, Buffer or Uint8Array");
|
63
|
+
}
|
64
|
+
if (this._requestBodyLength + data.length <= this._options.maxBodyLength) {
|
65
|
+
this._requestBodyLength += data.length;
|
66
|
+
this._requestBodyBuffers.push({ data: data, encoding: encoding });
|
67
|
+
this._currentRequest.write(data, encoding, callback);
|
68
|
+
}
|
69
|
+
else {
|
70
|
+
this.emit("error", new Error("Request body larger than maxBodyLength limit"));
|
71
|
+
this.abort();
|
72
|
+
}
|
105
73
|
};
|
106
74
|
|
107
|
-
//
|
108
|
-
RedirectableRequest.prototype.
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
// RFC7231§6.4: A client SHOULD detect and intervene
|
119
|
-
// in cyclical redirections (i.e., "infinite" redirection loops).
|
120
|
-
if (++this._redirectCount > this._options.maxRedirects) {
|
121
|
-
return this.emit('error', new Error('Max redirects exceeded.'));
|
122
|
-
}
|
123
|
-
|
124
|
-
// RFC7231§6.4: Automatic redirection needs to done with
|
125
|
-
// care for methods not known to be safe […],
|
126
|
-
// since the user might not wish to redirect an unsafe request.
|
127
|
-
// RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
|
128
|
-
// that the target resource resides temporarily under a different URI
|
129
|
-
// and the user agent MUST NOT change the request method
|
130
|
-
// if it performs an automatic redirection to that URI.
|
131
|
-
var header;
|
132
|
-
var headers = this._options.headers;
|
133
|
-
if (response.statusCode !== 307 && !(this._options.method in safeMethods)) {
|
134
|
-
this._options.method = 'GET';
|
135
|
-
// Drop a possible entity and headers related to it
|
136
|
-
this._bufferedWrites = [];
|
137
|
-
for (header in headers) {
|
138
|
-
if (/^content-/i.test(header)) {
|
139
|
-
delete headers[header];
|
140
|
-
}
|
141
|
-
}
|
142
|
-
}
|
143
|
-
|
144
|
-
// Drop the Host header, as the redirect might lead to a different host
|
145
|
-
if (!this._isRedirect) {
|
146
|
-
for (header in headers) {
|
147
|
-
if (/^host$/i.test(header)) {
|
148
|
-
delete headers[header];
|
149
|
-
}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
// Perform the redirected request
|
154
|
-
var redirectUrl = url.resolve(this._currentUrl, location);
|
155
|
-
debug('redirecting to', redirectUrl);
|
156
|
-
Object.assign(this._options, url.parse(redirectUrl));
|
157
|
-
this._isRedirect = true;
|
158
|
-
this._performRequest();
|
159
|
-
} else {
|
160
|
-
// The response is not a redirect; return it as-is
|
161
|
-
response.responseUrl = this._currentUrl;
|
162
|
-
this.emit('response', response);
|
163
|
-
|
164
|
-
// Clean up
|
165
|
-
delete this._options;
|
166
|
-
delete this._bufferedWrites;
|
167
|
-
}
|
75
|
+
// Ends the current native request
|
76
|
+
RedirectableRequest.prototype.end = function (data, encoding, callback) {
|
77
|
+
var currentRequest = this._currentRequest;
|
78
|
+
if (!data) {
|
79
|
+
currentRequest.end(null, null, callback);
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
this.write(data, encoding, function () {
|
83
|
+
currentRequest.end(null, null, callback);
|
84
|
+
});
|
85
|
+
}
|
168
86
|
};
|
169
87
|
|
170
|
-
//
|
171
|
-
RedirectableRequest.prototype.
|
172
|
-
|
88
|
+
// Sets a header value on the current native request
|
89
|
+
RedirectableRequest.prototype.setHeader = function (name, value) {
|
90
|
+
this._options.headers[name] = value;
|
91
|
+
this._currentRequest.setHeader(name, value);
|
173
92
|
};
|
174
93
|
|
175
|
-
//
|
176
|
-
RedirectableRequest.prototype.
|
177
|
-
|
94
|
+
// Clears a header value on the current native request
|
95
|
+
RedirectableRequest.prototype.removeHeader = function (name) {
|
96
|
+
delete this._options.headers[name];
|
97
|
+
this._currentRequest.removeHeader(name);
|
178
98
|
};
|
179
99
|
|
180
|
-
//
|
181
|
-
|
182
|
-
|
183
|
-
|
100
|
+
// Proxy all other public ClientRequest methods
|
101
|
+
[
|
102
|
+
"abort", "flushHeaders", "getHeader",
|
103
|
+
"setNoDelay", "setSocketKeepAlive", "setTimeout",
|
104
|
+
].forEach(function (method) {
|
105
|
+
RedirectableRequest.prototype[method] = function (a, b) {
|
106
|
+
return this._currentRequest[method](a, b);
|
107
|
+
};
|
108
|
+
});
|
184
109
|
|
185
|
-
//
|
186
|
-
|
187
|
-
|
188
|
-
}
|
110
|
+
// Proxy all public ClientRequest properties
|
111
|
+
["aborted", "connection", "socket"].forEach(function (property) {
|
112
|
+
Object.defineProperty(RedirectableRequest.prototype, property, {
|
113
|
+
get: function () { return this._currentRequest[property]; },
|
114
|
+
});
|
115
|
+
});
|
189
116
|
|
190
|
-
//
|
191
|
-
RedirectableRequest.prototype.
|
192
|
-
|
193
|
-
|
117
|
+
// Executes the next native request (initial or redirect)
|
118
|
+
RedirectableRequest.prototype._performRequest = function () {
|
119
|
+
// Load the native protocol
|
120
|
+
var protocol = this._options.protocol;
|
121
|
+
var nativeProtocol = this._options.nativeProtocols[protocol];
|
194
122
|
|
195
|
-
//
|
196
|
-
|
197
|
-
|
198
|
-
|
123
|
+
// If specified, use the agent corresponding to the protocol
|
124
|
+
// (HTTP and HTTPS use different types of agents)
|
125
|
+
if (this._options.agents) {
|
126
|
+
var scheme = protocol.substr(0, protocol.length - 1);
|
127
|
+
this._options.agent = this._options.agents[scheme];
|
128
|
+
}
|
129
|
+
|
130
|
+
// Create the native request
|
131
|
+
var request = this._currentRequest =
|
132
|
+
nativeProtocol.request(this._options, this._onNativeResponse);
|
133
|
+
this._currentUrl = url.format(this._options);
|
134
|
+
|
135
|
+
// Set up event handlers
|
136
|
+
request._redirectable = this;
|
137
|
+
for (var event in eventHandlers) {
|
138
|
+
/* istanbul ignore else */
|
139
|
+
if (event) {
|
140
|
+
request.on(event, eventHandlers[event]);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
// End a redirected request
|
145
|
+
// (The first request must be ended explicitly with RedirectableRequest#end)
|
146
|
+
if (this._isRedirect) {
|
147
|
+
// Write the request entity and end.
|
148
|
+
var requestBodyBuffers = this._requestBodyBuffers;
|
149
|
+
(function writeNext() {
|
150
|
+
if (requestBodyBuffers.length !== 0) {
|
151
|
+
var buffer = requestBodyBuffers.pop();
|
152
|
+
request.write(buffer.data, buffer.encoding, writeNext);
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
request.end();
|
156
|
+
}
|
157
|
+
}());
|
158
|
+
}
|
199
159
|
};
|
200
160
|
|
201
|
-
//
|
202
|
-
RedirectableRequest.prototype.
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
161
|
+
// Processes a response from the current native request
|
162
|
+
RedirectableRequest.prototype._processResponse = function (response) {
|
163
|
+
// Store the redirected response
|
164
|
+
if (this._options.trackRedirects) {
|
165
|
+
this._redirects.push({
|
166
|
+
url: this._currentUrl,
|
167
|
+
headers: response.headers,
|
168
|
+
statusCode: response.statusCode,
|
169
|
+
});
|
170
|
+
}
|
171
|
+
|
172
|
+
// RFC7231§6.4: The 3xx (Redirection) class of status code indicates
|
173
|
+
// that further action needs to be taken by the user agent in order to
|
174
|
+
// fulfill the request. If a Location header field is provided,
|
175
|
+
// the user agent MAY automatically redirect its request to the URI
|
176
|
+
// referenced by the Location field value,
|
177
|
+
// even if the specific status code is not understood.
|
178
|
+
var location = response.headers.location;
|
179
|
+
if (location && this._options.followRedirects !== false &&
|
180
|
+
response.statusCode >= 300 && response.statusCode < 400) {
|
181
|
+
// RFC7231§6.4: A client SHOULD detect and intervene
|
182
|
+
// in cyclical redirections (i.e., "infinite" redirection loops).
|
183
|
+
if (++this._redirectCount > this._options.maxRedirects) {
|
184
|
+
this.emit("error", new Error("Max redirects exceeded."));
|
185
|
+
return;
|
186
|
+
}
|
187
|
+
|
188
|
+
// RFC7231§6.4: Automatic redirection needs to done with
|
189
|
+
// care for methods not known to be safe […],
|
190
|
+
// since the user might not wish to redirect an unsafe request.
|
191
|
+
// RFC7231§6.4.7: The 307 (Temporary Redirect) status code indicates
|
192
|
+
// that the target resource resides temporarily under a different URI
|
193
|
+
// and the user agent MUST NOT change the request method
|
194
|
+
// if it performs an automatic redirection to that URI.
|
195
|
+
var header;
|
196
|
+
var headers = this._options.headers;
|
197
|
+
if (response.statusCode !== 307 && !(this._options.method in SAFE_METHODS)) {
|
198
|
+
this._options.method = "GET";
|
199
|
+
// Drop a possible entity and headers related to it
|
200
|
+
this._requestBodyBuffers = [];
|
201
|
+
for (header in headers) {
|
202
|
+
if (/^content-/i.test(header)) {
|
203
|
+
delete headers[header];
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
|
208
|
+
// Drop the Host header, as the redirect might lead to a different host
|
209
|
+
if (!this._isRedirect) {
|
210
|
+
for (header in headers) {
|
211
|
+
if (/^host$/i.test(header)) {
|
212
|
+
delete headers[header];
|
213
|
+
}
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
// Perform the redirected request
|
218
|
+
var redirectUrl = url.resolve(this._currentUrl, location);
|
219
|
+
debug("redirecting to", redirectUrl);
|
220
|
+
Object.assign(this._options, url.parse(redirectUrl));
|
221
|
+
this._isRedirect = true;
|
222
|
+
this._performRequest();
|
223
|
+
}
|
224
|
+
else {
|
225
|
+
// The response is not a redirect; return it as-is
|
226
|
+
response.responseUrl = this._currentUrl;
|
227
|
+
response.redirects = this._redirects;
|
228
|
+
this.emit("response", response);
|
229
|
+
|
230
|
+
// Clean up
|
231
|
+
this._requestBodyBuffers = [];
|
232
|
+
}
|
207
233
|
};
|
208
234
|
|
209
|
-
//
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
235
|
+
// Wraps the key/value object of protocols with redirect functionality
|
236
|
+
function wrap(protocols) {
|
237
|
+
// Default settings
|
238
|
+
var exports = {
|
239
|
+
maxRedirects: 21,
|
240
|
+
maxBodyLength: 10 * 1024 * 1024,
|
241
|
+
};
|
242
|
+
|
243
|
+
// Wrap each protocol
|
244
|
+
var nativeProtocols = {};
|
245
|
+
Object.keys(protocols).forEach(function (scheme) {
|
246
|
+
var protocol = scheme + ":";
|
247
|
+
var nativeProtocol = nativeProtocols[protocol] = protocols[scheme];
|
248
|
+
var wrappedProtocol = exports[scheme] = Object.create(nativeProtocol);
|
249
|
+
|
250
|
+
// Executes a request, following redirects
|
251
|
+
wrappedProtocol.request = function (options, callback) {
|
252
|
+
if (typeof options === "string") {
|
253
|
+
options = url.parse(options);
|
254
|
+
options.maxRedirects = exports.maxRedirects;
|
255
|
+
}
|
256
|
+
else {
|
257
|
+
options = Object.assign({
|
258
|
+
protocol: protocol,
|
259
|
+
maxRedirects: exports.maxRedirects,
|
260
|
+
maxBodyLength: exports.maxBodyLength,
|
261
|
+
}, options);
|
262
|
+
}
|
263
|
+
options.nativeProtocols = nativeProtocols;
|
264
|
+
assert.equal(options.protocol, protocol, "protocol mismatch");
|
265
|
+
debug("options", options);
|
266
|
+
return new RedirectableRequest(options, callback);
|
267
|
+
};
|
268
|
+
|
269
|
+
// Executes a GET request, following redirects
|
270
|
+
wrappedProtocol.get = function (options, callback) {
|
271
|
+
var request = wrappedProtocol.request(options, callback);
|
272
|
+
request.end();
|
273
|
+
return request;
|
274
|
+
};
|
275
|
+
});
|
276
|
+
return exports;
|
277
|
+
}
|
278
|
+
|
279
|
+
// Exports
|
280
|
+
module.exports = wrap({ http: http, https: https });
|
281
|
+
module.exports.wrap = wrap;
|
package/package.json
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
{
|
2
2
|
"name": "follow-redirects",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.5.0",
|
4
4
|
"description": "HTTP and HTTPS modules that follow redirects.",
|
5
5
|
"main": "index.js",
|
6
6
|
"engines": {
|
7
7
|
"node": ">=4.0"
|
8
8
|
},
|
9
9
|
"scripts": {
|
10
|
-
"test": "
|
10
|
+
"test": "npm run lint && npm run mocha",
|
11
|
+
"lint": "eslint *.js test",
|
12
|
+
"mocha": "nyc mocha"
|
11
13
|
},
|
12
14
|
"repository": {
|
13
15
|
"type": "git",
|
@@ -45,13 +47,13 @@
|
|
45
47
|
"debug": "^3.1.0"
|
46
48
|
},
|
47
49
|
"devDependencies": {
|
48
|
-
"bluebird": "^3.
|
49
|
-
"concat-stream": "^1.
|
50
|
+
"bluebird": "^3.5.1",
|
51
|
+
"concat-stream": "^1.6.0",
|
50
52
|
"coveralls": "^3.0.0",
|
51
|
-
"
|
52
|
-
"
|
53
|
-
"
|
54
|
-
"
|
53
|
+
"eslint": "^4.19.1",
|
54
|
+
"express": "^4.16.2",
|
55
|
+
"mocha": "^5.0.0",
|
56
|
+
"nyc": "^11.8.0"
|
55
57
|
},
|
56
58
|
"license": "MIT",
|
57
59
|
"nyc": {
|
@@ -59,10 +61,5 @@
|
|
59
61
|
"lcov",
|
60
62
|
"text"
|
61
63
|
]
|
62
|
-
},
|
63
|
-
"xo": {
|
64
|
-
"envs": [
|
65
|
-
"mocha"
|
66
|
-
]
|
67
64
|
}
|
68
65
|
}
|