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