getta 1.0.5 → 1.0.6

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,665 +1,2 @@
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;
1
+ "use strict";var e=require("@babel/runtime/helpers/defineProperty");require("core-js/modules/es.array.push.js");var t=require("lodash-es"),r=require("ts-md5"),s=require("query-string");const a="arrayBuffer",i="blob",h="formData",o="json",c="text",n={ARRAY_BUFFER_FORMAT:a,BLOB_FORMAT:i,FORM_DATA_FORMAT:h,JSON_FORMAT:o,TEXT_FORMAT:c},_=e=>e,p=5e3,d={"content-type":"application/json"},u=5,E=3,R=/({type})|({id})|({id,\+})|({brief\|standard})/g,m=/({\w+\?})/g,l=50,T=100,x="Getta expected to receive 'basePath' in the constructor options,\n but recevied undefined.",y="The request exceeded the maximum number of redirects, which is",g="The request exceeded the maximum number of retries, which is",f="Getta expected to receive 'get', 'post', 'put' or 'delete', but received",O="The requested resource could not been found.",P="The request timed out. Getta did not get a response within",q="get",A="post",v="put",D="delete",S=[q,A,v,D],L="information",C="successful",b="redirection",w="clientError",M="serverError",F="ETag",H="Location",k="If-None-Match",I="Cache-Control",N="request_sent",U="response_received",$=(e,t,r)=>{const s=Object.keys(t);return e.replace(r,(e=>{for(const r of s)if(e.includes(r)&&void 0!==t[r])return String(t[r]);return""}))},G=(e,t,{optionalPathTemplateRegExp:r,pathTemplateCallback:a,pathTemplateData:i,pathTemplateRegExp:h,queryParams:o})=>{const c=e.endsWith("/")||t.startsWith("/")?"":"/";let n=`${e}${c}${t}`;if(i&&(n=a(n,i,h)),n=n.replace(r,""),n.endsWith("/")&&(n=n.slice(0,Math.max(0,n.length-1))),o&&Object.keys(o).length>0){n=`${n}${s.extract(n)?"&":"?"}${s.stringify(o)}`}return n};class Q{constructor(t){e(this,"_basePath",void 0),e(this,"_bodyParser",void 0),e(this,"_cache",void 0),e(this,"_conditionalRequestsEnabled",void 0),e(this,"_fetchTimeout",void 0),e(this,"_headers",void 0),e(this,"_log",void 0),e(this,"_maxRedirects",void 0),e(this,"_maxRetries",void 0),e(this,"_optionalPathTemplateRegExp",void 0),e(this,"_pathTemplateCallback",void 0),e(this,"_pathTemplateRegExp",void 0),e(this,"_performance",void 0),e(this,"_queryParams",void 0),e(this,"_rateLimit",void 0),e(this,"_rateLimitCount",0),e(this,"_rateLimitedRequestQueue",[]),e(this,"_rateLimitPerSecond",void 0),e(this,"_rateLimitTimer",void 0),e(this,"_requestRetryWait",void 0),e(this,"_requestTracker",{active:[],pending:new Map}),e(this,"_streamReader",void 0);const{basePath:r,bodyParser:s=_,cache:a,enableConditionalRequests:i=!0,fetchTimeout:h=p,headers:c,log:n,maxRedirects:y=u,maxRetries:g=E,optionalPathTemplateRegExp:f=m,pathTemplateCallback:O=$,pathTemplateRegExp:P=R,performance:q,queryParams:A={},rateLimit:v=!1,rateLimitPerSecond:D=l,requestRetryWait:S=T,streamReader:L=o}=t;if(!r)throw new Error(x);this._basePath=r,this._bodyParser=s,this._cache=a,this._conditionalRequestsEnabled=i,this._fetchTimeout=h,this._headers={...d,...c},this._log=n,this._maxRedirects=y,this._maxRetries=g,this._optionalPathTemplateRegExp=f,this._pathTemplateCallback=O,this._pathTemplateRegExp=P,this._performance=q,this._queryParams=A,this._rateLimit=v,this._rateLimitPerSecond=D,this._requestRetryWait=S,this._streamReader=L}get cache(){return this._cache}createShortcut(e,r,{method:s,...a}){if(!S.includes(s))throw new Error(`${f} ${s}`);this[e]=async({method:e,...i}={},h)=>this[e??s](r,t.merge({},a,i),h)}async delete(e,t={},r){return this._delete(e,t,r)}async get(e,t={},r){return this._get(e,t,r)}async post(e,t,r){return this._request(e,{...t,method:A},r)}async put(e,t,r){return this._request(e,{...t,method:v},r)}_addRequestToRateLimitedQueue(e,t,r){return new Promise((s=>{this._rateLimitedRequestQueue.push([s,e,t,r])}))}async _cacheEntryDelete(e){return!!this._cache&&this._cache.delete(e)}async _cacheEntryGet(e){if(this._cache)return this._cache.get(e)}async _cacheEntryHas(e){if(!this._cache)return!1;try{return await this._cache.has(e)}catch{return!1}}async _cacheEntrySet(e,t,r){if(this._cache)return this._cache.set(e,t,{cacheHeaders:r})}async _delete(e,{headers:t={},pathTemplateData:s,queryParams:a={},...i},h){const o=G(this._basePath,e,{optionalPathTemplateRegExp:this._optionalPathTemplateRegExp,pathTemplateCallback:this._pathTemplateCallback,pathTemplateData:s,pathTemplateRegExp:this._pathTemplateRegExp,queryParams:{...this._queryParams,...a}}),c=r.Md5.hashStr(o);return await this._cacheEntryHas(c)&&this._cacheEntryDelete(c),this._fetch(o,{headers:{...this._headers,...t},method:D,...i},h)}async _fetch(e,r,s={}){s.startTime=this._performance.now();try{const{redirects:t,retries:a,...i}=r;return await new Promise(((h,o)=>{(async()=>{const c=setTimeout((()=>{o(new Error(`${P} ${this._fetchTimeout}ms.`))}),this._fetchTimeout);if(this._rateLimit&&(this._startRateLimit(),!(this._rateLimitCount<this._rateLimitPerSecond)))return clearTimeout(c),void h(await this._addRequestToRateLimitedQueue(e,r,s));t||a||this._log?.(N,{context:{redirects:t,retries:a,url:e,...i,...s},stats:{startTime:s.startTime}});const n=await fetch(e,i);clearTimeout(c);const{body:_,headers:p,status:d}=n,u=(e=>{switch(!0){case e<200:return L;case e<300:return C;case e<400:return b;case e<500:return w;default:return M}})(d);if(u===b&&p.has(H))return void h(await this._fetchRedirectHandler(n,p.get(H),{redirects:t,status:d,...i},s));if(u===M)return void h(await this._fetchRetryHandler(n,e,{retries:a,...i},s));const E=n;try{Object.defineProperty(E,"data",{enumerable:!0,value:_?this._bodyParser(await n[this._streamReader]()):void 0,writable:!0}),this._logResponse(E,e,r,s),h(E)}catch(t){o([t,new Error(`Unable to ${i.method} ${e} due to previous error`)])}})()}))}catch(a){const i={errors:t.castArray(a)};return this._logResponse(i,e,r,s),i}}async _fetchRedirectHandler(e,t,r,s){const{method:a,redirects:i=1,status:h,...o}=r;if(i===this._maxRedirects){const a=e;return a.errors=[new Error(`${y} ${this._maxRedirects}.`)],this._logResponse(a,t,r,s),a}const c=303===h?q:a;return this._fetch(t,{method:c,redirects:i+1,...o})}async _fetchRetryHandler(e,t,r,s){const{retries:a=1,...i}=r;if(a===this._maxRetries){const a=e;return a.errors=[new Error(`${g} ${this._maxRetries}.`)],this._logResponse(a,t,r,s),a}var h;return await(h=this._requestRetryWait,new Promise((e=>setTimeout(e,h)))),this._fetch(t,{retries:a+1,...i})}async _get(e,{headers:t={},pathTemplateData:s,queryParams:a={}},i){const h=G(this._basePath,e,{optionalPathTemplateRegExp:this._optionalPathTemplateRegExp,pathTemplateCallback:this._pathTemplateCallback,pathTemplateData:s,pathTemplateRegExp:this._pathTemplateRegExp,queryParams:{...this._queryParams,...a}}),o=r.Md5.hashStr(h),c=await this._cacheEntryHas(o);if(c){if((e=>!e.metadata.cacheControl.noCache&&e.checkTTL())(c))return{data:await this._cacheEntryGet(o),headers:new Headers({"cache-control":c.printCacheControl()})};this._conditionalRequestsEnabled&&c.metadata.etag&&(t[k]=c.metadata.etag)}const n=this._trackRequest(o);return n||this._getResolve(o,await this._fetch(h,{headers:{...this._headers,...t},method:q},i))}async _getResolve(e,t){const{data:r,headers:s,status:a}=t;if(404===a){this._cacheEntryDelete(e);let{errors:r}=t;r||(r=[]),r.push(new Error(O)),t.errors=r}else if(304===a){const r=await this._cacheEntryGet(e);r&&(this._cacheEntrySet(e,r,{cacheControl:s.get(I)??void 0,etag:s.get(F)??void 0}),t.data=r)}else r&&this._cacheEntrySet(e,r,{cacheControl:s.get(I)??void 0,etag:s.get(F)??void 0});return this._resolvePendingRequests(e,t),this._requestTracker.active=this._requestTracker.active.filter((t=>t!==e)),t}_logResponse(e,t,r,s){const{data:a,errors:i,headers:h,status:o}=e,{method:c,redirects:n,retries:_}=r,{startTime:p,...d}=s,u=this._performance.now(),E=p?u-p:0;this._log?.(U,{context:{body:a?{data:a}:{errors:i??[]},headers:h,method:c,redirects:n,retries:_,status:o,url:t,...d},stats:{duration:E,endTime:u,startTime:p}})}async _releaseRateLimitedRequestQueue(){for(const[e,t,r,s]of this._rateLimitedRequestQueue)e(await this._fetch(t,r,s));this._rateLimitedRequestQueue=[]}async _request(e,{body:t,headers:r,method:s,pathTemplateData:a,queryParams:i,...h},o){const c=G(this._basePath,e,{optionalPathTemplateRegExp:this._optionalPathTemplateRegExp,pathTemplateCallback:this._pathTemplateCallback,pathTemplateData:a,pathTemplateRegExp:this._pathTemplateRegExp,queryParams:{...this._queryParams,...i}});return this._fetch(c,{body:t,headers:{...this._headers,...r},method:s,...h},o)}_resolvePendingRequests(e,t){const r=this._requestTracker.pending.get(e);if(r){for(const{resolve:e}of r)e(t);this._requestTracker.pending.delete(e)}}_setPendingRequest(e,t){let r=this._requestTracker.pending.get(e);r||(r=[]),r.push(t),this._requestTracker.pending.set(e,r)}_startRateLimit(){this._rateLimitTimer||(this._rateLimitTimer=setTimeout((()=>{this._rateLimitTimer=void 0,this._rateLimitCount=0,this._rateLimitedRequestQueue.length>0&&this._releaseRateLimitedRequestQueue()}),1e3)),this._rateLimitCount+=1}_trackRequest(e){if(this._requestTracker.active.includes(e))return new Promise((t=>{this._setPendingRequest(e,{resolve:t})}));this._requestTracker.active.push(e)}}exports.ARRAY_BUFFER_FORMAT=a,exports.BLOB_FORMAT=i,exports.CACHE_CONTROL_HEADER=I,exports.CLIENT_ERROR_REPSONSE=w,exports.COOKIE_HEADER="Cookie",exports.DEFAULT_BODY_PARSER=_,exports.DEFAULT_FETCH_TIMEOUT=p,exports.DEFAULT_HEADERS=d,exports.DEFAULT_MAX_REDIRECTS=u,exports.DEFAULT_MAX_RETRIES=E,exports.DEFAULT_PATH_TEMPLATE_REGEX=R,exports.DEFAULT_RATE_LIMIT=l,exports.DEFAULT_REQUEST_RETRY_WAIT=T,exports.DELETE_METHOD=D,exports.ETAG_HEADER=F,exports.FETCH_METHODS=S,exports.FETCH_TIMEOUT_ERROR=P,exports.FORM_DATA_FORMAT=h,exports.GET_METHOD=q,exports.Getta=Q,exports.IF_NONE_MATCH_HEADER=k,exports.INFORMATION_REPSONSE=L,exports.INVALID_FETCH_METHOD_ERROR=f,exports.JSON_FORMAT=o,exports.LOCATION_HEADER=H,exports.MAX_REDIRECTS_EXCEEDED_ERROR=y,exports.MAX_RETRIES_EXCEEDED_ERROR=g,exports.MISSING_BASE_PATH_ERROR=x,exports.NOT_FOUND_STATUS_CODE=404,exports.NOT_MODIFIED_STATUS_CODE=304,exports.OPTIONAL_PATH_TEMPLATE_REGEX=m,exports.POST_METHOD=A,exports.PUT_METHOD=v,exports.REDIRECTION_REPSONSE=b,exports.REQUEST_SENT=N,exports.RESOURCE_NOT_FOUND_ERROR=O,exports.RESPONSE_RECEIVED=U,exports.SERVER_ERROR_REPSONSE=M,exports.STREAM_READERS=n,exports.SUCCESSFUL_REPSONSE=C,exports.TEXT_FORMAT=c,exports.createRestClient=(e,t)=>{const r=new Q(e);if(!t)return r;for(const e of Object.keys(t)){const s=t[e];s&&r.createShortcut(e,...s)}return r},exports.defaultPathTemplateCallback=$;
665
2
  //# sourceMappingURL=index.cjs.map