@algolia/client-common 5.0.0-alpha.1 → 5.0.0-alpha.100

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 (84) hide show
  1. package/dist/{client-common.cjs.js → client-common.cjs} +189 -226
  2. package/dist/client-common.esm.node.js +188 -222
  3. package/dist/index.d.ts +9 -9
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/src/cache/createBrowserLocalStorageCache.d.ts +2 -2
  6. package/dist/src/cache/createBrowserLocalStorageCache.d.ts.map +1 -1
  7. package/dist/src/cache/createFallbackableCache.d.ts +2 -2
  8. package/dist/src/cache/createFallbackableCache.d.ts.map +1 -1
  9. package/dist/src/cache/createMemoryCache.d.ts +2 -2
  10. package/dist/src/cache/createMemoryCache.d.ts.map +1 -1
  11. package/dist/src/cache/createNullCache.d.ts +2 -2
  12. package/dist/src/cache/createNullCache.d.ts.map +1 -1
  13. package/dist/src/cache/index.d.ts +4 -4
  14. package/dist/src/cache/index.d.ts.map +1 -1
  15. package/dist/src/constants.d.ts +6 -6
  16. package/dist/src/constants.d.ts.map +1 -1
  17. package/dist/src/createAlgoliaAgent.d.ts +2 -2
  18. package/dist/src/createAlgoliaAgent.d.ts.map +1 -1
  19. package/dist/src/createAuth.d.ts +5 -5
  20. package/dist/src/createAuth.d.ts.map +1 -1
  21. package/dist/src/createEchoRequester.d.ts +6 -6
  22. package/dist/src/createEchoRequester.d.ts.map +1 -1
  23. package/dist/src/createIterablePromise.d.ts +13 -0
  24. package/dist/src/createIterablePromise.d.ts.map +1 -0
  25. package/dist/src/getAlgoliaAgent.d.ts +7 -7
  26. package/dist/src/getAlgoliaAgent.d.ts.map +1 -1
  27. package/dist/src/transporter/createStatefulHost.d.ts +2 -2
  28. package/dist/src/transporter/createStatefulHost.d.ts.map +1 -1
  29. package/dist/src/transporter/createTransporter.d.ts +2 -2
  30. package/dist/src/transporter/createTransporter.d.ts.map +1 -1
  31. package/dist/src/transporter/errors.d.ts +37 -20
  32. package/dist/src/transporter/errors.d.ts.map +1 -1
  33. package/dist/src/transporter/helpers.d.ts +8 -8
  34. package/dist/src/transporter/helpers.d.ts.map +1 -1
  35. package/dist/src/transporter/index.d.ts +6 -6
  36. package/dist/src/transporter/index.d.ts.map +1 -1
  37. package/dist/src/transporter/responses.d.ts +4 -4
  38. package/dist/src/transporter/responses.d.ts.map +1 -1
  39. package/dist/src/transporter/stackTrace.d.ts +3 -3
  40. package/dist/src/transporter/stackTrace.d.ts.map +1 -1
  41. package/dist/src/types/{Cache.d.ts → cache.d.ts} +61 -47
  42. package/dist/src/types/cache.d.ts.map +1 -0
  43. package/dist/src/types/createClient.d.ts +12 -0
  44. package/dist/src/types/createClient.d.ts.map +1 -0
  45. package/dist/src/types/createIterablePromise.d.ts +36 -0
  46. package/dist/src/types/createIterablePromise.d.ts.map +1 -0
  47. package/dist/src/types/{Host.d.ts → host.d.ts} +33 -33
  48. package/dist/src/types/host.d.ts.map +1 -0
  49. package/dist/src/types/index.d.ts +6 -6
  50. package/dist/src/types/index.d.ts.map +1 -1
  51. package/dist/src/types/{Requester.d.ts → requester.d.ts} +66 -66
  52. package/dist/src/types/requester.d.ts.map +1 -0
  53. package/dist/src/types/{Transporter.d.ts → transporter.d.ts} +128 -128
  54. package/dist/src/types/transporter.d.ts.map +1 -0
  55. package/index.ts +1 -1
  56. package/package.json +13 -9
  57. package/src/__tests__/cache/browser-local-storage-cache.test.ts +61 -9
  58. package/src/__tests__/create-iterable-promise.test.ts +238 -0
  59. package/src/cache/createBrowserLocalStorageCache.ts +55 -6
  60. package/src/createEchoRequester.ts +2 -2
  61. package/src/createIterablePromise.ts +47 -0
  62. package/src/transporter/createTransporter.ts +4 -1
  63. package/src/transporter/errors.ts +39 -3
  64. package/src/transporter/helpers.ts +14 -6
  65. package/src/types/{Cache.ts → cache.ts} +17 -0
  66. package/src/types/{CreateClient.ts → createClient.ts} +2 -2
  67. package/src/types/createIterablePromise.ts +40 -0
  68. package/src/types/index.ts +6 -6
  69. package/src/types/{Requester.ts → requester.ts} +1 -1
  70. package/src/types/{Transporter.ts → transporter.ts} +3 -3
  71. package/dist/src/createRetryablePromise.d.ts +0 -14
  72. package/dist/src/createRetryablePromise.d.ts.map +0 -1
  73. package/dist/src/types/Cache.d.ts.map +0 -1
  74. package/dist/src/types/CreateClient.d.ts +0 -12
  75. package/dist/src/types/CreateClient.d.ts.map +0 -1
  76. package/dist/src/types/CreateRetryablePromise.d.ts +0 -19
  77. package/dist/src/types/CreateRetryablePromise.d.ts.map +0 -1
  78. package/dist/src/types/Host.d.ts.map +0 -1
  79. package/dist/src/types/Requester.d.ts.map +0 -1
  80. package/dist/src/types/Transporter.d.ts.map +0 -1
  81. package/src/__tests__/create-retryable-promise.test.ts +0 -86
  82. package/src/createRetryablePromise.ts +0 -52
  83. package/src/types/CreateRetryablePromise.ts +0 -21
  84. /package/src/types/{Host.ts → host.ts} +0 -0
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  function createAuth(appId, apiKey, authMode = 'WithinHeaders') {
6
4
  const credentials = {
7
5
  'x-algolia-api-key': apiKey,
@@ -11,11 +9,9 @@ function createAuth(appId, apiKey, authMode = 'WithinHeaders') {
11
9
  headers() {
12
10
  return authMode === 'WithinHeaders' ? credentials : {};
13
11
  },
14
-
15
12
  queryParameters() {
16
13
  return authMode === 'WithinQueryParameters' ? credentials : {};
17
14
  }
18
-
19
15
  };
20
16
  }
21
17
 
@@ -26,15 +22,12 @@ function getUrlParams({
26
22
  }) {
27
23
  const algoliaAgent = urlSearchParams.get('x-algolia-agent') || '';
28
24
  const searchParams = {};
29
-
30
25
  for (const [k, v] of urlSearchParams) {
31
26
  if (k === 'x-algolia-agent') {
32
27
  continue;
33
28
  }
34
-
35
29
  searchParams[k] = v;
36
30
  }
37
-
38
31
  return {
39
32
  host,
40
33
  algoliaAgent,
@@ -42,7 +35,6 @@ function getUrlParams({
42
35
  path: pathname
43
36
  };
44
37
  }
45
-
46
38
  function createEchoRequester({
47
39
  getURL,
48
40
  status = 200
@@ -54,11 +46,12 @@ function createEchoRequester({
54
46
  algoliaAgent,
55
47
  path
56
48
  } = getUrlParams(getURL(request.url));
57
- const content = { ...request,
49
+ const content = {
50
+ ...request,
58
51
  data: request.data ? JSON.parse(request.data) : undefined,
59
52
  path,
60
53
  host,
61
- algoliaAgent: encodeURI(algoliaAgent),
54
+ algoliaAgent: encodeURIComponent(algoliaAgent),
62
55
  searchParams
63
56
  };
64
57
  return Promise.resolve({
@@ -67,95 +60,108 @@ function createEchoRequester({
67
60
  status
68
61
  });
69
62
  }
70
-
71
63
  return {
72
64
  send
73
65
  };
74
66
  }
75
67
 
76
- const DEFAULT_MAX_RETRIES = 50;
77
- const DEFAULT_TIMEOUT = retryCount => Math.min(retryCount * 200, 5000);
78
- /**
79
- * Return a promise that retry a task until it meets the condition.
80
- *
81
- * @param createRetryablePromiseOptions - The createRetryablePromise options.
82
- * @param createRetryablePromiseOptions.func - The function to run, which returns a promise.
83
- * @param createRetryablePromiseOptions.validate - The validator function. It receives the resolved return of `func`.
84
- * @param createRetryablePromiseOptions.maxRetries - The maximum number of retries. 50 by default.
85
- * @param createRetryablePromiseOptions.timeout - The function to decide how long to wait between retries.
68
+ /**
69
+ * Helper: Returns the promise of a given `func` to iterate on, based on a given `validate` condition.
70
+ *
71
+ * @param createIterator - The createIterator options.
72
+ * @param createIterator.func - The function to run, which returns a promise.
73
+ * @param createIterator.validate - The validator function. It receives the resolved return of `func`.
74
+ * @param createIterator.aggregator - The function that runs right after the `func` method has been executed, allows you to do anything with the response before `validate`.
75
+ * @param createIterator.error - The `validate` condition to throw an error, and its message.
76
+ * @param createIterator.timeout - The function to decide how long to wait between iterations.
86
77
  */
87
-
88
- function createRetryablePromise({
78
+ function createIterablePromise({
89
79
  func,
90
80
  validate,
91
- maxRetries = DEFAULT_MAX_RETRIES,
92
- timeout = DEFAULT_TIMEOUT
81
+ aggregator,
82
+ error,
83
+ timeout = () => 0
93
84
  }) {
94
- let retryCount = 0;
95
-
96
- const retry = () => {
85
+ const retry = previousResponse => {
97
86
  return new Promise((resolve, reject) => {
98
- func().then(response => {
99
- const isValid = validate(response);
100
-
101
- if (isValid) {
102
- resolve(response);
103
- } else if (retryCount + 1 >= maxRetries) {
104
- reject(new Error(`The maximum number of retries exceeded. (${retryCount + 1}/${maxRetries})`));
105
- } else {
106
- retryCount += 1;
107
- setTimeout(() => {
108
- retry().then(resolve).catch(reject);
109
- }, timeout(retryCount));
87
+ func(previousResponse).then(response => {
88
+ if (aggregator) {
89
+ aggregator(response);
110
90
  }
111
- }).catch(error => {
112
- reject(error);
91
+ if (validate(response)) {
92
+ return resolve(response);
93
+ }
94
+ if (error && error.validate(response)) {
95
+ return reject(new Error(error.message(response)));
96
+ }
97
+ return setTimeout(() => {
98
+ retry(response).then(resolve).catch(reject);
99
+ }, timeout());
100
+ }).catch(err => {
101
+ reject(err);
113
102
  });
114
103
  });
115
104
  };
116
-
117
105
  return retry();
118
106
  }
119
107
 
120
108
  function createBrowserLocalStorageCache(options) {
121
- let storage; // We've changed the namespace to avoid conflicts with v4, as this version is a huge breaking change
122
-
109
+ let storage;
110
+ // We've changed the namespace to avoid conflicts with v4, as this version is a huge breaking change
123
111
  const namespaceKey = `algolia-client-js-${options.key}`;
124
-
125
112
  function getStorage() {
126
113
  if (storage === undefined) {
127
114
  storage = options.localStorage || window.localStorage;
128
115
  }
129
-
130
116
  return storage;
131
117
  }
132
-
133
118
  function getNamespace() {
134
119
  return JSON.parse(getStorage().getItem(namespaceKey) || '{}');
135
120
  }
136
-
121
+ function setNamespace(namespace) {
122
+ getStorage().setItem(namespaceKey, JSON.stringify(namespace));
123
+ }
124
+ function removeOutdatedCacheItems() {
125
+ const timeToLive = options.timeToLive ? options.timeToLive * 1000 : null;
126
+ const namespace = getNamespace();
127
+ const filteredNamespaceWithoutOldFormattedCacheItems = Object.fromEntries(Object.entries(namespace).filter(([, cacheItem]) => {
128
+ return cacheItem.timestamp !== undefined;
129
+ }));
130
+ setNamespace(filteredNamespaceWithoutOldFormattedCacheItems);
131
+ if (!timeToLive) {
132
+ return;
133
+ }
134
+ const filteredNamespaceWithoutExpiredItems = Object.fromEntries(Object.entries(filteredNamespaceWithoutOldFormattedCacheItems).filter(([, cacheItem]) => {
135
+ const currentTimestamp = new Date().getTime();
136
+ const isExpired = cacheItem.timestamp + timeToLive < currentTimestamp;
137
+ return !isExpired;
138
+ }));
139
+ setNamespace(filteredNamespaceWithoutExpiredItems);
140
+ }
137
141
  return {
138
142
  get(key, defaultValue, events = {
139
143
  miss: () => Promise.resolve()
140
144
  }) {
141
145
  return Promise.resolve().then(() => {
142
- const keyAsString = JSON.stringify(key);
143
- const value = getNamespace()[keyAsString];
144
- return Promise.all([value || defaultValue(), value !== undefined]);
146
+ removeOutdatedCacheItems();
147
+ return getNamespace()[JSON.stringify(key)];
148
+ }).then(value => {
149
+ return Promise.all([value ? value.value : defaultValue(), value !== undefined]);
145
150
  }).then(([value, exists]) => {
146
151
  return Promise.all([value, exists || events.miss(value)]);
147
152
  }).then(([value]) => value);
148
153
  },
149
-
150
154
  set(key, value) {
151
155
  return Promise.resolve().then(() => {
152
156
  const namespace = getNamespace();
153
- namespace[JSON.stringify(key)] = value;
157
+ namespace[JSON.stringify(key)] = {
158
+ timestamp: new Date().getTime(),
159
+ value
160
+ };
154
161
  getStorage().setItem(namespaceKey, JSON.stringify(namespace));
155
162
  return value;
156
163
  });
157
164
  },
158
-
159
165
  delete(key) {
160
166
  return Promise.resolve().then(() => {
161
167
  const namespace = getNamespace();
@@ -163,13 +169,11 @@ function createBrowserLocalStorageCache(options) {
163
169
  getStorage().setItem(namespaceKey, JSON.stringify(namespace));
164
170
  });
165
171
  },
166
-
167
172
  clear() {
168
173
  return Promise.resolve().then(() => {
169
174
  getStorage().removeItem(namespaceKey);
170
175
  });
171
176
  }
172
-
173
177
  };
174
178
  }
175
179
 
@@ -181,30 +185,24 @@ function createNullCache() {
181
185
  const value = defaultValue();
182
186
  return value.then(result => Promise.all([result, events.miss(result)])).then(([result]) => result);
183
187
  },
184
-
185
188
  set(_key, value) {
186
189
  return Promise.resolve(value);
187
190
  },
188
-
189
191
  delete(_key) {
190
192
  return Promise.resolve();
191
193
  },
192
-
193
194
  clear() {
194
195
  return Promise.resolve();
195
196
  }
196
-
197
197
  };
198
198
  }
199
199
 
200
200
  function createFallbackableCache(options) {
201
201
  const caches = [...options.caches];
202
202
  const current = caches.shift();
203
-
204
203
  if (current === undefined) {
205
204
  return createNullCache();
206
205
  }
207
-
208
206
  return {
209
207
  get(key, defaultValue, events = {
210
208
  miss: () => Promise.resolve()
@@ -215,7 +213,6 @@ function createFallbackableCache(options) {
215
213
  }).get(key, defaultValue, events);
216
214
  });
217
215
  },
218
-
219
216
  set(key, value) {
220
217
  return current.set(key, value).catch(() => {
221
218
  return createFallbackableCache({
@@ -223,7 +220,6 @@ function createFallbackableCache(options) {
223
220
  }).set(key, value);
224
221
  });
225
222
  },
226
-
227
223
  delete(key) {
228
224
  return current.delete(key).catch(() => {
229
225
  return createFallbackableCache({
@@ -231,7 +227,6 @@ function createFallbackableCache(options) {
231
227
  }).delete(key);
232
228
  });
233
229
  },
234
-
235
230
  clear() {
236
231
  return current.clear().catch(() => {
237
232
  return createFallbackableCache({
@@ -239,7 +234,6 @@ function createFallbackableCache(options) {
239
234
  }).clear();
240
235
  });
241
236
  }
242
-
243
237
  };
244
238
  }
245
239
 
@@ -252,30 +246,24 @@ function createMemoryCache(options = {
252
246
  miss: () => Promise.resolve()
253
247
  }) {
254
248
  const keyAsString = JSON.stringify(key);
255
-
256
249
  if (keyAsString in cache) {
257
250
  return Promise.resolve(options.serializable ? JSON.parse(cache[keyAsString]) : cache[keyAsString]);
258
251
  }
259
-
260
252
  const promise = defaultValue();
261
253
  return promise.then(value => events.miss(value)).then(() => promise);
262
254
  },
263
-
264
255
  set(key, value) {
265
256
  cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
266
257
  return Promise.resolve(value);
267
258
  },
268
-
269
259
  delete(key) {
270
260
  delete cache[JSON.stringify(key)];
271
261
  return Promise.resolve();
272
262
  },
273
-
274
263
  clear() {
275
264
  cache = {};
276
265
  return Promise.resolve();
277
266
  }
278
-
279
267
  };
280
268
  }
281
269
 
@@ -284,16 +272,14 @@ function createMemoryCache(options = {
284
272
  const EXPIRATION_DELAY = 2 * 60 * 1000;
285
273
  function createStatefulHost(host, status = 'up') {
286
274
  const lastUpdate = Date.now();
287
-
288
275
  function isUp() {
289
276
  return status === 'up' || Date.now() - lastUpdate > EXPIRATION_DELAY;
290
277
  }
291
-
292
278
  function isTimedOut() {
293
279
  return status === 'timed out' && Date.now() - lastUpdate <= EXPIRATION_DELAY;
294
280
  }
295
-
296
- return { ...host,
281
+ return {
282
+ ...host,
297
283
  status,
298
284
  lastUpdate,
299
285
  isUp,
@@ -301,7 +287,22 @@ function createStatefulHost(host, status = 'up') {
301
287
  };
302
288
  }
303
289
 
290
+ function _toPrimitive(t, r) {
291
+ if ("object" != typeof t || !t) return t;
292
+ var e = t[Symbol.toPrimitive];
293
+ if (void 0 !== e) {
294
+ var i = e.call(t, r || "default");
295
+ if ("object" != typeof i) return i;
296
+ throw new TypeError("@@toPrimitive must return a primitive value.");
297
+ }
298
+ return ("string" === r ? String : Number)(t);
299
+ }
300
+ function _toPropertyKey(t) {
301
+ var i = _toPrimitive(t, "string");
302
+ return "symbol" == typeof i ? i : String(i);
303
+ }
304
304
  function _defineProperty(obj, key, value) {
305
+ key = _toPropertyKey(key);
305
306
  if (key in obj) {
306
307
  Object.defineProperty(obj, key, {
307
308
  value: value,
@@ -312,92 +313,82 @@ function _defineProperty(obj, key, value) {
312
313
  } else {
313
314
  obj[key] = value;
314
315
  }
315
-
316
316
  return obj;
317
317
  }
318
318
 
319
319
  class AlgoliaError extends Error {
320
320
  constructor(message, name) {
321
321
  super(message);
322
-
323
322
  _defineProperty(this, "name", 'AlgoliaError');
324
-
325
323
  if (name) {
326
324
  this.name = name;
327
325
  }
328
326
  }
329
-
330
327
  }
331
328
  class ErrorWithStackTrace extends AlgoliaError {
332
329
  constructor(message, stackTrace, name) {
333
- super(message, name); // the array and object should be frozen to reflect the stackTrace at the time of the error
334
-
330
+ super(message, name);
331
+ // the array and object should be frozen to reflect the stackTrace at the time of the error
335
332
  _defineProperty(this, "stackTrace", void 0);
336
-
337
333
  this.stackTrace = stackTrace;
338
334
  }
339
-
340
335
  }
341
336
  class RetryError extends ErrorWithStackTrace {
342
337
  constructor(stackTrace) {
343
- super('Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.', stackTrace, 'RetryError');
338
+ super('Unreachable hosts - your application id may be incorrect. If the error persists, please create a ticket at https://support.algolia.com/ sharing steps we can use to reproduce the issue.', stackTrace, 'RetryError');
344
339
  }
345
-
346
340
  }
347
341
  class ApiError extends ErrorWithStackTrace {
348
- constructor(message, status, stackTrace) {
349
- super(message, stackTrace, 'ApiError');
350
-
342
+ constructor(message, status, stackTrace, name = 'ApiError') {
343
+ super(message, stackTrace, name);
351
344
  _defineProperty(this, "status", void 0);
352
-
353
345
  this.status = status;
354
346
  }
355
-
356
347
  }
357
348
  class DeserializationError extends AlgoliaError {
358
349
  constructor(message, response) {
359
350
  super(message, 'DeserializationError');
360
-
361
351
  _defineProperty(this, "response", void 0);
362
-
363
352
  this.response = response;
364
353
  }
365
-
354
+ }
355
+ // DetailedApiError is only used by the ingestion client to return more informative error, other clients will use ApiClient.
356
+ class DetailedApiError extends ApiError {
357
+ constructor(message, status, error, stackTrace) {
358
+ super(message, status, stackTrace, 'DetailedApiError');
359
+ _defineProperty(this, "error", void 0);
360
+ this.error = error;
361
+ }
366
362
  }
367
363
 
368
364
  function shuffle(array) {
369
365
  const shuffledArray = array;
370
-
371
366
  for (let c = array.length - 1; c > 0; c--) {
372
367
  const b = Math.floor(Math.random() * (c + 1));
373
368
  const a = array[c];
374
369
  shuffledArray[c] = array[b];
375
370
  shuffledArray[b] = a;
376
371
  }
377
-
378
372
  return shuffledArray;
379
373
  }
380
374
  function serializeUrl(host, path, queryParameters) {
381
375
  const queryParametersAsString = serializeQueryParameters(queryParameters);
382
376
  let url = `${host.protocol}://${host.url}/${path.charAt(0) === '/' ? path.substr(1) : path}`;
383
-
384
377
  if (queryParametersAsString.length) {
385
378
  url += `?${queryParametersAsString}`;
386
379
  }
387
-
388
380
  return url;
389
381
  }
390
382
  function serializeQueryParameters(parameters) {
391
383
  const isObjectOrArray = value => Object.prototype.toString.call(value) === '[object Object]' || Object.prototype.toString.call(value) === '[object Array]';
392
-
393
- return Object.keys(parameters).map(key => `${key}=${isObjectOrArray(parameters[key]) ? JSON.stringify(parameters[key]) : parameters[key]}`).join('&');
384
+ return Object.keys(parameters).map(key => `${key}=${encodeURIComponent(isObjectOrArray(parameters[key]) ? JSON.stringify(parameters[key]) : parameters[key])}`).join('&');
394
385
  }
395
386
  function serializeData(request, requestOptions) {
396
387
  if (request.method === 'GET' || request.data === undefined && requestOptions.data === undefined) {
397
388
  return undefined;
398
389
  }
399
-
400
- const data = Array.isArray(request.data) ? request.data : { ...request.data,
390
+ const data = Array.isArray(request.data) ? request.data : {
391
+ ...request.data,
401
392
  ...requestOptions.data
402
393
  };
403
394
  return JSON.stringify(data);
@@ -427,14 +418,16 @@ function deserializeFailure({
427
418
  content,
428
419
  status
429
420
  }, stackFrame) {
430
- let message = content;
431
-
432
421
  try {
433
- message = JSON.parse(content).message;
434
- } catch (e) {// ..
422
+ const parsed = JSON.parse(content);
423
+ if ('error' in parsed) {
424
+ return new DetailedApiError(parsed.message, status, parsed.error, stackFrame);
425
+ }
426
+ return new ApiError(parsed.message, status, stackFrame);
427
+ } catch (e) {
428
+ // ..
435
429
  }
436
-
437
- return new ApiError(message, status, stackFrame);
430
+ return new ApiError(content, status, stackFrame);
438
431
  }
439
432
 
440
433
  function isNetworkError({
@@ -465,9 +458,12 @@ function stackFrameWithoutCredentials(stackFrame) {
465
458
  const modifiedHeaders = stackFrame.request.headers['x-algolia-api-key'] ? {
466
459
  'x-algolia-api-key': '*****'
467
460
  } : {};
468
- return { ...stackFrame,
469
- request: { ...stackFrame.request,
470
- headers: { ...stackFrame.request.headers,
461
+ return {
462
+ ...stackFrame,
463
+ request: {
464
+ ...stackFrame.request,
465
+ headers: {
466
+ ...stackFrame.request.headers,
471
467
  ...modifiedHeaders
472
468
  }
473
469
  }
@@ -492,51 +488,49 @@ function createTransporter({
492
488
  });
493
489
  }));
494
490
  const hostsUp = statefulHosts.filter(host => host.isUp());
495
- const hostsTimedOut = statefulHosts.filter(host => host.isTimedOut()); // Note, we put the hosts that previously timed out on the end of the list.
496
-
491
+ const hostsTimedOut = statefulHosts.filter(host => host.isTimedOut());
492
+ // Note, we put the hosts that previously timed out on the end of the list.
497
493
  const hostsAvailable = [...hostsUp, ...hostsTimedOut];
498
494
  const compatibleHostsAvailable = hostsAvailable.length > 0 ? hostsAvailable : compatibleHosts;
499
495
  return {
500
496
  hosts: compatibleHostsAvailable,
501
-
502
497
  getTimeout(timeoutsCount, baseTimeout) {
503
- /**
504
- * Imagine that you have 4 hosts, if timeouts will increase
505
- * on the following way: 1 (timed out) > 4 (timed out) > 5 (200).
506
- *
507
- * Note that, the very next request, we start from the previous timeout.
508
- *
509
- * 5 (timed out) > 6 (timed out) > 7 ...
510
- *
511
- * This strategy may need to be reviewed, but is the strategy on the our
512
- * current v3 version.
498
+ /**
499
+ * Imagine that you have 4 hosts, if timeouts will increase
500
+ * on the following way: 1 (timed out) > 4 (timed out) > 5 (200).
501
+ *
502
+ * Note that, the very next request, we start from the previous timeout.
503
+ *
504
+ * 5 (timed out) > 6 (timed out) > 7 ...
505
+ *
506
+ * This strategy may need to be reviewed, but is the strategy on the our
507
+ * current v3 version.
513
508
  */
514
509
  const timeoutMultiplier = hostsTimedOut.length === 0 && timeoutsCount === 0 ? 1 : hostsTimedOut.length + 3 + timeoutsCount;
515
510
  return timeoutMultiplier * baseTimeout;
516
511
  }
517
-
518
512
  };
519
513
  }
520
-
521
514
  async function retryableRequest(request, requestOptions, isRead = true) {
522
515
  const stackTrace = [];
523
- /**
524
- * First we prepare the payload that do not depend from hosts.
516
+ /**
517
+ * First we prepare the payload that do not depend from hosts.
525
518
  */
526
-
527
519
  const data = serializeData(request, requestOptions);
528
- const headers = serializeHeaders(baseHeaders, request.headers, requestOptions.headers); // On `GET`, the data is proxied to query parameters.
529
-
530
- const dataQueryParameters = request.method === 'GET' ? { ...request.data,
520
+ const headers = serializeHeaders(baseHeaders, request.headers, requestOptions.headers);
521
+ // On `GET`, the data is proxied to query parameters.
522
+ const dataQueryParameters = request.method === 'GET' ? {
523
+ ...request.data,
531
524
  ...requestOptions.data
532
525
  } : {};
533
526
  const queryParameters = {
534
- 'x-algolia-agent': algoliaAgent.value,
535
527
  ...baseQueryParameters,
536
528
  ...request.queryParameters,
537
529
  ...dataQueryParameters
538
530
  };
539
-
531
+ if (algoliaAgent.value) {
532
+ queryParameters['x-algolia-agent'] = algoliaAgent.value;
533
+ }
540
534
  if (requestOptions && requestOptions.queryParameters) {
541
535
  for (const key of Object.keys(requestOptions.queryParameters)) {
542
536
  // We want to keep `undefined` and `null` values,
@@ -549,25 +543,19 @@ function createTransporter({
549
543
  }
550
544
  }
551
545
  }
552
-
553
546
  let timeoutsCount = 0;
554
-
555
547
  const retry = async (retryableHosts, getTimeout) => {
556
- /**
557
- * We iterate on each host, until there is no host left.
548
+ /**
549
+ * We iterate on each host, until there is no host left.
558
550
  */
559
551
  const host = retryableHosts.pop();
560
-
561
552
  if (host === undefined) {
562
553
  throw new RetryError(stackTraceWithoutCredentials(stackTrace));
563
554
  }
564
-
565
555
  let responseTimeout = requestOptions.timeout;
566
-
567
556
  if (responseTimeout === undefined) {
568
557
  responseTimeout = isRead ? timeouts.read : timeouts.write;
569
558
  }
570
-
571
559
  const payload = {
572
560
  data,
573
561
  headers,
@@ -576,12 +564,11 @@ function createTransporter({
576
564
  connectTimeout: getTimeout(timeoutsCount, timeouts.connect),
577
565
  responseTimeout: getTimeout(timeoutsCount, responseTimeout)
578
566
  };
579
- /**
580
- * The stackFrame is pushed to the stackTrace so we
581
- * can have information about onRetry and onFailure
582
- * decisions.
567
+ /**
568
+ * The stackFrame is pushed to the stackTrace so we
569
+ * can have information about onRetry and onFailure
570
+ * decisions.
583
571
  */
584
-
585
572
  const pushToStackTrace = response => {
586
573
  const stackFrame = {
587
574
  request: payload,
@@ -592,102 +579,85 @@ function createTransporter({
592
579
  stackTrace.push(stackFrame);
593
580
  return stackFrame;
594
581
  };
595
-
596
582
  const response = await requester.send(payload);
597
-
598
583
  if (isRetryable(response)) {
599
- const stackFrame = pushToStackTrace(response); // If response is a timeout, we increase the number of timeouts so we can increase the timeout later.
600
-
584
+ const stackFrame = pushToStackTrace(response);
585
+ // If response is a timeout, we increase the number of timeouts so we can increase the timeout later.
601
586
  if (response.isTimedOut) {
602
587
  timeoutsCount++;
603
588
  }
604
- /**
605
- * Failures are individually sent to the logger, allowing
606
- * the end user to debug / store stack frames even
607
- * when a retry error does not happen.
589
+ /**
590
+ * Failures are individually sent to the logger, allowing
591
+ * the end user to debug / store stack frames even
592
+ * when a retry error does not happen.
608
593
  */
609
594
  // eslint-disable-next-line no-console -- this will be fixed by exposing a `logger` to the transporter
610
-
611
-
612
595
  console.log('Retryable failure', stackFrameWithoutCredentials(stackFrame));
613
- /**
614
- * We also store the state of the host in failure cases. If the host, is
615
- * down it will remain down for the next 2 minutes. In a timeout situation,
616
- * this host will be added end of the list of hosts on the next request.
596
+ /**
597
+ * We also store the state of the host in failure cases. If the host, is
598
+ * down it will remain down for the next 2 minutes. In a timeout situation,
599
+ * this host will be added end of the list of hosts on the next request.
617
600
  */
618
-
619
601
  await hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? 'timed out' : 'down'));
620
602
  return retry(retryableHosts, getTimeout);
621
603
  }
622
-
623
604
  if (isSuccess(response)) {
624
605
  return deserializeSuccess(response);
625
606
  }
626
-
627
607
  pushToStackTrace(response);
628
608
  throw deserializeFailure(response, stackTrace);
629
609
  };
630
- /**
631
- * Finally, for each retryable host perform request until we got a non
632
- * retryable response. Some notes here:
633
- *
634
- * 1. The reverse here is applied so we can apply a `pop` later on => more performant.
635
- * 2. We also get from the retryable options a timeout multiplier that is tailored
636
- * for the current context.
610
+ /**
611
+ * Finally, for each retryable host perform request until we got a non
612
+ * retryable response. Some notes here:
613
+ *
614
+ * 1. The reverse here is applied so we can apply a `pop` later on => more performant.
615
+ * 2. We also get from the retryable options a timeout multiplier that is tailored
616
+ * for the current context.
637
617
  */
638
-
639
-
640
618
  const compatibleHosts = hosts.filter(host => host.accept === 'readWrite' || (isRead ? host.accept === 'read' : host.accept === 'write'));
641
619
  const options = await createRetryableOptions(compatibleHosts);
642
620
  return retry([...options.hosts].reverse(), options.getTimeout);
643
621
  }
644
-
645
622
  function createRequest(request, requestOptions = {}) {
646
- /**
647
- * A read request is either a `GET` request, or a request that we make
648
- * via the `read` transporter (e.g. `search`).
623
+ /**
624
+ * A read request is either a `GET` request, or a request that we make
625
+ * via the `read` transporter (e.g. `search`).
649
626
  */
650
627
  const isRead = request.useReadTransporter || request.method === 'GET';
651
-
652
628
  if (!isRead) {
653
- /**
654
- * On write requests, no cache mechanisms are applied, and we
655
- * proxy the request immediately to the requester.
629
+ /**
630
+ * On write requests, no cache mechanisms are applied, and we
631
+ * proxy the request immediately to the requester.
656
632
  */
657
633
  return retryableRequest(request, requestOptions, isRead);
658
634
  }
659
-
660
635
  const createRetryableRequest = () => {
661
- /**
662
- * Then, we prepare a function factory that contains the construction of
663
- * the retryable request. At this point, we may *not* perform the actual
664
- * request. But we want to have the function factory ready.
636
+ /**
637
+ * Then, we prepare a function factory that contains the construction of
638
+ * the retryable request. At this point, we may *not* perform the actual
639
+ * request. But we want to have the function factory ready.
665
640
  */
666
641
  return retryableRequest(request, requestOptions);
667
642
  };
668
- /**
669
- * Once we have the function factory ready, we need to determine of the
670
- * request is "cacheable" - should be cached. Note that, once again,
671
- * the user can force this option.
643
+ /**
644
+ * Once we have the function factory ready, we need to determine of the
645
+ * request is "cacheable" - should be cached. Note that, once again,
646
+ * the user can force this option.
672
647
  */
673
-
674
-
675
648
  const cacheable = requestOptions.cacheable || request.cacheable;
676
- /**
677
- * If is not "cacheable", we immediately trigger the retryable request, no
678
- * need to check cache implementations.
649
+ /**
650
+ * If is not "cacheable", we immediately trigger the retryable request, no
651
+ * need to check cache implementations.
679
652
  */
680
-
681
653
  if (cacheable !== true) {
682
654
  return createRetryableRequest();
683
655
  }
684
- /**
685
- * If the request is "cacheable", we need to first compute the key to ask
686
- * the cache implementations if this request is on progress or if the
687
- * response already exists on the cache.
656
+ /**
657
+ * If the request is "cacheable", we need to first compute the key to ask
658
+ * the cache implementations if this request is on progress or if the
659
+ * response already exists on the cache.
688
660
  */
689
-
690
-
691
661
  const key = {
692
662
  request,
693
663
  requestOptions,
@@ -696,33 +666,31 @@ function createTransporter({
696
666
  headers: baseHeaders
697
667
  }
698
668
  };
699
- /**
700
- * With the computed key, we first ask the responses cache
701
- * implementation if this request was been resolved before.
669
+ /**
670
+ * With the computed key, we first ask the responses cache
671
+ * implementation if this request was been resolved before.
702
672
  */
703
-
704
673
  return responsesCache.get(key, () => {
705
- /**
706
- * If the request has never resolved before, we actually ask if there
707
- * is a current request with the same key on progress.
674
+ /**
675
+ * If the request has never resolved before, we actually ask if there
676
+ * is a current request with the same key on progress.
708
677
  */
709
678
  return requestsCache.get(key, () =>
710
- /**
711
- * Finally, if there is no request in progress with the same key,
712
- * this `createRetryableRequest()` will actually trigger the
713
- * retryable request.
679
+ /**
680
+ * Finally, if there is no request in progress with the same key,
681
+ * this `createRetryableRequest()` will actually trigger the
682
+ * retryable request.
714
683
  */
715
684
  requestsCache.set(key, createRetryableRequest()).then(response => Promise.all([requestsCache.delete(key), response]), err => Promise.all([requestsCache.delete(key), Promise.reject(err)])).then(([_, response]) => response));
716
685
  }, {
717
- /**
718
- * Of course, once we get this response back from the server, we
719
- * tell response cache to actually store the received response
720
- * to be used later.
686
+ /**
687
+ * Of course, once we get this response back from the server, we
688
+ * tell response cache to actually store the received response
689
+ * to be used later.
721
690
  */
722
691
  miss: response => responsesCache.set(key, response)
723
692
  });
724
693
  }
725
-
726
694
  return {
727
695
  hostsCache,
728
696
  requester,
@@ -740,17 +708,13 @@ function createTransporter({
740
708
  function createAlgoliaAgent(version) {
741
709
  const algoliaAgent = {
742
710
  value: `Algolia for JavaScript (${version})`,
743
-
744
711
  add(options) {
745
712
  const addedAlgoliaAgent = `; ${options.segment}${options.version !== undefined ? ` (${options.version})` : ''}`;
746
-
747
713
  if (algoliaAgent.value.indexOf(addedAlgoliaAgent) === -1) {
748
714
  algoliaAgent.value = `${algoliaAgent.value}${addedAlgoliaAgent}`;
749
715
  }
750
-
751
716
  return algoliaAgent;
752
717
  }
753
-
754
718
  };
755
719
  return algoliaAgent;
756
720
  }
@@ -779,13 +743,12 @@ exports.AlgoliaError = AlgoliaError;
779
743
  exports.ApiError = ApiError;
780
744
  exports.DEFAULT_CONNECT_TIMEOUT_BROWSER = DEFAULT_CONNECT_TIMEOUT_BROWSER;
781
745
  exports.DEFAULT_CONNECT_TIMEOUT_NODE = DEFAULT_CONNECT_TIMEOUT_NODE;
782
- exports.DEFAULT_MAX_RETRIES = DEFAULT_MAX_RETRIES;
783
746
  exports.DEFAULT_READ_TIMEOUT_BROWSER = DEFAULT_READ_TIMEOUT_BROWSER;
784
747
  exports.DEFAULT_READ_TIMEOUT_NODE = DEFAULT_READ_TIMEOUT_NODE;
785
- exports.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
786
748
  exports.DEFAULT_WRITE_TIMEOUT_BROWSER = DEFAULT_WRITE_TIMEOUT_BROWSER;
787
749
  exports.DEFAULT_WRITE_TIMEOUT_NODE = DEFAULT_WRITE_TIMEOUT_NODE;
788
750
  exports.DeserializationError = DeserializationError;
751
+ exports.DetailedApiError = DetailedApiError;
789
752
  exports.ErrorWithStackTrace = ErrorWithStackTrace;
790
753
  exports.RetryError = RetryError;
791
754
  exports.createAlgoliaAgent = createAlgoliaAgent;
@@ -793,9 +756,9 @@ exports.createAuth = createAuth;
793
756
  exports.createBrowserLocalStorageCache = createBrowserLocalStorageCache;
794
757
  exports.createEchoRequester = createEchoRequester;
795
758
  exports.createFallbackableCache = createFallbackableCache;
759
+ exports.createIterablePromise = createIterablePromise;
796
760
  exports.createMemoryCache = createMemoryCache;
797
761
  exports.createNullCache = createNullCache;
798
- exports.createRetryablePromise = createRetryablePromise;
799
762
  exports.createStatefulHost = createStatefulHost;
800
763
  exports.createTransporter = createTransporter;
801
764
  exports.deserializeFailure = deserializeFailure;