rqlite-js 2.6.0 → 3.0.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.
Files changed (98) hide show
  1. package/README.md +207 -29
  2. package/dist/index.cjs +904 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +329 -0
  5. package/dist/index.d.ts +329 -0
  6. package/dist/index.js +865 -0
  7. package/dist/index.js.map +1 -0
  8. package/docs/MIGRATION-v2-to-v3.md +71 -0
  9. package/package.json +56 -35
  10. package/src/api/backup/index.ts +69 -0
  11. package/src/api/backup-formats.ts +8 -0
  12. package/src/api/client/index.ts +97 -0
  13. package/src/api/consistency-levels.ts +10 -0
  14. package/src/api/data/index.ts +87 -0
  15. package/src/api/paths.ts +13 -0
  16. package/src/api/query-params.ts +15 -0
  17. package/src/api/results/data-result-error.ts +41 -0
  18. package/src/api/results/data-result.ts +91 -0
  19. package/src/api/results/data-results.ts +91 -0
  20. package/src/api/results/index.ts +7 -0
  21. package/src/api/results/result-fields.ts +14 -0
  22. package/src/api/status/index.ts +53 -0
  23. package/src/http-request/auth-keys.ts +14 -0
  24. package/src/http-request/content-types.ts +4 -0
  25. package/src/http-request/errors.ts +17 -0
  26. package/src/http-request/http-headers.ts +19 -0
  27. package/src/http-request/http-methods.ts +12 -0
  28. package/src/http-request/index.ts +676 -0
  29. package/src/http-request/retryable.ts +41 -0
  30. package/src/index.ts +38 -0
  31. package/lib/api/backup/index.js +0 -72
  32. package/lib/api/backup/index.js.map +0 -1
  33. package/lib/api/backup/test.unit.js +0 -45
  34. package/lib/api/backup/test.unit.js.map +0 -1
  35. package/lib/api/backup-formats.js +0 -16
  36. package/lib/api/backup-formats.js.map +0 -1
  37. package/lib/api/client/index.js +0 -105
  38. package/lib/api/client/index.js.map +0 -1
  39. package/lib/api/client/test.unit.js +0 -53
  40. package/lib/api/client/test.unit.js.map +0 -1
  41. package/lib/api/consistency-levels.js +0 -30
  42. package/lib/api/consistency-levels.js.map +0 -1
  43. package/lib/api/data/index.js +0 -108
  44. package/lib/api/data/index.js.map +0 -1
  45. package/lib/api/data/test.unit.js +0 -98
  46. package/lib/api/data/test.unit.js.map +0 -1
  47. package/lib/api/paths.js +0 -33
  48. package/lib/api/paths.js.map +0 -1
  49. package/lib/api/query-params.js +0 -43
  50. package/lib/api/query-params.js.map +0 -1
  51. package/lib/api/results/data-result-error.js +0 -62
  52. package/lib/api/results/data-result-error.js.map +0 -1
  53. package/lib/api/results/data-result.js +0 -141
  54. package/lib/api/results/data-result.js.map +0 -1
  55. package/lib/api/results/data-results.js +0 -142
  56. package/lib/api/results/data-results.js.map +0 -1
  57. package/lib/api/results/index.js +0 -8
  58. package/lib/api/results/index.js.map +0 -1
  59. package/lib/api/results/result-fields.js +0 -47
  60. package/lib/api/results/result-fields.js.map +0 -1
  61. package/lib/api/results/test.unit.js +0 -238
  62. package/lib/api/results/test.unit.js.map +0 -1
  63. package/lib/api/status/index.js +0 -67
  64. package/lib/api/status/index.js.map +0 -1
  65. package/lib/api/status/test.unit.js +0 -57
  66. package/lib/api/status/test.unit.js.map +0 -1
  67. package/lib/http-request/auth-keys.js +0 -15
  68. package/lib/http-request/auth-keys.js.map +0 -1
  69. package/lib/http-request/content-types.js +0 -5
  70. package/lib/http-request/content-types.js.map +0 -1
  71. package/lib/http-request/errors.js +0 -17
  72. package/lib/http-request/errors.js.map +0 -1
  73. package/lib/http-request/http-headers.js +0 -20
  74. package/lib/http-request/http-headers.js.map +0 -1
  75. package/lib/http-request/http-methods.js +0 -40
  76. package/lib/http-request/http-methods.js.map +0 -1
  77. package/lib/http-request/index.js +0 -764
  78. package/lib/http-request/index.js.map +0 -1
  79. package/lib/http-request/retryable.js +0 -42
  80. package/lib/http-request/retryable.js.map +0 -1
  81. package/lib/http-request/test.unit.js +0 -560
  82. package/lib/http-request/test.unit.js.map +0 -1
  83. package/lib/index.js +0 -39
  84. package/lib/index.js.map +0 -1
  85. package/lib/test/api-data-execute-nock.js +0 -142
  86. package/lib/test/api-data-execute-nock.js.map +0 -1
  87. package/lib/test/api-data-query-nock.js +0 -210
  88. package/lib/test/api-data-query-nock.js.map +0 -1
  89. package/lib/test/backups/backup-nock.js +0 -29
  90. package/lib/test/backups/backup-nock.js.map +0 -1
  91. package/lib/test/backups/restore-nock.js +0 -30
  92. package/lib/test/backups/restore-nock.js.map +0 -1
  93. package/lib/test/env.js +0 -15
  94. package/lib/test/env.js.map +0 -1
  95. package/lib/test/unit/index.unit.js +0 -27
  96. package/lib/test/unit/index.unit.js.map +0 -1
  97. package/lib/test.integration.js +0 -238
  98. package/lib/test.integration.js.map +0 -1
