generated from thegrind/laravel-dockerized
644 lines
19 KiB
JavaScript
644 lines
19 KiB
JavaScript
// src/cache/createBrowserLocalStorageCache.ts
|
|
function createBrowserLocalStorageCache(options) {
|
|
let storage;
|
|
const namespaceKey = `algolia-client-js-${options.key}`;
|
|
function getStorage() {
|
|
if (storage === void 0) {
|
|
storage = options.localStorage || window.localStorage;
|
|
}
|
|
return storage;
|
|
}
|
|
function getNamespace() {
|
|
return JSON.parse(getStorage().getItem(namespaceKey) || "{}");
|
|
}
|
|
function setNamespace(namespace) {
|
|
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
}
|
|
function removeOutdatedCacheItems() {
|
|
const timeToLive = options.timeToLive ? options.timeToLive * 1e3 : null;
|
|
const namespace = getNamespace();
|
|
const filteredNamespaceWithoutOldFormattedCacheItems = Object.fromEntries(
|
|
Object.entries(namespace).filter(([, cacheItem]) => {
|
|
return cacheItem.timestamp !== void 0;
|
|
})
|
|
);
|
|
setNamespace(filteredNamespaceWithoutOldFormattedCacheItems);
|
|
if (!timeToLive) {
|
|
return;
|
|
}
|
|
const filteredNamespaceWithoutExpiredItems = Object.fromEntries(
|
|
Object.entries(filteredNamespaceWithoutOldFormattedCacheItems).filter(([, cacheItem]) => {
|
|
const currentTimestamp = (/* @__PURE__ */ new Date()).getTime();
|
|
const isExpired = cacheItem.timestamp + timeToLive < currentTimestamp;
|
|
return !isExpired;
|
|
})
|
|
);
|
|
setNamespace(filteredNamespaceWithoutExpiredItems);
|
|
}
|
|
return {
|
|
get(key, defaultValue, events = {
|
|
miss: () => Promise.resolve()
|
|
}) {
|
|
return Promise.resolve().then(() => {
|
|
removeOutdatedCacheItems();
|
|
return getNamespace()[JSON.stringify(key)];
|
|
}).then((value) => {
|
|
return Promise.all([value ? value.value : defaultValue(), value !== void 0]);
|
|
}).then(([value, exists]) => {
|
|
return Promise.all([value, exists || events.miss(value)]);
|
|
}).then(([value]) => value);
|
|
},
|
|
set(key, value) {
|
|
return Promise.resolve().then(() => {
|
|
const namespace = getNamespace();
|
|
namespace[JSON.stringify(key)] = {
|
|
timestamp: (/* @__PURE__ */ new Date()).getTime(),
|
|
value
|
|
};
|
|
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
return value;
|
|
});
|
|
},
|
|
delete(key) {
|
|
return Promise.resolve().then(() => {
|
|
const namespace = getNamespace();
|
|
delete namespace[JSON.stringify(key)];
|
|
getStorage().setItem(namespaceKey, JSON.stringify(namespace));
|
|
});
|
|
},
|
|
clear() {
|
|
return Promise.resolve().then(() => {
|
|
getStorage().removeItem(namespaceKey);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/cache/createNullCache.ts
|
|
function createNullCache() {
|
|
return {
|
|
get(_key, defaultValue, events = {
|
|
miss: () => Promise.resolve()
|
|
}) {
|
|
const value = defaultValue();
|
|
return value.then((result) => Promise.all([result, events.miss(result)])).then(([result]) => result);
|
|
},
|
|
set(_key, value) {
|
|
return Promise.resolve(value);
|
|
},
|
|
delete(_key) {
|
|
return Promise.resolve();
|
|
},
|
|
clear() {
|
|
return Promise.resolve();
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/cache/createFallbackableCache.ts
|
|
function createFallbackableCache(options) {
|
|
const caches = [...options.caches];
|
|
const current = caches.shift();
|
|
if (current === void 0) {
|
|
return createNullCache();
|
|
}
|
|
return {
|
|
get(key, defaultValue, events = {
|
|
miss: () => Promise.resolve()
|
|
}) {
|
|
return current.get(key, defaultValue, events).catch(() => {
|
|
return createFallbackableCache({ caches }).get(key, defaultValue, events);
|
|
});
|
|
},
|
|
set(key, value) {
|
|
return current.set(key, value).catch(() => {
|
|
return createFallbackableCache({ caches }).set(key, value);
|
|
});
|
|
},
|
|
delete(key) {
|
|
return current.delete(key).catch(() => {
|
|
return createFallbackableCache({ caches }).delete(key);
|
|
});
|
|
},
|
|
clear() {
|
|
return current.clear().catch(() => {
|
|
return createFallbackableCache({ caches }).clear();
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/cache/createMemoryCache.ts
|
|
function createMemoryCache(options = { serializable: true }) {
|
|
let cache = {};
|
|
return {
|
|
get(key, defaultValue, events = {
|
|
miss: () => Promise.resolve()
|
|
}) {
|
|
const keyAsString = JSON.stringify(key);
|
|
if (keyAsString in cache) {
|
|
return Promise.resolve(options.serializable ? JSON.parse(cache[keyAsString]) : cache[keyAsString]);
|
|
}
|
|
const promise = defaultValue();
|
|
return promise.then((value) => events.miss(value)).then(() => promise);
|
|
},
|
|
set(key, value) {
|
|
cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
|
|
return Promise.resolve(value);
|
|
},
|
|
delete(key) {
|
|
delete cache[JSON.stringify(key)];
|
|
return Promise.resolve();
|
|
},
|
|
clear() {
|
|
cache = {};
|
|
return Promise.resolve();
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/constants.ts
|
|
var DEFAULT_CONNECT_TIMEOUT_BROWSER = 1e3;
|
|
var DEFAULT_READ_TIMEOUT_BROWSER = 2e3;
|
|
var DEFAULT_WRITE_TIMEOUT_BROWSER = 3e4;
|
|
var DEFAULT_CONNECT_TIMEOUT_NODE = 2e3;
|
|
var DEFAULT_READ_TIMEOUT_NODE = 5e3;
|
|
var DEFAULT_WRITE_TIMEOUT_NODE = 3e4;
|
|
|
|
// src/createAlgoliaAgent.ts
|
|
function createAlgoliaAgent(version) {
|
|
const algoliaAgent = {
|
|
value: `Algolia for JavaScript (${version})`,
|
|
add(options) {
|
|
const addedAlgoliaAgent = `; ${options.segment}${options.version !== void 0 ? ` (${options.version})` : ""}`;
|
|
if (algoliaAgent.value.indexOf(addedAlgoliaAgent) === -1) {
|
|
algoliaAgent.value = `${algoliaAgent.value}${addedAlgoliaAgent}`;
|
|
}
|
|
return algoliaAgent;
|
|
}
|
|
};
|
|
return algoliaAgent;
|
|
}
|
|
|
|
// src/createAuth.ts
|
|
function createAuth(appId, apiKey, authMode = "WithinHeaders") {
|
|
const credentials = {
|
|
"x-algolia-api-key": apiKey,
|
|
"x-algolia-application-id": appId
|
|
};
|
|
return {
|
|
headers() {
|
|
return authMode === "WithinHeaders" ? credentials : {};
|
|
},
|
|
queryParameters() {
|
|
return authMode === "WithinQueryParameters" ? credentials : {};
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/createIterablePromise.ts
|
|
function createIterablePromise({
|
|
func,
|
|
validate,
|
|
aggregator,
|
|
error,
|
|
timeout = () => 0
|
|
}) {
|
|
const retry = (previousResponse) => {
|
|
return new Promise((resolve, reject) => {
|
|
func(previousResponse).then(async (response) => {
|
|
if (aggregator) {
|
|
await aggregator(response);
|
|
}
|
|
if (await validate(response)) {
|
|
return resolve(response);
|
|
}
|
|
if (error && await error.validate(response)) {
|
|
return reject(new Error(await error.message(response)));
|
|
}
|
|
return setTimeout(
|
|
() => {
|
|
retry(response).then(resolve).catch(reject);
|
|
},
|
|
await timeout()
|
|
);
|
|
}).catch((err) => {
|
|
reject(err);
|
|
});
|
|
});
|
|
};
|
|
return retry();
|
|
}
|
|
|
|
// src/getAlgoliaAgent.ts
|
|
function getAlgoliaAgent({ algoliaAgents, client, version }) {
|
|
const defaultAlgoliaAgent = createAlgoliaAgent(version).add({
|
|
segment: client,
|
|
version
|
|
});
|
|
algoliaAgents.forEach((algoliaAgent) => defaultAlgoliaAgent.add(algoliaAgent));
|
|
return defaultAlgoliaAgent;
|
|
}
|
|
|
|
// src/logger/createNullLogger.ts
|
|
function createNullLogger() {
|
|
return {
|
|
debug(_message, _args) {
|
|
return Promise.resolve();
|
|
},
|
|
info(_message, _args) {
|
|
return Promise.resolve();
|
|
},
|
|
error(_message, _args) {
|
|
return Promise.resolve();
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/transporter/createStatefulHost.ts
|
|
var EXPIRATION_DELAY = 2 * 60 * 1e3;
|
|
function createStatefulHost(host, status = "up") {
|
|
const lastUpdate = Date.now();
|
|
function isUp() {
|
|
return status === "up" || Date.now() - lastUpdate > EXPIRATION_DELAY;
|
|
}
|
|
function isTimedOut() {
|
|
return status === "timed out" && Date.now() - lastUpdate <= EXPIRATION_DELAY;
|
|
}
|
|
return { ...host, status, lastUpdate, isUp, isTimedOut };
|
|
}
|
|
|
|
// src/transporter/errors.ts
|
|
var AlgoliaError = class extends Error {
|
|
name = "AlgoliaError";
|
|
constructor(message, name) {
|
|
super(message);
|
|
if (name) {
|
|
this.name = name;
|
|
}
|
|
}
|
|
};
|
|
var IndexNotFoundError = class extends AlgoliaError {
|
|
constructor(indexName) {
|
|
super(`${indexName} does not exist`, "IndexNotFoundError");
|
|
}
|
|
};
|
|
var IndicesInSameAppError = class extends AlgoliaError {
|
|
constructor() {
|
|
super("Indices are in the same application. Use operationIndex instead.", "IndicesInSameAppError");
|
|
}
|
|
};
|
|
var IndexAlreadyExistsError = class extends AlgoliaError {
|
|
constructor(indexName) {
|
|
super(`${indexName} index already exists.`, "IndexAlreadyExistsError");
|
|
}
|
|
};
|
|
var ErrorWithStackTrace = class extends AlgoliaError {
|
|
stackTrace;
|
|
constructor(message, stackTrace, name) {
|
|
super(message, name);
|
|
this.stackTrace = stackTrace;
|
|
}
|
|
};
|
|
var RetryError = class extends ErrorWithStackTrace {
|
|
constructor(stackTrace) {
|
|
super(
|
|
"Unreachable hosts - your application id may be incorrect. If the error persists, please reach out to the Algolia Support team: https://alg.li/support.",
|
|
stackTrace,
|
|
"RetryError"
|
|
);
|
|
}
|
|
};
|
|
var ApiError = class extends ErrorWithStackTrace {
|
|
status;
|
|
constructor(message, status, stackTrace, name = "ApiError") {
|
|
super(message, stackTrace, name);
|
|
this.status = status;
|
|
}
|
|
};
|
|
var DeserializationError = class extends AlgoliaError {
|
|
response;
|
|
constructor(message, response) {
|
|
super(message, "DeserializationError");
|
|
this.response = response;
|
|
}
|
|
};
|
|
var DetailedApiError = class extends ApiError {
|
|
error;
|
|
constructor(message, status, error, stackTrace) {
|
|
super(message, status, stackTrace, "DetailedApiError");
|
|
this.error = error;
|
|
}
|
|
};
|
|
|
|
// src/transporter/helpers.ts
|
|
function shuffle(array) {
|
|
const shuffledArray = array;
|
|
for (let c = array.length - 1; c > 0; c--) {
|
|
const b = Math.floor(Math.random() * (c + 1));
|
|
const a = array[c];
|
|
shuffledArray[c] = array[b];
|
|
shuffledArray[b] = a;
|
|
}
|
|
return shuffledArray;
|
|
}
|
|
function serializeUrl(host, path, queryParameters) {
|
|
const queryParametersAsString = serializeQueryParameters(queryParameters);
|
|
let url = `${host.protocol}://${host.url}${host.port ? `:${host.port}` : ""}/${path.charAt(0) === "/" ? path.substring(1) : path}`;
|
|
if (queryParametersAsString.length) {
|
|
url += `?${queryParametersAsString}`;
|
|
}
|
|
return url;
|
|
}
|
|
function serializeQueryParameters(parameters) {
|
|
return Object.keys(parameters).filter((key) => parameters[key] !== void 0).sort().map(
|
|
(key) => `${key}=${encodeURIComponent(
|
|
Object.prototype.toString.call(parameters[key]) === "[object Array]" ? parameters[key].join(",") : parameters[key]
|
|
).replace(/\+/g, "%20")}`
|
|
).join("&");
|
|
}
|
|
function serializeData(request, requestOptions) {
|
|
if (request.method === "GET" || request.data === void 0 && requestOptions.data === void 0) {
|
|
return void 0;
|
|
}
|
|
const data = Array.isArray(request.data) ? request.data : { ...request.data, ...requestOptions.data };
|
|
return JSON.stringify(data);
|
|
}
|
|
function serializeHeaders(baseHeaders, requestHeaders, requestOptionsHeaders) {
|
|
const headers = {
|
|
Accept: "application/json",
|
|
...baseHeaders,
|
|
...requestHeaders,
|
|
...requestOptionsHeaders
|
|
};
|
|
const serializedHeaders = {};
|
|
Object.keys(headers).forEach((header) => {
|
|
const value = headers[header];
|
|
serializedHeaders[header.toLowerCase()] = value;
|
|
});
|
|
return serializedHeaders;
|
|
}
|
|
function deserializeSuccess(response) {
|
|
try {
|
|
return JSON.parse(response.content);
|
|
} catch (e) {
|
|
throw new DeserializationError(e.message, response);
|
|
}
|
|
}
|
|
function deserializeFailure({ content, status }, stackFrame) {
|
|
try {
|
|
const parsed = JSON.parse(content);
|
|
if ("error" in parsed) {
|
|
return new DetailedApiError(parsed.message, status, parsed.error, stackFrame);
|
|
}
|
|
return new ApiError(parsed.message, status, stackFrame);
|
|
} catch {
|
|
}
|
|
return new ApiError(content, status, stackFrame);
|
|
}
|
|
|
|
// src/transporter/responses.ts
|
|
function isNetworkError({ isTimedOut, status }) {
|
|
return !isTimedOut && ~~status === 0;
|
|
}
|
|
function isRetryable({ isTimedOut, status }) {
|
|
return isTimedOut || isNetworkError({ isTimedOut, status }) || ~~(status / 100) !== 2 && ~~(status / 100) !== 4;
|
|
}
|
|
function isSuccess({ status }) {
|
|
return ~~(status / 100) === 2;
|
|
}
|
|
|
|
// src/transporter/stackTrace.ts
|
|
function stackTraceWithoutCredentials(stackTrace) {
|
|
return stackTrace.map((stackFrame) => stackFrameWithoutCredentials(stackFrame));
|
|
}
|
|
function stackFrameWithoutCredentials(stackFrame) {
|
|
const modifiedHeaders = stackFrame.request.headers["x-algolia-api-key"] ? { "x-algolia-api-key": "*****" } : {};
|
|
return {
|
|
...stackFrame,
|
|
request: {
|
|
...stackFrame.request,
|
|
headers: {
|
|
...stackFrame.request.headers,
|
|
...modifiedHeaders
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/transporter/createTransporter.ts
|
|
function createTransporter({
|
|
hosts,
|
|
hostsCache,
|
|
baseHeaders,
|
|
logger,
|
|
baseQueryParameters,
|
|
algoliaAgent,
|
|
timeouts,
|
|
requester,
|
|
requestsCache,
|
|
responsesCache
|
|
}) {
|
|
async function createRetryableOptions(compatibleHosts) {
|
|
const statefulHosts = await Promise.all(
|
|
compatibleHosts.map((compatibleHost) => {
|
|
return hostsCache.get(compatibleHost, () => {
|
|
return Promise.resolve(createStatefulHost(compatibleHost));
|
|
});
|
|
})
|
|
);
|
|
const hostsUp = statefulHosts.filter((host) => host.isUp());
|
|
const hostsTimedOut = statefulHosts.filter((host) => host.isTimedOut());
|
|
const hostsAvailable = [...hostsUp, ...hostsTimedOut];
|
|
const compatibleHostsAvailable = hostsAvailable.length > 0 ? hostsAvailable : compatibleHosts;
|
|
return {
|
|
hosts: compatibleHostsAvailable,
|
|
getTimeout(timeoutsCount, baseTimeout) {
|
|
const timeoutMultiplier = hostsTimedOut.length === 0 && timeoutsCount === 0 ? 1 : hostsTimedOut.length + 3 + timeoutsCount;
|
|
return timeoutMultiplier * baseTimeout;
|
|
}
|
|
};
|
|
}
|
|
async function retryableRequest(request, requestOptions, isRead = true) {
|
|
const stackTrace = [];
|
|
const data = serializeData(request, requestOptions);
|
|
const headers = serializeHeaders(baseHeaders, request.headers, requestOptions.headers);
|
|
const dataQueryParameters = request.method === "GET" ? {
|
|
...request.data,
|
|
...requestOptions.data
|
|
} : {};
|
|
const queryParameters = {
|
|
...baseQueryParameters,
|
|
...request.queryParameters,
|
|
...dataQueryParameters
|
|
};
|
|
if (algoliaAgent.value) {
|
|
queryParameters["x-algolia-agent"] = algoliaAgent.value;
|
|
}
|
|
if (requestOptions && requestOptions.queryParameters) {
|
|
for (const key of Object.keys(requestOptions.queryParameters)) {
|
|
if (!requestOptions.queryParameters[key] || Object.prototype.toString.call(requestOptions.queryParameters[key]) === "[object Object]") {
|
|
queryParameters[key] = requestOptions.queryParameters[key];
|
|
} else {
|
|
queryParameters[key] = requestOptions.queryParameters[key].toString();
|
|
}
|
|
}
|
|
}
|
|
let timeoutsCount = 0;
|
|
const retry = async (retryableHosts, getTimeout) => {
|
|
const host = retryableHosts.pop();
|
|
if (host === void 0) {
|
|
throw new RetryError(stackTraceWithoutCredentials(stackTrace));
|
|
}
|
|
const timeout = { ...timeouts, ...requestOptions.timeouts };
|
|
const payload = {
|
|
data,
|
|
headers,
|
|
method: request.method,
|
|
url: serializeUrl(host, request.path, queryParameters),
|
|
connectTimeout: getTimeout(timeoutsCount, timeout.connect),
|
|
responseTimeout: getTimeout(timeoutsCount, isRead ? timeout.read : timeout.write)
|
|
};
|
|
const pushToStackTrace = (response2) => {
|
|
const stackFrame = {
|
|
request: payload,
|
|
response: response2,
|
|
host,
|
|
triesLeft: retryableHosts.length
|
|
};
|
|
stackTrace.push(stackFrame);
|
|
return stackFrame;
|
|
};
|
|
const response = await requester.send(payload);
|
|
if (isRetryable(response)) {
|
|
const stackFrame = pushToStackTrace(response);
|
|
if (response.isTimedOut) {
|
|
timeoutsCount++;
|
|
}
|
|
logger.info("Retryable failure", stackFrameWithoutCredentials(stackFrame));
|
|
await hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? "timed out" : "down"));
|
|
return retry(retryableHosts, getTimeout);
|
|
}
|
|
if (isSuccess(response)) {
|
|
return deserializeSuccess(response);
|
|
}
|
|
pushToStackTrace(response);
|
|
throw deserializeFailure(response, stackTrace);
|
|
};
|
|
const compatibleHosts = hosts.filter(
|
|
(host) => host.accept === "readWrite" || (isRead ? host.accept === "read" : host.accept === "write")
|
|
);
|
|
const options = await createRetryableOptions(compatibleHosts);
|
|
return retry([...options.hosts].reverse(), options.getTimeout);
|
|
}
|
|
function createRequest(request, requestOptions = {}) {
|
|
const isRead = request.useReadTransporter || request.method === "GET";
|
|
if (!isRead) {
|
|
return retryableRequest(request, requestOptions, isRead);
|
|
}
|
|
const createRetryableRequest = () => {
|
|
return retryableRequest(request, requestOptions);
|
|
};
|
|
const cacheable = requestOptions.cacheable || request.cacheable;
|
|
if (cacheable !== true) {
|
|
return createRetryableRequest();
|
|
}
|
|
const key = {
|
|
request,
|
|
requestOptions,
|
|
transporter: {
|
|
queryParameters: baseQueryParameters,
|
|
headers: baseHeaders
|
|
}
|
|
};
|
|
return responsesCache.get(
|
|
key,
|
|
() => {
|
|
return requestsCache.get(
|
|
key,
|
|
() => (
|
|
/**
|
|
* Finally, if there is no request in progress with the same key,
|
|
* this `createRetryableRequest()` will actually trigger the
|
|
* retryable request.
|
|
*/
|
|
requestsCache.set(key, createRetryableRequest()).then(
|
|
(response) => Promise.all([requestsCache.delete(key), response]),
|
|
(err) => Promise.all([requestsCache.delete(key), Promise.reject(err)])
|
|
).then(([_, response]) => response)
|
|
)
|
|
);
|
|
},
|
|
{
|
|
/**
|
|
* Of course, once we get this response back from the server, we
|
|
* tell response cache to actually store the received response
|
|
* to be used later.
|
|
*/
|
|
miss: (response) => responsesCache.set(key, response)
|
|
}
|
|
);
|
|
}
|
|
return {
|
|
hostsCache,
|
|
requester,
|
|
timeouts,
|
|
logger,
|
|
algoliaAgent,
|
|
baseHeaders,
|
|
baseQueryParameters,
|
|
hosts,
|
|
request: createRequest,
|
|
requestsCache,
|
|
responsesCache
|
|
};
|
|
}
|
|
|
|
// src/types/logger.ts
|
|
var LogLevelEnum = {
|
|
Debug: 1,
|
|
Info: 2,
|
|
Error: 3
|
|
};
|
|
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,
|
|
IndexAlreadyExistsError,
|
|
IndexNotFoundError,
|
|
IndicesInSameAppError,
|
|
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
|
|
};
|
|
//# sourceMappingURL=common.js.map
|