swiftyper-node 1.0.6 → 1.0.7

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.
@@ -1,338 +1,338 @@
1
- 'use strict';
2
-
3
- const http = require('http');
4
- const https = require('https');
5
- const path = require('path');
6
-
7
- const utils = require('./utils');
8
- const {
9
- SwiftyperConnectionError,
10
- SwiftyperError,
11
- SwiftyperAPIError,
12
- } = require('./Error');
13
-
14
- const defaultHttpAgent = new http.Agent({keepAlive: true});
15
- const defaultHttpsAgent = new https.Agent({keepAlive: true});
16
- let requests = 0;
17
-
18
- SwiftyperResource.extend = utils.protoExtend;
19
-
20
- SwiftyperResource.method = require('./SwiftyperMethod');
21
-
22
- const MAX_RETRY_AFTER_WAIT = 60;
23
-
24
- function SwiftyperResource(swiftyper) {
25
- this._swiftyper = swiftyper;
26
-
27
- this.basePath = utils.makeURLInterpolator(
28
- this.basePath || swiftyper.getApiField('basePath')
29
- );
30
- this.resourcePath = this.path;
31
- this.path = utils.makeURLInterpolator(this.path);
32
-
33
- this.initialize(...arguments);
34
- }
35
-
36
- SwiftyperResource.prototype = {
37
- path: '',
38
-
39
- basePath: null,
40
-
41
- initialize() {},
42
-
43
- requestDataProcessor: null,
44
-
45
- createFullPath(commandPath, urlData) {
46
- return path
47
- .join(
48
- this.basePath(urlData),
49
- this.path(urlData),
50
- typeof commandPath == 'function' ? commandPath(urlData) : commandPath
51
- )
52
- .replace(/\\/g, '/');
53
- },
54
-
55
- createResourcePathWithSymbols(pathWithSymbols) {
56
- return `/${path
57
- .join(this.resourcePath, pathWithSymbols || '')
58
- .replace(/\\/g, '/')}`;
59
- },
60
-
61
- _timeoutHandler(timeout, req) {
62
- return () => {
63
- const timeoutErr = new TypeError('ETIMEDOUT');
64
- timeoutErr.code = 'ETIMEDOUT';
65
-
66
- req.destroy(timeoutErr);
67
- };
68
- },
69
-
70
- _responseHandler(req, callback) {
71
- return (res) => {
72
- let response = '';
73
-
74
- res.setEncoding('utf8');
75
- res.on('data', (chunk) => {
76
- response += chunk;
77
- });
78
- res.once('end', () => {
79
- const headers = res.headers || {};
80
-
81
- const requestEndTime = Date.now();
82
- const requestDurationMs = requestEndTime - req._requestStart;
83
-
84
- const responseEvent = utils.removeNullish({
85
- method: req._requestEvent.method,
86
- path: req._requestEvent.path,
87
- status: res.statusCode,
88
- elapsed: requestDurationMs,
89
- request_start_time: req._requestStart,
90
- request_end_time: requestEndTime,
91
- });
92
-
93
- this._swiftyper._emitter.emit('response', responseEvent);
94
-
95
- try {
96
- response = JSON.parse(response);
97
-
98
- if (response.error) {
99
- let err;
100
-
101
- response.error.headers = headers;
102
- response.error.statusCode = res.statusCode;
103
-
104
- if (res.statusCode === 500) {
105
- err = new SwiftyperAPIError(response.error);
106
- } else {
107
- err = SwiftyperError.generate(response.error);
108
- }
109
- return callback.call(this, err, null);
110
- }
111
- } catch (e) {
112
- return callback.call(
113
- this,
114
- new SwiftyperAPIError({
115
- message: 'Invalid JSON received from the Swiftyper API',
116
- response,
117
- exception: e,
118
- }),
119
- null
120
- );
121
- }
122
-
123
- Object.defineProperty(response, 'lastResponse', {
124
- enumerable: false,
125
- writable: false,
126
- value: res,
127
- });
128
- callback.call(this, null, response);
129
- });
130
- };
131
- },
132
-
133
- _generateConnectionErrorMessage(requestRetries) {
134
- return `An error occurred with our connection to Swiftyper.${
135
- requestRetries > 0 ? ` Request was retried ${requestRetries} times.` : ''
136
- }`;
137
- },
138
-
139
- _shouldRetry(res, numRetries, maxRetries) {
140
- if (numRetries >= maxRetries) {
141
- return false;
142
- }
143
-
144
- if (!res) {
145
- return true;
146
- }
147
-
148
- if (res.headers && res.headers['swiftyper-should-retry'] === 'false') {
149
- return false;
150
- }
151
-
152
- if (res.headers && res.headers['swiftyper-should-retry'] === 'true') {
153
- return true;
154
- }
155
-
156
- if (res.statusCode === 409) {
157
- return true;
158
- }
159
-
160
- if (res.statusCode >= 500) {
161
- return true;
162
- }
163
-
164
- return false;
165
- },
166
-
167
- _getSleepTimeInMS(numRetries, retryAfter = null) {
168
- const initialNetworkRetryDelay =
169
- this._swiftyper.getInitialNetworkRetryDelay();
170
- const maxNetworkRetryDelay = this._swiftyper.getMaxNetworkRetryDelay();
171
-
172
- let sleepSeconds = Math.min(
173
- initialNetworkRetryDelay * Math.pow(numRetries - 1, 2),
174
- maxNetworkRetryDelay
175
- );
176
-
177
- sleepSeconds *= 0.5 * (1 + Math.random());
178
-
179
- sleepSeconds = Math.max(initialNetworkRetryDelay, sleepSeconds);
180
-
181
- if (Number.isInteger(retryAfter) && retryAfter <= MAX_RETRY_AFTER_WAIT) {
182
- sleepSeconds = Math.max(sleepSeconds, retryAfter);
183
- }
184
-
185
- return sleepSeconds * 1000;
186
- },
187
-
188
- _getMaxNetworkRetries(settings = {}) {
189
- return settings.maxNetworkRetries &&
190
- Number.isInteger(settings.maxNetworkRetries)
191
- ? settings.maxNetworkRetries
192
- : this._swiftyper.getMaxNetworkRetries();
193
- },
194
-
195
- _makeHeaders(contentLength, method, userSuppliedHeaders) {
196
- const defaultHeaders = {
197
- Accept: 'application/json',
198
- 'Content-Type': 'application/x-www-form-urlencoded',
199
- 'Content-Length': contentLength,
200
- };
201
-
202
- return Object.assign(
203
- utils.removeNullish(defaultHeaders),
204
- utils.normalizeHeaders(userSuppliedHeaders)
205
- );
206
- },
207
-
208
- _request(method, host, path, data, auth, options = {}, callback) {
209
- let requestData;
210
-
211
- data.__req = requests++;
212
- data.api_key = auth ? auth : this._swiftyper.getApiField('auth');
213
-
214
- const retryRequest = (requestFn, headers, requestRetries, retryAfter) => {
215
- return setTimeout(
216
- requestFn,
217
- this._getSleepTimeInMS(requestRetries, retryAfter),
218
- headers,
219
- requestRetries + 1
220
- );
221
- };
222
-
223
- const makeRequest = (headers, numRetries) => {
224
- const protocol = this._swiftyper.getApiField('protocol');
225
- const timeout =
226
- options.settings &&
227
- Number.isInteger(options.settings.timeout) &&
228
- options.settings.timeout >= 0
229
- ? options.settings.timeout
230
- : this._swiftyper.getApiField('timeout');
231
- const isInsecureConnection = protocol === 'http';
232
- const agent = isInsecureConnection ? defaultHttpAgent : defaultHttpsAgent;
233
-
234
- const req = (isInsecureConnection ? http : https).request({
235
- host: host || this._swiftyper.getApiField('host'),
236
- port: this._swiftyper.getApiField('port'),
237
- protocol: protocol + ':',
238
- path,
239
- method,
240
- agent,
241
- headers,
242
- ciphers: 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!MD5',
243
- });
244
-
245
- this._swiftyper._lastRequest = req;
246
-
247
- const requestStartTime = Date.now();
248
-
249
- const requestEvent = utils.removeNullish({
250
- method,
251
- path,
252
- request_start_time: requestStartTime,
253
- });
254
-
255
- const requestRetries = numRetries || 0;
256
-
257
- const maxRetries = this._getMaxNetworkRetries(options.settings);
258
-
259
- req._requestEvent = requestEvent;
260
-
261
- req._requestStart = requestStartTime;
262
-
263
- this._swiftyper._emitter.emit('request', requestEvent);
264
-
265
- req.setTimeout(timeout, this._timeoutHandler(timeout, req));
266
-
267
- req.once('response', (res) => {
268
- if (this._shouldRetry(res, requestRetries, maxRetries)) {
269
- return retryRequest(
270
- makeRequest,
271
- headers,
272
- requestRetries,
273
- ((res || {}).headers || {})['retry-after']
274
- );
275
- } else {
276
- return this._responseHandler(req, callback)(res);
277
- }
278
- });
279
-
280
- req.on('error', (error) => {
281
- if (this._shouldRetry(null, requestRetries, maxRetries)) {
282
- return retryRequest(makeRequest, headers, requestRetries, null);
283
- } else {
284
- if (error.code === 'ETIMEDOUT') {
285
- return callback.call(
286
- this,
287
- new SwiftyperConnectionError({
288
- message: `Request aborted due to timeout being reached (${timeout}ms)`,
289
- detail: error,
290
- })
291
- );
292
- }
293
- return callback.call(
294
- this,
295
- new SwiftyperConnectionError({
296
- message: this._generateConnectionErrorMessage(requestRetries),
297
- detail: error,
298
- }),
299
- null
300
- );
301
- }
302
- });
303
-
304
- req.write(requestData);
305
- req.end();
306
- };
307
-
308
- const prepareAndMakeRequest = (error, data) => {
309
- if (error) {
310
- return callback(error);
311
- }
312
-
313
- requestData = data;
314
-
315
- const headers = this._makeHeaders(
316
- requestData.length,
317
- method,
318
- options.headers,
319
- options.settings
320
- );
321
-
322
- makeRequest(headers);
323
- };
324
-
325
- if (this.requestDataProcessor) {
326
- this.requestDataProcessor(
327
- method,
328
- data,
329
- options.headers,
330
- prepareAndMakeRequest
331
- );
332
- } else {
333
- prepareAndMakeRequest(null, utils.stringifyRequestData(data || {}));
334
- }
335
- },
336
- };
337
-
338
- module.exports = SwiftyperResource;
1
+ 'use strict';
2
+
3
+ const http = require('http');
4
+ const https = require('https');
5
+ const path = require('path');
6
+
7
+ const utils = require('./utils');
8
+ const {
9
+ SwiftyperConnectionError,
10
+ SwiftyperError,
11
+ SwiftyperAPIError,
12
+ } = require('./Error');
13
+
14
+ const defaultHttpAgent = new http.Agent({keepAlive: true});
15
+ const defaultHttpsAgent = new https.Agent({keepAlive: true});
16
+ let requests = 0;
17
+
18
+ SwiftyperResource.extend = utils.protoExtend;
19
+
20
+ SwiftyperResource.method = require('./SwiftyperMethod');
21
+
22
+ const MAX_RETRY_AFTER_WAIT = 60;
23
+
24
+ function SwiftyperResource(swiftyper) {
25
+ this._swiftyper = swiftyper;
26
+
27
+ this.basePath = utils.makeURLInterpolator(
28
+ this.basePath || swiftyper.getApiField('basePath')
29
+ );
30
+ this.resourcePath = this.path;
31
+ this.path = utils.makeURLInterpolator(this.path);
32
+
33
+ this.initialize(...arguments);
34
+ }
35
+
36
+ SwiftyperResource.prototype = {
37
+ path: '',
38
+
39
+ basePath: null,
40
+
41
+ initialize() {},
42
+
43
+ requestDataProcessor: null,
44
+
45
+ createFullPath(commandPath, urlData) {
46
+ return path
47
+ .join(
48
+ this.basePath(urlData),
49
+ this.path(urlData),
50
+ typeof commandPath == 'function' ? commandPath(urlData) : commandPath
51
+ )
52
+ .replace(/\\/g, '/');
53
+ },
54
+
55
+ createResourcePathWithSymbols(pathWithSymbols) {
56
+ return `/${path
57
+ .join(this.resourcePath, pathWithSymbols || '')
58
+ .replace(/\\/g, '/')}`;
59
+ },
60
+
61
+ _timeoutHandler(timeout, req) {
62
+ return () => {
63
+ const timeoutErr = new TypeError('ETIMEDOUT');
64
+ timeoutErr.code = 'ETIMEDOUT';
65
+
66
+ req.destroy(timeoutErr);
67
+ };
68
+ },
69
+
70
+ _responseHandler(req, callback) {
71
+ return (res) => {
72
+ let response = '';
73
+
74
+ res.setEncoding('utf8');
75
+ res.on('data', (chunk) => {
76
+ response += chunk;
77
+ });
78
+ res.once('end', () => {
79
+ const headers = res.headers || {};
80
+
81
+ const requestEndTime = Date.now();
82
+ const requestDurationMs = requestEndTime - req._requestStart;
83
+
84
+ const responseEvent = utils.removeNullish({
85
+ method: req._requestEvent.method,
86
+ path: req._requestEvent.path,
87
+ status: res.statusCode,
88
+ elapsed: requestDurationMs,
89
+ request_start_time: req._requestStart,
90
+ request_end_time: requestEndTime,
91
+ });
92
+
93
+ this._swiftyper._emitter.emit('response', responseEvent);
94
+
95
+ try {
96
+ response = JSON.parse(response);
97
+
98
+ if (response.error) {
99
+ let err;
100
+
101
+ response.error.headers = headers;
102
+ response.error.statusCode = res.statusCode;
103
+
104
+ if (res.statusCode === 500) {
105
+ err = new SwiftyperAPIError(response.error);
106
+ } else {
107
+ err = SwiftyperError.generate(response.error);
108
+ }
109
+ return callback.call(this, err, null);
110
+ }
111
+ } catch (e) {
112
+ return callback.call(
113
+ this,
114
+ new SwiftyperAPIError({
115
+ message: 'Invalid JSON received from the Swiftyper API',
116
+ response,
117
+ exception: e,
118
+ }),
119
+ null
120
+ );
121
+ }
122
+
123
+ Object.defineProperty(response, 'lastResponse', {
124
+ enumerable: false,
125
+ writable: false,
126
+ value: res,
127
+ });
128
+ callback.call(this, null, response);
129
+ });
130
+ };
131
+ },
132
+
133
+ _generateConnectionErrorMessage(requestRetries) {
134
+ return `An error occurred with our connection to Swiftyper.${
135
+ requestRetries > 0 ? ` Request was retried ${requestRetries} times.` : ''
136
+ }`;
137
+ },
138
+
139
+ _shouldRetry(res, numRetries, maxRetries) {
140
+ if (numRetries >= maxRetries) {
141
+ return false;
142
+ }
143
+
144
+ if (!res) {
145
+ return true;
146
+ }
147
+
148
+ if (res.headers && res.headers['swiftyper-should-retry'] === 'false') {
149
+ return false;
150
+ }
151
+
152
+ if (res.headers && res.headers['swiftyper-should-retry'] === 'true') {
153
+ return true;
154
+ }
155
+
156
+ if (res.statusCode === 409) {
157
+ return true;
158
+ }
159
+
160
+ if (res.statusCode >= 500) {
161
+ return true;
162
+ }
163
+
164
+ return false;
165
+ },
166
+
167
+ _getSleepTimeInMS(numRetries, retryAfter = null) {
168
+ const initialNetworkRetryDelay =
169
+ this._swiftyper.getInitialNetworkRetryDelay();
170
+ const maxNetworkRetryDelay = this._swiftyper.getMaxNetworkRetryDelay();
171
+
172
+ let sleepSeconds = Math.min(
173
+ initialNetworkRetryDelay * Math.pow(numRetries - 1, 2),
174
+ maxNetworkRetryDelay
175
+ );
176
+
177
+ sleepSeconds *= 0.5 * (1 + Math.random());
178
+
179
+ sleepSeconds = Math.max(initialNetworkRetryDelay, sleepSeconds);
180
+
181
+ if (Number.isInteger(retryAfter) && retryAfter <= MAX_RETRY_AFTER_WAIT) {
182
+ sleepSeconds = Math.max(sleepSeconds, retryAfter);
183
+ }
184
+
185
+ return sleepSeconds * 1000;
186
+ },
187
+
188
+ _getMaxNetworkRetries(settings = {}) {
189
+ return settings.maxNetworkRetries &&
190
+ Number.isInteger(settings.maxNetworkRetries)
191
+ ? settings.maxNetworkRetries
192
+ : this._swiftyper.getMaxNetworkRetries();
193
+ },
194
+
195
+ _makeHeaders(contentLength, method, userSuppliedHeaders) {
196
+ const defaultHeaders = {
197
+ Accept: 'application/json',
198
+ 'Content-Type': 'application/x-www-form-urlencoded',
199
+ 'Content-Length': contentLength,
200
+ };
201
+
202
+ return Object.assign(
203
+ utils.removeNullish(defaultHeaders),
204
+ utils.normalizeHeaders(userSuppliedHeaders)
205
+ );
206
+ },
207
+
208
+ _request(method, host, path, data, auth, options = {}, callback) {
209
+ let requestData;
210
+
211
+ data.__req = requests++;
212
+ data.api_key = auth ? auth : this._swiftyper.getApiField('auth');
213
+
214
+ const retryRequest = (requestFn, headers, requestRetries, retryAfter) => {
215
+ return setTimeout(
216
+ requestFn,
217
+ this._getSleepTimeInMS(requestRetries, retryAfter),
218
+ headers,
219
+ requestRetries + 1
220
+ );
221
+ };
222
+
223
+ const makeRequest = (headers, numRetries) => {
224
+ const protocol = this._swiftyper.getApiField('protocol');
225
+ const timeout =
226
+ options.settings &&
227
+ Number.isInteger(options.settings.timeout) &&
228
+ options.settings.timeout >= 0
229
+ ? options.settings.timeout
230
+ : this._swiftyper.getApiField('timeout');
231
+ const isInsecureConnection = protocol === 'http';
232
+ const agent = isInsecureConnection ? defaultHttpAgent : defaultHttpsAgent;
233
+
234
+ const req = (isInsecureConnection ? http : https).request({
235
+ host: host || this._swiftyper.getApiField('host'),
236
+ port: this._swiftyper.getApiField('port'),
237
+ protocol: protocol + ':',
238
+ path,
239
+ method,
240
+ agent,
241
+ headers,
242
+ ciphers: 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!MD5',
243
+ });
244
+
245
+ this._swiftyper._lastRequest = req;
246
+
247
+ const requestStartTime = Date.now();
248
+
249
+ const requestEvent = utils.removeNullish({
250
+ method,
251
+ path,
252
+ request_start_time: requestStartTime,
253
+ });
254
+
255
+ const requestRetries = numRetries || 0;
256
+
257
+ const maxRetries = this._getMaxNetworkRetries(options.settings);
258
+
259
+ req._requestEvent = requestEvent;
260
+
261
+ req._requestStart = requestStartTime;
262
+
263
+ this._swiftyper._emitter.emit('request', requestEvent);
264
+
265
+ req.setTimeout(timeout, this._timeoutHandler(timeout, req));
266
+
267
+ req.once('response', (res) => {
268
+ if (this._shouldRetry(res, requestRetries, maxRetries)) {
269
+ return retryRequest(
270
+ makeRequest,
271
+ headers,
272
+ requestRetries,
273
+ ((res || {}).headers || {})['retry-after']
274
+ );
275
+ } else {
276
+ return this._responseHandler(req, callback)(res);
277
+ }
278
+ });
279
+
280
+ req.on('error', (error) => {
281
+ if (this._shouldRetry(null, requestRetries, maxRetries)) {
282
+ return retryRequest(makeRequest, headers, requestRetries, null);
283
+ } else {
284
+ if (error.code === 'ETIMEDOUT') {
285
+ return callback.call(
286
+ this,
287
+ new SwiftyperConnectionError({
288
+ message: `Request aborted due to timeout being reached (${timeout}ms)`,
289
+ detail: error,
290
+ })
291
+ );
292
+ }
293
+ return callback.call(
294
+ this,
295
+ new SwiftyperConnectionError({
296
+ message: this._generateConnectionErrorMessage(requestRetries),
297
+ detail: error,
298
+ }),
299
+ null
300
+ );
301
+ }
302
+ });
303
+
304
+ req.write(requestData);
305
+ req.end();
306
+ };
307
+
308
+ const prepareAndMakeRequest = (error, data) => {
309
+ if (error) {
310
+ return callback(error);
311
+ }
312
+
313
+ requestData = data;
314
+
315
+ const headers = this._makeHeaders(
316
+ requestData.length,
317
+ method,
318
+ options.headers,
319
+ options.settings
320
+ );
321
+
322
+ makeRequest(headers);
323
+ };
324
+
325
+ if (this.requestDataProcessor) {
326
+ this.requestDataProcessor(
327
+ method,
328
+ data,
329
+ options.headers,
330
+ prepareAndMakeRequest
331
+ );
332
+ } else {
333
+ prepareAndMakeRequest(null, utils.stringifyRequestData(data || {}));
334
+ }
335
+ },
336
+ };
337
+
338
+ module.exports = SwiftyperResource;