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