getta 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -109,14 +109,11 @@ The stream reader to use when parsing the response body. Default is `'json'`.
109
109
 
110
110
  ### Making reqeusts
111
111
 
112
- The rest client supports `GET`, `POST`, `PUT` and `DELETE` methods and has functions for each method.
112
+ The rest client supports `GET`, `POST`, `PUT` and `DELETE` methods and has functions for each method. The first argument is the path to make the request to. This can also be a path template with variable placeholders that will be replaced with data passed in on the `pathTemplateData` request option.
113
113
 
114
114
  ```typescript
115
- const pathTemplate = '/direct/rest/content/catalog/{type}/{id,+}?format={brief|standard}';
116
- const pathTemplateData = { 'brief|standard': 'standard', 'id,+': '136-7317', type: 'product' };
117
-
118
115
  // GET
119
- const getResponse = await restClient.get(pathTemplate, { pathTemplateData });
116
+ const getResponse = await restClient.get('/path/to/resource');
120
117
 
121
118
  // POST
122
119
  const postResponse = await restClient.post('/graphql/api', {
@@ -124,13 +121,12 @@ const postResponse = await restClient.post('/graphql/api', {
124
121
  });
125
122
 
126
123
  // PUT
127
- const putResponse = await restClient.put(pathTemplate, {
128
- body: JSON.stringify({ /* payload */ }),
129
- pathTemplateData,
124
+ const putResponse = await restClient.put('/path/to/resource', {
125
+ body: JSON.stringify({ /* payload */ }),
130
126
  });
131
127
 
132
128
  // DELETE
133
- const deleteResponse = await restClient.delete(pathTemplate, { pathTemplateData });
129
+ const deleteResponse = await restClient.delete('/path/to/resource');
134
130
  ```
135
131
 
136
132
  ### Request options
