@algolia/client-common 5.8.1 → 5.9.1
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/common.d.cts +562 -426
- package/dist/common.d.ts +562 -426
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +5 -5
- package/index.ts +0 -9
- package/src/__tests__/cache/browser-local-storage-cache.test.ts +0 -171
- package/src/__tests__/cache/fallbackable-cache.test.ts +0 -126
- package/src/__tests__/cache/memory-cache.test.ts +0 -82
- package/src/__tests__/cache/null-cache.test.ts +0 -47
- package/src/__tests__/create-iterable-promise.test.ts +0 -236
- package/src/__tests__/logger/null-logger.test.ts +0 -22
- package/src/cache/createBrowserLocalStorageCache.ts +0 -106
- package/src/cache/createFallbackableCache.ts +0 -43
- package/src/cache/createMemoryCache.ts +0 -43
- package/src/cache/createNullCache.ts +0 -29
- package/src/cache/index.ts +0 -4
- package/src/constants.ts +0 -7
- package/src/createAlgoliaAgent.ts +0 -18
- package/src/createAuth.ts +0 -25
- package/src/createIterablePromise.ts +0 -47
- package/src/getAlgoliaAgent.ts +0 -19
- package/src/logger/createNullLogger.ts +0 -15
- package/src/logger/index.ts +0 -1
- package/src/transporter/createStatefulHost.ts +0 -19
- package/src/transporter/createTransporter.ts +0 -315
- package/src/transporter/errors.ts +0 -77
- package/src/transporter/helpers.ts +0 -96
- package/src/transporter/index.ts +0 -6
- package/src/transporter/responses.ts +0 -13
- package/src/transporter/stackTrace.ts +0 -22
- package/src/types/cache.ts +0 -75
- package/src/types/createClient.ts +0 -15
- package/src/types/createIterablePromise.ts +0 -40
- package/src/types/host.ts +0 -43
- package/src/types/index.ts +0 -7
- package/src/types/logger.ts +0 -24
- package/src/types/requester.ts +0 -67
- package/src/types/transporter.ts +0 -153
package/dist/common.d.ts
CHANGED
|
@@ -1,450 +1,586 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
* The port of the host URL.
|
|
77
|
-
*/
|
|
78
|
-
port?: number;
|
|
79
|
-
};
|
|
80
|
-
type StatefulHost = Host & {
|
|
81
|
-
/**
|
|
82
|
-
* The status of the host.
|
|
83
|
-
*/
|
|
84
|
-
status: 'down' | 'timed out' | 'up';
|
|
85
|
-
/**
|
|
86
|
-
* The last update of the host status, used to compare with the expiration delay.
|
|
87
|
-
*/
|
|
88
|
-
lastUpdate: number;
|
|
89
|
-
/**
|
|
90
|
-
* Returns whether the host is up or not.
|
|
91
|
-
*/
|
|
92
|
-
isUp: () => boolean;
|
|
93
|
-
/**
|
|
94
|
-
* Returns whether the host is timed out or not.
|
|
95
|
-
*/
|
|
96
|
-
isTimedOut: () => boolean;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
declare const LogLevelEnum: Readonly<Record<string, LogLevelType>>;
|
|
100
|
-
type LogLevelType = 1 | 2 | 3;
|
|
101
|
-
type Logger = {
|
|
102
|
-
/**
|
|
103
|
-
* Logs debug messages.
|
|
104
|
-
*/
|
|
105
|
-
debug: (message: string, args?: any) => Promise<void>;
|
|
106
|
-
/**
|
|
107
|
-
* Logs info messages.
|
|
108
|
-
*/
|
|
109
|
-
info: (message: string, args?: any) => Promise<void>;
|
|
110
|
-
/**
|
|
111
|
-
* Logs error messages.
|
|
112
|
-
*/
|
|
113
|
-
error: (message: string, args?: any) => Promise<void>;
|
|
114
|
-
};
|
|
1
|
+
// src/cache/createBrowserLocalStorageCache.ts
|
|
2
|
+
function createBrowserLocalStorageCache(options) {
|
|
3
|
+
let storage;
|
|
4
|
+
const namespaceKey = `algolia-client-js-${options.key}`;
|
|
5
|
+
function getStorage() {
|
|
6
|
+
if (storage === void 0) {
|
|
7
|
+
storage = options.localStorage || window.localStorage;
|
|
8
|
+
}
|
|
9
|
+
return storage;
|
|
10
|
+
}
|
|
11
|
+
function getNamespace() {
|
|
12
|
+
return JSON.parse(getStorage().getItem(namespaceKey) || "{}");
|
|
13
|
+
}
|
|
14
|
+
function setNamespace(namespace) {
|
|
15
|
+
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
16
|
+
}
|
|
17
|
+
function removeOutdatedCacheItems() {
|
|
18
|
+
const timeToLive = options.timeToLive ? options.timeToLive * 1e3 : null;
|
|
19
|
+
const namespace = getNamespace();
|
|
20
|
+
const filteredNamespaceWithoutOldFormattedCacheItems = Object.fromEntries(
|
|
21
|
+
Object.entries(namespace).filter(([, cacheItem]) => {
|
|
22
|
+
return cacheItem.timestamp !== void 0;
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
setNamespace(filteredNamespaceWithoutOldFormattedCacheItems);
|
|
26
|
+
if (!timeToLive) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const filteredNamespaceWithoutExpiredItems = Object.fromEntries(
|
|
30
|
+
Object.entries(filteredNamespaceWithoutOldFormattedCacheItems).filter(([, cacheItem]) => {
|
|
31
|
+
const currentTimestamp = (/* @__PURE__ */ new Date()).getTime();
|
|
32
|
+
const isExpired = cacheItem.timestamp + timeToLive < currentTimestamp;
|
|
33
|
+
return !isExpired;
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
setNamespace(filteredNamespaceWithoutExpiredItems);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
get(key, defaultValue, events = {
|
|
40
|
+
miss: () => Promise.resolve()
|
|
41
|
+
}) {
|
|
42
|
+
return Promise.resolve().then(() => {
|
|
43
|
+
removeOutdatedCacheItems();
|
|
44
|
+
return getNamespace()[JSON.stringify(key)];
|
|
45
|
+
}).then((value) => {
|
|
46
|
+
return Promise.all([value ? value.value : defaultValue(), value !== void 0]);
|
|
47
|
+
}).then(([value, exists]) => {
|
|
48
|
+
return Promise.all([value, exists || events.miss(value)]);
|
|
49
|
+
}).then(([value]) => value);
|
|
50
|
+
},
|
|
51
|
+
set(key, value) {
|
|
52
|
+
return Promise.resolve().then(() => {
|
|
53
|
+
const namespace = getNamespace();
|
|
54
|
+
namespace[JSON.stringify(key)] = {
|
|
55
|
+
timestamp: (/* @__PURE__ */ new Date()).getTime(),
|
|
56
|
+
value
|
|
57
|
+
};
|
|
58
|
+
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
59
|
+
return value;
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
delete(key) {
|
|
63
|
+
return Promise.resolve().then(() => {
|
|
64
|
+
const namespace = getNamespace();
|
|
65
|
+
delete namespace[JSON.stringify(key)];
|
|
66
|
+
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
clear() {
|
|
70
|
+
return Promise.resolve().then(() => {
|
|
71
|
+
getStorage().removeItem(namespaceKey);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
115
76
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Some POST methods in the Algolia REST API uses the `read` transporter.
|
|
138
|
-
* This information is defined at the spec level.
|
|
139
|
-
*/
|
|
140
|
-
useReadTransporter?: boolean;
|
|
141
|
-
};
|
|
142
|
-
type EndRequest = Pick<Request, 'headers' | 'method'> & {
|
|
143
|
-
/**
|
|
144
|
-
* The full URL of the REST API.
|
|
145
|
-
*/
|
|
146
|
-
url: string;
|
|
147
|
-
/**
|
|
148
|
-
* The connection timeout, in milliseconds.
|
|
149
|
-
*/
|
|
150
|
-
connectTimeout: number;
|
|
151
|
-
/**
|
|
152
|
-
* The response timeout, in milliseconds.
|
|
153
|
-
*/
|
|
154
|
-
responseTimeout: number;
|
|
155
|
-
data?: string;
|
|
156
|
-
};
|
|
157
|
-
type Response = {
|
|
158
|
-
/**
|
|
159
|
-
* The body of the response.
|
|
160
|
-
*/
|
|
161
|
-
content: string;
|
|
162
|
-
/**
|
|
163
|
-
* Whether the API call is timed out or not.
|
|
164
|
-
*/
|
|
165
|
-
isTimedOut: boolean;
|
|
166
|
-
/**
|
|
167
|
-
* The HTTP status code of the response.
|
|
168
|
-
*/
|
|
169
|
-
status: number;
|
|
170
|
-
};
|
|
171
|
-
type Requester = {
|
|
172
|
-
/**
|
|
173
|
-
* Sends the given `request` to the server.
|
|
174
|
-
*/
|
|
175
|
-
send: (request: EndRequest) => Promise<Response>;
|
|
176
|
-
};
|
|
77
|
+
// src/cache/createNullCache.ts
|
|
78
|
+
function createNullCache() {
|
|
79
|
+
return {
|
|
80
|
+
get(_key, defaultValue, events = {
|
|
81
|
+
miss: () => Promise.resolve()
|
|
82
|
+
}) {
|
|
83
|
+
const value = defaultValue();
|
|
84
|
+
return value.then((result) => Promise.all([result, events.miss(result)])).then(([result]) => result);
|
|
85
|
+
},
|
|
86
|
+
set(_key, value) {
|
|
87
|
+
return Promise.resolve(value);
|
|
88
|
+
},
|
|
89
|
+
delete(_key) {
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
},
|
|
92
|
+
clear() {
|
|
93
|
+
return Promise.resolve();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
177
97
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
*/
|
|
211
|
-
segment: string;
|
|
212
|
-
/**
|
|
213
|
-
* The version. Usually the integration version.
|
|
214
|
-
*/
|
|
215
|
-
version?: string;
|
|
216
|
-
};
|
|
217
|
-
type AlgoliaAgent = {
|
|
218
|
-
/**
|
|
219
|
-
* The raw value of the user agent.
|
|
220
|
-
*/
|
|
221
|
-
value: string;
|
|
222
|
-
/**
|
|
223
|
-
* Mutates the current user agent adding the given user agent options.
|
|
224
|
-
*/
|
|
225
|
-
add: (options: AlgoliaAgentOptions) => AlgoliaAgent;
|
|
226
|
-
};
|
|
227
|
-
type Timeouts = {
|
|
228
|
-
/**
|
|
229
|
-
* Timeout in milliseconds before the connection is established.
|
|
230
|
-
*/
|
|
231
|
-
connect: number;
|
|
232
|
-
/**
|
|
233
|
-
* Timeout in milliseconds before reading the response on a read request.
|
|
234
|
-
*/
|
|
235
|
-
read: number;
|
|
236
|
-
/**
|
|
237
|
-
* Timeout in milliseconds before reading the response on a write request.
|
|
238
|
-
*/
|
|
239
|
-
write: number;
|
|
240
|
-
};
|
|
241
|
-
type TransporterOptions = {
|
|
242
|
-
/**
|
|
243
|
-
* The cache of the hosts. Usually used to persist
|
|
244
|
-
* the state of the host when its down.
|
|
245
|
-
*/
|
|
246
|
-
hostsCache: Cache;
|
|
247
|
-
/**
|
|
248
|
-
* The logger instance to send events of the transporter.
|
|
249
|
-
*/
|
|
250
|
-
logger: Logger;
|
|
251
|
-
/**
|
|
252
|
-
* The underlying requester used. Should differ
|
|
253
|
-
* depending of the environment where the client
|
|
254
|
-
* will be used.
|
|
255
|
-
*/
|
|
256
|
-
requester: Requester;
|
|
257
|
-
/**
|
|
258
|
-
* The cache of the requests. When requests are
|
|
259
|
-
* `cacheable`, the returned promised persists
|
|
260
|
-
* in this cache to shared in similar requests
|
|
261
|
-
* before being resolved.
|
|
262
|
-
*/
|
|
263
|
-
requestsCache: Cache;
|
|
264
|
-
/**
|
|
265
|
-
* The cache of the responses. When requests are
|
|
266
|
-
* `cacheable`, the returned responses persists
|
|
267
|
-
* in this cache to shared in similar requests.
|
|
268
|
-
*/
|
|
269
|
-
responsesCache: Cache;
|
|
270
|
-
/**
|
|
271
|
-
* The timeouts used by the requester. The transporter
|
|
272
|
-
* layer may increase this timeouts as defined on the
|
|
273
|
-
* retry strategy.
|
|
274
|
-
*/
|
|
275
|
-
timeouts: Timeouts;
|
|
276
|
-
/**
|
|
277
|
-
* The hosts used by the requester.
|
|
278
|
-
*/
|
|
279
|
-
hosts: Host[];
|
|
280
|
-
/**
|
|
281
|
-
* The headers used by the requester. The transporter
|
|
282
|
-
* layer may add some extra headers during the request
|
|
283
|
-
* for the user agent, and others.
|
|
284
|
-
*/
|
|
285
|
-
baseHeaders: Headers;
|
|
286
|
-
/**
|
|
287
|
-
* The query parameters used by the requester. The transporter
|
|
288
|
-
* layer may add some extra headers during the request
|
|
289
|
-
* for the user agent, and others.
|
|
290
|
-
*/
|
|
291
|
-
baseQueryParameters: QueryParameters;
|
|
292
|
-
/**
|
|
293
|
-
* The user agent used. Sent on query parameters.
|
|
294
|
-
*/
|
|
295
|
-
algoliaAgent: AlgoliaAgent;
|
|
296
|
-
};
|
|
297
|
-
type Transporter = TransporterOptions & {
|
|
298
|
-
/**
|
|
299
|
-
* Performs a request.
|
|
300
|
-
* The `baseRequest` and `baseRequestOptions` will be merged accordingly.
|
|
301
|
-
*/
|
|
302
|
-
request: <TResponse>(baseRequest: Request, baseRequestOptions?: RequestOptions) => Promise<TResponse>;
|
|
303
|
-
};
|
|
98
|
+
// src/cache/createFallbackableCache.ts
|
|
99
|
+
function createFallbackableCache(options) {
|
|
100
|
+
const caches = [...options.caches];
|
|
101
|
+
const current = caches.shift();
|
|
102
|
+
if (current === void 0) {
|
|
103
|
+
return createNullCache();
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
get(key, defaultValue, events = {
|
|
107
|
+
miss: () => Promise.resolve()
|
|
108
|
+
}) {
|
|
109
|
+
return current.get(key, defaultValue, events).catch(() => {
|
|
110
|
+
return createFallbackableCache({ caches }).get(key, defaultValue, events);
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
set(key, value) {
|
|
114
|
+
return current.set(key, value).catch(() => {
|
|
115
|
+
return createFallbackableCache({ caches }).set(key, value);
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
delete(key) {
|
|
119
|
+
return current.delete(key).catch(() => {
|
|
120
|
+
return createFallbackableCache({ caches }).delete(key);
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
clear() {
|
|
124
|
+
return current.clear().catch(() => {
|
|
125
|
+
return createFallbackableCache({ caches }).clear();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
304
130
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
131
|
+
// src/cache/createMemoryCache.ts
|
|
132
|
+
function createMemoryCache(options = { serializable: true }) {
|
|
133
|
+
let cache = {};
|
|
134
|
+
return {
|
|
135
|
+
get(key, defaultValue, events = {
|
|
136
|
+
miss: () => Promise.resolve()
|
|
137
|
+
}) {
|
|
138
|
+
const keyAsString = JSON.stringify(key);
|
|
139
|
+
if (keyAsString in cache) {
|
|
140
|
+
return Promise.resolve(options.serializable ? JSON.parse(cache[keyAsString]) : cache[keyAsString]);
|
|
141
|
+
}
|
|
142
|
+
const promise = defaultValue();
|
|
143
|
+
return promise.then((value) => events.miss(value)).then(() => promise);
|
|
144
|
+
},
|
|
145
|
+
set(key, value) {
|
|
146
|
+
cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
|
|
147
|
+
return Promise.resolve(value);
|
|
148
|
+
},
|
|
149
|
+
delete(key) {
|
|
150
|
+
delete cache[JSON.stringify(key)];
|
|
151
|
+
return Promise.resolve();
|
|
152
|
+
},
|
|
153
|
+
clear() {
|
|
154
|
+
cache = {};
|
|
155
|
+
return Promise.resolve();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
314
159
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
*/
|
|
323
|
-
error: {
|
|
324
|
-
/**
|
|
325
|
-
* The function to validate the error condition.
|
|
326
|
-
*/
|
|
327
|
-
validate: (response: TResponse) => boolean;
|
|
328
|
-
/**
|
|
329
|
-
* The error message to throw.
|
|
330
|
-
*/
|
|
331
|
-
message: (response: TResponse) => string;
|
|
332
|
-
};
|
|
333
|
-
/**
|
|
334
|
-
* The function to decide how long to wait between iterations.
|
|
335
|
-
*/
|
|
336
|
-
timeout: () => number;
|
|
337
|
-
}>;
|
|
338
|
-
type CreateIterablePromise<TResponse> = IterableOptions<TResponse> & {
|
|
339
|
-
/**
|
|
340
|
-
* The function to run, which returns a promise.
|
|
341
|
-
*
|
|
342
|
-
* The `previousResponse` parameter (`undefined` on the first call) allows you to build your request with incremental logic, to iterate on `page` or `cursor` for example.
|
|
343
|
-
*/
|
|
344
|
-
func: (previousResponse?: TResponse) => Promise<TResponse>;
|
|
345
|
-
/**
|
|
346
|
-
* The validator function. It receive the resolved return of the API call.
|
|
347
|
-
*/
|
|
348
|
-
validate: (response: TResponse) => boolean;
|
|
349
|
-
};
|
|
160
|
+
// src/constants.ts
|
|
161
|
+
var DEFAULT_CONNECT_TIMEOUT_BROWSER = 1e3;
|
|
162
|
+
var DEFAULT_READ_TIMEOUT_BROWSER = 2e3;
|
|
163
|
+
var DEFAULT_WRITE_TIMEOUT_BROWSER = 3e4;
|
|
164
|
+
var DEFAULT_CONNECT_TIMEOUT_NODE = 2e3;
|
|
165
|
+
var DEFAULT_READ_TIMEOUT_NODE = 5e3;
|
|
166
|
+
var DEFAULT_WRITE_TIMEOUT_NODE = 3e4;
|
|
350
167
|
|
|
351
|
-
|
|
168
|
+
// src/createAlgoliaAgent.ts
|
|
169
|
+
function createAlgoliaAgent(version) {
|
|
170
|
+
const algoliaAgent = {
|
|
171
|
+
value: `Algolia for JavaScript (${version})`,
|
|
172
|
+
add(options) {
|
|
173
|
+
const addedAlgoliaAgent = `; ${options.segment}${options.version !== void 0 ? ` (${options.version})` : ""}`;
|
|
174
|
+
if (algoliaAgent.value.indexOf(addedAlgoliaAgent) === -1) {
|
|
175
|
+
algoliaAgent.value = `${algoliaAgent.value}${addedAlgoliaAgent}`;
|
|
176
|
+
}
|
|
177
|
+
return algoliaAgent;
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
return algoliaAgent;
|
|
181
|
+
}
|
|
352
182
|
|
|
353
|
-
|
|
183
|
+
// src/createAuth.ts
|
|
184
|
+
function createAuth(appId, apiKey, authMode = "WithinHeaders") {
|
|
185
|
+
const credentials = {
|
|
186
|
+
"x-algolia-api-key": apiKey,
|
|
187
|
+
"x-algolia-application-id": appId
|
|
188
|
+
};
|
|
189
|
+
return {
|
|
190
|
+
headers() {
|
|
191
|
+
return authMode === "WithinHeaders" ? credentials : {};
|
|
192
|
+
},
|
|
193
|
+
queryParameters() {
|
|
194
|
+
return authMode === "WithinQueryParameters" ? credentials : {};
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
354
198
|
|
|
355
|
-
|
|
199
|
+
// src/createIterablePromise.ts
|
|
200
|
+
function createIterablePromise({
|
|
201
|
+
func,
|
|
202
|
+
validate,
|
|
203
|
+
aggregator,
|
|
204
|
+
error,
|
|
205
|
+
timeout = () => 0
|
|
206
|
+
}) {
|
|
207
|
+
const retry = (previousResponse) => {
|
|
208
|
+
return new Promise((resolve, reject) => {
|
|
209
|
+
func(previousResponse).then((response) => {
|
|
210
|
+
if (aggregator) {
|
|
211
|
+
aggregator(response);
|
|
212
|
+
}
|
|
213
|
+
if (validate(response)) {
|
|
214
|
+
return resolve(response);
|
|
215
|
+
}
|
|
216
|
+
if (error && error.validate(response)) {
|
|
217
|
+
return reject(new Error(error.message(response)));
|
|
218
|
+
}
|
|
219
|
+
return setTimeout(() => {
|
|
220
|
+
retry(response).then(resolve).catch(reject);
|
|
221
|
+
}, timeout());
|
|
222
|
+
}).catch((err) => {
|
|
223
|
+
reject(err);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
return retry();
|
|
228
|
+
}
|
|
356
229
|
|
|
357
|
-
|
|
230
|
+
// src/getAlgoliaAgent.ts
|
|
231
|
+
function getAlgoliaAgent({ algoliaAgents, client, version }) {
|
|
232
|
+
const defaultAlgoliaAgent = createAlgoliaAgent(version).add({
|
|
233
|
+
segment: client,
|
|
234
|
+
version
|
|
235
|
+
});
|
|
236
|
+
algoliaAgents.forEach((algoliaAgent) => defaultAlgoliaAgent.add(algoliaAgent));
|
|
237
|
+
return defaultAlgoliaAgent;
|
|
238
|
+
}
|
|
358
239
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
240
|
+
// src/logger/createNullLogger.ts
|
|
241
|
+
function createNullLogger() {
|
|
242
|
+
return {
|
|
243
|
+
debug(_message, _args) {
|
|
244
|
+
return Promise.resolve();
|
|
245
|
+
},
|
|
246
|
+
info(_message, _args) {
|
|
247
|
+
return Promise.resolve();
|
|
248
|
+
},
|
|
249
|
+
error(_message, _args) {
|
|
250
|
+
return Promise.resolve();
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
365
254
|
|
|
366
|
-
|
|
255
|
+
// src/transporter/createStatefulHost.ts
|
|
256
|
+
var EXPIRATION_DELAY = 2 * 60 * 1e3;
|
|
257
|
+
function createStatefulHost(host, status = "up") {
|
|
258
|
+
const lastUpdate = Date.now();
|
|
259
|
+
function isUp() {
|
|
260
|
+
return status === "up" || Date.now() - lastUpdate > EXPIRATION_DELAY;
|
|
261
|
+
}
|
|
262
|
+
function isTimedOut() {
|
|
263
|
+
return status === "timed out" && Date.now() - lastUpdate <= EXPIRATION_DELAY;
|
|
264
|
+
}
|
|
265
|
+
return { ...host, status, lastUpdate, isUp, isTimedOut };
|
|
266
|
+
}
|
|
367
267
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
268
|
+
// src/transporter/errors.ts
|
|
269
|
+
var AlgoliaError = class extends Error {
|
|
270
|
+
name = "AlgoliaError";
|
|
271
|
+
constructor(message, name) {
|
|
272
|
+
super(message);
|
|
273
|
+
if (name) {
|
|
274
|
+
this.name = name;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
371
277
|
};
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
278
|
+
var ErrorWithStackTrace = class extends AlgoliaError {
|
|
279
|
+
stackTrace;
|
|
280
|
+
constructor(message, stackTrace, name) {
|
|
281
|
+
super(message, name);
|
|
282
|
+
this.stackTrace = stackTrace;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
var RetryError = class extends ErrorWithStackTrace {
|
|
286
|
+
constructor(stackTrace) {
|
|
287
|
+
super(
|
|
288
|
+
"Unreachable hosts - your application id may be incorrect. If the error persists, please reach out to the Algolia Support team: https://alg.li/support.",
|
|
289
|
+
stackTrace,
|
|
290
|
+
"RetryError"
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
var ApiError = class extends ErrorWithStackTrace {
|
|
295
|
+
status;
|
|
296
|
+
constructor(message, status, stackTrace, name = "ApiError") {
|
|
297
|
+
super(message, stackTrace, name);
|
|
298
|
+
this.status = status;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
var DeserializationError = class extends AlgoliaError {
|
|
302
|
+
response;
|
|
303
|
+
constructor(message, response) {
|
|
304
|
+
super(message, "DeserializationError");
|
|
305
|
+
this.response = response;
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
var DetailedApiError = class extends ApiError {
|
|
309
|
+
error;
|
|
310
|
+
constructor(message, status, error, stackTrace) {
|
|
311
|
+
super(message, status, stackTrace, "DetailedApiError");
|
|
312
|
+
this.error = error;
|
|
313
|
+
}
|
|
389
314
|
};
|
|
390
|
-
declare function getAlgoliaAgent({ algoliaAgents, client, version }: GetAlgoliaAgent): AlgoliaAgent;
|
|
391
|
-
|
|
392
|
-
declare function createNullLogger(): Logger;
|
|
393
|
-
|
|
394
|
-
declare function createStatefulHost(host: Host, status?: StatefulHost['status']): StatefulHost;
|
|
395
|
-
|
|
396
|
-
declare function createTransporter({ hosts, hostsCache, baseHeaders, logger, baseQueryParameters, algoliaAgent, timeouts, requester, requestsCache, responsesCache, }: TransporterOptions): Transporter;
|
|
397
315
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
316
|
+
// src/transporter/helpers.ts
|
|
317
|
+
function shuffle(array) {
|
|
318
|
+
const shuffledArray = array;
|
|
319
|
+
for (let c = array.length - 1; c > 0; c--) {
|
|
320
|
+
const b = Math.floor(Math.random() * (c + 1));
|
|
321
|
+
const a = array[c];
|
|
322
|
+
shuffledArray[c] = array[b];
|
|
323
|
+
shuffledArray[b] = a;
|
|
324
|
+
}
|
|
325
|
+
return shuffledArray;
|
|
401
326
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
327
|
+
function serializeUrl(host, path, queryParameters) {
|
|
328
|
+
const queryParametersAsString = serializeQueryParameters(queryParameters);
|
|
329
|
+
let url = `${host.protocol}://${host.url}${host.port ? `:${host.port}` : ""}/${path.charAt(0) === "/" ? path.substring(1) : path}`;
|
|
330
|
+
if (queryParametersAsString.length) {
|
|
331
|
+
url += `?${queryParametersAsString}`;
|
|
332
|
+
}
|
|
333
|
+
return url;
|
|
405
334
|
}
|
|
406
|
-
|
|
407
|
-
|
|
335
|
+
function serializeQueryParameters(parameters) {
|
|
336
|
+
return Object.keys(parameters).filter((key) => parameters[key] !== void 0).sort().map(
|
|
337
|
+
(key) => `${key}=${encodeURIComponent(
|
|
338
|
+
Object.prototype.toString.call(parameters[key]) === "[object Array]" ? parameters[key].join(",") : parameters[key]
|
|
339
|
+
).replace(/\+/g, "%20")}`
|
|
340
|
+
).join("&");
|
|
408
341
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
342
|
+
function serializeData(request, requestOptions) {
|
|
343
|
+
if (request.method === "GET" || request.data === void 0 && requestOptions.data === void 0) {
|
|
344
|
+
return void 0;
|
|
345
|
+
}
|
|
346
|
+
const data = Array.isArray(request.data) ? request.data : { ...request.data, ...requestOptions.data };
|
|
347
|
+
return JSON.stringify(data);
|
|
412
348
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
349
|
+
function serializeHeaders(baseHeaders, requestHeaders, requestOptionsHeaders) {
|
|
350
|
+
const headers = {
|
|
351
|
+
Accept: "application/json",
|
|
352
|
+
...baseHeaders,
|
|
353
|
+
...requestHeaders,
|
|
354
|
+
...requestOptionsHeaders
|
|
355
|
+
};
|
|
356
|
+
const serializedHeaders = {};
|
|
357
|
+
Object.keys(headers).forEach((header) => {
|
|
358
|
+
const value = headers[header];
|
|
359
|
+
serializedHeaders[header.toLowerCase()] = value;
|
|
360
|
+
});
|
|
361
|
+
return serializedHeaders;
|
|
416
362
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
363
|
+
function deserializeSuccess(response) {
|
|
364
|
+
try {
|
|
365
|
+
return JSON.parse(response.content);
|
|
366
|
+
} catch (e) {
|
|
367
|
+
throw new DeserializationError(e.message, response);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function deserializeFailure({ content, status }, stackFrame) {
|
|
371
|
+
try {
|
|
372
|
+
const parsed = JSON.parse(content);
|
|
373
|
+
if ("error" in parsed) {
|
|
374
|
+
return new DetailedApiError(parsed.message, status, parsed.error, stackFrame);
|
|
375
|
+
}
|
|
376
|
+
return new ApiError(parsed.message, status, stackFrame);
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
return new ApiError(content, status, stackFrame);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// src/transporter/responses.ts
|
|
383
|
+
function isNetworkError({ isTimedOut, status }) {
|
|
384
|
+
return !isTimedOut && ~~status === 0;
|
|
385
|
+
}
|
|
386
|
+
function isRetryable({ isTimedOut, status }) {
|
|
387
|
+
return isTimedOut || isNetworkError({ isTimedOut, status }) || ~~(status / 100) !== 2 && ~~(status / 100) !== 4;
|
|
388
|
+
}
|
|
389
|
+
function isSuccess({ status }) {
|
|
390
|
+
return ~~(status / 100) === 2;
|
|
433
391
|
}
|
|
434
392
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
393
|
+
// src/transporter/stackTrace.ts
|
|
394
|
+
function stackTraceWithoutCredentials(stackTrace) {
|
|
395
|
+
return stackTrace.map((stackFrame) => stackFrameWithoutCredentials(stackFrame));
|
|
396
|
+
}
|
|
397
|
+
function stackFrameWithoutCredentials(stackFrame) {
|
|
398
|
+
const modifiedHeaders = stackFrame.request.headers["x-algolia-api-key"] ? { "x-algolia-api-key": "*****" } : {};
|
|
399
|
+
return {
|
|
400
|
+
...stackFrame,
|
|
401
|
+
request: {
|
|
402
|
+
...stackFrame.request,
|
|
403
|
+
headers: {
|
|
404
|
+
...stackFrame.request.headers,
|
|
405
|
+
...modifiedHeaders
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
}
|
|
442
410
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
411
|
+
// src/transporter/createTransporter.ts
|
|
412
|
+
function createTransporter({
|
|
413
|
+
hosts,
|
|
414
|
+
hostsCache,
|
|
415
|
+
baseHeaders,
|
|
416
|
+
logger,
|
|
417
|
+
baseQueryParameters,
|
|
418
|
+
algoliaAgent,
|
|
419
|
+
timeouts,
|
|
420
|
+
requester,
|
|
421
|
+
requestsCache,
|
|
422
|
+
responsesCache
|
|
423
|
+
}) {
|
|
424
|
+
async function createRetryableOptions(compatibleHosts) {
|
|
425
|
+
const statefulHosts = await Promise.all(
|
|
426
|
+
compatibleHosts.map((compatibleHost) => {
|
|
427
|
+
return hostsCache.get(compatibleHost, () => {
|
|
428
|
+
return Promise.resolve(createStatefulHost(compatibleHost));
|
|
429
|
+
});
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
const hostsUp = statefulHosts.filter((host) => host.isUp());
|
|
433
|
+
const hostsTimedOut = statefulHosts.filter((host) => host.isTimedOut());
|
|
434
|
+
const hostsAvailable = [...hostsUp, ...hostsTimedOut];
|
|
435
|
+
const compatibleHostsAvailable = hostsAvailable.length > 0 ? hostsAvailable : compatibleHosts;
|
|
436
|
+
return {
|
|
437
|
+
hosts: compatibleHostsAvailable,
|
|
438
|
+
getTimeout(timeoutsCount, baseTimeout) {
|
|
439
|
+
const timeoutMultiplier = hostsTimedOut.length === 0 && timeoutsCount === 0 ? 1 : hostsTimedOut.length + 3 + timeoutsCount;
|
|
440
|
+
return timeoutMultiplier * baseTimeout;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
async function retryableRequest(request, requestOptions, isRead = true) {
|
|
445
|
+
const stackTrace = [];
|
|
446
|
+
const data = serializeData(request, requestOptions);
|
|
447
|
+
const headers = serializeHeaders(baseHeaders, request.headers, requestOptions.headers);
|
|
448
|
+
const dataQueryParameters = request.method === "GET" ? {
|
|
449
|
+
...request.data,
|
|
450
|
+
...requestOptions.data
|
|
451
|
+
} : {};
|
|
452
|
+
const queryParameters = {
|
|
453
|
+
...baseQueryParameters,
|
|
454
|
+
...request.queryParameters,
|
|
455
|
+
...dataQueryParameters
|
|
456
|
+
};
|
|
457
|
+
if (algoliaAgent.value) {
|
|
458
|
+
queryParameters["x-algolia-agent"] = algoliaAgent.value;
|
|
459
|
+
}
|
|
460
|
+
if (requestOptions && requestOptions.queryParameters) {
|
|
461
|
+
for (const key of Object.keys(requestOptions.queryParameters)) {
|
|
462
|
+
if (!requestOptions.queryParameters[key] || Object.prototype.toString.call(requestOptions.queryParameters[key]) === "[object Object]") {
|
|
463
|
+
queryParameters[key] = requestOptions.queryParameters[key];
|
|
464
|
+
} else {
|
|
465
|
+
queryParameters[key] = requestOptions.queryParameters[key].toString();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
let timeoutsCount = 0;
|
|
470
|
+
const retry = async (retryableHosts, getTimeout) => {
|
|
471
|
+
const host = retryableHosts.pop();
|
|
472
|
+
if (host === void 0) {
|
|
473
|
+
throw new RetryError(stackTraceWithoutCredentials(stackTrace));
|
|
474
|
+
}
|
|
475
|
+
const timeout = { ...timeouts, ...requestOptions.timeouts };
|
|
476
|
+
const payload = {
|
|
477
|
+
data,
|
|
478
|
+
headers,
|
|
479
|
+
method: request.method,
|
|
480
|
+
url: serializeUrl(host, request.path, queryParameters),
|
|
481
|
+
connectTimeout: getTimeout(timeoutsCount, timeout.connect),
|
|
482
|
+
responseTimeout: getTimeout(timeoutsCount, isRead ? timeout.read : timeout.write)
|
|
483
|
+
};
|
|
484
|
+
const pushToStackTrace = (response2) => {
|
|
485
|
+
const stackFrame = {
|
|
486
|
+
request: payload,
|
|
487
|
+
response: response2,
|
|
488
|
+
host,
|
|
489
|
+
triesLeft: retryableHosts.length
|
|
490
|
+
};
|
|
491
|
+
stackTrace.push(stackFrame);
|
|
492
|
+
return stackFrame;
|
|
493
|
+
};
|
|
494
|
+
const response = await requester.send(payload);
|
|
495
|
+
if (isRetryable(response)) {
|
|
496
|
+
const stackFrame = pushToStackTrace(response);
|
|
497
|
+
if (response.isTimedOut) {
|
|
498
|
+
timeoutsCount++;
|
|
499
|
+
}
|
|
500
|
+
logger.info("Retryable failure", stackFrameWithoutCredentials(stackFrame));
|
|
501
|
+
await hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? "timed out" : "down"));
|
|
502
|
+
return retry(retryableHosts, getTimeout);
|
|
503
|
+
}
|
|
504
|
+
if (isSuccess(response)) {
|
|
505
|
+
return deserializeSuccess(response);
|
|
506
|
+
}
|
|
507
|
+
pushToStackTrace(response);
|
|
508
|
+
throw deserializeFailure(response, stackTrace);
|
|
509
|
+
};
|
|
510
|
+
const compatibleHosts = hosts.filter(
|
|
511
|
+
(host) => host.accept === "readWrite" || (isRead ? host.accept === "read" : host.accept === "write")
|
|
512
|
+
);
|
|
513
|
+
const options = await createRetryableOptions(compatibleHosts);
|
|
514
|
+
return retry([...options.hosts].reverse(), options.getTimeout);
|
|
515
|
+
}
|
|
516
|
+
function createRequest(request, requestOptions = {}) {
|
|
517
|
+
const isRead = request.useReadTransporter || request.method === "GET";
|
|
518
|
+
if (!isRead) {
|
|
519
|
+
return retryableRequest(request, requestOptions, isRead);
|
|
520
|
+
}
|
|
521
|
+
const createRetryableRequest = () => {
|
|
522
|
+
return retryableRequest(request, requestOptions);
|
|
523
|
+
};
|
|
524
|
+
const cacheable = requestOptions.cacheable || request.cacheable;
|
|
525
|
+
if (cacheable !== true) {
|
|
526
|
+
return createRetryableRequest();
|
|
527
|
+
}
|
|
528
|
+
const key = {
|
|
529
|
+
request,
|
|
530
|
+
requestOptions,
|
|
531
|
+
transporter: {
|
|
532
|
+
queryParameters: baseQueryParameters,
|
|
533
|
+
headers: baseHeaders
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
return responsesCache.get(
|
|
537
|
+
key,
|
|
538
|
+
() => {
|
|
539
|
+
return requestsCache.get(
|
|
540
|
+
key,
|
|
541
|
+
() => (
|
|
542
|
+
/**
|
|
543
|
+
* Finally, if there is no request in progress with the same key,
|
|
544
|
+
* this `createRetryableRequest()` will actually trigger the
|
|
545
|
+
* retryable request.
|
|
546
|
+
*/
|
|
547
|
+
requestsCache.set(key, createRetryableRequest()).then(
|
|
548
|
+
(response) => Promise.all([requestsCache.delete(key), response]),
|
|
549
|
+
(err) => Promise.all([requestsCache.delete(key), Promise.reject(err)])
|
|
550
|
+
).then(([_, response]) => response)
|
|
551
|
+
)
|
|
552
|
+
);
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
/**
|
|
556
|
+
* Of course, once we get this response back from the server, we
|
|
557
|
+
* tell response cache to actually store the received response
|
|
558
|
+
* to be used later.
|
|
559
|
+
*/
|
|
560
|
+
miss: (response) => responsesCache.set(key, response)
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
return {
|
|
565
|
+
hostsCache,
|
|
566
|
+
requester,
|
|
567
|
+
timeouts,
|
|
568
|
+
logger,
|
|
569
|
+
algoliaAgent,
|
|
570
|
+
baseHeaders,
|
|
571
|
+
baseQueryParameters,
|
|
572
|
+
hosts,
|
|
573
|
+
request: createRequest,
|
|
574
|
+
requestsCache,
|
|
575
|
+
responsesCache
|
|
576
|
+
};
|
|
577
|
+
}
|
|
446
578
|
|
|
447
|
-
|
|
448
|
-
|
|
579
|
+
// src/types/logger.ts
|
|
580
|
+
var LogLevelEnum = {
|
|
581
|
+
Debug: 1,
|
|
582
|
+
Info: 2,
|
|
583
|
+
Error: 3
|
|
584
|
+
};
|
|
449
585
|
|
|
450
|
-
export {
|
|
586
|
+
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, LogLevelEnum, RetryError, createAlgoliaAgent, createAuth, createBrowserLocalStorageCache, createFallbackableCache, createIterablePromise, createMemoryCache, createNullCache, createNullLogger, createStatefulHost, createTransporter, deserializeFailure, deserializeSuccess, getAlgoliaAgent, isNetworkError, isRetryable, isSuccess, serializeData, serializeHeaders, serializeQueryParameters, serializeUrl, shuffle, stackFrameWithoutCredentials, stackTraceWithoutCredentials };
|