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