@algolia/client-common 5.0.0-alpha.11 → 5.0.0-alpha.111

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