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