@@ -0,0 +1,665 @@
1
+ 'use strict';
2
+
3
+ var _defineProperty = require('@babel/runtime/helpers/defineProperty');
4
+ require('core-js/modules/es.array.push.js');
5
+ var lodashEs = require('lodash-es');
6
+ var tsMd5 = require('ts-md5');
7
+ var queryString = require('query-string');
8
+
9
+ const ARRAY_BUFFER_FORMAT = 'arrayBuffer';
10
+ const BLOB_FORMAT = 'blob';
11
+ const FORM_DATA_FORMAT = 'formData';
12
+ const JSON_FORMAT = 'json';
13
+ const TEXT_FORMAT = 'text';
14
+ const STREAM_READERS = {
15
+ ARRAY_BUFFER_FORMAT,
16
+ BLOB_FORMAT,
17
+ FORM_DATA_FORMAT,
18
+ JSON_FORMAT,
19
+ TEXT_FORMAT
20
+ };
21
+ const DEFAULT_BODY_PARSER = body => body;
22
+ const DEFAULT_FETCH_TIMEOUT = 5000;
23
+ const DEFAULT_HEADERS = {
24
+ 'content-type': 'application/json'
25
+ };
26
+ const DEFAULT_MAX_REDIRECTS = 5;
27
+ const DEFAULT_MAX_RETRIES = 3;
28
+ const DEFAULT_PATH_TEMPLATE_REGEX = /({type})|({id})|({id,\+})|({brief\|standard})/g;
29
+ const OPTIONAL_PATH_TEMPLATE_REGEX = /({\w+\?})/g;
30
+ const DEFAULT_RATE_LIMIT = 50;
31
+ const DEFAULT_REQUEST_RETRY_WAIT = 100;
32
+ const MISSING_BASE_PATH_ERROR = `Getta expected to receive 'basePath' in the constructor options,
33
+ but recevied undefined.`;
34
+ const MAX_REDIRECTS_EXCEEDED_ERROR = 'The request exceeded the maximum number of redirects, which is';
35
+ const MAX_RETRIES_EXCEEDED_ERROR = 'The request exceeded the maximum number of retries, which is';
36
+ const INVALID_FETCH_METHOD_ERROR = "Getta expected to receive 'get', 'post', 'put' or 'delete', but received";
37
+ const RESOURCE_NOT_FOUND_ERROR = 'The requested resource could not been found.';
38
+ const FETCH_TIMEOUT_ERROR = 'The request timed out. Getta did not get a response within';
39
+ const GET_METHOD = 'get';
40
+ const POST_METHOD = 'post';
41
+ const PUT_METHOD = 'put';
42
+ const DELETE_METHOD = 'delete';
43
+ const FETCH_METHODS = [GET_METHOD, POST_METHOD, PUT_METHOD, DELETE_METHOD];
44
+ const INFORMATION_REPSONSE = 'information';
45
+ const SUCCESSFUL_REPSONSE = 'successful';
46
+ const REDIRECTION_REPSONSE = 'redirection';
47
+ const CLIENT_ERROR_REPSONSE = 'clientError';
48
+ const SERVER_ERROR_REPSONSE = 'serverError';
49
+ const NOT_MODIFIED_STATUS_CODE = 304;
50
+ const NOT_FOUND_STATUS_CODE = 404;
51
+ const COOKIE_HEADER = 'Cookie';
52
+ const ETAG_HEADER = 'ETag';
53
+ const LOCATION_HEADER = 'Location';
54
+ const IF_NONE_MATCH_HEADER = 'If-None-Match';
55
+ const CACHE_CONTROL_HEADER = 'Cache-Control';
56
+ const REQUEST_SENT = 'request_sent';
57
+ const RESPONSE_RECEIVED = 'response_received';
58
+
59
+ const defaultPathTemplateCallback = (pathTemplate, data, pathTemplateRegExp) => {
60
+ const dataKeys = Object.keys(data);
61
+ return pathTemplate.replace(pathTemplateRegExp, match => {
62
+ for (const key of dataKeys) {
63
+ if (match.includes(key) && data[key]) {
64
+ return data[key];
65
+ }
66
+ }
67
+ return '';
68
+ });
69
+ };
70
+
71
+ const buildEndpoint = (basePath, path, {
72
+ optionalPathTemplateRegExp,
73
+ pathTemplateCallback,
74
+ pathTemplateData,
75
+ pathTemplateRegExp,
76
+ queryParams
77
+ }) => {
78
+ const pathJoiner = basePath.endsWith('/') || path.startsWith('/') ? '' : '/';
79
+ let endpoint = `${basePath}${pathJoiner}${path}`;
80
+ if (pathTemplateData) {
81
+ endpoint = pathTemplateCallback(endpoint, pathTemplateData, pathTemplateRegExp);
82
+ }
83
+ endpoint = endpoint.replace(optionalPathTemplateRegExp, '');
84
+ if (endpoint.endsWith('/')) {
85
+ endpoint = endpoint.slice(0, Math.max(0, endpoint.length - 1));
86
+ }
87
+ if (queryParams && Object.keys(queryParams).length > 0) {
88
+ const queryJoin = queryString.extract(endpoint) ? '&' : '?';
89
+ endpoint = `${endpoint}${queryJoin}${queryString.stringify(queryParams)}`;
90
+ }
91
+ return endpoint;
92
+ };
93
+
94
+ const delay = ms => {
95
+ return new Promise(resolve => setTimeout(resolve, ms));
96
+ };
97
+
98
+ const getResponseGroup = status => {
99
+ switch (true) {
100
+ case status < 200:
101
+ {
102
+ return INFORMATION_REPSONSE;
103
+ }
104
+ case status < 300:
105
+ {
106
+ return SUCCESSFUL_REPSONSE;
107
+ }
108
+ case status < 400:
109
+ {
110
+ return REDIRECTION_REPSONSE;
111
+ }
112
+ case status < 500:
113
+ {
114
+ return CLIENT_ERROR_REPSONSE;
115
+ }
116
+ default:
117
+ {
118
+ return SERVER_ERROR_REPSONSE;
119
+ }
120
+ }
121
+ };
122
+
123
+ const isCacheabilityValid = cacheability => {
124
+ const noCache = cacheability.metadata.cacheControl.noCache ?? false;
125
+ return !noCache && cacheability.checkTTL();
126
+ };
127
+
128
+ class Getta {
129
+ constructor(options) {
130
+ _defineProperty(this, "_basePath", void 0);
131
+ _defineProperty(this, "_bodyParser", void 0);
132
+ _defineProperty(this, "_cache", void 0);
133
+ _defineProperty(this, "_conditionalRequestsEnabled", void 0);
134
+ _defineProperty(this, "_fetchTimeout", void 0);
135
+ _defineProperty(this, "_headers", void 0);
136
+ _defineProperty(this, "_log", void 0);
137
+ _defineProperty(this, "_maxRedirects", void 0);
138
+ _defineProperty(this, "_maxRetries", void 0);
139
+ _defineProperty(this, "_optionalPathTemplateRegExp", void 0);
140
+ _defineProperty(this, "_pathTemplateCallback", void 0);
141
+ _defineProperty(this, "_pathTemplateRegExp", void 0);
142
+ _defineProperty(this, "_performance", void 0);
143
+ _defineProperty(this, "_queryParams", void 0);
144
+ _defineProperty(this, "_rateLimit", void 0);
145
+ _defineProperty(this, "_rateLimitCount", 0);
146
+ _defineProperty(this, "_rateLimitedRequestQueue", []);
147
+ _defineProperty(this, "_rateLimitPerSecond", void 0);
148
+ _defineProperty(this, "_rateLimitTimer", undefined);
149
+ _defineProperty(this, "_requestRetryWait", void 0);
150
+ _defineProperty(this, "_requestTracker", {
151
+ active: [],
152
+ pending: new Map()
153
+ });
154
+ _defineProperty(this, "_streamReader", void 0);
155
+ const {
156
+ basePath,
157
+ bodyParser = DEFAULT_BODY_PARSER,
158
+ cache,
159
+ enableConditionalRequests = true,
160
+ fetchTimeout = DEFAULT_FETCH_TIMEOUT,
161
+ headers,
162
+ log,
163
+ maxRedirects = DEFAULT_MAX_REDIRECTS,
164
+ maxRetries = DEFAULT_MAX_RETRIES,
165
+ optionalPathTemplateRegExp = OPTIONAL_PATH_TEMPLATE_REGEX,
166
+ pathTemplateCallback = defaultPathTemplateCallback,
167
+ pathTemplateRegExp = DEFAULT_PATH_TEMPLATE_REGEX,
168
+ performance,
169
+ queryParams = {},
170
+ rateLimit = false,
171
+ rateLimitPerSecond = DEFAULT_RATE_LIMIT,
172
+ requestRetryWait = DEFAULT_REQUEST_RETRY_WAIT,
173
+ streamReader = JSON_FORMAT
174
+ } = options;
175
+ if (!basePath) {
176
+ throw new Error(MISSING_BASE_PATH_ERROR);
177
+ }
178
+ this._basePath = basePath;
179
+ this._bodyParser = bodyParser;
180
+ this._cache = cache;
181
+ this._conditionalRequestsEnabled = enableConditionalRequests;
182
+ this._fetchTimeout = fetchTimeout;
183
+ this._headers = {
184
+ ...DEFAULT_HEADERS,
185
+ ...headers
186
+ };
187
+ this._log = log;
188
+ this._maxRedirects = maxRedirects;
189
+ this._maxRetries = maxRetries;
190
+ this._optionalPathTemplateRegExp = optionalPathTemplateRegExp;
191
+ this._pathTemplateCallback = pathTemplateCallback;
192
+ this._pathTemplateRegExp = pathTemplateRegExp;
193
+ this._performance = performance;
194
+ this._queryParams = queryParams;
195
+ this._rateLimit = rateLimit;
196
+ this._rateLimitPerSecond = rateLimitPerSecond;
197
+ this._requestRetryWait = requestRetryWait;
198
+ this._streamReader = streamReader;
199
+ }
200
+ get cache() {
201
+ return this._cache;
202
+ }
203
+ createShortcut(name, path, {
204
+ method,
205
+ ...otherOptions
206
+ }) {
207
+ if (!FETCH_METHODS.includes(method)) {
208
+ throw new Error(`${INVALID_FETCH_METHOD_ERROR} ${method}`);
209
+ }
210
+ this[name] = async ({
211
+ method: requestMethod,
212
+ ...otherOptionOverrides
213
+ } = {}, context) => this[requestMethod ?? method](path, lodashEs.merge({}, otherOptions, otherOptionOverrides), context);
214
+ }
215
+ async delete(path, options = {}, context) {
216
+ return this._delete(path, options, context);
217
+ }
218
+ async get(path, options = {}, context) {
219
+ return this._get(path, options, context);
220
+ }
221
+ async post(path, options, context) {
222
+ return this._request(path, {
223
+ ...options,
224
+ method: POST_METHOD
225
+ }, context);
226
+ }
227
+ async put(path, options, context) {
228
+ return this._request(path, {
229
+ ...options,
230
+ method: PUT_METHOD
231
+ }, context);
232
+ }
233
+ _addRequestToRateLimitedQueue(endpoint, options, context) {
234
+ return new Promise(resolve => {
235
+ this._rateLimitedRequestQueue.push([resolve, endpoint, options, context]);
236
+ });
237
+ }
238
+ async _cacheEntryDelete(requestHash) {
239
+ if (!this._cache) {
240
+ return false;
241
+ }
242
+ return this._cache.delete(requestHash);
243
+ }
244
+ async _cacheEntryGet(requestHash) {
245
+ if (!this._cache) {
246
+ return undefined;
247
+ }
248
+ return this._cache.get(requestHash);
249
+ }
250
+ async _cacheEntryHas(requestHash) {
251
+ if (!this._cache) {
252
+ return false;
253
+ }
254
+ try {
255
+ return await this._cache.has(requestHash);
256
+ } catch {
257
+ return false;
258
+ }
259
+ }
260
+ async _cacheEntrySet(requestHash, data, cacheHeaders) {
261
+ if (!this._cache) {
262
+ return undefined;
263
+ }
264
+ return this._cache.set(requestHash, data, {
265
+ cacheHeaders
266
+ });
267
+ }
268
+ async _delete(path, {
269
+ headers = {},
270
+ pathTemplateData,
271
+ queryParams = {},
272
+ ...rest
273
+ }, context) {
274
+ const endpoint = buildEndpoint(this._basePath, path, {
275
+ optionalPathTemplateRegExp: this._optionalPathTemplateRegExp,
276
+ pathTemplateCallback: this._pathTemplateCallback,
277
+ pathTemplateData,
278
+ pathTemplateRegExp: this._pathTemplateRegExp,
279
+ queryParams: {
280
+ ...this._queryParams,
281
+ ...queryParams
282
+ }
283
+ });
284
+ const requestHash = tsMd5.Md5.hashStr(endpoint);
285
+ const cacheability = await this._cacheEntryHas(requestHash);
286
+ if (cacheability) {
287
+ void this._cacheEntryDelete(requestHash);
288
+ }
289
+ return this._fetch(endpoint, {
290
+ headers: {
291
+ ...this._headers,
292
+ ...headers
293
+ },
294
+ method: DELETE_METHOD,
295
+ ...rest
296
+ }, context);
297
+ }
298
+ async _fetch(endpoint, options, context = {}) {
299
+ context.startTime = this._performance.now();
300
+ try {
301
+ const {
302
+ redirects,
303
+ retries,
304
+ ...rest
305
+ } = options;
306
+ return await new Promise((resolve, reject) => {
307
+ void (async () => {
308
+ const fetchTimer = setTimeout(() => {
309
+ reject(new Error(`${FETCH_TIMEOUT_ERROR} ${this._fetchTimeout}ms.`));
310
+ }, this._fetchTimeout);
311
+ if (this._rateLimit) {
312
+ this._startRateLimit();
313
+ if (!(this._rateLimitCount < this._rateLimitPerSecond)) {
314
+ clearTimeout(fetchTimer);
315
+ resolve(await this._addRequestToRateLimitedQueue(endpoint, options, context));
316
+ return;
317
+ }
318
+ }
319
+ if (!redirects && !retries) {
320
+ this._log?.(REQUEST_SENT, {
321
+ context: {
322
+ redirects,
323
+ retries,
324
+ url: endpoint,
325
+ ...rest,
326
+ ...context
327
+ },
328
+ stats: {
329
+ startTime: context.startTime
330
+ }
331
+ });
332
+ }
333
+ const res = await fetch(endpoint, rest);
334
+ clearTimeout(fetchTimer);
335
+ const {
336
+ body,
337
+ headers,
338
+ status
339
+ } = res;
340
+ const responseGroup = getResponseGroup(status);
341
+ if (responseGroup === REDIRECTION_REPSONSE && headers.has(LOCATION_HEADER)) {
342
+ resolve(await this._fetchRedirectHandler(res, headers.get(LOCATION_HEADER), {
343
+ redirects,
344
+ status,
345
+ ...rest
346
+ }, context));
347
+ return;
348
+ }
349
+ if (responseGroup === SERVER_ERROR_REPSONSE) {
350
+ resolve(await this._fetchRetryHandler(res, endpoint, {
351
+ retries,
352
+ ...rest
353
+ }, context));
354
+ return;
355
+ }
356
+ const fetchRes = res;
357
+ try {
358
+ Object.defineProperty(fetchRes, 'data', {
359
+ enumerable: true,
360
+ value: body ? this._bodyParser(await res[this._streamReader]()) : undefined,
361
+ writable: true
362
+ });
363
+ this._logResponse(fetchRes, endpoint, options, context);
364
+ resolve(fetchRes);
365
+ } catch (error) {
366
+ reject([error, new Error(`Unable to ${rest.method} ${endpoint} due to previous error`)]);
367
+ }
368
+ })();
369
+ });
370
+ } catch (error) {
371
+ const fetchRes = {
372
+ errors: lodashEs.castArray(error)
373
+ };
374
+ this._logResponse(fetchRes, endpoint, options, context);
375
+ return fetchRes;
376
+ }
377
+ }
378
+ async _fetchRedirectHandler(res, endpoint, options, context) {
379
+ const {
380
+ method,
381
+ redirects = 1,
382
+ status,
383
+ ...rest
384
+ } = options;
385
+ if (redirects === this._maxRedirects) {
386
+ const fetchRes = res;
387
+ fetchRes.errors = [new Error(`${MAX_REDIRECTS_EXCEEDED_ERROR} ${this._maxRedirects}.`)];
388
+ this._logResponse(fetchRes, endpoint, options, context);
389
+ return fetchRes;
390
+ }
391
+ const redirectMethod = status === 303 ? GET_METHOD : method;
392
+ return this._fetch(endpoint, {
393
+ method: redirectMethod,
394
+ redirects: redirects + 1,
395
+ ...rest
396
+ });
397
+ }
398
+ async _fetchRetryHandler(res, endpoint, options, context) {
399
+ const {
400
+ retries = 1,
401
+ ...rest
402
+ } = options;
403
+ if (retries === this._maxRetries) {
404
+ const fetchRes = res;
405
+ fetchRes.errors = [new Error(`${MAX_RETRIES_EXCEEDED_ERROR} ${this._maxRetries}.`)];
406
+ this._logResponse(fetchRes, endpoint, options, context);
407
+ return fetchRes;
408
+ }
409
+ await delay(this._requestRetryWait);
410
+ return this._fetch(endpoint, {
411
+ retries: retries + 1,
412
+ ...rest
413
+ });
414
+ }
415
+ async _get(path, {
416
+ headers = {},
417
+ pathTemplateData,
418
+ queryParams = {}
419
+ }, context) {
420
+ const endpoint = buildEndpoint(this._basePath, path, {
421
+ optionalPathTemplateRegExp: this._optionalPathTemplateRegExp,
422
+ pathTemplateCallback: this._pathTemplateCallback,
423
+ pathTemplateData,
424
+ pathTemplateRegExp: this._pathTemplateRegExp,
425
+ queryParams: {
426
+ ...this._queryParams,
427
+ ...queryParams
428
+ }
429
+ });
430
+ const requestHash = tsMd5.Md5.hashStr(endpoint);
431
+ const cacheability = await this._cacheEntryHas(requestHash);
432
+ if (cacheability) {
433
+ if (isCacheabilityValid(cacheability)) {
434
+ return {
435
+ data: await this._cacheEntryGet(requestHash),
436
+ headers: new Headers({
437
+ 'cache-control': cacheability.printCacheControl()
438
+ })
439
+ };
440
+ }
441
+ if (this._conditionalRequestsEnabled && cacheability.metadata.etag) {
442
+ headers[IF_NONE_MATCH_HEADER] = cacheability.metadata.etag;
443
+ }
444
+ }
445
+ const pendingRequest = this._trackRequest(requestHash);
446
+ if (pendingRequest) {
447
+ return pendingRequest;
448
+ }
449
+ return this._getResolve(requestHash, await this._fetch(endpoint, {
450
+ headers: {
451
+ ...this._headers,
452
+ ...headers
453
+ },
454
+ method: GET_METHOD
455
+ }, context));
456
+ }
457
+ async _getResolve(requestHash, res) {
458
+ const {
459
+ data,
460
+ headers,
461
+ status
462
+ } = res;
463
+ if (status === NOT_FOUND_STATUS_CODE) {
464
+ void this._cacheEntryDelete(requestHash);
465
+ let {
466
+ errors
467
+ } = res;
468
+ if (!errors) {
469
+ errors = [];
470
+ }
471
+ errors.push(new Error(RESOURCE_NOT_FOUND_ERROR));
472
+ res.errors = errors;
473
+ } else if (status === NOT_MODIFIED_STATUS_CODE) {
474
+ const cachedData = await this._cacheEntryGet(requestHash);
475
+ if (cachedData) {
476
+ void this._cacheEntrySet(requestHash, cachedData, {
477
+ cacheControl: headers.get(CACHE_CONTROL_HEADER) ?? undefined,
478
+ etag: headers.get(ETAG_HEADER) ?? undefined
479
+ });
480
+ res.data = cachedData;
481
+ }
482
+ } else if (data) {
483
+ void this._cacheEntrySet(requestHash, data, {
484
+ cacheControl: headers.get(CACHE_CONTROL_HEADER) ?? undefined,
485
+ etag: headers.get(ETAG_HEADER) ?? undefined
486
+ });
487
+ }
488
+ this._resolvePendingRequests(requestHash, res);
489
+ this._requestTracker.active = this._requestTracker.active.filter(value => value !== requestHash);
490
+ return res;
491
+ }
492
+ _logResponse(res, endpoint, options, context) {
493
+ const {
494
+ data,
495
+ errors,
496
+ headers,
497
+ status
498
+ } = res;
499
+ const {
500
+ method,
501
+ redirects,
502
+ retries
503
+ } = options;
504
+ const {
505
+ startTime,
506
+ ...otherContext
507
+ } = context;
508
+ const endTime = this._performance.now();
509
+ const duration = startTime ? endTime - startTime : 0;
510
+ this._log?.(RESPONSE_RECEIVED, {
511
+ context: {
512
+ body: data ? {
513
+ data
514
+ } : {
515
+ errors: errors ?? []
516
+ },
517
+ headers,
518
+ method,
519
+ redirects,
520
+ retries,
521
+ status,
522
+ url: endpoint,
523
+ ...otherContext
524
+ },
525
+ stats: {
526
+ duration,
527
+ endTime,
528
+ startTime
529
+ }
530
+ });
531
+ }
532
+ async _releaseRateLimitedRequestQueue() {
533
+ for (const [resolve, endpoint, options, context] of this._rateLimitedRequestQueue) {
534
+ resolve(await this._fetch(endpoint, options, context));
535
+ }
536
+ this._rateLimitedRequestQueue = [];
537
+ }
538
+ async _request(path, {
539
+ body,
540
+ headers,
541
+ method,
542
+ pathTemplateData,
543
+ queryParams,
544
+ ...rest
545
+ }, context) {
546
+ const endpoint = buildEndpoint(this._basePath, path, {
547
+ optionalPathTemplateRegExp: this._optionalPathTemplateRegExp,
548
+ pathTemplateCallback: this._pathTemplateCallback,
549
+ pathTemplateData,
550
+ pathTemplateRegExp: this._pathTemplateRegExp,
551
+ queryParams: {
552
+ ...this._queryParams,
553
+ ...queryParams
554
+ }
555
+ });
556
+ return this._fetch(endpoint, {
557
+ body,
558
+ headers: {
559
+ ...this._headers,
560
+ ...headers
561
+ },
562
+ method,
563
+ ...rest
564
+ }, context);
565
+ }
566
+ _resolvePendingRequests(requestHash, responseData) {
567
+ const pendingRequests = this._requestTracker.pending.get(requestHash);
568
+ if (!pendingRequests) {
569
+ return;
570
+ }
571
+ for (const {
572
+ resolve
573
+ } of pendingRequests) {
574
+ resolve(responseData);
575
+ }
576
+ this._requestTracker.pending.delete(requestHash);
577
+ }
578
+ _setPendingRequest(requestHash, resolver) {
579
+ let pending = this._requestTracker.pending.get(requestHash);
580
+ if (!pending) pending = [];
581
+ pending.push(resolver);
582
+ this._requestTracker.pending.set(requestHash, pending);
583
+ }
584
+ _startRateLimit() {
585
+ if (!this._rateLimitTimer) {
586
+ this._rateLimitTimer = setTimeout(() => {
587
+ this._rateLimitTimer = undefined;
588
+ this._rateLimitCount = 0;
589
+ if (this._rateLimitedRequestQueue.length > 0) {
590
+ void this._releaseRateLimitedRequestQueue();
591
+ }
592
+ }, 1000);
593
+ }
594
+ this._rateLimitCount += 1;
595
+ }
596
+ _trackRequest(requestHash) {
597
+ if (this._requestTracker.active.includes(requestHash)) {
598
+ return new Promise(resolve => {
599
+ this._setPendingRequest(requestHash, {
600
+ resolve
601
+ });
602
+ });
603
+ }
604
+ this._requestTracker.active.push(requestHash);
605
+ return;
606
+ }
607
+ }
608
+ const createRestClient = (options, shortcuts) => {
609
+ const getta = new Getta(options);
610
+ if (!shortcuts) {
611
+ return getta;
612
+ }
613
+ for (const key of Object.keys(shortcuts)) {
614
+ const shortcut = shortcuts[key];
615
+ if (shortcut) {
616
+ getta.createShortcut(key, ...shortcut);
617
+ }
618
+ }
619
+ return getta;
620
+ };
621
+
622
+ exports.ARRAY_BUFFER_FORMAT = ARRAY_BUFFER_FORMAT;
623
+ exports.BLOB_FORMAT = BLOB_FORMAT;
624
+ exports.CACHE_CONTROL_HEADER = CACHE_CONTROL_HEADER;
625
+ exports.CLIENT_ERROR_REPSONSE = CLIENT_ERROR_REPSONSE;
626
+ exports.COOKIE_HEADER = COOKIE_HEADER;
627
+ exports.DEFAULT_BODY_PARSER = DEFAULT_BODY_PARSER;
628
+ exports.DEFAULT_FETCH_TIMEOUT = DEFAULT_FETCH_TIMEOUT;
629
+ exports.DEFAULT_HEADERS = DEFAULT_HEADERS;
630
+ exports.DEFAULT_MAX_REDIRECTS = DEFAULT_MAX_REDIRECTS;
631
+ exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES;
632
+ exports.DEFAULT_PATH_TEMPLATE_REGEX = DEFAULT_PATH_TEMPLATE_REGEX;
633
+ exports.DEFAULT_RATE_LIMIT = DEFAULT_RATE_LIMIT;
634
+ exports.DEFAULT_REQUEST_RETRY_WAIT = DEFAULT_REQUEST_RETRY_WAIT;
635
+ exports.DELETE_METHOD = DELETE_METHOD;
636
+ exports.ETAG_HEADER = ETAG_HEADER;
637
+ exports.FETCH_METHODS = FETCH_METHODS;
638
+ exports.FETCH_TIMEOUT_ERROR = FETCH_TIMEOUT_ERROR;
639
+ exports.FORM_DATA_FORMAT = FORM_DATA_FORMAT;
640
+ exports.GET_METHOD = GET_METHOD;
641
+ exports.Getta = Getta;
642
+ exports.IF_NONE_MATCH_HEADER = IF_NONE_MATCH_HEADER;
643
+ exports.INFORMATION_REPSONSE = INFORMATION_REPSONSE;
644
+ exports.INVALID_FETCH_METHOD_ERROR = INVALID_FETCH_METHOD_ERROR;
645
+ exports.JSON_FORMAT = JSON_FORMAT;
646
+ exports.LOCATION_HEADER = LOCATION_HEADER;
647
+ exports.MAX_REDIRECTS_EXCEEDED_ERROR = MAX_REDIRECTS_EXCEEDED_ERROR;
648
+ exports.MAX_RETRIES_EXCEEDED_ERROR = MAX_RETRIES_EXCEEDED_ERROR;
649
+ exports.MISSING_BASE_PATH_ERROR = MISSING_BASE_PATH_ERROR;
650
+ exports.NOT_FOUND_STATUS_CODE = NOT_FOUND_STATUS_CODE;
651
+ exports.NOT_MODIFIED_STATUS_CODE = NOT_MODIFIED_STATUS_CODE;
652
+ exports.OPTIONAL_PATH_TEMPLATE_REGEX = OPTIONAL_PATH_TEMPLATE_REGEX;
653
+ exports.POST_METHOD = POST_METHOD;
654
+ exports.PUT_METHOD = PUT_METHOD;
655
+ exports.REDIRECTION_REPSONSE = REDIRECTION_REPSONSE;
656
+ exports.REQUEST_SENT = REQUEST_SENT;
657
+ exports.RESOURCE_NOT_FOUND_ERROR = RESOURCE_NOT_FOUND_ERROR;
658
+ exports.RESPONSE_RECEIVED = RESPONSE_RECEIVED;
659
+ exports.SERVER_ERROR_REPSONSE = SERVER_ERROR_REPSONSE;
660
+ exports.STREAM_READERS = STREAM_READERS;
661
+ exports.SUCCESSFUL_REPSONSE = SUCCESSFUL_REPSONSE;
662
+ exports.TEXT_FORMAT = TEXT_FORMAT;
663
+ exports.createRestClient = createRestClient;
664
+ exports.defaultPathTemplateCallback = defaultPathTemplateCallback;
665
+ //# sourceMappingURL=index.cjs.map