@@ -1,764 +0,0 @@
1
- "use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.DEAULT_TIMEOUT = exports.DEAULT_RETRY_DELAY = void 0;exports.createDefaultHeaders = createDefaultHeaders;exports.default = void 0;exports.getWaitTimeExponential = getWaitTimeExponential;
2
-
3
-
4
-
5
-
6
- var _axios = _interopRequireDefault(require("axios"));
7
- var _qs = require("qs");
8
- var _httpMethods = require("./http-methods");
9
-
10
-
11
-
12
- var _contentTypes = require("./content-types");
13
-
14
-
15
- var _errors = require("./errors");
16
- var _retryable = require("./retryable");
17
-
18
-
19
-
20
-
21
- var _authKeys = require("./auth-keys");
22
- var _httpHeaders = require("./http-headers"); /**
23
- * Plain HTTP client to be used when creating RQLite specific API HTTP clients
24
- * @module http-request
25
- * @see https://rqlite.io/docs/api/api/
26
- */ /**
27
- * RQliteJS HTTP Request options
28
- * @typedef HttpRequestOptions
29
- * @type {Object}
30
- * @property {Object} [auth] A object for user authentication
31
- * @property {String} [auth.username] The username for authentication
32
- * @property {String} [auth.password] The password for authentication
33
- * @property {Object} [body] The body of the HTTP request
34
- * @property {Object} [headers={}] HTTP headers to send with the request
35
- * @property {String} [httpMethod=HTTP_METHOD_GET] The HTTP method for the request
36
- * i.e. GET or POST
37
- * @property {Object} [query] An object with the query to send with the HTTP request
38
- * @property {Boolean} [stream=false] When true the returned value is a request object with
39
- * stream support instead of a request-promise result
40
- * @property {Number} [timeout=DEAULT_TIMEOUT] Optional timeout to override default
41
- * @property {String} [uri] The uri for the request which can be a relative path to use
42
- * the currently active host or a full i.e. http://localhost:4001/db/query which is used
43
- * literally
44
- * @property {Boolean} [useLeader=false] When true the request will use the master host, the
45
- * first host in this.hosts, this is ideal for write operations to skip the redirect
46
- * @property {Number} [retries] The number of retries, defaults to the number of
47
- * hosts times 3
48
- * @property {Number} [maxRedirects=10] The maximum number of HTTP redirects to follow before
49
- * throwing an error
50
- * @property {Number} [attempt=0] The current attempt count when retrying or redirecting
51
- * @property {Number} [retryAttempt=0] The current attempt based on retry logic
52
- * @property {Number} [redirectAttempt=0] The current attempt based on redirect logic
53
- * @property {Number} [attemptHostIndex] When in a retry state the host index of the last
54
- * attempt which is used to get the next host index
55
- * @property {Number} [exponentailBackoffBase] Optional exponential backoff base override
56
- * @property {Number} [exponentailBackoffExponent] Optional backoff exponent override
57
- * @property {Boolean} [json] Legacy option; axios uses JSON unless stream is true
58
- * @property {import('http').Agent} [httpAgent] An option http agent, useful for
59
- * keepalive pools using plain HTTP
60
- * @property {import('https').Agent} [httpsAgent] An option http agent, useful
61
- * for keepalive pools using SSL
62
- */ /**
63
- * The default timeout value
64
- */
65
- const DEAULT_TIMEOUT = exports.DEAULT_TIMEOUT = 30000;
66
-
67
- /**
68
- * The default to retry a request using the next host in the chain
69
- */
70
- const DEAULT_RETRY_DELAY = exports.DEAULT_RETRY_DELAY = 30000;
71
-
72
- /**
73
- * Create default header for all HTTP requests
74
- * @param {Object} [headers={}] HTTP headers to send with the request
75
- * @returns {Object} The headers with defaults applied
76
- */
77
- function createDefaultHeaders(headers = {}) {
78
- const accept = headers[_httpHeaders.HTTP_HEADER_ACCEPT] || _contentTypes.CONTENT_TYPE_APPLICATION_JSON;
79
- return { ...headers, [_httpHeaders.HTTP_HEADER_ACCEPT]: accept };
80
- }
81
-
82
- /**
83
- * Clean the request path remove / from the beginning
84
- * @param {String} path The path to clean
85
- * @returns {String} The clean path
86
- */
87
- function cleanPath(path) {
88
- return String(path).replace(/^\//, '');
89
- }
90
-
91
- /**
92
- * Returns the next wait interval, in milliseconds, using an exponential
93
- * backoff algorithm.
94
- * @param {Number} attempt The retry attempt
95
- * @param {Number} base The base of the exponential backoff
96
- * @param {Number} exponent The exponential power
97
- * @returns {Number} The time to wait in milliseconds
98
- */
99
- function getWaitTimeExponential(attempt = 0, base = 100, exponent = 2) {
100
- if (attempt === 0) {
101
- return 0;
102
- }
103
- return exponent ** attempt * base;
104
- }
105
-
106
- /**
107
- * Generic HTTP Request class which all RQLiteJS client
108
- * should extend for consistent communitication with an RQLite
109
- * server
110
- */
111
- class HttpRequest {
112
- /**
113
- * The index of the host in this.hosts which will be tried
114
- * first before attempting other hosts
115
- * @type {Number}
116
- */
117
- activeHostIndex = 0;
118
-
119
- /**
120
- * Whether or not the setNextActiveHostIndex() should
121
- * perform a round robin strategy
122
- */
123
- activeHostRoundRobin = true;
124
-
125
- /**
126
- * The regex pattern to check if a uri is absolute or relative,
127
- * if it is absolute the host is not appended
128
- */
129
- absoluteUriPattern = /^https?:\/\//;
130
-
131
- /**
132
- * A list of hosts that are tried in round robin fashion
133
- * when certain HTTP responses are received
134
- * @type {String[]}
135
- */
136
- hosts = [];
137
-
138
- /**
139
- * @type {import('http').Agent} The http agent if it is set
140
- */
141
- httpAgent;
142
-
143
- /**
144
- * @type {import('https').Agent} The https agent if it is set
145
- */
146
- httpsAgent;
147
-
148
- /**
149
- * The host list index of the leader node defaults
150
- * to the first host
151
- * @type {Number}
152
- */
153
- leaderHostIndex = 0;
154
-
155
- /**
156
- * Http error codes which are considered retryable
157
- * @type {Set<String>}
158
- */
159
- retryableErrorCodes = _retryable.RETRYABLE_ERROR_CODES;
160
-
161
- /**
162
- * Http status codes which are considered retryable
163
- * @type {Set<Number>}
164
- */
165
- retryableStatusCodes = _retryable.RETRYABLE_STATUS_CODES;
166
-
167
- /**
168
- * Http methods which are considered retryable
169
- * @type {Set<String>}
170
- */
171
- retryableHttpMethods = _retryable.RETRYABLE_HTTP_METHODS;
172
-
173
- /**
174
- * The exponential backoff base for retries
175
- */
176
- exponentailBackoffBase = 100;
177
-
178
- /**
179
- * The exponent to increase backoff each try
180
- */
181
- exponentailBackoffExponent = 1.1;
182
-
183
- /**
184
- * Authentication Map
185
- * @type {Map<String, String>}
186
- */
187
- authentication = new Map();
188
-
189
- /**
190
- * Construtor for HttpRequest
191
- * @param {String[]|String} hosts An array of RQLite hosts or a string
192
- * that will be split on "," to create an array of hosts, the first
193
- * host will be tried first when there are multiple hosts
194
- * @param {Object} [options={}] Additional options
195
- * @param {Object} [options.authentication] Authentication options
196
- * @param {String} [options.authentication.username] The host authentication username
197
- * @param {String} [options.authentication.password] The host authentication password
198
- * @param {Boolean} [options.activeHostRoundRobin=true] If true this.setNextActiveHostIndex()
199
- * will perform a round robin when called
200
- * @param {import('http').Agent} [options.httpAgent] An option http agent, useful for
201
- * keepalive pools using plain HTTP
202
- * @param {import('https').Agent} [options.httpsAgent] An option http agent, useful
203
- * for keepalive pools using SSL
204
- * @param {Set|String[]} [options.retryableErrorCodes] The list of retryable error codes
205
- * @param {Set|Number[]} [options.retryableStatusCodes] The list of retryable http status codes
206
- * @param {Set|String[]} [options.retryableHttpMethods] The list of retryable http methods
207
- * @param {Number} [options.exponentailBackoffBase] The value for exponentail backoff base
208
- * for retry exponential backoff
209
- * @param {Number} [options.exponentailBackoffExponent] Exponent to increase backoff each try
210
- */
211
- constructor(hosts, options = {}) {
212
- this.setHosts(hosts);
213
- if (this.getTotalHosts() === 0) {
214
- throw new Error('At least one host must be provided');
215
- }
216
- const {
217
- activeHostRoundRobin = true,
218
- httpAgent,
219
- httpsAgent,
220
- retryableErrorCodes,
221
- retryableStatusCodes,
222
- retryableHttpMethods,
223
- exponentailBackoffExponent,
224
- exponentailBackoffBase,
225
- authentication
226
- } = options;
227
- if (typeof authentication === 'object') {
228
- const { username, password } = authentication;
229
- if (username) {
230
- this.authentication.set(_authKeys.AUTH_USERNAME, username);
231
- }
232
- if (password) {
233
- this.authentication.set(_authKeys.AUTH_PASSWORD, password);
234
- }
235
- }
236
- if (typeof activeHostRoundRobin !== 'undefined') {
237
- this.setActiveHostRoundRobin(activeHostRoundRobin);
238
- }
239
- if (typeof httpAgent !== 'undefined') {
240
- this.setHttpAgent(httpAgent);
241
- }
242
- if (typeof httpsAgent !== 'undefined') {
243
- this.setHttpsAgent(httpsAgent);
244
- }
245
- if (retryableErrorCodes instanceof Set || Array.isArray(retryableErrorCodes)) {
246
- this.setRetryableErrorCodes(
247
- Array.isArray(retryableErrorCodes) ? new Set(retryableErrorCodes) : retryableErrorCodes
248
- );
249
- }
250
- if (retryableStatusCodes instanceof Set || Array.isArray(retryableStatusCodes)) {
251
- this.setRetryableStatusCodes(
252
- Array.isArray(retryableStatusCodes) ? new Set(retryableStatusCodes) : retryableStatusCodes
253
- );
254
- }
255
- if (retryableHttpMethods instanceof Set || Array.isArray(retryableHttpMethods)) {
256
- this.setRetryableHttpMethods(
257
- Array.isArray(retryableHttpMethods) ? new Set(retryableHttpMethods) : retryableHttpMethods
258
- );
259
- }
260
- if (Number.isFinite(exponentailBackoffBase)) {
261
- this.setExponentailBackoffBase(exponentailBackoffBase);
262
- }
263
- if (Number.isFinite(exponentailBackoffExponent)) {
264
- this.setExponentailBackoffExponent(exponentailBackoffExponent);
265
- }
266
- }
267
-
268
- /**
269
- * Set authentication information
270
- * @param {Object} [authentication] Authentication data
271
- * @param {String} [authentication.username] The host authentication username
272
- * @param {String} [authentication.password] The host authentication password
273
- */
274
- setAuthentication(authentication = {}) {
275
- const { username, password } = authentication;
276
- if (username) {
277
- this.authentication.set(_authKeys.AUTH_USERNAME, username);
278
- }
279
- if (password) {
280
- this.authentication.set(_authKeys.AUTH_PASSWORD, password);
281
- }
282
- }
283
-
284
- /**
285
- * Set the exponentail backoff base
286
- * @param {Number} exponentailBackoffBase
287
- */
288
- setExponentailBackoffBase(exponentailBackoffBase) {
289
- this.exponentailBackoffBase = exponentailBackoffBase;
290
- }
291
-
292
- /**
293
- * Get the exponentail backoff base
294
- * @returns {Number} The exponentail backoff base
295
- */
296
- getExponentailBackoffBase() {
297
- return this.exponentailBackoffBase;
298
- }
299
-
300
- /**
301
- * Set the exponentail backoff exponent
302
- * @param {Number} exponentailBackoffExponent
303
- */
304
- setExponentailBackoffExponent(exponentailBackoffExponent) {
305
- this.exponentailBackoffExponent = exponentailBackoffExponent;
306
- }
307
-
308
- /**
309
- * Get the exponentail backoff exponent
310
- * @returns {Number} The exponentail backoff exponent
311
- */
312
- getExponentailBackoffExponent() {
313
- return this.exponentailBackoffExponent;
314
- }
315
-
316
- /**
317
- * Set the retryable error codes
318
- * @param {Set<String>} retryableErrorCodes
319
- */
320
- setRetryableErrorCodes(retryableErrorCodes) {
321
- this.retryableErrorCodes = retryableErrorCodes;
322
- }
323
-
324
- /**
325
- * Get the retryable error codes
326
- * @returns {Set<String>}
327
- */
328
- getRetryableErrorCodes() {
329
- return this.retryableErrorCodes;
330
- }
331
-
332
- /**
333
- * Set the retryable status codes
334
- * @param {Set<Number>} retryableStatusCodes
335
- */
336
- setRetryableStatusCodes(retryableStatusCodes) {
337
- this.retryableStatusCodes = retryableStatusCodes;
338
- }
339
-
340
- /**
341
- * Get the retryable status codes
342
- * @returns {Set<Number>}
343
- */
344
- getRetryableStatusCodes() {
345
- return this.retryableStatusCodes;
346
- }
347
-
348
- /**
349
- * Set the retryable http methods
350
- * @param {Set<String>} retryableHttpMethods
351
- */
352
- setRetryableHttpMethods(retryableHttpMethods) {
353
- this.retryableHttpMethods = retryableHttpMethods;
354
- }
355
-
356
- /**
357
- * Get the retryable http methods
358
- * @returns {Set<String>}
359
- */
360
- getRetryableHttpMethods() {
361
- return this.retryableHttpMethods;
362
- }
363
-
364
- /**
365
- * Set an http agent which is useful for http keepalive requests
366
- * @param {import('http').Agent} httpAgent An http agent
367
- */
368
- setHttpAgent(httpAgent) {
369
- this.httpAgent = httpAgent;
370
- }
371
-
372
- /**
373
- * Get the set http agent
374
- * @returns {import('http').Agent|undefined} The https agent if it is set
375
- */
376
- getHttpAgent() {
377
- return this.httpAgent;
378
- }
379
-
380
- /**
381
- * Set an https agent which is useful for https keepalive requests
382
- * @param {import('https').Agent} httpsAgent An https agent
383
- */
384
- setHttpsAgent(httpsAgent) {
385
- this.httpsAgent = httpsAgent;
386
- }
387
-
388
- /**
389
- * Get the set https agent
390
- * @returns {import('https').Agent|undefined} The https agent if it is set
391
- */
392
- getHttpsAgent() {
393
- return this.httpsAgent;
394
- }
395
-
396
- /**
397
- * Set the list of hosts
398
- * @param {String[]|String} hosts An array of RQLite hosts or a string
399
- * that will be split on "," to create an array of hosts, the first
400
- * host will be tried first when there are multiple hosts
401
- */
402
- setHosts(hosts) {
403
- this.hosts = !Array.isArray(hosts) ? String(hosts).split(',') : hosts;
404
- this.hosts = this.hosts.reduce((acc, v) => {
405
- // Remove trailing slashed from hosts
406
- const host = String(v).trim().replace(/\/$/, '');
407
- if (!host) {
408
- return acc;
409
- }
410
- return acc.concat(host);
411
- }, []);
412
- }
413
-
414
- /**
415
- * Get the list of hosts
416
- * @returns {String[]} The list of hosts
417
- */
418
- getHosts() {
419
- return this.hosts;
420
- }
421
-
422
- /**
423
- * Given a host string find the index of that host in the hosts
424
- * @param {String} host A host to find in hosts
425
- * @returns {Number} The found host index or -1 if not found
426
- */
427
- findHostIndex(host) {
428
- let parsedHostToFind;
429
- try {
430
- parsedHostToFind = new URL(host);
431
- } catch (e) {
432
- return -1;
433
- }
434
- return this.getHosts().findIndex((v) => {
435
- try {
436
- const parsedHost = new URL(v);
437
- // Find a host where all the parsed fields match the requested host
438
- return ['hostname', 'protocol', 'port', 'pathname'].every(
439
- (field) => parsedHostToFind[field] === parsedHost[field]
440
- );
441
- } catch (e) {
442
- return false;
443
- }
444
- });
445
- }
446
-
447
- /**
448
- * Get the current active host from the hosts array
449
- * @param {Boolean} useLeader If true use the first host which is always
450
- * the master, this is prefered for write operations
451
- * @returns {String} The active host
452
- */
453
- getActiveHost(useLeader) {
454
- // When useLeader is true we should just use the first host
455
- const activeHostIndex = useLeader ? this.getLeaderHostIndex() : this.getActiveHostIndex();
456
- return this.getHosts()[activeHostIndex];
457
- }
458
-
459
- /**
460
- * Set the active host index with check based on this.hosts
461
- * @param {Number} activeHostIndex The index
462
- * @returns {Number} The active host index
463
- */
464
- setActiveHostIndex(activeHostIndex) {
465
- if (!Number.isFinite(activeHostIndex)) {
466
- throw new Error('The activeHostIndex should be a finite number');
467
- }
468
- const totalHosts = this.getTotalHosts();
469
- if (activeHostIndex < 0) {
470
- // Don't allow an index less then zero
471
- this.activeHostIndex = 0;
472
- } else if (activeHostIndex >= totalHosts) {
473
- // Don't allow an index greater then the length of the hosts
474
- this.activeHostIndex = totalHosts - 1;
475
- } else {
476
- this.activeHostIndex = activeHostIndex;
477
- }
478
- return this.activeHostIndex;
479
- }
480
-
481
- /**
482
- * Get the host index for the leader node
483
- * @returns {Number} The host index for the leader node
484
- */
485
- getLeaderHostIndex() {
486
- return this.leaderHostIndex;
487
- }
488
-
489
- /**
490
- * Set the index in the host array for the leader node
491
- * @param {Number} leaderHostIndex The index of the host that is the leader node
492
- * @returns {Number} The host index for the leader node
493
- */
494
- setLeaderHostIndex(leaderHostIndex) {
495
- if (!Number.isFinite(leaderHostIndex)) {
496
- throw new Error('The leaderHostIndex should be a finite number');
497
- }
498
- const totalHosts = this.getTotalHosts();
499
- if (leaderHostIndex < 0) {
500
- this.leaderHostIndex = 0;
501
- } else if (leaderHostIndex > totalHosts) {
502
- this.leaderHostIndex = totalHosts - 1;
503
- } else {
504
- this.leaderHostIndex = leaderHostIndex;
505
- }
506
- return this.leaderHostIndex;
507
- }
508
-
509
- /**
510
- * Get the active host index
511
- * @returns {Number} The active host index
512
- */
513
- getActiveHostIndex() {
514
- return this.activeHostIndex;
515
- }
516
-
517
- /**
518
- * Set active host round robin value
519
- * @param {Boolean} activeHostRoundRobin If true setActiveHostIndex() will
520
- * perform a round robin
521
- */
522
- setActiveHostRoundRobin(activeHostRoundRobin) {
523
- if (typeof activeHostRoundRobin !== 'boolean') {
524
- throw new Error('The activeHostRoundRobin argument must be boolean');
525
- }
526
- this.activeHostRoundRobin = activeHostRoundRobin;
527
- }
528
-
529
- /**
530
- * Get active host round robin value
531
- * @returns {Boolean} The value of activeHostRoundRobin
532
- */
533
- getActiveHostRoundRobin() {
534
- return this.activeHostRoundRobin;
535
- }
536
-
537
- /**
538
- * Get the next active host index
539
- * @param {Number} [activeHostIndex] An optional paramater to provide the active host index
540
- * @returns {Number} The next active host index which will wrap around to zero
541
- */
542
- getNextActiveHostIndex(activeHostIndex = this.getActiveHostIndex()) {
543
- const totalHosts = this.getTotalHosts();
544
- const nextIndex = activeHostIndex + 1;
545
- // If we are past the last index start back over at 1
546
- if (totalHosts === nextIndex) {
547
- return 0;
548
- }
549
- return nextIndex;
550
- }
551
-
552
- /**
553
- * Set the active host index to the next host using a
554
- * round robin strategy
555
- */
556
- setNextActiveHostIndex() {
557
- // Don't bother if we only have one host
558
- if (!this.getActiveHostRoundRobin()) {
559
- return;
560
- }
561
- const totalHosts = this.getTotalHosts();
562
- if (this.getActiveHostRoundRobin() && totalHosts <= 1) {
563
- return;
564
- }
565
- this.setActiveHostIndex(this.getNextActiveHostIndex());
566
- }
567
-
568
- /**
569
- * Get the total number of hosts
570
- * @returns {Number} The total number of hosts
571
- */
572
- getTotalHosts() {
573
- return this.getHosts().length;
574
- }
575
-
576
- /**
577
- * Returns whether or not the uri passes a test for this.absoluteUriPattern
578
- * @returns {Boolean} True if the path is absolute
579
- */
580
- uriIsAbsolute(uri) {
581
- return this.absoluteUriPattern.test(uri);
582
- }
583
-
584
- /**
585
- * Returns true when the HTTP request is retryable
586
- * @param {Object} [options={}] The options
587
- * @param {Number} [options.statusCode] The HTTP status code
588
- * @param {String} [options.errorCode] The error code
589
- * @param {String} [options.httpMethod] The http method
590
- * @returns {Boolean} True if the request is retry able
591
- */
592
- requestIsRetryable(options = {}) {
593
- const {
594
- statusCode,
595
- errorCode,
596
- httpMethod
597
- } = options;
598
- // Honor strictly the http method
599
- if (!this.getRetryableHttpMethods().has(httpMethod)) {
600
- return false;
601
- }
602
- if (statusCode && this.getRetryableStatusCodes().has(statusCode)) {
603
- return true;
604
- }
605
- if (errorCode && this.getRetryableErrorCodes().has(errorCode)) {
606
- return true;
607
- }
608
- return false;
609
- }
610
-
611
- /**
612
- * Perform an HTTP request using the provided options
613
- * @param {HttpRequestOptions} [options={}] Options for the HTTP client
614
- * @returns {Promise<{status: Number, body: Object|String}>} An object with a status and body
615
- * property when stream is false and a stream when the stream option is true
616
- * @throws {ERROR_HTTP_REQUEST_MAX_REDIRECTS} When the maximum number of redirect has been reached
617
- */
618
- async fetch(options = {}) {
619
- const {
620
- body,
621
- headers = {},
622
- httpMethod = _httpMethods.HTTP_METHOD_GET,
623
- query,
624
- stream = false,
625
- timeout = DEAULT_TIMEOUT,
626
- useLeader = false,
627
- retries = this.getTotalHosts() * 3,
628
- maxRedirects = 10,
629
- attempt = 0,
630
- retryAttempt = 0,
631
- redirectAttempt = 0,
632
- attemptHostIndex,
633
- exponentailBackoffExponent = this.getExponentailBackoffExponent(),
634
- exponentailBackoffBase = this.getExponentailBackoffBase(),
635
- httpAgent = this.getHttpAgent(),
636
- httpsAgent = this.getHttpsAgent()
637
- } = options;
638
- // Honor the supplied attemptHostIndex or get the active host
639
- const activeHost = Number.isFinite(attemptHostIndex) ? this.getHosts()[attemptHostIndex] :
640
- this.getActiveHost(useLeader);
641
- let { uri } = options;
642
- if (!uri) {
643
- throw new Error('The uri option is required');
644
- }
645
- uri = this.uriIsAbsolute(uri) ? uri : `${activeHost}/${cleanPath(uri)}`;
646
- try {
647
- let auth;
648
- if (this.authentication.size) {
649
- auth = {
650
- [_authKeys.AUTH_USERNAME]: this.authentication.get(_authKeys.AUTH_USERNAME),
651
- [_authKeys.AUTH_PASSWORD]: this.authentication.get(_authKeys.AUTH_PASSWORD)
652
- };
653
- }
654
- const response = await (0, _axios.default)({
655
- url: uri,
656
- auth,
657
- data: body,
658
- maxRedirects: 0, // Handle redirects manually to allow reposting data
659
- headers: createDefaultHeaders(headers),
660
- responseType: stream ? 'stream' : 'json',
661
- method: httpMethod,
662
- params: query,
663
- timeout,
664
- httpsAgent,
665
- httpAgent,
666
- paramsSerializer(params) {
667
- return (0, _qs.stringify)(params, { arrayFormat: 'brackets' });
668
- }
669
- });
670
- if (stream) {
671
- return response.data;
672
- }
673
- return {
674
- body: response.data,
675
- status: response.status
676
- };
677
- } catch (e) {
678
- const { response = {}, code: errorCode } = e;
679
- const { status: responseStatus, headers: responseHeaders = {} } = response;
680
- // Check if the error was a redirect
681
- const retryable = this.requestIsRetryable({
682
- statusCode: responseStatus,
683
- errorCode,
684
- httpMethod
685
- });
686
- // Save the next active host index and pass it to retry manually
687
- let nextAttemptHostIndex = Number.isFinite(attemptHostIndex) ? attemptHostIndex :
688
- this.getActiveHostIndex();
689
- nextAttemptHostIndex += 1;
690
- // We go past the last index start from zero
691
- if (nextAttemptHostIndex === this.getTotalHosts()) {
692
- nextAttemptHostIndex = 0;
693
- }
694
- // First check if this is a redirect error
695
- if (responseStatus === 301 || responseStatus === 302) {
696
- // We maxed out on redirect attempts
697
- if (redirectAttempt >= maxRedirects) {
698
- throw new _errors.ERROR_HTTP_REQUEST_MAX_REDIRECTS(`The maximum number of redirects ${maxRedirects} has been reached`);
699
- }
700
- const location = typeof responseHeaders === 'object' ?
701
- responseHeaders[_httpHeaders.HTTP_HEADER_LOCATION.toLowerCase()] ||
702
- responseHeaders[_httpHeaders.HTTP_HEADER_LOCATION] :
703
- undefined;
704
- // If we were asked to use the leader, but got redirect the leader moved so remember it
705
- if (useLeader) {
706
- const newLeaderHostIndex = this.findHostIndex(location);
707
- // If the redirect exists in the hosts list remember it for next time
708
- if (newLeaderHostIndex > -1) {
709
- this.setLeaderHostIndex(newLeaderHostIndex);
710
- }
711
- }
712
- return this.fetch({
713
- ...options,
714
- uri: location,
715
- attempt: attempt + 1,
716
- redirectAttempt: redirectAttempt + 1,
717
- attemptHostIndex: nextAttemptHostIndex
718
- });
719
- }
720
- if (retryable && retryAttempt < retries) {
721
- const waitTime = getWaitTimeExponential(
722
- retryAttempt,
723
- exponentailBackoffBase,
724
- exponentailBackoffExponent
725
- );
726
- await new Promise((resolve) => {
727
- setTimeout(() => {
728
- resolve(undefined);
729
- }, waitTime);
730
- });
731
- return this.fetch({
732
- ...options,
733
- attempt: attempt + 1,
734
- retryAttempt: retryAttempt + 1,
735
- attemptHostIndex: nextAttemptHostIndex
736
- });
737
- }
738
- throw e;
739
- }
740
- }
741
-
742
- /**
743
- * Perform an HTTP GET request
744
- * @param {...*} args HttpRequestOptions, or (path, sql, options) when overridden by ApiClient
745
- * @returns {Promise<*>}
746
- * @see HttpRequest#fetch
747
- */
748
- async get(...args) {
749
- const options = args[0] || {};
750
- return this.fetch({ ...options, httpMethod: _httpMethods.HTTP_METHOD_GET });
751
- }
752
-
753
- /**
754
- * Perform an HTTP POST request
755
- * @param {...*} args HttpRequestOptions, or (path, sql, options) when overridden by ApiClient
756
- * @returns {Promise<*>}
757
- * @see HttpRequest#fetch
758
- */
759
- async post(...args) {
760
- const options = args[0] || {};
761
- return this.fetch({ ...options, httpMethod: _httpMethods.HTTP_METHOD_POST });
762
- }
763
- }exports.default = HttpRequest;
764
- //# sourceMappingURL=index.js.map