diff --git a/assets/algoliasearch/README.md b/assets/algoliasearch/README.md
new file mode 100644
index 00000000..9e227e85
--- /dev/null
+++ b/assets/algoliasearch/README.md
@@ -0,0 +1,82 @@
+
+
+
+
+
+
The perfect starting point to integrate Algolia within your JavaScript project
+
+
+
+
+
+
+
+
+
+
+ Documentation •
+ InstantSearch •
+ Community Forum •
+ Stack Overflow •
+ Report a bug •
+ Support
+
+
+## ✨ Features
+
+- Thin & **minimal low-level HTTP client** to interact with Algolia's API
+- Works both on the **browser** and **node.js**
+- **UMD compatible**, you can use it with any module loader
+- Built with TypeScript
+
+## 💡 Getting Started
+
+First, install Algolia JavaScript API Client via the [npm](https://www.npmjs.com/get-npm) package manager:
+
+```bash
+npm install algoliasearch
+```
+
+Then, create objects on your index:
+
+```js
+const algoliasearch = require("algoliasearch");
+
+const client = algoliasearch("YourApplicationID", "YourAdminAPIKey");
+const index = client.initIndex("your_index_name");
+
+const objects = [
+ {
+ objectID: 1,
+ name: "Foo"
+ }
+];
+
+index
+ .saveObjects(objects)
+ .then(({ objectIDs }) => {
+ console.log(objectIDs);
+ })
+ .catch(err => {
+ console.log(err);
+ });
+```
+
+Finally, let's actually search using the `search` method:
+
+```js
+index
+ .search("Fo")
+ .then(({ hits }) => {
+ console.log(hits);
+ })
+ .catch(err => {
+ console.log(err);
+ });
+```
+
+For full documentation, visit the **[online documentation](https://www.algolia.com/doc/api-client/getting-started/install/javascript/)**.
+
+## 📄 License
+
+Algolia JavaScript API Client is an open-sourced software licensed under the [MIT license](LICENSE.md).
diff --git a/assets/algoliasearch/dist/algoliasearch-lite.d.ts b/assets/algoliasearch/dist/algoliasearch-lite.d.ts
new file mode 100644
index 00000000..b408c244
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch-lite.d.ts
@@ -0,0 +1,49 @@
+import { ClientTransporterOptions } from '@algolia/client-common';
+import { FindAnswersOptions } from '@algolia/client-search';
+import { FindAnswersResponse } from '@algolia/client-search';
+import { MultipleQueriesOptions } from '@algolia/client-search';
+import { MultipleQueriesQuery } from '@algolia/client-search';
+import { MultipleQueriesResponse } from '@algolia/client-search';
+import { Request } from '@algolia/transporter';
+import { RequestOptions } from '@algolia/transporter';
+import { SearchClient as SearchClient_2 } from '@algolia/client-search';
+import { SearchClientOptions } from '@algolia/client-search';
+import { SearchForFacetValuesQueryParams } from '@algolia/client-search';
+import { SearchForFacetValuesResponse } from '@algolia/client-search';
+import { SearchIndex as SearchIndex_2 } from '@algolia/client-search';
+import { SearchOptions } from '@algolia/client-search';
+import { SearchResponse } from '@algolia/client-search';
+
+declare function algoliasearch(appId: string, apiKey: string, options?: AlgoliaSearchOptions): SearchClient;
+
+declare namespace algoliasearch {
+ var version: string;
+}
+export default algoliasearch;
+
+export declare type AlgoliaSearchOptions = Partial & WithoutCredentials;
+
+declare type Credentials = {
+ readonly appId: string;
+ readonly apiKey: string;
+};
+
+export declare type SearchClient = SearchClient_2 & {
+ readonly initIndex: (indexName: string) => SearchIndex;
+ readonly search: (queries: readonly MultipleQueriesQuery[], requestOptions?: RequestOptions & MultipleQueriesOptions) => Readonly>>;
+ readonly searchForFacetValues: (queries: ReadonlyArray<{
+ readonly indexName: string;
+ readonly params: SearchForFacetValuesQueryParams & SearchOptions;
+ }>, requestOptions?: RequestOptions) => Readonly>;
+ readonly customRequest: (request: Request, requestOptions?: RequestOptions) => Readonly>;
+};
+
+export declare type SearchIndex = SearchIndex_2 & {
+ readonly search: (query: string, requestOptions?: RequestOptions & SearchOptions) => Readonly>>;
+ readonly searchForFacetValues: (facetName: string, facetQuery: string, requestOptions?: RequestOptions & SearchOptions) => Readonly>;
+ readonly findAnswers: (query: string, queryLanguages: readonly string[], requestOptions?: RequestOptions & FindAnswersOptions) => Readonly>>;
+};
+
+export declare type WithoutCredentials = Omit;
+
+export { }
diff --git a/assets/algoliasearch/dist/algoliasearch-lite.esm.browser.js b/assets/algoliasearch/dist/algoliasearch-lite.esm.browser.js
new file mode 100644
index 00000000..aae2774f
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch-lite.esm.browser.js
@@ -0,0 +1,915 @@
+function createBrowserLocalStorageCache(options) {
+ const namespaceKey = `algoliasearch-client-js-${options.key}`;
+ // eslint-disable-next-line functional/no-let
+ let storage;
+ const getStorage = () => {
+ if (storage === undefined) {
+ storage = options.localStorage || window.localStorage;
+ }
+ return storage;
+ };
+ const getNamespace = () => {
+ return JSON.parse(getStorage().getItem(namespaceKey) || '{}');
+ };
+ return {
+ get(key, defaultValue, events = {
+ miss: () => Promise.resolve(),
+ }) {
+ return Promise.resolve()
+ .then(() => {
+ const keyAsString = JSON.stringify(key);
+ const value = getNamespace()[keyAsString];
+ return Promise.all([value || defaultValue(), value !== undefined]);
+ })
+ .then(([value, exists]) => {
+ return Promise.all([value, exists || events.miss(value)]);
+ })
+ .then(([value]) => value);
+ },
+ set(key, value) {
+ return Promise.resolve().then(() => {
+ const namespace = getNamespace();
+ // eslint-disable-next-line functional/immutable-data
+ namespace[JSON.stringify(key)] = value;
+ getStorage().setItem(namespaceKey, JSON.stringify(namespace));
+ return value;
+ });
+ },
+ delete(key) {
+ return Promise.resolve().then(() => {
+ const namespace = getNamespace();
+ // eslint-disable-next-line functional/immutable-data
+ delete namespace[JSON.stringify(key)];
+ getStorage().setItem(namespaceKey, JSON.stringify(namespace));
+ });
+ },
+ clear() {
+ return Promise.resolve().then(() => {
+ getStorage().removeItem(namespaceKey);
+ });
+ },
+ };
+}
+
+// @todo Add logger on options to debug when caches go wrong.
+function createFallbackableCache(options) {
+ const caches = [...options.caches];
+ const current = caches.shift(); // eslint-disable-line functional/immutable-data
+ if (current === undefined) {
+ 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();
+ });
+ },
+ };
+}
+
+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();
+ },
+ };
+}
+
+function createInMemoryCache(options = { serializable: true }) {
+ // eslint-disable-next-line functional/no-let
+ 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();
+ const miss = (events && events.miss) || (() => Promise.resolve());
+ return promise.then((value) => miss(value)).then(() => promise);
+ },
+ set(key, value) {
+ // eslint-disable-next-line functional/immutable-data
+ cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
+ return Promise.resolve(value);
+ },
+ delete(key) {
+ // eslint-disable-next-line functional/immutable-data
+ delete cache[JSON.stringify(key)];
+ return Promise.resolve();
+ },
+ clear() {
+ cache = {};
+ return Promise.resolve();
+ },
+ };
+}
+
+function createAuth(authMode, appId, apiKey) {
+ const credentials = {
+ 'x-algolia-api-key': apiKey,
+ 'x-algolia-application-id': appId,
+ };
+ return {
+ headers() {
+ return authMode === AuthMode.WithinHeaders ? credentials : {};
+ },
+ queryParameters() {
+ return authMode === AuthMode.WithinQueryParameters ? credentials : {};
+ },
+ };
+}
+
+// eslint-disable-next-line functional/prefer-readonly-type
+function shuffle(array) {
+ let c = array.length - 1; // eslint-disable-line functional/no-let
+ // eslint-disable-next-line functional/no-loop-statement
+ for (c; c > 0; c--) {
+ const b = Math.floor(Math.random() * (c + 1));
+ const a = array[c];
+ array[c] = array[b]; // eslint-disable-line functional/immutable-data, no-param-reassign
+ array[b] = a; // eslint-disable-line functional/immutable-data, no-param-reassign
+ }
+ return array;
+}
+function addMethods(base, methods) {
+ if (!methods) {
+ return base;
+ }
+ Object.keys(methods).forEach(key => {
+ // eslint-disable-next-line functional/immutable-data, no-param-reassign
+ base[key] = methods[key](base);
+ });
+ return base;
+}
+function encode(format, ...args) {
+ // eslint-disable-next-line functional/no-let
+ let i = 0;
+ return format.replace(/%s/g, () => encodeURIComponent(args[i++]));
+}
+
+const version = '4.14.2';
+
+const AuthMode = {
+ /**
+ * If auth credentials should be in query parameters.
+ */
+ WithinQueryParameters: 0,
+ /**
+ * If auth credentials should be in headers.
+ */
+ WithinHeaders: 1,
+};
+
+function createMappedRequestOptions(requestOptions, timeout) {
+ const options = requestOptions || {};
+ const data = options.data || {};
+ Object.keys(options).forEach(key => {
+ if (['timeout', 'headers', 'queryParameters', 'data', 'cacheable'].indexOf(key) === -1) {
+ data[key] = options[key]; // eslint-disable-line functional/immutable-data
+ }
+ });
+ return {
+ data: Object.entries(data).length > 0 ? data : undefined,
+ timeout: options.timeout || timeout,
+ headers: options.headers || {},
+ queryParameters: options.queryParameters || {},
+ cacheable: options.cacheable,
+ };
+}
+
+const CallEnum = {
+ /**
+ * If the host is read only.
+ */
+ Read: 1,
+ /**
+ * If the host is write only.
+ */
+ Write: 2,
+ /**
+ * If the host is both read and write.
+ */
+ Any: 3,
+};
+
+const HostStatusEnum = {
+ Up: 1,
+ Down: 2,
+ Timeouted: 3,
+};
+
+// By default, API Clients at Algolia have expiration delay
+// of 5 mins. In the JavaScript client, we have 2 mins.
+const EXPIRATION_DELAY = 2 * 60 * 1000;
+function createStatefulHost(host, status = HostStatusEnum.Up) {
+ return {
+ ...host,
+ status,
+ lastUpdate: Date.now(),
+ };
+}
+function isStatefulHostUp(host) {
+ return host.status === HostStatusEnum.Up || Date.now() - host.lastUpdate > EXPIRATION_DELAY;
+}
+function isStatefulHostTimeouted(host) {
+ return (host.status === HostStatusEnum.Timeouted && Date.now() - host.lastUpdate <= EXPIRATION_DELAY);
+}
+
+function createStatelessHost(options) {
+ if (typeof options === 'string') {
+ return {
+ protocol: 'https',
+ url: options,
+ accept: CallEnum.Any,
+ };
+ }
+ return {
+ protocol: options.protocol || 'https',
+ url: options.url,
+ accept: options.accept || CallEnum.Any,
+ };
+}
+
+const MethodEnum = {
+ Delete: 'DELETE',
+ Get: 'GET',
+ Post: 'POST',
+ Put: 'PUT',
+};
+
+function createRetryableOptions(hostsCache, statelessHosts) {
+ return Promise.all(statelessHosts.map(statelessHost => {
+ return hostsCache.get(statelessHost, () => {
+ return Promise.resolve(createStatefulHost(statelessHost));
+ });
+ })).then(statefulHosts => {
+ const hostsUp = statefulHosts.filter(host => isStatefulHostUp(host));
+ const hostsTimeouted = statefulHosts.filter(host => isStatefulHostTimeouted(host));
+ /**
+ * Note, we put the hosts that previously timeouted on the end of the list.
+ */
+ const hostsAvailable = [...hostsUp, ...hostsTimeouted];
+ const statelessHostsAvailable = hostsAvailable.length > 0
+ ? hostsAvailable.map(host => createStatelessHost(host))
+ : statelessHosts;
+ return {
+ getTimeout(timeoutsCount, baseTimeout) {
+ /**
+ * Imagine that you have 4 hosts, if timeouts will increase
+ * on the following way: 1 (timeouted) > 4 (timeouted) > 5 (200)
+ *
+ * Note that, the very next request, we start from the previous timeout
+ *
+ * 5 (timeouted) > 6 (timeouted) > 7 ...
+ *
+ * This strategy may need to be reviewed, but is the strategy on the our
+ * current v3 version.
+ */
+ const timeoutMultiplier = hostsTimeouted.length === 0 && timeoutsCount === 0
+ ? 1
+ : hostsTimeouted.length + 3 + timeoutsCount;
+ return timeoutMultiplier * baseTimeout;
+ },
+ statelessHosts: statelessHostsAvailable,
+ };
+ });
+}
+
+const isNetworkError = ({ isTimedOut, status }) => {
+ return !isTimedOut && ~~status === 0;
+};
+const isRetryable = (response) => {
+ const status = response.status;
+ const isTimedOut = response.isTimedOut;
+ return (isTimedOut || isNetworkError(response) || (~~(status / 100) !== 2 && ~~(status / 100) !== 4));
+};
+const isSuccess = ({ status }) => {
+ return ~~(status / 100) === 2;
+};
+const retryDecision = (response, outcomes) => {
+ if (isRetryable(response)) {
+ return outcomes.onRetry(response);
+ }
+ if (isSuccess(response)) {
+ return outcomes.onSuccess(response);
+ }
+ return outcomes.onFail(response);
+};
+
+function retryableRequest(transporter, statelessHosts, request, requestOptions) {
+ const stackTrace = []; // eslint-disable-line functional/prefer-readonly-type
+ /**
+ * First we prepare the payload that do not depend from hosts.
+ */
+ const data = serializeData(request, requestOptions);
+ const headers = serializeHeaders(transporter, requestOptions);
+ const method = request.method;
+ // On `GET`, the data is proxied to query parameters.
+ const dataQueryParameters = request.method !== MethodEnum.Get
+ ? {}
+ : {
+ ...request.data,
+ ...requestOptions.data,
+ };
+ const queryParameters = {
+ 'x-algolia-agent': transporter.userAgent.value,
+ ...transporter.queryParameters,
+ ...dataQueryParameters,
+ ...requestOptions.queryParameters,
+ };
+ let timeoutsCount = 0; // eslint-disable-line functional/no-let
+ const retry = (hosts, // eslint-disable-line functional/prefer-readonly-type
+ getTimeout) => {
+ /**
+ * We iterate on each host, until there is no host left.
+ */
+ const host = hosts.pop(); // eslint-disable-line functional/immutable-data
+ if (host === undefined) {
+ throw createRetryError(stackTraceWithoutCredentials(stackTrace));
+ }
+ const payload = {
+ data,
+ headers,
+ method,
+ url: serializeUrl(host, request.path, queryParameters),
+ connectTimeout: getTimeout(timeoutsCount, transporter.timeouts.connect),
+ responseTimeout: getTimeout(timeoutsCount, requestOptions.timeout),
+ };
+ /**
+ * The stackFrame is pushed to the stackTrace so we
+ * can have information about onRetry and onFailure
+ * decisions.
+ */
+ const pushToStackTrace = (response) => {
+ const stackFrame = {
+ request: payload,
+ response,
+ host,
+ triesLeft: hosts.length,
+ };
+ // eslint-disable-next-line functional/immutable-data
+ stackTrace.push(stackFrame);
+ return stackFrame;
+ };
+ const decisions = {
+ onSuccess: response => deserializeSuccess(response),
+ onRetry(response) {
+ const stackFrame = pushToStackTrace(response);
+ /**
+ * If response is a timeout, we increaset the number of
+ * timeouts so we can increase the timeout later.
+ */
+ if (response.isTimedOut) {
+ timeoutsCount++;
+ }
+ return Promise.all([
+ /**
+ * Failures are individually send the logger, allowing
+ * the end user to debug / store stack frames even
+ * when a retry error does not happen.
+ */
+ transporter.logger.info('Retryable failure', stackFrameWithoutCredentials(stackFrame)),
+ /**
+ * We also store the state of the host in failure cases. If the host, is
+ * down it will remain down for the next 2 minutes. In a timeout situation,
+ * this host will be added end of the list of hosts on the next request.
+ */
+ transporter.hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? HostStatusEnum.Timeouted : HostStatusEnum.Down)),
+ ]).then(() => retry(hosts, getTimeout));
+ },
+ onFail(response) {
+ pushToStackTrace(response);
+ throw deserializeFailure(response, stackTraceWithoutCredentials(stackTrace));
+ },
+ };
+ return transporter.requester.send(payload).then(response => {
+ return retryDecision(response, decisions);
+ });
+ };
+ /**
+ * Finally, for each retryable host perform request until we got a non
+ * retryable response. Some notes here:
+ *
+ * 1. The reverse here is applied so we can apply a `pop` later on => more performant.
+ * 2. We also get from the retryable options a timeout multiplier that is tailored
+ * for the current context.
+ */
+ return createRetryableOptions(transporter.hostsCache, statelessHosts).then(options => {
+ return retry([...options.statelessHosts].reverse(), options.getTimeout);
+ });
+}
+
+function createTransporter(options) {
+ const { hostsCache, logger, requester, requestsCache, responsesCache, timeouts, userAgent, hosts, queryParameters, headers, } = options;
+ const transporter = {
+ hostsCache,
+ logger,
+ requester,
+ requestsCache,
+ responsesCache,
+ timeouts,
+ userAgent,
+ headers,
+ queryParameters,
+ hosts: hosts.map(host => createStatelessHost(host)),
+ read(request, requestOptions) {
+ /**
+ * First, we compute the user request options. Now, keep in mind,
+ * that using request options the user is able to modified the intire
+ * payload of the request. Such as headers, query parameters, and others.
+ */
+ const mappedRequestOptions = createMappedRequestOptions(requestOptions, transporter.timeouts.read);
+ const createRetryableRequest = () => {
+ /**
+ * Then, we prepare a function factory that contains the construction of
+ * the retryable request. At this point, we may *not* perform the actual
+ * request. But we want to have the function factory ready.
+ */
+ return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Read) !== 0), request, mappedRequestOptions);
+ };
+ /**
+ * Once we have the function factory ready, we need to determine of the
+ * request is "cacheable" - should be cached. Note that, once again,
+ * the user can force this option.
+ */
+ const cacheable = mappedRequestOptions.cacheable !== undefined
+ ? mappedRequestOptions.cacheable
+ : request.cacheable;
+ /**
+ * If is not "cacheable", we immediatly trigger the retryable request, no
+ * need to check cache implementations.
+ */
+ if (cacheable !== true) {
+ return createRetryableRequest();
+ }
+ /**
+ * If the request is "cacheable", we need to first compute the key to ask
+ * the cache implementations if this request is on progress or if the
+ * response already exists on the cache.
+ */
+ const key = {
+ request,
+ mappedRequestOptions,
+ transporter: {
+ queryParameters: transporter.queryParameters,
+ headers: transporter.headers,
+ },
+ };
+ /**
+ * With the computed key, we first ask the responses cache
+ * implemention if this request was been resolved before.
+ */
+ return transporter.responsesCache.get(key, () => {
+ /**
+ * If the request has never resolved before, we actually ask if there
+ * is a current request with the same key on progress.
+ */
+ return transporter.requestsCache.get(key, () => {
+ return (transporter.requestsCache
+ /**
+ * Finally, if there is no request in progress with the same key,
+ * this `createRetryableRequest()` will actually trigger the
+ * retryable request.
+ */
+ .set(key, createRetryableRequest())
+ .then(response => Promise.all([transporter.requestsCache.delete(key), response]), err => Promise.all([transporter.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 => transporter.responsesCache.set(key, response),
+ });
+ },
+ write(request, requestOptions) {
+ /**
+ * On write requests, no cache mechanisms are applied, and we
+ * proxy the request immediately to the requester.
+ */
+ return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Write) !== 0), request, createMappedRequestOptions(requestOptions, transporter.timeouts.write));
+ },
+ };
+ return transporter;
+}
+
+function createUserAgent(version) {
+ const userAgent = {
+ value: `Algolia for JavaScript (${version})`,
+ add(options) {
+ const addedUserAgent = `; ${options.segment}${options.version !== undefined ? ` (${options.version})` : ''}`;
+ if (userAgent.value.indexOf(addedUserAgent) === -1) {
+ // eslint-disable-next-line functional/immutable-data
+ userAgent.value = `${userAgent.value}${addedUserAgent}`;
+ }
+ return userAgent;
+ },
+ };
+ return userAgent;
+}
+
+function deserializeSuccess(response) {
+ // eslint-disable-next-line functional/no-try-statement
+ try {
+ return JSON.parse(response.content);
+ }
+ catch (e) {
+ throw createDeserializationError(e.message, response);
+ }
+}
+function deserializeFailure({ content, status }, stackFrame) {
+ // eslint-disable-next-line functional/no-let
+ let message = content;
+ // eslint-disable-next-line functional/no-try-statement
+ try {
+ message = JSON.parse(content).message;
+ }
+ catch (e) {
+ // ..
+ }
+ return createApiError(message, status, stackFrame);
+}
+
+function serializeUrl(host, path, queryParameters) {
+ const queryParametersAsString = serializeQueryParameters(queryParameters);
+ // eslint-disable-next-line functional/no-let
+ let url = `${host.protocol}://${host.url}/${path.charAt(0) === '/' ? path.substr(1) : path}`;
+ if (queryParametersAsString.length) {
+ url += `?${queryParametersAsString}`;
+ }
+ return url;
+}
+function serializeQueryParameters(parameters) {
+ const isObjectOrArray = (value) => Object.prototype.toString.call(value) === '[object Object]' ||
+ Object.prototype.toString.call(value) === '[object Array]';
+ return Object.keys(parameters)
+ .map(key => encode('%s=%s', key, isObjectOrArray(parameters[key]) ? JSON.stringify(parameters[key]) : parameters[key]))
+ .join('&');
+}
+function serializeData(request, requestOptions) {
+ if (request.method === MethodEnum.Get ||
+ (request.data === undefined && requestOptions.data === undefined)) {
+ return undefined;
+ }
+ const data = Array.isArray(request.data)
+ ? request.data
+ : { ...request.data, ...requestOptions.data };
+ return JSON.stringify(data);
+}
+function serializeHeaders(transporter, requestOptions) {
+ const headers = {
+ ...transporter.headers,
+ ...requestOptions.headers,
+ };
+ const serializedHeaders = {};
+ Object.keys(headers).forEach(header => {
+ const value = headers[header];
+ // @ts-ignore
+ // eslint-disable-next-line functional/immutable-data
+ serializedHeaders[header.toLowerCase()] = value;
+ });
+ return serializedHeaders;
+}
+
+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,
+ },
+ },
+ };
+}
+
+function createApiError(message, status, transporterStackTrace) {
+ return {
+ name: 'ApiError',
+ message,
+ status,
+ transporterStackTrace,
+ };
+}
+
+function createDeserializationError(message, response) {
+ return {
+ name: 'DeserializationError',
+ message,
+ response,
+ };
+}
+
+function createRetryError(transporterStackTrace) {
+ return {
+ name: 'RetryError',
+ message: 'Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.',
+ transporterStackTrace,
+ };
+}
+
+const createSearchClient = options => {
+ const appId = options.appId;
+ const auth = createAuth(options.authMode !== undefined ? options.authMode : AuthMode.WithinHeaders, appId, options.apiKey);
+ const transporter = createTransporter({
+ hosts: [
+ { url: `${appId}-dsn.algolia.net`, accept: CallEnum.Read },
+ { url: `${appId}.algolia.net`, accept: CallEnum.Write },
+ ].concat(shuffle([
+ { url: `${appId}-1.algolianet.com` },
+ { url: `${appId}-2.algolianet.com` },
+ { url: `${appId}-3.algolianet.com` },
+ ])),
+ ...options,
+ headers: {
+ ...auth.headers(),
+ ...{ 'content-type': 'application/x-www-form-urlencoded' },
+ ...options.headers,
+ },
+ queryParameters: {
+ ...auth.queryParameters(),
+ ...options.queryParameters,
+ },
+ });
+ const base = {
+ transporter,
+ appId,
+ addAlgoliaAgent(segment, version) {
+ transporter.userAgent.add({ segment, version });
+ },
+ clearCache() {
+ return Promise.all([
+ transporter.requestsCache.clear(),
+ transporter.responsesCache.clear(),
+ ]).then(() => undefined);
+ },
+ };
+ return addMethods(base, options.methods);
+};
+
+const customRequest = (base) => {
+ return (request, requestOptions) => {
+ if (request.method === MethodEnum.Get) {
+ return base.transporter.read(request, requestOptions);
+ }
+ return base.transporter.write(request, requestOptions);
+ };
+};
+
+const initIndex = (base) => {
+ return (indexName, options = {}) => {
+ const searchIndex = {
+ transporter: base.transporter,
+ appId: base.appId,
+ indexName,
+ };
+ return addMethods(searchIndex, options.methods);
+ };
+};
+
+const multipleQueries = (base) => {
+ return (queries, requestOptions) => {
+ const requests = queries.map(query => {
+ return {
+ ...query,
+ params: serializeQueryParameters(query.params || {}),
+ };
+ });
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: '1/indexes/*/queries',
+ data: {
+ requests,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const multipleSearchForFacetValues = (base) => {
+ return (queries, requestOptions) => {
+ return Promise.all(queries.map(query => {
+ const { facetName, facetQuery, ...params } = query.params;
+ return initIndex(base)(query.indexName, {
+ methods: { searchForFacetValues },
+ }).searchForFacetValues(facetName, facetQuery, {
+ ...requestOptions,
+ ...params,
+ });
+ }));
+ };
+};
+
+const findAnswers = (base) => {
+ return (query, queryLanguages, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/answers/%s/prediction', base.indexName),
+ data: {
+ query,
+ queryLanguages,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const search = (base) => {
+ return (query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/query', base.indexName),
+ data: {
+ query,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const searchForFacetValues = (base) => {
+ return (facetName, facetQuery, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/facets/%s/query', base.indexName, facetName),
+ data: {
+ facetQuery,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const LogLevelEnum = {
+ Debug: 1,
+ Info: 2,
+ Error: 3,
+};
+
+/* eslint no-console: 0 */
+function createConsoleLogger(logLevel) {
+ return {
+ debug(message, args) {
+ if (LogLevelEnum.Debug >= logLevel) {
+ console.debug(message, args);
+ }
+ return Promise.resolve();
+ },
+ info(message, args) {
+ if (LogLevelEnum.Info >= logLevel) {
+ console.info(message, args);
+ }
+ return Promise.resolve();
+ },
+ error(message, args) {
+ console.error(message, args);
+ return Promise.resolve();
+ },
+ };
+}
+
+function createBrowserXhrRequester() {
+ return {
+ send(request) {
+ return new Promise((resolve) => {
+ const baseRequester = new XMLHttpRequest();
+ baseRequester.open(request.method, request.url, true);
+ Object.keys(request.headers).forEach(key => baseRequester.setRequestHeader(key, request.headers[key]));
+ const createTimeout = (timeout, content) => {
+ return setTimeout(() => {
+ baseRequester.abort();
+ resolve({
+ status: 0,
+ content,
+ isTimedOut: true,
+ });
+ }, timeout * 1000);
+ };
+ const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
+ // eslint-disable-next-line functional/no-let
+ let responseTimeout;
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onreadystatechange = () => {
+ if (baseRequester.readyState > baseRequester.OPENED && responseTimeout === undefined) {
+ clearTimeout(connectTimeout);
+ responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
+ }
+ };
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onerror = () => {
+ // istanbul ignore next
+ if (baseRequester.status === 0) {
+ clearTimeout(connectTimeout);
+ clearTimeout(responseTimeout);
+ resolve({
+ content: baseRequester.responseText || 'Network request failed',
+ status: baseRequester.status,
+ isTimedOut: false,
+ });
+ }
+ };
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onload = () => {
+ clearTimeout(connectTimeout);
+ clearTimeout(responseTimeout);
+ resolve({
+ content: baseRequester.responseText,
+ status: baseRequester.status,
+ isTimedOut: false,
+ });
+ };
+ baseRequester.send(request.data);
+ });
+ },
+ };
+}
+
+function algoliasearch(appId, apiKey, options) {
+ const commonOptions = {
+ appId,
+ apiKey,
+ timeouts: {
+ connect: 1,
+ read: 2,
+ write: 30,
+ },
+ requester: createBrowserXhrRequester(),
+ logger: createConsoleLogger(LogLevelEnum.Error),
+ responsesCache: createInMemoryCache(),
+ requestsCache: createInMemoryCache({ serializable: false }),
+ hostsCache: createFallbackableCache({
+ caches: [
+ createBrowserLocalStorageCache({ key: `${version}-${appId}` }),
+ createInMemoryCache(),
+ ],
+ }),
+ userAgent: createUserAgent(version).add({
+ segment: 'Browser',
+ version: 'lite',
+ }),
+ authMode: AuthMode.WithinQueryParameters,
+ };
+ return createSearchClient({
+ ...commonOptions,
+ ...options,
+ methods: {
+ search: multipleQueries,
+ searchForFacetValues: multipleSearchForFacetValues,
+ multipleQueries,
+ multipleSearchForFacetValues,
+ customRequest,
+ initIndex: base => (indexName) => {
+ return initIndex(base)(indexName, {
+ methods: { search, searchForFacetValues, findAnswers },
+ });
+ },
+ },
+ });
+}
+// eslint-disable-next-line functional/immutable-data
+algoliasearch.version = version;
+
+export default algoliasearch;
diff --git a/assets/algoliasearch/dist/algoliasearch-lite.umd.js b/assets/algoliasearch/dist/algoliasearch-lite.umd.js
new file mode 100644
index 00000000..0dad1433
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch-lite.umd.js
@@ -0,0 +1,2 @@
+/*! algoliasearch-lite.umd.js | 4.14.2 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).algoliasearch=t()}(this,(function(){"use strict";function e(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}function o(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if(!(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)))return;var r=[],n=!0,o=!1,a=void 0;try{for(var u,i=e[Symbol.iterator]();!(n=(u=i.next()).done)&&(r.push(u.value),!t||r.length!==t);n=!0);}catch(e){o=!0,a=e}finally{try{n||null==i.return||i.return()}finally{if(o)throw a}}return r}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function a(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){var r=JSON.stringify(e),n=a()[r];return Promise.all([n||t(),void 0!==n])})).then((function(e){var t=o(e,2),n=t[0],a=t[1];return Promise.all([n,a||r.miss(n)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve().then((function(){var o=a();return o[JSON.stringify(e)]=t,n().setItem(r,JSON.stringify(o)),t}))},delete:function(e){return Promise.resolve().then((function(){var t=a();delete t[JSON.stringify(e)],n().setItem(r,JSON.stringify(t))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function i(e){var t=a(e.caches),r=t.shift();return void 0===r?{get:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},n=t();return n.then((function(e){return Promise.all([e,r.miss(e)])})).then((function(e){return o(e,1)[0]}))},set:function(e,t){return Promise.resolve(t)},delete:function(e){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(e,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(e,n,o).catch((function(){return i({caches:t}).get(e,n,o)}))},set:function(e,n){return r.set(e,n).catch((function(){return i({caches:t}).set(e,n)}))},delete:function(e){return r.delete(e).catch((function(){return i({caches:t}).delete(e)}))},clear:function(){return r.clear().catch((function(){return i({caches:t}).clear()}))}}}function s(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},t={};return{get:function(r,n){var o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},a=JSON.stringify(r);if(a in t)return Promise.resolve(e.serializable?JSON.parse(t[a]):t[a]);var u=n(),i=o&&o.miss||function(){return Promise.resolve()};return u.then((function(e){return i(e)})).then((function(){return u}))},set:function(r,n){return t[JSON.stringify(r)]=e.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(e){return delete t[JSON.stringify(e)],Promise.resolve()},clear:function(){return t={},Promise.resolve()}}}function c(e){for(var t=e.length-1;t>0;t--){var r=Math.floor(Math.random()*(t+1)),n=e[t];e[t]=e[r],e[r]=n}return e}function l(e,t){return t?(Object.keys(t).forEach((function(r){e[r]=t[r](e)})),e):e}function f(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n0?n:void 0,timeout:r.timeout||t,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var m={Read:1,Write:2,Any:3},p=1,v=2,y=3;function g(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:p;return r(r({},e),{},{status:t,lastUpdate:Date.now()})}function b(e){return"string"==typeof e?{protocol:"https",url:e,accept:m.Any}:{protocol:e.protocol||"https",url:e.url,accept:e.accept||m.Any}}var O="GET",P="POST";function q(e,t){return Promise.all(t.map((function(t){return e.get(t,(function(){return Promise.resolve(g(t))}))}))).then((function(e){var r=e.filter((function(e){return function(e){return e.status===p||Date.now()-e.lastUpdate>12e4}(e)})),n=e.filter((function(e){return function(e){return e.status===y&&Date.now()-e.lastUpdate<=12e4}(e)})),o=[].concat(a(r),a(n));return{getTimeout:function(e,t){return(0===n.length&&0===e?1:n.length+3+e)*t},statelessHosts:o.length>0?o.map((function(e){return b(e)})):t}}))}function w(e,t,n,o){var u=[],i=function(e,t){if(e.method===O||void 0===e.data&&void 0===t.data)return;var n=Array.isArray(e.data)?e.data:r(r({},e.data),t.data);return JSON.stringify(n)}(n,o),s=function(e,t){var n=r(r({},e.headers),t.headers),o={};return Object.keys(n).forEach((function(e){var t=n[e];o[e.toLowerCase()]=t})),o}(e,o),c=n.method,l=n.method!==O?{}:r(r({},n.data),o.data),f=r(r(r({"x-algolia-agent":e.userAgent.value},e.queryParameters),l),o.queryParameters),h=0,d=function t(r,a){var l=r.pop();if(void 0===l)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:A(u)};var d={data:i,headers:s,method:c,url:S(l,n.path,f),connectTimeout:a(h,e.timeouts.connect),responseTimeout:a(h,o.timeout)},m=function(e){var t={request:d,response:e,host:l,triesLeft:r.length};return u.push(t),t},p={onSuccess:function(e){return function(e){try{return JSON.parse(e.content)}catch(t){throw function(e,t){return{name:"DeserializationError",message:e,response:t}}(t.message,e)}}(e)},onRetry:function(n){var o=m(n);return n.isTimedOut&&h++,Promise.all([e.logger.info("Retryable failure",x(o)),e.hostsCache.set(l,g(l,n.isTimedOut?y:v))]).then((function(){return t(r,a)}))},onFail:function(e){throw m(e),function(e,t){var r=e.content,n=e.status,o=r;try{o=JSON.parse(r).message}catch(e){}return function(e,t,r){return{name:"ApiError",message:e,status:t,transporterStackTrace:r}}(o,n,t)}(e,A(u))}};return e.requester.send(d).then((function(e){return function(e,t){return function(e){var t=e.status;return e.isTimedOut||function(e){var t=e.isTimedOut,r=e.status;return!t&&0==~~r}(e)||2!=~~(t/100)&&4!=~~(t/100)}(e)?t.onRetry(e):2==~~(e.status/100)?t.onSuccess(e):t.onFail(e)}(e,p)}))};return q(e.hostsCache,t).then((function(e){return d(a(e.statelessHosts).reverse(),e.getTimeout)}))}function j(e){var t={value:"Algolia for JavaScript (".concat(e,")"),add:function(e){var r="; ".concat(e.segment).concat(void 0!==e.version?" (".concat(e.version,")"):"");return-1===t.value.indexOf(r)&&(t.value="".concat(t.value).concat(r)),t}};return t}function S(e,t,r){var n=T(r),o="".concat(e.protocol,"://").concat(e.url,"/").concat("/"===t.charAt(0)?t.substr(1):t);return n.length&&(o+="?".concat(n)),o}function T(e){return Object.keys(e).map((function(t){return f("%s=%s",t,(r=e[t],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(e[t]):e[t]));var r})).join("&")}function A(e){return e.map((function(e){return x(e)}))}function x(e){var t=e.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},e),{},{request:r(r({},e.request),{},{headers:r(r({},e.request.headers),t)})})}var N=function(e){var t=e.appId,n=function(e,t,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":t};return{headers:function(){return e===h.WithinHeaders?n:{}},queryParameters:function(){return e===h.WithinQueryParameters?n:{}}}}(void 0!==e.authMode?e.authMode:h.WithinHeaders,t,e.apiKey),a=function(e){var t=e.hostsCache,r=e.logger,n=e.requester,a=e.requestsCache,u=e.responsesCache,i=e.timeouts,s=e.userAgent,c=e.hosts,l=e.queryParameters,f={hostsCache:t,logger:r,requester:n,requestsCache:a,responsesCache:u,timeouts:i,userAgent:s,headers:e.headers,queryParameters:l,hosts:c.map((function(e){return b(e)})),read:function(e,t){var r=d(t,f.timeouts.read),n=function(){return w(f,f.hosts.filter((function(e){return 0!=(e.accept&m.Read)})),e,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:e.cacheable))return n();var a={request:e,mappedRequestOptions:r,transporter:{queryParameters:f.queryParameters,headers:f.headers}};return f.responsesCache.get(a,(function(){return f.requestsCache.get(a,(function(){return f.requestsCache.set(a,n()).then((function(e){return Promise.all([f.requestsCache.delete(a),e])}),(function(e){return Promise.all([f.requestsCache.delete(a),Promise.reject(e)])})).then((function(e){var t=o(e,2);t[0];return t[1]}))}))}),{miss:function(e){return f.responsesCache.set(a,e)}})},write:function(e,t){return w(f,f.hosts.filter((function(e){return 0!=(e.accept&m.Write)})),e,d(t,f.timeouts.write))}};return f}(r(r({hosts:[{url:"".concat(t,"-dsn.algolia.net"),accept:m.Read},{url:"".concat(t,".algolia.net"),accept:m.Write}].concat(c([{url:"".concat(t,"-1.algolianet.com")},{url:"".concat(t,"-2.algolianet.com")},{url:"".concat(t,"-3.algolianet.com")}]))},e),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),e.headers),queryParameters:r(r({},n.queryParameters()),e.queryParameters)}));return l({transporter:a,appId:t,addAlgoliaAgent:function(e,t){a.userAgent.add({segment:e,version:t})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},e.methods)},C=function(e){return function(t,r){return t.method===O?e.transporter.read(t,r):e.transporter.write(t,r)}},k=function(e){return function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={transporter:e.transporter,appId:e.appId,indexName:t};return l(n,r.methods)}},J=function(e){return function(t,n){var o=t.map((function(e){return r(r({},e),{},{params:T(e.params||{})})}));return e.transporter.read({method:P,path:"1/indexes/*/queries",data:{requests:o},cacheable:!0},n)}},E=function(e){return function(t,o){return Promise.all(t.map((function(t){var a=t.params,u=a.facetName,i=a.facetQuery,s=n(a,["facetName","facetQuery"]);return k(e)(t.indexName,{methods:{searchForFacetValues:R}}).searchForFacetValues(u,i,r(r({},o),s))})))}},I=function(e){return function(t,r,n){return e.transporter.read({method:P,path:f("1/answers/%s/prediction",e.indexName),data:{query:t,queryLanguages:r},cacheable:!0},n)}},F=function(e){return function(t,r){return e.transporter.read({method:P,path:f("1/indexes/%s/query",e.indexName),data:{query:t},cacheable:!0},r)}},R=function(e){return function(t,r,n){return e.transporter.read({method:P,path:f("1/indexes/%s/facets/%s/query",e.indexName,t),data:{facetQuery:r},cacheable:!0},n)}},D=1,W=2,H=3;function Q(e,t,n){var o,a={appId:e,apiKey:t,timeouts:{connect:1,read:2,write:30},requester:{send:function(e){return new Promise((function(t){var r=new XMLHttpRequest;r.open(e.method,e.url,!0),Object.keys(e.headers).forEach((function(t){return r.setRequestHeader(t,e.headers[t])}));var n,o=function(e,n){return setTimeout((function(){r.abort(),t({status:0,content:n,isTimedOut:!0})}),1e3*e)},a=o(e.connectTimeout,"Connection timeout");r.onreadystatechange=function(){r.readyState>r.OPENED&&void 0===n&&(clearTimeout(a),n=o(e.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(a),clearTimeout(n),t({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(a),clearTimeout(n),t({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(e.data)}))}},logger:(o=H,{debug:function(e,t){return D>=o&&console.debug(e,t),Promise.resolve()},info:function(e,t){return W>=o&&console.info(e,t),Promise.resolve()},error:function(e,t){return console.error(e,t),Promise.resolve()}}),responsesCache:s(),requestsCache:s({serializable:!1}),hostsCache:i({caches:[u({key:"".concat("4.14.2","-").concat(e)}),s()]}),userAgent:j("4.14.2").add({segment:"Browser",version:"lite"}),authMode:h.WithinQueryParameters};return N(r(r(r({},a),n),{},{methods:{search:J,searchForFacetValues:E,multipleQueries:J,multipleSearchForFacetValues:E,customRequest:C,initIndex:function(e){return function(t){return k(e)(t,{methods:{search:F,searchForFacetValues:R,findAnswers:I}})}}}}))}return Q.version="4.14.2",Q}));
diff --git a/assets/algoliasearch/dist/algoliasearch.cjs.js b/assets/algoliasearch/dist/algoliasearch.cjs.js
new file mode 100644
index 00000000..aa74431a
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch.cjs.js
@@ -0,0 +1,156 @@
+'use strict';
+
+var cacheCommon = require('@algolia/cache-common');
+var cacheInMemory = require('@algolia/cache-in-memory');
+var clientAnalytics = require('@algolia/client-analytics');
+var clientCommon = require('@algolia/client-common');
+var clientPersonalization = require('@algolia/client-personalization');
+var clientSearch = require('@algolia/client-search');
+var loggerCommon = require('@algolia/logger-common');
+var requesterNodeHttp = require('@algolia/requester-node-http');
+var transporter = require('@algolia/transporter');
+
+function algoliasearch(appId, apiKey, options) {
+ const commonOptions = {
+ appId,
+ apiKey,
+ timeouts: {
+ connect: 2,
+ read: 5,
+ write: 30,
+ },
+ requester: requesterNodeHttp.createNodeHttpRequester(),
+ logger: loggerCommon.createNullLogger(),
+ responsesCache: cacheCommon.createNullCache(),
+ requestsCache: cacheCommon.createNullCache(),
+ hostsCache: cacheInMemory.createInMemoryCache(),
+ userAgent: transporter.createUserAgent(clientCommon.version).add({
+ segment: 'Node.js',
+ version: process.versions.node,
+ }),
+ };
+ const searchClientOptions = { ...commonOptions, ...options };
+ const initPersonalization = () => (clientOptions) => {
+ return clientPersonalization.createPersonalizationClient({
+ ...commonOptions,
+ ...clientOptions,
+ methods: {
+ getPersonalizationStrategy: clientPersonalization.getPersonalizationStrategy,
+ setPersonalizationStrategy: clientPersonalization.setPersonalizationStrategy,
+ },
+ });
+ };
+ return clientSearch.createSearchClient({
+ ...searchClientOptions,
+ methods: {
+ search: clientSearch.multipleQueries,
+ searchForFacetValues: clientSearch.multipleSearchForFacetValues,
+ multipleBatch: clientSearch.multipleBatch,
+ multipleGetObjects: clientSearch.multipleGetObjects,
+ multipleQueries: clientSearch.multipleQueries,
+ copyIndex: clientSearch.copyIndex,
+ copySettings: clientSearch.copySettings,
+ copyRules: clientSearch.copyRules,
+ copySynonyms: clientSearch.copySynonyms,
+ moveIndex: clientSearch.moveIndex,
+ listIndices: clientSearch.listIndices,
+ getLogs: clientSearch.getLogs,
+ listClusters: clientSearch.listClusters,
+ multipleSearchForFacetValues: clientSearch.multipleSearchForFacetValues,
+ getApiKey: clientSearch.getApiKey,
+ addApiKey: clientSearch.addApiKey,
+ listApiKeys: clientSearch.listApiKeys,
+ updateApiKey: clientSearch.updateApiKey,
+ deleteApiKey: clientSearch.deleteApiKey,
+ restoreApiKey: clientSearch.restoreApiKey,
+ assignUserID: clientSearch.assignUserID,
+ assignUserIDs: clientSearch.assignUserIDs,
+ getUserID: clientSearch.getUserID,
+ searchUserIDs: clientSearch.searchUserIDs,
+ listUserIDs: clientSearch.listUserIDs,
+ getTopUserIDs: clientSearch.getTopUserIDs,
+ removeUserID: clientSearch.removeUserID,
+ hasPendingMappings: clientSearch.hasPendingMappings,
+ generateSecuredApiKey: clientSearch.generateSecuredApiKey,
+ getSecuredApiKeyRemainingValidity: clientSearch.getSecuredApiKeyRemainingValidity,
+ destroy: clientCommon.destroy,
+ clearDictionaryEntries: clientSearch.clearDictionaryEntries,
+ deleteDictionaryEntries: clientSearch.deleteDictionaryEntries,
+ getDictionarySettings: clientSearch.getDictionarySettings,
+ getAppTask: clientSearch.getAppTask,
+ replaceDictionaryEntries: clientSearch.replaceDictionaryEntries,
+ saveDictionaryEntries: clientSearch.saveDictionaryEntries,
+ searchDictionaryEntries: clientSearch.searchDictionaryEntries,
+ setDictionarySettings: clientSearch.setDictionarySettings,
+ waitAppTask: clientSearch.waitAppTask,
+ customRequest: clientSearch.customRequest,
+ initIndex: base => (indexName) => {
+ return clientSearch.initIndex(base)(indexName, {
+ methods: {
+ batch: clientSearch.batch,
+ delete: clientSearch.deleteIndex,
+ findAnswers: clientSearch.findAnswers,
+ getObject: clientSearch.getObject,
+ getObjects: clientSearch.getObjects,
+ saveObject: clientSearch.saveObject,
+ saveObjects: clientSearch.saveObjects,
+ search: clientSearch.search,
+ searchForFacetValues: clientSearch.searchForFacetValues,
+ waitTask: clientSearch.waitTask,
+ setSettings: clientSearch.setSettings,
+ getSettings: clientSearch.getSettings,
+ partialUpdateObject: clientSearch.partialUpdateObject,
+ partialUpdateObjects: clientSearch.partialUpdateObjects,
+ deleteObject: clientSearch.deleteObject,
+ deleteObjects: clientSearch.deleteObjects,
+ deleteBy: clientSearch.deleteBy,
+ clearObjects: clientSearch.clearObjects,
+ browseObjects: clientSearch.browseObjects,
+ getObjectPosition: clientSearch.getObjectPosition,
+ findObject: clientSearch.findObject,
+ exists: clientSearch.exists,
+ saveSynonym: clientSearch.saveSynonym,
+ saveSynonyms: clientSearch.saveSynonyms,
+ getSynonym: clientSearch.getSynonym,
+ searchSynonyms: clientSearch.searchSynonyms,
+ browseSynonyms: clientSearch.browseSynonyms,
+ deleteSynonym: clientSearch.deleteSynonym,
+ clearSynonyms: clientSearch.clearSynonyms,
+ replaceAllObjects: clientSearch.replaceAllObjects,
+ replaceAllSynonyms: clientSearch.replaceAllSynonyms,
+ searchRules: clientSearch.searchRules,
+ getRule: clientSearch.getRule,
+ deleteRule: clientSearch.deleteRule,
+ saveRule: clientSearch.saveRule,
+ saveRules: clientSearch.saveRules,
+ replaceAllRules: clientSearch.replaceAllRules,
+ browseRules: clientSearch.browseRules,
+ clearRules: clientSearch.clearRules,
+ },
+ });
+ },
+ initAnalytics: () => (clientOptions) => {
+ return clientAnalytics.createAnalyticsClient({
+ ...commonOptions,
+ ...clientOptions,
+ methods: {
+ addABTest: clientAnalytics.addABTest,
+ getABTest: clientAnalytics.getABTest,
+ getABTests: clientAnalytics.getABTests,
+ stopABTest: clientAnalytics.stopABTest,
+ deleteABTest: clientAnalytics.deleteABTest,
+ },
+ });
+ },
+ initPersonalization,
+ initRecommendation: () => (clientOptions) => {
+ searchClientOptions.logger.info('The `initRecommendation` method is deprecated. Use `initPersonalization` instead.');
+ return initPersonalization()(clientOptions);
+ },
+ },
+ });
+}
+// eslint-disable-next-line functional/immutable-data
+algoliasearch.version = clientCommon.version;
+
+module.exports = algoliasearch;
diff --git a/assets/algoliasearch/dist/algoliasearch.d.ts b/assets/algoliasearch/dist/algoliasearch.d.ts
new file mode 100644
index 00000000..554c1eed
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch.d.ts
@@ -0,0 +1,247 @@
+import { ABTest } from '@algolia/client-analytics';
+import { AddABTestResponse } from '@algolia/client-analytics';
+import { AddApiKeyOptions } from '@algolia/client-search';
+import { AddApiKeyResponse } from '@algolia/client-search';
+import { AnalyticsClient as AnalyticsClient_2 } from '@algolia/client-analytics';
+import { AnalyticsClientOptions } from '@algolia/client-analytics';
+import { ApiKeyACLType } from '@algolia/client-search';
+import { AssignUserIDResponse } from '@algolia/client-search';
+import { AssignUserIDsResponse } from '@algolia/client-search';
+import { BatchRequest } from '@algolia/client-search';
+import { BatchResponse } from '@algolia/client-search';
+import { BrowseOptions } from '@algolia/client-search';
+import { ChunkedBatchResponse } from '@algolia/client-search';
+import { ChunkOptions } from '@algolia/client-search';
+import { ClearRulesOptions } from '@algolia/client-search';
+import { ClearSynonymsOptions } from '@algolia/client-search';
+import { ClientTransporterOptions } from '@algolia/client-common';
+import { CopyIndexOptions } from '@algolia/client-search';
+import { DeleteABTestResponse } from '@algolia/client-analytics';
+import { DeleteApiKeyResponse } from '@algolia/client-search';
+import { DeleteByFiltersOptions } from '@algolia/client-search';
+import { DeleteResponse } from '@algolia/client-search';
+import { DeleteSynonymOptions } from '@algolia/client-search';
+import { Destroyable } from '@algolia/requester-common';
+import { DictionaryEntriesOptions } from '@algolia/client-search';
+import { DictionaryEntriesResponse } from '@algolia/client-search';
+import { DictionaryEntry } from '@algolia/client-search';
+import { DictionaryName } from '@algolia/client-search';
+import { DictionarySettings } from '@algolia/client-search';
+import { FindAnswersOptions } from '@algolia/client-search';
+import { FindAnswersResponse } from '@algolia/client-search';
+import { FindObjectOptions } from '@algolia/client-search';
+import { FindObjectResponse } from '@algolia/client-search';
+import { GetABTestResponse } from '@algolia/client-analytics';
+import { GetABTestsOptions } from '@algolia/client-analytics';
+import { GetABTestsResponse } from '@algolia/client-analytics';
+import { GetApiKeyResponse } from '@algolia/client-search';
+import { GetDictionarySettingsResponse } from '@algolia/client-search';
+import { GetLogsResponse } from '@algolia/client-search';
+import { GetObjectOptions } from '@algolia/client-search';
+import { GetObjectsOptions } from '@algolia/client-search';
+import { GetObjectsResponse } from '@algolia/client-search';
+import { GetPersonalizationStrategyResponse } from '@algolia/client-personalization';
+import { GetTopUserIDsResponse } from '@algolia/client-search';
+import { HasPendingMappingsOptions } from '@algolia/client-search';
+import { HasPendingMappingsResponse } from '@algolia/client-search';
+import { IndexOperationResponse } from '@algolia/client-search';
+import { ListApiKeysResponse } from '@algolia/client-search';
+import { ListClustersResponse } from '@algolia/client-search';
+import { ListIndicesResponse } from '@algolia/client-search';
+import { ListUserIDsOptions } from '@algolia/client-search';
+import { ListUserIDsResponse } from '@algolia/client-search';
+import { MultipleBatchRequest } from '@algolia/client-search';
+import { MultipleBatchResponse } from '@algolia/client-search';
+import { MultipleGetObject } from '@algolia/client-search';
+import { MultipleGetObjectsResponse } from '@algolia/client-search';
+import { MultipleQueriesOptions } from '@algolia/client-search';
+import { MultipleQueriesQuery } from '@algolia/client-search';
+import { MultipleQueriesResponse } from '@algolia/client-search';
+import { ObjectWithObjectID } from '@algolia/client-search';
+import { PartialUpdateObjectResponse } from '@algolia/client-search';
+import { PartialUpdateObjectsOptions } from '@algolia/client-search';
+import { PersonalizationClient as PersonalizationClient_2 } from '@algolia/client-personalization';
+import { PersonalizationClientOptions } from '@algolia/client-personalization';
+import { PersonalizationStrategy } from '@algolia/client-personalization';
+import { RemoveUserIDResponse } from '@algolia/client-search';
+import { ReplaceAllObjectsOptions } from '@algolia/client-search';
+import { Request } from '@algolia/transporter';
+import { RequestOptions } from '@algolia/transporter';
+import { RestoreApiKeyResponse } from '@algolia/client-search';
+import { Rule } from '@algolia/client-search';
+import { SaveObjectResponse } from '@algolia/client-search';
+import { SaveObjectsOptions } from '@algolia/client-search';
+import { SaveRuleResponse } from '@algolia/client-search';
+import { SaveRulesOptions } from '@algolia/client-search';
+import { SaveRulesResponse } from '@algolia/client-search';
+import { SaveSynonymResponse } from '@algolia/client-search';
+import { SaveSynonymsOptions } from '@algolia/client-search';
+import { SaveSynonymsResponse } from '@algolia/client-search';
+import { SearchClient as SearchClient_2 } from '@algolia/client-search';
+import { SearchClientOptions } from '@algolia/client-search';
+import { SearchDictionaryEntriesResponse } from '@algolia/client-search';
+import { SearchForFacetValuesQueryParams } from '@algolia/client-search';
+import { SearchForFacetValuesResponse } from '@algolia/client-search';
+import { SearchIndex as SearchIndex_2 } from '@algolia/client-search';
+import { SearchOptions } from '@algolia/client-search';
+import { SearchResponse } from '@algolia/client-search';
+import { SearchRulesOptions } from '@algolia/client-search';
+import { SearchSynonymsOptions } from '@algolia/client-search';
+import { SearchSynonymsResponse } from '@algolia/client-search';
+import { SearchUserIDsOptions } from '@algolia/client-search';
+import { SearchUserIDsResponse } from '@algolia/client-search';
+import { SecuredApiKeyRestrictions } from '@algolia/client-search';
+import { SetPersonalizationStrategyResponse } from '@algolia/client-personalization';
+import { SetSettingsResponse } from '@algolia/client-search';
+import { Settings } from '@algolia/client-search';
+import { StopABTestResponse } from '@algolia/client-analytics';
+import { Synonym } from '@algolia/client-search';
+import { TaskStatusResponse } from '@algolia/client-search';
+import { UpdateApiKeyOptions } from '@algolia/client-search';
+import { UpdateApiKeyResponse } from '@algolia/client-search';
+import { UserIDResponse } from '@algolia/client-search';
+import { WaitablePromise } from '@algolia/client-common';
+
+declare function algoliasearch(appId: string, apiKey: string, options?: AlgoliaSearchOptions): SearchClient;
+
+declare namespace algoliasearch {
+ var version: string;
+}
+export default algoliasearch;
+
+export declare type AlgoliaSearchOptions = Partial & WithoutCredentials;
+
+export declare type AnalyticsClient = AnalyticsClient_2 & {
+ readonly addABTest: (abTest: ABTest, requestOptions?: RequestOptions) => Readonly>;
+ readonly getABTest: (abTestID: number, requestOptions?: RequestOptions) => Readonly>;
+ readonly getABTests: (requestOptions?: RequestOptions & GetABTestsOptions) => Readonly>;
+ readonly stopABTest: (abTestID: number, requestOptions?: RequestOptions) => Readonly>;
+ readonly deleteABTest: (abTestID: number, requestOptions?: RequestOptions) => Readonly>;
+};
+
+declare type Credentials = {
+ readonly appId: string;
+ readonly apiKey: string;
+};
+
+export declare type InitAnalyticsOptions = Partial & OptionalCredentials;
+
+export declare type InitPersonalizationOptions = Partial & OptionalCredentials;
+
+/**
+ * @deprecated Use `InitPersonalizationOptions` instead.
+ */
+export declare type InitRecommendationOptions = InitPersonalizationOptions;
+
+export declare type OptionalCredentials = Omit & Pick, keyof Credentials>;
+
+export declare type PersonalizationClient = PersonalizationClient_2 & {
+ readonly getPersonalizationStrategy: (requestOptions?: RequestOptions) => Readonly>;
+ readonly setPersonalizationStrategy: (personalizationStrategy: PersonalizationStrategy, requestOptions?: RequestOptions) => Readonly>;
+};
+
+/**
+ * @deprecated Use `PersonalizationClient` instead.
+ */
+export declare type RecommendationClient = PersonalizationClient;
+
+export declare type SearchClient = SearchClient_2 & {
+ readonly initIndex: (indexName: string) => SearchIndex;
+ readonly search: (queries: readonly MultipleQueriesQuery[], requestOptions?: RequestOptions & MultipleQueriesOptions) => Readonly>>;
+ readonly searchForFacetValues: (queries: ReadonlyArray<{
+ readonly indexName: string;
+ readonly params: SearchForFacetValuesQueryParams & SearchOptions;
+ }>, requestOptions?: RequestOptions) => Readonly>;
+ readonly multipleBatch: (requests: readonly MultipleBatchRequest[], requestOptions?: RequestOptions) => Readonly>;
+ readonly multipleGetObjects: (requests: readonly MultipleGetObject[], requestOptions?: RequestOptions) => Readonly>>;
+ readonly multipleQueries: (queries: readonly MultipleQueriesQuery[], requestOptions?: RequestOptions & MultipleQueriesOptions) => Readonly>>;
+ readonly copyIndex: (from: string, to: string, requestOptions?: CopyIndexOptions & RequestOptions) => Readonly>;
+ readonly copySettings: (from: string, to: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly copyRules: (from: string, to: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly copySynonyms: (from: string, to: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly moveIndex: (from: string, to: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly listIndices: (requestOptions?: RequestOptions) => Readonly>;
+ readonly getLogs: (requestOptions?: RequestOptions) => Readonly>;
+ readonly listClusters: (requestOptions?: RequestOptions) => Readonly>;
+ readonly multipleSearchForFacetValues: (queries: ReadonlyArray<{
+ readonly indexName: string;
+ readonly params: SearchForFacetValuesQueryParams & SearchOptions;
+ }>, requestOptions?: RequestOptions) => Readonly>;
+ readonly getApiKey: (apiKey: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly addApiKey: (acl: readonly ApiKeyACLType[], requestOptions?: AddApiKeyOptions & Pick>) => Readonly>;
+ readonly listApiKeys: (requestOptions?: RequestOptions) => Readonly>;
+ readonly updateApiKey: (apiKey: string, requestOptions?: UpdateApiKeyOptions & Pick>) => Readonly>;
+ readonly deleteApiKey: (apiKey: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly restoreApiKey: (apiKey: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly assignUserID: (userID: string, clusterName: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly assignUserIDs: (userIDs: readonly string[], clusterName: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly getUserID: (userID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly searchUserIDs: (query: string, requestOptions?: SearchUserIDsOptions & RequestOptions) => Readonly>;
+ readonly listUserIDs: (requestOptions?: ListUserIDsOptions & RequestOptions) => Readonly>;
+ readonly getTopUserIDs: (requestOptions?: RequestOptions) => Readonly>;
+ readonly removeUserID: (userID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly hasPendingMappings: (requestOptions?: HasPendingMappingsOptions & RequestOptions) => Readonly>;
+ readonly generateSecuredApiKey: (parentApiKey: string, restrictions: SecuredApiKeyRestrictions) => string;
+ readonly getSecuredApiKeyRemainingValidity: (securedApiKey: string) => number;
+ readonly clearDictionaryEntries: (dictionary: DictionaryName, requestOptions?: RequestOptions & DictionaryEntriesOptions) => Readonly>;
+ readonly deleteDictionaryEntries: (dictionary: DictionaryName, objectIDs: readonly string[], requestOptions?: RequestOptions & DictionaryEntriesOptions) => Readonly>;
+ readonly replaceDictionaryEntries: (dictionary: DictionaryName, entries: readonly DictionaryEntry[], requestOptions?: RequestOptions & DictionaryEntriesOptions) => Readonly>;
+ readonly saveDictionaryEntries: (dictionary: DictionaryName, entries: readonly DictionaryEntry[], requestOptions?: RequestOptions & DictionaryEntriesOptions) => Readonly>;
+ readonly searchDictionaryEntries: (dictionary: DictionaryName, query: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly getDictionarySettings: (requestOptions?: RequestOptions) => Readonly>;
+ readonly setDictionarySettings: (settings: DictionarySettings, requestOptions?: RequestOptions) => Readonly>;
+ readonly getAppTask: (taskID: number, requestOptions?: RequestOptions) => Readonly>;
+ readonly customRequest: (request: Request, requestOptions?: RequestOptions) => Readonly>;
+ readonly initAnalytics: (options?: InitAnalyticsOptions) => AnalyticsClient;
+ readonly initPersonalization: (options?: InitPersonalizationOptions) => PersonalizationClient;
+ /**
+ * @deprecated Use `initPersonalization` instead.
+ */
+ readonly initRecommendation: (options?: InitPersonalizationOptions) => PersonalizationClient;
+} & Destroyable;
+
+export declare type SearchIndex = SearchIndex_2 & {
+ readonly search: (query: string, requestOptions?: RequestOptions & SearchOptions) => Readonly>>;
+ readonly searchForFacetValues: (facetName: string, facetQuery: string, requestOptions?: RequestOptions & SearchOptions) => Readonly>;
+ readonly findAnswers: (query: string, queryLanguages: readonly string[], requestOptions?: RequestOptions & FindAnswersOptions) => Readonly>>;
+ readonly batch: (requests: readonly BatchRequest[], requestOptions?: RequestOptions) => Readonly>;
+ readonly delete: (requestOptions?: RequestOptions) => Readonly>;
+ readonly getObject: (objectID: string, requestOptions?: RequestOptions & GetObjectOptions) => Readonly>;
+ readonly getObjects: (objectIDs: readonly string[], requestOptions?: RequestOptions & GetObjectsOptions) => Readonly>>;
+ readonly saveObject: (object: Readonly>, requestOptions?: RequestOptions & ChunkOptions & SaveObjectsOptions) => Readonly>;
+ readonly saveObjects: (objects: ReadonlyArray>>, requestOptions?: RequestOptions & ChunkOptions & SaveObjectsOptions) => Readonly>;
+ readonly waitTask: (taskID: number, requestOptions?: RequestOptions) => Readonly>;
+ readonly setSettings: (settings: Settings, requestOptions?: RequestOptions) => Readonly>;
+ readonly getSettings: (requestOptions?: RequestOptions) => Readonly>;
+ readonly partialUpdateObject: (object: Record, requestOptions?: RequestOptions & ChunkOptions & PartialUpdateObjectsOptions) => Readonly>;
+ readonly partialUpdateObjects: (objects: ReadonlyArray>, requestOptions?: RequestOptions & ChunkOptions & PartialUpdateObjectsOptions) => Readonly>;
+ readonly deleteObject: (objectID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly deleteObjects: (objectIDs: readonly string[], requestOptions?: RequestOptions & ChunkOptions) => Readonly>;
+ readonly deleteBy: (filters: DeleteByFiltersOptions, requestOptions?: RequestOptions) => Readonly>;
+ readonly clearObjects: (requestOptions?: RequestOptions) => Readonly>;
+ readonly browseObjects: (requestOptions?: SearchOptions & BrowseOptions & RequestOptions) => Readonly>;
+ readonly getObjectPosition: (searchResponse: SearchResponse<{}>, objectID: string) => number;
+ readonly findObject: (callback: (object: TObject & ObjectWithObjectID) => boolean, requestOptions?: FindObjectOptions & RequestOptions) => Readonly>>;
+ readonly exists: (requestOptions?: RequestOptions) => Readonly>;
+ readonly saveSynonym: (synonym: Synonym, requestOptions?: RequestOptions & SaveSynonymsOptions) => Readonly>;
+ readonly saveSynonyms: (synonyms: readonly Synonym[], requestOptions?: SaveSynonymsOptions & RequestOptions) => Readonly>;
+ readonly getSynonym: (objectID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly searchSynonyms: (query: string, requestOptions?: SearchSynonymsOptions & RequestOptions) => Readonly>;
+ readonly browseSynonyms: (requestOptions?: SearchSynonymsOptions & BrowseOptions & RequestOptions) => Readonly>;
+ readonly deleteSynonym: (objectID: string, requestOptions?: DeleteSynonymOptions & RequestOptions) => Readonly>;
+ readonly clearSynonyms: (requestOptions?: ClearSynonymsOptions & RequestOptions) => Readonly>;
+ readonly replaceAllObjects: (objects: ReadonlyArray>>, requestOptions?: ReplaceAllObjectsOptions & ChunkOptions & SaveObjectsOptions & RequestOptions) => Readonly>;
+ readonly replaceAllSynonyms: (synonyms: readonly Synonym[], requestOptions?: RequestOptions & Pick>) => Readonly>;
+ readonly searchRules: (query: string, requestOptions?: RequestOptions & SearchRulesOptions) => Readonly>>;
+ readonly getRule: (objectID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly deleteRule: (objectID: string, requestOptions?: RequestOptions) => Readonly>;
+ readonly saveRule: (rule: Rule, requestOptions?: RequestOptions & SaveRulesOptions) => Readonly>;
+ readonly saveRules: (rules: readonly Rule[], requestOptions?: RequestOptions & SaveRulesOptions) => Readonly>;
+ readonly replaceAllRules: (rules: readonly Rule[], requestOptions?: RequestOptions & SaveRulesOptions) => Readonly>;
+ readonly browseRules: (requestOptions?: SearchRulesOptions & BrowseOptions & RequestOptions) => Readonly>;
+ readonly clearRules: (requestOptions?: RequestOptions & ClearRulesOptions) => Readonly>;
+};
+
+export declare type WithoutCredentials = Omit;
+
+export { }
diff --git a/assets/algoliasearch/dist/algoliasearch.esm.browser.js b/assets/algoliasearch/dist/algoliasearch.esm.browser.js
new file mode 100644
index 00000000..3168b2a4
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch.esm.browser.js
@@ -0,0 +1,2221 @@
+function createBrowserLocalStorageCache(options) {
+ const namespaceKey = `algoliasearch-client-js-${options.key}`;
+ // eslint-disable-next-line functional/no-let
+ let storage;
+ const getStorage = () => {
+ if (storage === undefined) {
+ storage = options.localStorage || window.localStorage;
+ }
+ return storage;
+ };
+ const getNamespace = () => {
+ return JSON.parse(getStorage().getItem(namespaceKey) || '{}');
+ };
+ return {
+ get(key, defaultValue, events = {
+ miss: () => Promise.resolve(),
+ }) {
+ return Promise.resolve()
+ .then(() => {
+ const keyAsString = JSON.stringify(key);
+ const value = getNamespace()[keyAsString];
+ return Promise.all([value || defaultValue(), value !== undefined]);
+ })
+ .then(([value, exists]) => {
+ return Promise.all([value, exists || events.miss(value)]);
+ })
+ .then(([value]) => value);
+ },
+ set(key, value) {
+ return Promise.resolve().then(() => {
+ const namespace = getNamespace();
+ // eslint-disable-next-line functional/immutable-data
+ namespace[JSON.stringify(key)] = value;
+ getStorage().setItem(namespaceKey, JSON.stringify(namespace));
+ return value;
+ });
+ },
+ delete(key) {
+ return Promise.resolve().then(() => {
+ const namespace = getNamespace();
+ // eslint-disable-next-line functional/immutable-data
+ delete namespace[JSON.stringify(key)];
+ getStorage().setItem(namespaceKey, JSON.stringify(namespace));
+ });
+ },
+ clear() {
+ return Promise.resolve().then(() => {
+ getStorage().removeItem(namespaceKey);
+ });
+ },
+ };
+}
+
+// @todo Add logger on options to debug when caches go wrong.
+function createFallbackableCache(options) {
+ const caches = [...options.caches];
+ const current = caches.shift(); // eslint-disable-line functional/immutable-data
+ if (current === undefined) {
+ 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();
+ });
+ },
+ };
+}
+
+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();
+ },
+ };
+}
+
+function createInMemoryCache(options = { serializable: true }) {
+ // eslint-disable-next-line functional/no-let
+ 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();
+ const miss = (events && events.miss) || (() => Promise.resolve());
+ return promise.then((value) => miss(value)).then(() => promise);
+ },
+ set(key, value) {
+ // eslint-disable-next-line functional/immutable-data
+ cache[JSON.stringify(key)] = options.serializable ? JSON.stringify(value) : value;
+ return Promise.resolve(value);
+ },
+ delete(key) {
+ // eslint-disable-next-line functional/immutable-data
+ delete cache[JSON.stringify(key)];
+ return Promise.resolve();
+ },
+ clear() {
+ cache = {};
+ return Promise.resolve();
+ },
+ };
+}
+
+function createAuth(authMode, appId, apiKey) {
+ const credentials = {
+ 'x-algolia-api-key': apiKey,
+ 'x-algolia-application-id': appId,
+ };
+ return {
+ headers() {
+ return authMode === AuthMode.WithinHeaders ? credentials : {};
+ },
+ queryParameters() {
+ return authMode === AuthMode.WithinQueryParameters ? credentials : {};
+ },
+ };
+}
+
+function createRetryablePromise(callback) {
+ let retriesCount = 0; // eslint-disable-line functional/no-let
+ const retry = () => {
+ retriesCount++;
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(callback(retry));
+ }, Math.min(100 * retriesCount, 1000));
+ });
+ };
+ return callback(retry);
+}
+
+function createWaitablePromise(promise, wait = (_response, _requestOptions) => {
+ return Promise.resolve();
+}) {
+ // eslint-disable-next-line functional/immutable-data
+ return Object.assign(promise, {
+ wait(requestOptions) {
+ return createWaitablePromise(promise
+ .then(response => Promise.all([wait(response, requestOptions), response]))
+ .then(promiseResults => promiseResults[1]));
+ },
+ });
+}
+
+// eslint-disable-next-line functional/prefer-readonly-type
+function shuffle(array) {
+ let c = array.length - 1; // eslint-disable-line functional/no-let
+ // eslint-disable-next-line functional/no-loop-statement
+ for (c; c > 0; c--) {
+ const b = Math.floor(Math.random() * (c + 1));
+ const a = array[c];
+ array[c] = array[b]; // eslint-disable-line functional/immutable-data, no-param-reassign
+ array[b] = a; // eslint-disable-line functional/immutable-data, no-param-reassign
+ }
+ return array;
+}
+function addMethods(base, methods) {
+ if (!methods) {
+ return base;
+ }
+ Object.keys(methods).forEach(key => {
+ // eslint-disable-next-line functional/immutable-data, no-param-reassign
+ base[key] = methods[key](base);
+ });
+ return base;
+}
+function encode(format, ...args) {
+ // eslint-disable-next-line functional/no-let
+ let i = 0;
+ return format.replace(/%s/g, () => encodeURIComponent(args[i++]));
+}
+
+const version = '4.14.2';
+
+const AuthMode = {
+ /**
+ * If auth credentials should be in query parameters.
+ */
+ WithinQueryParameters: 0,
+ /**
+ * If auth credentials should be in headers.
+ */
+ WithinHeaders: 1,
+};
+
+function createMappedRequestOptions(requestOptions, timeout) {
+ const options = requestOptions || {};
+ const data = options.data || {};
+ Object.keys(options).forEach(key => {
+ if (['timeout', 'headers', 'queryParameters', 'data', 'cacheable'].indexOf(key) === -1) {
+ data[key] = options[key]; // eslint-disable-line functional/immutable-data
+ }
+ });
+ return {
+ data: Object.entries(data).length > 0 ? data : undefined,
+ timeout: options.timeout || timeout,
+ headers: options.headers || {},
+ queryParameters: options.queryParameters || {},
+ cacheable: options.cacheable,
+ };
+}
+
+const CallEnum = {
+ /**
+ * If the host is read only.
+ */
+ Read: 1,
+ /**
+ * If the host is write only.
+ */
+ Write: 2,
+ /**
+ * If the host is both read and write.
+ */
+ Any: 3,
+};
+
+const HostStatusEnum = {
+ Up: 1,
+ Down: 2,
+ Timeouted: 3,
+};
+
+// By default, API Clients at Algolia have expiration delay
+// of 5 mins. In the JavaScript client, we have 2 mins.
+const EXPIRATION_DELAY = 2 * 60 * 1000;
+function createStatefulHost(host, status = HostStatusEnum.Up) {
+ return {
+ ...host,
+ status,
+ lastUpdate: Date.now(),
+ };
+}
+function isStatefulHostUp(host) {
+ return host.status === HostStatusEnum.Up || Date.now() - host.lastUpdate > EXPIRATION_DELAY;
+}
+function isStatefulHostTimeouted(host) {
+ return (host.status === HostStatusEnum.Timeouted && Date.now() - host.lastUpdate <= EXPIRATION_DELAY);
+}
+
+function createStatelessHost(options) {
+ if (typeof options === 'string') {
+ return {
+ protocol: 'https',
+ url: options,
+ accept: CallEnum.Any,
+ };
+ }
+ return {
+ protocol: options.protocol || 'https',
+ url: options.url,
+ accept: options.accept || CallEnum.Any,
+ };
+}
+
+const MethodEnum = {
+ Delete: 'DELETE',
+ Get: 'GET',
+ Post: 'POST',
+ Put: 'PUT',
+};
+
+function createRetryableOptions(hostsCache, statelessHosts) {
+ return Promise.all(statelessHosts.map(statelessHost => {
+ return hostsCache.get(statelessHost, () => {
+ return Promise.resolve(createStatefulHost(statelessHost));
+ });
+ })).then(statefulHosts => {
+ const hostsUp = statefulHosts.filter(host => isStatefulHostUp(host));
+ const hostsTimeouted = statefulHosts.filter(host => isStatefulHostTimeouted(host));
+ /**
+ * Note, we put the hosts that previously timeouted on the end of the list.
+ */
+ const hostsAvailable = [...hostsUp, ...hostsTimeouted];
+ const statelessHostsAvailable = hostsAvailable.length > 0
+ ? hostsAvailable.map(host => createStatelessHost(host))
+ : statelessHosts;
+ return {
+ getTimeout(timeoutsCount, baseTimeout) {
+ /**
+ * Imagine that you have 4 hosts, if timeouts will increase
+ * on the following way: 1 (timeouted) > 4 (timeouted) > 5 (200)
+ *
+ * Note that, the very next request, we start from the previous timeout
+ *
+ * 5 (timeouted) > 6 (timeouted) > 7 ...
+ *
+ * This strategy may need to be reviewed, but is the strategy on the our
+ * current v3 version.
+ */
+ const timeoutMultiplier = hostsTimeouted.length === 0 && timeoutsCount === 0
+ ? 1
+ : hostsTimeouted.length + 3 + timeoutsCount;
+ return timeoutMultiplier * baseTimeout;
+ },
+ statelessHosts: statelessHostsAvailable,
+ };
+ });
+}
+
+const isNetworkError = ({ isTimedOut, status }) => {
+ return !isTimedOut && ~~status === 0;
+};
+const isRetryable = (response) => {
+ const status = response.status;
+ const isTimedOut = response.isTimedOut;
+ return (isTimedOut || isNetworkError(response) || (~~(status / 100) !== 2 && ~~(status / 100) !== 4));
+};
+const isSuccess = ({ status }) => {
+ return ~~(status / 100) === 2;
+};
+const retryDecision = (response, outcomes) => {
+ if (isRetryable(response)) {
+ return outcomes.onRetry(response);
+ }
+ if (isSuccess(response)) {
+ return outcomes.onSuccess(response);
+ }
+ return outcomes.onFail(response);
+};
+
+function retryableRequest(transporter, statelessHosts, request, requestOptions) {
+ const stackTrace = []; // eslint-disable-line functional/prefer-readonly-type
+ /**
+ * First we prepare the payload that do not depend from hosts.
+ */
+ const data = serializeData(request, requestOptions);
+ const headers = serializeHeaders(transporter, requestOptions);
+ const method = request.method;
+ // On `GET`, the data is proxied to query parameters.
+ const dataQueryParameters = request.method !== MethodEnum.Get
+ ? {}
+ : {
+ ...request.data,
+ ...requestOptions.data,
+ };
+ const queryParameters = {
+ 'x-algolia-agent': transporter.userAgent.value,
+ ...transporter.queryParameters,
+ ...dataQueryParameters,
+ ...requestOptions.queryParameters,
+ };
+ let timeoutsCount = 0; // eslint-disable-line functional/no-let
+ const retry = (hosts, // eslint-disable-line functional/prefer-readonly-type
+ getTimeout) => {
+ /**
+ * We iterate on each host, until there is no host left.
+ */
+ const host = hosts.pop(); // eslint-disable-line functional/immutable-data
+ if (host === undefined) {
+ throw createRetryError(stackTraceWithoutCredentials(stackTrace));
+ }
+ const payload = {
+ data,
+ headers,
+ method,
+ url: serializeUrl(host, request.path, queryParameters),
+ connectTimeout: getTimeout(timeoutsCount, transporter.timeouts.connect),
+ responseTimeout: getTimeout(timeoutsCount, requestOptions.timeout),
+ };
+ /**
+ * The stackFrame is pushed to the stackTrace so we
+ * can have information about onRetry and onFailure
+ * decisions.
+ */
+ const pushToStackTrace = (response) => {
+ const stackFrame = {
+ request: payload,
+ response,
+ host,
+ triesLeft: hosts.length,
+ };
+ // eslint-disable-next-line functional/immutable-data
+ stackTrace.push(stackFrame);
+ return stackFrame;
+ };
+ const decisions = {
+ onSuccess: response => deserializeSuccess(response),
+ onRetry(response) {
+ const stackFrame = pushToStackTrace(response);
+ /**
+ * If response is a timeout, we increaset the number of
+ * timeouts so we can increase the timeout later.
+ */
+ if (response.isTimedOut) {
+ timeoutsCount++;
+ }
+ return Promise.all([
+ /**
+ * Failures are individually send the logger, allowing
+ * the end user to debug / store stack frames even
+ * when a retry error does not happen.
+ */
+ transporter.logger.info('Retryable failure', stackFrameWithoutCredentials(stackFrame)),
+ /**
+ * We also store the state of the host in failure cases. If the host, is
+ * down it will remain down for the next 2 minutes. In a timeout situation,
+ * this host will be added end of the list of hosts on the next request.
+ */
+ transporter.hostsCache.set(host, createStatefulHost(host, response.isTimedOut ? HostStatusEnum.Timeouted : HostStatusEnum.Down)),
+ ]).then(() => retry(hosts, getTimeout));
+ },
+ onFail(response) {
+ pushToStackTrace(response);
+ throw deserializeFailure(response, stackTraceWithoutCredentials(stackTrace));
+ },
+ };
+ return transporter.requester.send(payload).then(response => {
+ return retryDecision(response, decisions);
+ });
+ };
+ /**
+ * Finally, for each retryable host perform request until we got a non
+ * retryable response. Some notes here:
+ *
+ * 1. The reverse here is applied so we can apply a `pop` later on => more performant.
+ * 2. We also get from the retryable options a timeout multiplier that is tailored
+ * for the current context.
+ */
+ return createRetryableOptions(transporter.hostsCache, statelessHosts).then(options => {
+ return retry([...options.statelessHosts].reverse(), options.getTimeout);
+ });
+}
+
+function createTransporter(options) {
+ const { hostsCache, logger, requester, requestsCache, responsesCache, timeouts, userAgent, hosts, queryParameters, headers, } = options;
+ const transporter = {
+ hostsCache,
+ logger,
+ requester,
+ requestsCache,
+ responsesCache,
+ timeouts,
+ userAgent,
+ headers,
+ queryParameters,
+ hosts: hosts.map(host => createStatelessHost(host)),
+ read(request, requestOptions) {
+ /**
+ * First, we compute the user request options. Now, keep in mind,
+ * that using request options the user is able to modified the intire
+ * payload of the request. Such as headers, query parameters, and others.
+ */
+ const mappedRequestOptions = createMappedRequestOptions(requestOptions, transporter.timeouts.read);
+ const createRetryableRequest = () => {
+ /**
+ * Then, we prepare a function factory that contains the construction of
+ * the retryable request. At this point, we may *not* perform the actual
+ * request. But we want to have the function factory ready.
+ */
+ return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Read) !== 0), request, mappedRequestOptions);
+ };
+ /**
+ * Once we have the function factory ready, we need to determine of the
+ * request is "cacheable" - should be cached. Note that, once again,
+ * the user can force this option.
+ */
+ const cacheable = mappedRequestOptions.cacheable !== undefined
+ ? mappedRequestOptions.cacheable
+ : request.cacheable;
+ /**
+ * If is not "cacheable", we immediatly trigger the retryable request, no
+ * need to check cache implementations.
+ */
+ if (cacheable !== true) {
+ return createRetryableRequest();
+ }
+ /**
+ * If the request is "cacheable", we need to first compute the key to ask
+ * the cache implementations if this request is on progress or if the
+ * response already exists on the cache.
+ */
+ const key = {
+ request,
+ mappedRequestOptions,
+ transporter: {
+ queryParameters: transporter.queryParameters,
+ headers: transporter.headers,
+ },
+ };
+ /**
+ * With the computed key, we first ask the responses cache
+ * implemention if this request was been resolved before.
+ */
+ return transporter.responsesCache.get(key, () => {
+ /**
+ * If the request has never resolved before, we actually ask if there
+ * is a current request with the same key on progress.
+ */
+ return transporter.requestsCache.get(key, () => {
+ return (transporter.requestsCache
+ /**
+ * Finally, if there is no request in progress with the same key,
+ * this `createRetryableRequest()` will actually trigger the
+ * retryable request.
+ */
+ .set(key, createRetryableRequest())
+ .then(response => Promise.all([transporter.requestsCache.delete(key), response]), err => Promise.all([transporter.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 => transporter.responsesCache.set(key, response),
+ });
+ },
+ write(request, requestOptions) {
+ /**
+ * On write requests, no cache mechanisms are applied, and we
+ * proxy the request immediately to the requester.
+ */
+ return retryableRequest(transporter, transporter.hosts.filter(host => (host.accept & CallEnum.Write) !== 0), request, createMappedRequestOptions(requestOptions, transporter.timeouts.write));
+ },
+ };
+ return transporter;
+}
+
+function createUserAgent(version) {
+ const userAgent = {
+ value: `Algolia for JavaScript (${version})`,
+ add(options) {
+ const addedUserAgent = `; ${options.segment}${options.version !== undefined ? ` (${options.version})` : ''}`;
+ if (userAgent.value.indexOf(addedUserAgent) === -1) {
+ // eslint-disable-next-line functional/immutable-data
+ userAgent.value = `${userAgent.value}${addedUserAgent}`;
+ }
+ return userAgent;
+ },
+ };
+ return userAgent;
+}
+
+function deserializeSuccess(response) {
+ // eslint-disable-next-line functional/no-try-statement
+ try {
+ return JSON.parse(response.content);
+ }
+ catch (e) {
+ throw createDeserializationError(e.message, response);
+ }
+}
+function deserializeFailure({ content, status }, stackFrame) {
+ // eslint-disable-next-line functional/no-let
+ let message = content;
+ // eslint-disable-next-line functional/no-try-statement
+ try {
+ message = JSON.parse(content).message;
+ }
+ catch (e) {
+ // ..
+ }
+ return createApiError(message, status, stackFrame);
+}
+
+function serializeUrl(host, path, queryParameters) {
+ const queryParametersAsString = serializeQueryParameters(queryParameters);
+ // eslint-disable-next-line functional/no-let
+ let url = `${host.protocol}://${host.url}/${path.charAt(0) === '/' ? path.substr(1) : path}`;
+ if (queryParametersAsString.length) {
+ url += `?${queryParametersAsString}`;
+ }
+ return url;
+}
+function serializeQueryParameters(parameters) {
+ const isObjectOrArray = (value) => Object.prototype.toString.call(value) === '[object Object]' ||
+ Object.prototype.toString.call(value) === '[object Array]';
+ return Object.keys(parameters)
+ .map(key => encode('%s=%s', key, isObjectOrArray(parameters[key]) ? JSON.stringify(parameters[key]) : parameters[key]))
+ .join('&');
+}
+function serializeData(request, requestOptions) {
+ if (request.method === MethodEnum.Get ||
+ (request.data === undefined && requestOptions.data === undefined)) {
+ return undefined;
+ }
+ const data = Array.isArray(request.data)
+ ? request.data
+ : { ...request.data, ...requestOptions.data };
+ return JSON.stringify(data);
+}
+function serializeHeaders(transporter, requestOptions) {
+ const headers = {
+ ...transporter.headers,
+ ...requestOptions.headers,
+ };
+ const serializedHeaders = {};
+ Object.keys(headers).forEach(header => {
+ const value = headers[header];
+ // @ts-ignore
+ // eslint-disable-next-line functional/immutable-data
+ serializedHeaders[header.toLowerCase()] = value;
+ });
+ return serializedHeaders;
+}
+
+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,
+ },
+ },
+ };
+}
+
+function createApiError(message, status, transporterStackTrace) {
+ return {
+ name: 'ApiError',
+ message,
+ status,
+ transporterStackTrace,
+ };
+}
+
+function createDeserializationError(message, response) {
+ return {
+ name: 'DeserializationError',
+ message,
+ response,
+ };
+}
+
+function createRetryError(transporterStackTrace) {
+ return {
+ name: 'RetryError',
+ message: 'Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.',
+ transporterStackTrace,
+ };
+}
+
+const createAnalyticsClient = options => {
+ const region = options.region || 'us';
+ const auth = createAuth(AuthMode.WithinHeaders, options.appId, options.apiKey);
+ const transporter = createTransporter({
+ hosts: [{ url: `analytics.${region}.algolia.com` }],
+ ...options,
+ headers: {
+ ...auth.headers(),
+ ...{ 'content-type': 'application/json' },
+ ...options.headers,
+ },
+ queryParameters: {
+ ...auth.queryParameters(),
+ ...options.queryParameters,
+ },
+ });
+ const appId = options.appId;
+ return addMethods({ appId, transporter }, options.methods);
+};
+
+const addABTest = (base) => {
+ return (abTest, requestOptions) => {
+ return base.transporter.write({
+ method: MethodEnum.Post,
+ path: '2/abtests',
+ data: abTest,
+ }, requestOptions);
+ };
+};
+
+const deleteABTest = (base) => {
+ return (abTestID, requestOptions) => {
+ return base.transporter.write({
+ method: MethodEnum.Delete,
+ path: encode('2/abtests/%s', abTestID),
+ }, requestOptions);
+ };
+};
+
+const getABTest = (base) => {
+ return (abTestID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('2/abtests/%s', abTestID),
+ }, requestOptions);
+ };
+};
+
+const getABTests = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '2/abtests',
+ }, requestOptions);
+ };
+};
+
+const stopABTest = (base) => {
+ return (abTestID, requestOptions) => {
+ return base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('2/abtests/%s/stop', abTestID),
+ }, requestOptions);
+ };
+};
+
+const createPersonalizationClient = options => {
+ const region = options.region || 'us';
+ const auth = createAuth(AuthMode.WithinHeaders, options.appId, options.apiKey);
+ const transporter = createTransporter({
+ hosts: [{ url: `personalization.${region}.algolia.com` }],
+ ...options,
+ headers: {
+ ...auth.headers(),
+ ...{ 'content-type': 'application/json' },
+ ...options.headers,
+ },
+ queryParameters: {
+ ...auth.queryParameters(),
+ ...options.queryParameters,
+ },
+ });
+ return addMethods({ appId: options.appId, transporter }, options.methods);
+};
+
+const getPersonalizationStrategy = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/strategies/personalization',
+ }, requestOptions);
+ };
+};
+
+const setPersonalizationStrategy = (base) => {
+ return (personalizationStrategy, requestOptions) => {
+ return base.transporter.write({
+ method: MethodEnum.Post,
+ path: '1/strategies/personalization',
+ data: personalizationStrategy,
+ }, requestOptions);
+ };
+};
+
+function createBrowsablePromise(options) {
+ const browse = (data) => {
+ return options.request(data).then(response => {
+ /**
+ * First we send to the developer the
+ * batch retrieved from the API.
+ */
+ if (options.batch !== undefined) {
+ options.batch(response.hits);
+ }
+ /**
+ * Then, we ask to the browse concrete implementation
+ * if we should stop browsing. As example, the `browseObjects`
+ * method will stop if the cursor is not present on the response.
+ */
+ if (options.shouldStop(response)) {
+ return undefined;
+ }
+ /**
+ * Finally, if the response contains a cursor, we browse to the next
+ * batch using that same cursor. Otherwise, we just use the traditional
+ * browsing using the page element.
+ */
+ if (response.cursor) {
+ return browse({
+ cursor: response.cursor,
+ });
+ }
+ return browse({
+ page: (data.page || 0) + 1,
+ });
+ });
+ };
+ return browse({});
+}
+
+const createSearchClient = options => {
+ const appId = options.appId;
+ const auth = createAuth(options.authMode !== undefined ? options.authMode : AuthMode.WithinHeaders, appId, options.apiKey);
+ const transporter = createTransporter({
+ hosts: [
+ { url: `${appId}-dsn.algolia.net`, accept: CallEnum.Read },
+ { url: `${appId}.algolia.net`, accept: CallEnum.Write },
+ ].concat(shuffle([
+ { url: `${appId}-1.algolianet.com` },
+ { url: `${appId}-2.algolianet.com` },
+ { url: `${appId}-3.algolianet.com` },
+ ])),
+ ...options,
+ headers: {
+ ...auth.headers(),
+ ...{ 'content-type': 'application/x-www-form-urlencoded' },
+ ...options.headers,
+ },
+ queryParameters: {
+ ...auth.queryParameters(),
+ ...options.queryParameters,
+ },
+ });
+ const base = {
+ transporter,
+ appId,
+ addAlgoliaAgent(segment, version) {
+ transporter.userAgent.add({ segment, version });
+ },
+ clearCache() {
+ return Promise.all([
+ transporter.requestsCache.clear(),
+ transporter.responsesCache.clear(),
+ ]).then(() => undefined);
+ },
+ };
+ return addMethods(base, options.methods);
+};
+
+function createMissingObjectIDError() {
+ return {
+ name: 'MissingObjectIDError',
+ message: 'All objects must have an unique objectID ' +
+ '(like a primary key) to be valid. ' +
+ 'Algolia is also able to generate objectIDs ' +
+ "automatically but *it's not recommended*. " +
+ "To do it, use the `{'autoGenerateObjectIDIfNotExist': true}` option.",
+ };
+}
+
+function createObjectNotFoundError() {
+ return {
+ name: 'ObjectNotFoundError',
+ message: 'Object not found.',
+ };
+}
+
+const addApiKey = (base) => {
+ return (acl, requestOptions) => {
+ const { queryParameters, ...options } = requestOptions || {};
+ const data = {
+ acl,
+ ...(queryParameters !== undefined ? { queryParameters } : {}),
+ };
+ const wait = (response, waitRequestOptions) => {
+ return createRetryablePromise(retry => {
+ return getApiKey(base)(response.key, waitRequestOptions).catch((apiError) => {
+ if (apiError.status !== 404) {
+ throw apiError;
+ }
+ return retry();
+ });
+ });
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: '1/keys',
+ data,
+ }, options), wait);
+ };
+};
+
+const assignUserID = (base) => {
+ return (userID, clusterName, requestOptions) => {
+ const mappedRequestOptions = createMappedRequestOptions(requestOptions);
+ // eslint-disable-next-line functional/immutable-data
+ mappedRequestOptions.queryParameters['X-Algolia-User-ID'] = userID;
+ return base.transporter.write({
+ method: MethodEnum.Post,
+ path: '1/clusters/mapping',
+ data: { cluster: clusterName },
+ }, mappedRequestOptions);
+ };
+};
+
+const assignUserIDs = (base) => {
+ return (userIDs, clusterName, requestOptions) => {
+ return base.transporter.write({
+ method: MethodEnum.Post,
+ path: '1/clusters/mapping/batch',
+ data: {
+ users: userIDs,
+ cluster: clusterName,
+ },
+ }, requestOptions);
+ };
+};
+
+const clearDictionaryEntries = (base) => {
+ return (dictionary, requestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('/1/dictionaries/%s/batch', dictionary),
+ data: {
+ clearExistingDictionaryEntries: true,
+ requests: { action: 'addEntry', body: [] },
+ },
+ }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const copyIndex = (base) => {
+ return (from, to, requestOptions) => {
+ const wait = (response, waitRequestOptions) => {
+ return initIndex(base)(from, {
+ methods: { waitTask },
+ }).waitTask(response.taskID, waitRequestOptions);
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/operation', from),
+ data: {
+ operation: 'copy',
+ destination: to,
+ },
+ }, requestOptions), wait);
+ };
+};
+
+const copyRules = (base) => {
+ return (from, to, requestOptions) => {
+ return copyIndex(base)(from, to, {
+ ...requestOptions,
+ scope: [ScopeEnum.Rules],
+ });
+ };
+};
+
+const copySettings = (base) => {
+ return (from, to, requestOptions) => {
+ return copyIndex(base)(from, to, {
+ ...requestOptions,
+ scope: [ScopeEnum.Settings],
+ });
+ };
+};
+
+const copySynonyms = (base) => {
+ return (from, to, requestOptions) => {
+ return copyIndex(base)(from, to, {
+ ...requestOptions,
+ scope: [ScopeEnum.Synonyms],
+ });
+ };
+};
+
+const customRequest = (base) => {
+ return (request, requestOptions) => {
+ if (request.method === MethodEnum.Get) {
+ return base.transporter.read(request, requestOptions);
+ }
+ return base.transporter.write(request, requestOptions);
+ };
+};
+
+const deleteApiKey = (base) => {
+ return (apiKey, requestOptions) => {
+ const wait = (_, waitRequestOptions) => {
+ return createRetryablePromise(retry => {
+ return getApiKey(base)(apiKey, waitRequestOptions)
+ .then(retry)
+ .catch((apiError) => {
+ if (apiError.status !== 404) {
+ throw apiError;
+ }
+ });
+ });
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Delete,
+ path: encode('1/keys/%s', apiKey),
+ }, requestOptions), wait);
+ };
+};
+
+const deleteDictionaryEntries = (base) => {
+ return (dictionary, objectIDs, requestOptions) => {
+ const requests = objectIDs.map(objectID => ({
+ action: 'deleteEntry',
+ body: { objectID },
+ }));
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('/1/dictionaries/%s/batch', dictionary),
+ data: { clearExistingDictionaryEntries: false, requests },
+ }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const getApiKey = (base) => {
+ return (apiKey, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/keys/%s', apiKey),
+ }, requestOptions);
+ };
+};
+
+const getAppTask = (base) => {
+ return (taskID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/task/%s', taskID.toString()),
+ }, requestOptions);
+ };
+};
+
+const getDictionarySettings = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '/1/dictionaries/*/settings',
+ }, requestOptions);
+ };
+};
+
+const getLogs = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/logs',
+ }, requestOptions);
+ };
+};
+
+const getTopUserIDs = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/clusters/mapping/top',
+ }, requestOptions);
+ };
+};
+
+const getUserID = (base) => {
+ return (userID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/clusters/mapping/%s', userID),
+ }, requestOptions);
+ };
+};
+
+const hasPendingMappings = (base) => {
+ return (requestOptions) => {
+ const { retrieveMappings, ...options } = requestOptions || {};
+ if (retrieveMappings === true) {
+ // eslint-disable-next-line functional/immutable-data
+ options.getClusters = true;
+ }
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/clusters/mapping/pending',
+ }, options);
+ };
+};
+
+const initIndex = (base) => {
+ return (indexName, options = {}) => {
+ const searchIndex = {
+ transporter: base.transporter,
+ appId: base.appId,
+ indexName,
+ };
+ return addMethods(searchIndex, options.methods);
+ };
+};
+
+const listApiKeys = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/keys',
+ }, requestOptions);
+ };
+};
+
+const listClusters = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/clusters',
+ }, requestOptions);
+ };
+};
+
+const listIndices = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/indexes',
+ }, requestOptions);
+ };
+};
+
+const listUserIDs = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: '1/clusters/mapping',
+ }, requestOptions);
+ };
+};
+
+const moveIndex = (base) => {
+ return (from, to, requestOptions) => {
+ const wait = (response, waitRequestOptions) => {
+ return initIndex(base)(from, {
+ methods: { waitTask },
+ }).waitTask(response.taskID, waitRequestOptions);
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/operation', from),
+ data: {
+ operation: 'move',
+ destination: to,
+ },
+ }, requestOptions), wait);
+ };
+};
+
+const multipleBatch = (base) => {
+ return (requests, requestOptions) => {
+ const wait = (response, waitRequestOptions) => {
+ return Promise.all(Object.keys(response.taskID).map(indexName => {
+ return initIndex(base)(indexName, {
+ methods: { waitTask },
+ }).waitTask(response.taskID[indexName], waitRequestOptions);
+ }));
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: '1/indexes/*/batch',
+ data: {
+ requests,
+ },
+ }, requestOptions), wait);
+ };
+};
+
+const multipleGetObjects = (base) => {
+ return (requests, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: '1/indexes/*/objects',
+ data: {
+ requests,
+ },
+ }, requestOptions);
+ };
+};
+
+const multipleQueries = (base) => {
+ return (queries, requestOptions) => {
+ const requests = queries.map(query => {
+ return {
+ ...query,
+ params: serializeQueryParameters(query.params || {}),
+ };
+ });
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: '1/indexes/*/queries',
+ data: {
+ requests,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const multipleSearchForFacetValues = (base) => {
+ return (queries, requestOptions) => {
+ return Promise.all(queries.map(query => {
+ const { facetName, facetQuery, ...params } = query.params;
+ return initIndex(base)(query.indexName, {
+ methods: { searchForFacetValues },
+ }).searchForFacetValues(facetName, facetQuery, {
+ ...requestOptions,
+ ...params,
+ });
+ }));
+ };
+};
+
+const removeUserID = (base) => {
+ return (userID, requestOptions) => {
+ const mappedRequestOptions = createMappedRequestOptions(requestOptions);
+ // eslint-disable-next-line functional/immutable-data
+ mappedRequestOptions.queryParameters['X-Algolia-User-ID'] = userID;
+ return base.transporter.write({
+ method: MethodEnum.Delete,
+ path: '1/clusters/mapping',
+ }, mappedRequestOptions);
+ };
+};
+
+const replaceDictionaryEntries = (base) => {
+ return (dictionary, entries, requestOptions) => {
+ const requests = entries.map(entry => ({
+ action: 'addEntry',
+ body: entry,
+ }));
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('/1/dictionaries/%s/batch', dictionary),
+ data: { clearExistingDictionaryEntries: true, requests },
+ }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const restoreApiKey = (base) => {
+ return (apiKey, requestOptions) => {
+ const wait = (_, waitRequestOptions) => {
+ return createRetryablePromise(retry => {
+ return getApiKey(base)(apiKey, waitRequestOptions).catch((apiError) => {
+ if (apiError.status !== 404) {
+ throw apiError;
+ }
+ return retry();
+ });
+ });
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/keys/%s/restore', apiKey),
+ }, requestOptions), wait);
+ };
+};
+
+const saveDictionaryEntries = (base) => {
+ return (dictionary, entries, requestOptions) => {
+ const requests = entries.map(entry => ({
+ action: 'addEntry',
+ body: entry,
+ }));
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('/1/dictionaries/%s/batch', dictionary),
+ data: { clearExistingDictionaryEntries: false, requests },
+ }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const searchDictionaryEntries = (base) => {
+ return (dictionary, query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('/1/dictionaries/%s/search', dictionary),
+ data: {
+ query,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const searchUserIDs = (base) => {
+ return (query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: '1/clusters/mapping/search',
+ data: {
+ query,
+ },
+ }, requestOptions);
+ };
+};
+
+const setDictionarySettings = (base) => {
+ return (settings, requestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Put,
+ path: '/1/dictionaries/*/settings',
+ data: settings,
+ }, requestOptions), (response, waitRequestOptions) => waitAppTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const updateApiKey = (base) => {
+ return (apiKey, requestOptions) => {
+ const updatedFields = Object.assign({}, requestOptions);
+ const { queryParameters, ...options } = requestOptions || {};
+ const data = queryParameters ? { queryParameters } : {};
+ const apiKeyFields = [
+ 'acl',
+ 'indexes',
+ 'referers',
+ 'restrictSources',
+ 'queryParameters',
+ 'description',
+ 'maxQueriesPerIPPerHour',
+ 'maxHitsPerQuery',
+ ];
+ const hasChanged = (getApiKeyResponse) => {
+ return Object.keys(updatedFields)
+ .filter((updatedField) => apiKeyFields.indexOf(updatedField) !== -1)
+ .every(updatedField => {
+ return getApiKeyResponse[updatedField] === updatedFields[updatedField];
+ });
+ };
+ const wait = (_, waitRequestOptions) => createRetryablePromise(retry => {
+ return getApiKey(base)(apiKey, waitRequestOptions).then(getApiKeyResponse => {
+ return hasChanged(getApiKeyResponse) ? Promise.resolve() : retry();
+ });
+ });
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Put,
+ path: encode('1/keys/%s', apiKey),
+ data,
+ }, options), wait);
+ };
+};
+
+const waitAppTask = (base) => {
+ return (taskID, requestOptions) => {
+ return createRetryablePromise(retry => {
+ return getAppTask(base)(taskID, requestOptions).then(response => {
+ return response.status !== 'published' ? retry() : undefined;
+ });
+ });
+ };
+};
+
+const batch = (base) => {
+ return (requests, requestOptions) => {
+ const wait = (response, waitRequestOptions) => {
+ return waitTask(base)(response.taskID, waitRequestOptions);
+ };
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/batch', base.indexName),
+ data: {
+ requests,
+ },
+ }, requestOptions), wait);
+ };
+};
+
+const browseObjects = (base) => {
+ return (requestOptions) => {
+ return createBrowsablePromise({
+ shouldStop: response => response.cursor === undefined,
+ ...requestOptions,
+ request: (data) => base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/browse', base.indexName),
+ data,
+ }, requestOptions),
+ });
+ };
+};
+
+const browseRules = (base) => {
+ return (requestOptions) => {
+ const options = {
+ hitsPerPage: 1000,
+ ...requestOptions,
+ };
+ return createBrowsablePromise({
+ shouldStop: response => response.hits.length < options.hitsPerPage,
+ ...options,
+ request(data) {
+ return searchRules(base)('', { ...options, ...data }).then((response) => {
+ return {
+ ...response,
+ hits: response.hits.map(rule => {
+ // eslint-disable-next-line functional/immutable-data,no-param-reassign
+ delete rule._highlightResult;
+ return rule;
+ }),
+ };
+ });
+ },
+ });
+ };
+};
+
+const browseSynonyms = (base) => {
+ return (requestOptions) => {
+ const options = {
+ hitsPerPage: 1000,
+ ...requestOptions,
+ };
+ return createBrowsablePromise({
+ shouldStop: response => response.hits.length < options.hitsPerPage,
+ ...options,
+ request(data) {
+ return searchSynonyms(base)('', { ...options, ...data }).then((response) => {
+ return {
+ ...response,
+ hits: response.hits.map(synonym => {
+ // eslint-disable-next-line functional/immutable-data,no-param-reassign
+ delete synonym._highlightResult;
+ return synonym;
+ }),
+ };
+ });
+ },
+ });
+ };
+};
+
+const chunkedBatch = (base) => {
+ return (bodies, action, requestOptions) => {
+ const { batchSize, ...options } = requestOptions || {};
+ const response = {
+ taskIDs: [],
+ objectIDs: [],
+ };
+ const forEachBatch = (lastIndex = 0) => {
+ // eslint-disable-next-line functional/prefer-readonly-type
+ const bodiesChunk = [];
+ // eslint-disable-next-line functional/no-let
+ let index;
+ /* eslint-disable-next-line functional/no-loop-statement */
+ for (index = lastIndex; index < bodies.length; index++) {
+ // eslint-disable-next-line functional/immutable-data
+ bodiesChunk.push(bodies[index]);
+ if (bodiesChunk.length === (batchSize || 1000)) {
+ break;
+ }
+ }
+ if (bodiesChunk.length === 0) {
+ return Promise.resolve(response);
+ }
+ return batch(base)(bodiesChunk.map(body => {
+ return {
+ action,
+ body,
+ };
+ }), options).then(res => {
+ response.objectIDs = response.objectIDs.concat(res.objectIDs); // eslint-disable-line functional/immutable-data
+ response.taskIDs.push(res.taskID); // eslint-disable-line functional/immutable-data
+ index++;
+ return forEachBatch(index);
+ });
+ };
+ return createWaitablePromise(forEachBatch(), (chunkedBatchResponse, waitRequestOptions) => {
+ return Promise.all(chunkedBatchResponse.taskIDs.map(taskID => {
+ return waitTask(base)(taskID, waitRequestOptions);
+ }));
+ });
+ };
+};
+
+const clearObjects = (base) => {
+ return (requestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/clear', base.indexName),
+ }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const clearRules = (base) => {
+ return (requestOptions) => {
+ const { forwardToReplicas, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/rules/clear', base.indexName),
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const clearSynonyms = (base) => {
+ return (requestOptions) => {
+ const { forwardToReplicas, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/synonyms/clear', base.indexName),
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const deleteBy = (base) => {
+ return (filters, requestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/deleteByQuery', base.indexName),
+ data: filters,
+ }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const deleteIndex = (base) => {
+ return (requestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Delete,
+ path: encode('1/indexes/%s', base.indexName),
+ }, requestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const deleteObject = (base) => {
+ return (objectID, requestOptions) => {
+ return createWaitablePromise(deleteObjects(base)([objectID], requestOptions).then(response => {
+ return { taskID: response.taskIDs[0] };
+ }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const deleteObjects = (base) => {
+ return (objectIDs, requestOptions) => {
+ const objects = objectIDs.map(objectID => {
+ return { objectID };
+ });
+ return chunkedBatch(base)(objects, BatchActionEnum.DeleteObject, requestOptions);
+ };
+};
+
+const deleteRule = (base) => {
+ return (objectID, requestOptions) => {
+ const { forwardToReplicas, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Delete,
+ path: encode('1/indexes/%s/rules/%s', base.indexName, objectID),
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const deleteSynonym = (base) => {
+ return (objectID, requestOptions) => {
+ const { forwardToReplicas, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Delete,
+ path: encode('1/indexes/%s/synonyms/%s', base.indexName, objectID),
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const exists = (base) => {
+ return (requestOptions) => {
+ return getSettings(base)(requestOptions)
+ .then(() => true)
+ .catch(error => {
+ if (error.status !== 404) {
+ throw error;
+ }
+ return false;
+ });
+ };
+};
+
+const findAnswers = (base) => {
+ return (query, queryLanguages, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/answers/%s/prediction', base.indexName),
+ data: {
+ query,
+ queryLanguages,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const findObject = (base) => {
+ return (callback, requestOptions) => {
+ const { query, paginate, ...options } = requestOptions || {};
+ // eslint-disable-next-line functional/no-let
+ let page = 0;
+ const forEachPage = () => {
+ return search(base)(query || '', { ...options, page }).then(result => {
+ // eslint-disable-next-line functional/no-loop-statement
+ for (const [position, hit] of Object.entries(result.hits)) {
+ // eslint-disable-next-line promise/no-callback-in-promise
+ if (callback(hit)) {
+ return {
+ object: hit,
+ position: parseInt(position, 10),
+ page,
+ };
+ }
+ }
+ page++;
+ // paginate if option was set and has next page
+ if (paginate === false || page >= result.nbPages) {
+ throw createObjectNotFoundError();
+ }
+ return forEachPage();
+ });
+ };
+ return forEachPage();
+ };
+};
+
+const getObject = (base) => {
+ return (objectID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/indexes/%s/%s', base.indexName, objectID),
+ }, requestOptions);
+ };
+};
+
+const getObjectPosition = () => {
+ return (searchResponse, objectID) => {
+ // eslint-disable-next-line functional/no-loop-statement
+ for (const [position, hit] of Object.entries(searchResponse.hits)) {
+ if (hit.objectID === objectID) {
+ return parseInt(position, 10);
+ }
+ }
+ return -1;
+ };
+};
+
+const getObjects = (base) => {
+ return (objectIDs, requestOptions) => {
+ const { attributesToRetrieve, ...options } = requestOptions || {};
+ const requests = objectIDs.map(objectID => {
+ return {
+ indexName: base.indexName,
+ objectID,
+ ...(attributesToRetrieve ? { attributesToRetrieve } : {}),
+ };
+ });
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: '1/indexes/*/objects',
+ data: {
+ requests,
+ },
+ }, options);
+ };
+};
+
+const getRule = (base) => {
+ return (objectID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/indexes/%s/rules/%s', base.indexName, objectID),
+ }, requestOptions);
+ };
+};
+
+const getSettings = (base) => {
+ return (requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/indexes/%s/settings', base.indexName),
+ data: {
+ getVersion: 2,
+ },
+ }, requestOptions);
+ };
+};
+
+const getSynonym = (base) => {
+ return (objectID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode(`1/indexes/%s/synonyms/%s`, base.indexName, objectID),
+ }, requestOptions);
+ };
+};
+
+const getTask = (base) => {
+ return (taskID, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Get,
+ path: encode('1/indexes/%s/task/%s', base.indexName, taskID.toString()),
+ }, requestOptions);
+ };
+};
+
+const partialUpdateObject = (base) => {
+ return (object, requestOptions) => {
+ return createWaitablePromise(partialUpdateObjects(base)([object], requestOptions).then(response => {
+ return {
+ objectID: response.objectIDs[0],
+ taskID: response.taskIDs[0],
+ };
+ }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const partialUpdateObjects = (base) => {
+ return (objects, requestOptions) => {
+ const { createIfNotExists, ...options } = requestOptions || {};
+ const action = createIfNotExists
+ ? BatchActionEnum.PartialUpdateObject
+ : BatchActionEnum.PartialUpdateObjectNoCreate;
+ return chunkedBatch(base)(objects, action, options);
+ };
+};
+
+const replaceAllObjects = (base) => {
+ return (objects, requestOptions) => {
+ const { safe, autoGenerateObjectIDIfNotExist, batchSize, ...options } = requestOptions || {};
+ const operation = (from, to, type, operationRequestOptions) => {
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/operation', from),
+ data: {
+ operation: type,
+ destination: to,
+ },
+ }, operationRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+ const randomSuffix = Math.random()
+ .toString(36)
+ .substring(7);
+ const temporaryIndexName = `${base.indexName}_tmp_${randomSuffix}`;
+ const saveObjectsInTemporary = saveObjects({
+ appId: base.appId,
+ transporter: base.transporter,
+ indexName: temporaryIndexName,
+ });
+ // @ts-ignore
+ // eslint-disable-next-line prefer-const, functional/no-let, functional/prefer-readonly-type
+ let responses = [];
+ const copyWaitablePromise = operation(base.indexName, temporaryIndexName, 'copy', {
+ ...options,
+ scope: ['settings', 'synonyms', 'rules'],
+ });
+ // eslint-disable-next-line functional/immutable-data
+ responses.push(copyWaitablePromise);
+ const result = (safe
+ ? copyWaitablePromise.wait(options)
+ : copyWaitablePromise)
+ .then(() => {
+ const saveObjectsWaitablePromise = saveObjectsInTemporary(objects, {
+ ...options,
+ autoGenerateObjectIDIfNotExist,
+ batchSize,
+ });
+ // eslint-disable-next-line functional/immutable-data
+ responses.push(saveObjectsWaitablePromise);
+ return safe ? saveObjectsWaitablePromise.wait(options) : saveObjectsWaitablePromise;
+ })
+ .then(() => {
+ const moveWaitablePromise = operation(temporaryIndexName, base.indexName, 'move', options);
+ // eslint-disable-next-line functional/immutable-data
+ responses.push(moveWaitablePromise);
+ return safe ? moveWaitablePromise.wait(options) : moveWaitablePromise;
+ })
+ .then(() => Promise.all(responses))
+ .then(([copyResponse, saveObjectsResponse, moveResponse]) => {
+ return {
+ objectIDs: saveObjectsResponse.objectIDs,
+ taskIDs: [copyResponse.taskID, ...saveObjectsResponse.taskIDs, moveResponse.taskID],
+ };
+ });
+ return createWaitablePromise(result, (_, waitRequestOptions) => {
+ return Promise.all(responses.map(response => response.wait(waitRequestOptions)));
+ });
+ };
+};
+
+const replaceAllRules = (base) => {
+ return (rules, requestOptions) => {
+ return saveRules(base)(rules, {
+ ...requestOptions,
+ clearExistingRules: true,
+ });
+ };
+};
+
+const replaceAllSynonyms = (base) => {
+ return (synonyms, requestOptions) => {
+ return saveSynonyms(base)(synonyms, {
+ ...requestOptions,
+ clearExistingSynonyms: true,
+ });
+ };
+};
+
+const saveObject = (base) => {
+ return (object, requestOptions) => {
+ return createWaitablePromise(saveObjects(base)([object], requestOptions).then(response => {
+ return {
+ objectID: response.objectIDs[0],
+ taskID: response.taskIDs[0],
+ };
+ }), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const saveObjects = (base) => {
+ return (objects, requestOptions) => {
+ const { autoGenerateObjectIDIfNotExist, ...options } = requestOptions || {};
+ const action = autoGenerateObjectIDIfNotExist
+ ? BatchActionEnum.AddObject
+ : BatchActionEnum.UpdateObject;
+ if (action === BatchActionEnum.UpdateObject) {
+ // eslint-disable-next-line functional/no-loop-statement
+ for (const object of objects) {
+ if (object.objectID === undefined) {
+ return createWaitablePromise(Promise.reject(createMissingObjectIDError()));
+ }
+ }
+ }
+ return chunkedBatch(base)(objects, action, options);
+ };
+};
+
+const saveRule = (base) => {
+ return (rule, requestOptions) => {
+ return saveRules(base)([rule], requestOptions);
+ };
+};
+
+const saveRules = (base) => {
+ return (rules, requestOptions) => {
+ const { forwardToReplicas, clearExistingRules, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ if (clearExistingRules) {
+ mappedRequestOptions.queryParameters.clearExistingRules = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/rules/batch', base.indexName),
+ data: rules,
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const saveSynonym = (base) => {
+ return (synonym, requestOptions) => {
+ return saveSynonyms(base)([synonym], requestOptions);
+ };
+};
+
+const saveSynonyms = (base) => {
+ return (synonyms, requestOptions) => {
+ const { forwardToReplicas, clearExistingSynonyms, replaceExistingSynonyms, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ if (replaceExistingSynonyms || clearExistingSynonyms) {
+ mappedRequestOptions.queryParameters.replaceExistingSynonyms = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/synonyms/batch', base.indexName),
+ data: synonyms,
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const search = (base) => {
+ return (query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/query', base.indexName),
+ data: {
+ query,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const searchForFacetValues = (base) => {
+ return (facetName, facetQuery, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/facets/%s/query', base.indexName, facetName),
+ data: {
+ facetQuery,
+ },
+ cacheable: true,
+ }, requestOptions);
+ };
+};
+
+const searchRules = (base) => {
+ return (query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/rules/search', base.indexName),
+ data: {
+ query,
+ },
+ }, requestOptions);
+ };
+};
+
+const searchSynonyms = (base) => {
+ return (query, requestOptions) => {
+ return base.transporter.read({
+ method: MethodEnum.Post,
+ path: encode('1/indexes/%s/synonyms/search', base.indexName),
+ data: {
+ query,
+ },
+ }, requestOptions);
+ };
+};
+
+const setSettings = (base) => {
+ return (settings, requestOptions) => {
+ const { forwardToReplicas, ...options } = requestOptions || {};
+ const mappedRequestOptions = createMappedRequestOptions(options);
+ if (forwardToReplicas) {
+ mappedRequestOptions.queryParameters.forwardToReplicas = 1; // eslint-disable-line functional/immutable-data
+ }
+ return createWaitablePromise(base.transporter.write({
+ method: MethodEnum.Put,
+ path: encode('1/indexes/%s/settings', base.indexName),
+ data: settings,
+ }, mappedRequestOptions), (response, waitRequestOptions) => waitTask(base)(response.taskID, waitRequestOptions));
+ };
+};
+
+const waitTask = (base) => {
+ return (taskID, requestOptions) => {
+ return createRetryablePromise(retry => {
+ return getTask(base)(taskID, requestOptions).then(response => {
+ return response.status !== 'published' ? retry() : undefined;
+ });
+ });
+ };
+};
+
+const BatchActionEnum = {
+ AddObject: 'addObject',
+ UpdateObject: 'updateObject',
+ PartialUpdateObject: 'partialUpdateObject',
+ PartialUpdateObjectNoCreate: 'partialUpdateObjectNoCreate',
+ DeleteObject: 'deleteObject',
+ DeleteIndex: 'delete',
+ ClearIndex: 'clear',
+};
+
+const ScopeEnum = {
+ Settings: 'settings',
+ Synonyms: 'synonyms',
+ Rules: 'rules',
+};
+
+const LogLevelEnum = {
+ Debug: 1,
+ Info: 2,
+ Error: 3,
+};
+
+/* eslint no-console: 0 */
+function createConsoleLogger(logLevel) {
+ return {
+ debug(message, args) {
+ if (LogLevelEnum.Debug >= logLevel) {
+ console.debug(message, args);
+ }
+ return Promise.resolve();
+ },
+ info(message, args) {
+ if (LogLevelEnum.Info >= logLevel) {
+ console.info(message, args);
+ }
+ return Promise.resolve();
+ },
+ error(message, args) {
+ console.error(message, args);
+ return Promise.resolve();
+ },
+ };
+}
+
+function createBrowserXhrRequester() {
+ return {
+ send(request) {
+ return new Promise((resolve) => {
+ const baseRequester = new XMLHttpRequest();
+ baseRequester.open(request.method, request.url, true);
+ Object.keys(request.headers).forEach(key => baseRequester.setRequestHeader(key, request.headers[key]));
+ const createTimeout = (timeout, content) => {
+ return setTimeout(() => {
+ baseRequester.abort();
+ resolve({
+ status: 0,
+ content,
+ isTimedOut: true,
+ });
+ }, timeout * 1000);
+ };
+ const connectTimeout = createTimeout(request.connectTimeout, 'Connection timeout');
+ // eslint-disable-next-line functional/no-let
+ let responseTimeout;
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onreadystatechange = () => {
+ if (baseRequester.readyState > baseRequester.OPENED && responseTimeout === undefined) {
+ clearTimeout(connectTimeout);
+ responseTimeout = createTimeout(request.responseTimeout, 'Socket timeout');
+ }
+ };
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onerror = () => {
+ // istanbul ignore next
+ if (baseRequester.status === 0) {
+ clearTimeout(connectTimeout);
+ clearTimeout(responseTimeout);
+ resolve({
+ content: baseRequester.responseText || 'Network request failed',
+ status: baseRequester.status,
+ isTimedOut: false,
+ });
+ }
+ };
+ // eslint-disable-next-line functional/immutable-data
+ baseRequester.onload = () => {
+ clearTimeout(connectTimeout);
+ clearTimeout(responseTimeout);
+ resolve({
+ content: baseRequester.responseText,
+ status: baseRequester.status,
+ isTimedOut: false,
+ });
+ };
+ baseRequester.send(request.data);
+ });
+ },
+ };
+}
+
+function algoliasearch(appId, apiKey, options) {
+ const commonOptions = {
+ appId,
+ apiKey,
+ timeouts: {
+ connect: 1,
+ read: 2,
+ write: 30,
+ },
+ requester: createBrowserXhrRequester(),
+ logger: createConsoleLogger(LogLevelEnum.Error),
+ responsesCache: createInMemoryCache(),
+ requestsCache: createInMemoryCache({ serializable: false }),
+ hostsCache: createFallbackableCache({
+ caches: [
+ createBrowserLocalStorageCache({ key: `${version}-${appId}` }),
+ createInMemoryCache(),
+ ],
+ }),
+ userAgent: createUserAgent(version).add({ segment: 'Browser' }),
+ };
+ const searchClientOptions = { ...commonOptions, ...options };
+ const initPersonalization = () => (clientOptions) => {
+ return createPersonalizationClient({
+ ...commonOptions,
+ ...clientOptions,
+ methods: {
+ getPersonalizationStrategy,
+ setPersonalizationStrategy,
+ },
+ });
+ };
+ return createSearchClient({
+ ...searchClientOptions,
+ methods: {
+ search: multipleQueries,
+ searchForFacetValues: multipleSearchForFacetValues,
+ multipleBatch,
+ multipleGetObjects,
+ multipleQueries,
+ copyIndex,
+ copySettings,
+ copySynonyms,
+ copyRules,
+ moveIndex,
+ listIndices,
+ getLogs,
+ listClusters,
+ multipleSearchForFacetValues,
+ getApiKey,
+ addApiKey,
+ listApiKeys,
+ updateApiKey,
+ deleteApiKey,
+ restoreApiKey,
+ assignUserID,
+ assignUserIDs,
+ getUserID,
+ searchUserIDs,
+ listUserIDs,
+ getTopUserIDs,
+ removeUserID,
+ hasPendingMappings,
+ clearDictionaryEntries,
+ deleteDictionaryEntries,
+ getDictionarySettings,
+ getAppTask,
+ replaceDictionaryEntries,
+ saveDictionaryEntries,
+ searchDictionaryEntries,
+ setDictionarySettings,
+ waitAppTask,
+ customRequest,
+ initIndex: base => (indexName) => {
+ return initIndex(base)(indexName, {
+ methods: {
+ batch,
+ delete: deleteIndex,
+ findAnswers,
+ getObject,
+ getObjects,
+ saveObject,
+ saveObjects,
+ search,
+ searchForFacetValues,
+ waitTask,
+ setSettings,
+ getSettings,
+ partialUpdateObject,
+ partialUpdateObjects,
+ deleteObject,
+ deleteObjects,
+ deleteBy,
+ clearObjects,
+ browseObjects,
+ getObjectPosition,
+ findObject,
+ exists,
+ saveSynonym,
+ saveSynonyms,
+ getSynonym,
+ searchSynonyms,
+ browseSynonyms,
+ deleteSynonym,
+ clearSynonyms,
+ replaceAllObjects,
+ replaceAllSynonyms,
+ searchRules,
+ getRule,
+ deleteRule,
+ saveRule,
+ saveRules,
+ replaceAllRules,
+ browseRules,
+ clearRules,
+ },
+ });
+ },
+ initAnalytics: () => (clientOptions) => {
+ return createAnalyticsClient({
+ ...commonOptions,
+ ...clientOptions,
+ methods: {
+ addABTest,
+ getABTest,
+ getABTests,
+ stopABTest,
+ deleteABTest,
+ },
+ });
+ },
+ initPersonalization,
+ initRecommendation: () => (clientOptions) => {
+ searchClientOptions.logger.info('The `initRecommendation` method is deprecated. Use `initPersonalization` instead.');
+ return initPersonalization()(clientOptions);
+ },
+ },
+ });
+}
+// eslint-disable-next-line functional/immutable-data
+algoliasearch.version = version;
+
+export default algoliasearch;
diff --git a/assets/algoliasearch/dist/algoliasearch.umd.js b/assets/algoliasearch/dist/algoliasearch.umd.js
new file mode 100644
index 00000000..3c4bc57a
--- /dev/null
+++ b/assets/algoliasearch/dist/algoliasearch.umd.js
@@ -0,0 +1,2 @@
+/*! algoliasearch.umd.js | 4.14.2 | © Algolia, inc. | https://github.com/algolia/algoliasearch-client-javascript */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).algoliasearch=e()}(this,(function(){"use strict";function t(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function e(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,n)}return r}function r(r){for(var n=1;n=0||(a[r]=t[r]);return a}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(a[r]=t[r])}return a}function a(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if(!(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t)))return;var r=[],n=!0,a=!1,o=void 0;try{for(var i,u=t[Symbol.iterator]();!(n=(i=u.next()).done)&&(r.push(i.value),!e||r.length!==e);n=!0);}catch(t){a=!0,o=t}finally{try{n||null==u.return||u.return()}finally{if(a)throw o}}return r}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function o(t){return function(t){if(Array.isArray(t)){for(var e=0,r=new Array(t.length);e2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return Promise.resolve().then((function(){var r=JSON.stringify(t),n=o()[r];return Promise.all([n||e(),void 0!==n])})).then((function(t){var e=a(t,2),n=e[0],o=e[1];return Promise.all([n,o||r.miss(n)])})).then((function(t){return a(t,1)[0]}))},set:function(t,e){return Promise.resolve().then((function(){var a=o();return a[JSON.stringify(t)]=e,n().setItem(r,JSON.stringify(a)),e}))},delete:function(t){return Promise.resolve().then((function(){var e=o();delete e[JSON.stringify(t)],n().setItem(r,JSON.stringify(e))}))},clear:function(){return Promise.resolve().then((function(){n().removeItem(r)}))}}}function u(t){var e=o(t.caches),r=e.shift();return void 0===r?{get:function(t,e){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},n=e();return n.then((function(t){return Promise.all([t,r.miss(t)])})).then((function(t){return a(t,1)[0]}))},set:function(t,e){return Promise.resolve(e)},delete:function(t){return Promise.resolve()},clear:function(){return Promise.resolve()}}:{get:function(t,n){var a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}};return r.get(t,n,a).catch((function(){return u({caches:e}).get(t,n,a)}))},set:function(t,n){return r.set(t,n).catch((function(){return u({caches:e}).set(t,n)}))},delete:function(t){return r.delete(t).catch((function(){return u({caches:e}).delete(t)}))},clear:function(){return r.clear().catch((function(){return u({caches:e}).clear()}))}}}function s(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{serializable:!0},e={};return{get:function(r,n){var a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{miss:function(){return Promise.resolve()}},o=JSON.stringify(r);if(o in e)return Promise.resolve(t.serializable?JSON.parse(e[o]):e[o]);var i=n(),u=a&&a.miss||function(){return Promise.resolve()};return i.then((function(t){return u(t)})).then((function(){return i}))},set:function(r,n){return e[JSON.stringify(r)]=t.serializable?JSON.stringify(n):n,Promise.resolve(n)},delete:function(t){return delete e[JSON.stringify(t)],Promise.resolve()},clear:function(){return e={},Promise.resolve()}}}function c(t,e,r){var n={"x-algolia-api-key":r,"x-algolia-application-id":e};return{headers:function(){return t===m.WithinHeaders?n:{}},queryParameters:function(){return t===m.WithinQueryParameters?n:{}}}}function f(t){var e=0;return t((function r(){return e++,new Promise((function(n){setTimeout((function(){n(t(r))}),Math.min(100*e,1e3))}))}))}function d(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:function(t,e){return Promise.resolve()};return Object.assign(t,{wait:function(r){return d(t.then((function(t){return Promise.all([e(t,r),t])})).then((function(t){return t[1]})))}})}function l(t){for(var e=t.length-1;e>0;e--){var r=Math.floor(Math.random()*(e+1)),n=t[e];t[e]=t[r],t[r]=n}return t}function p(t,e){return e?(Object.keys(e).forEach((function(r){t[r]=e[r](t)})),t):t}function h(t){for(var e=arguments.length,r=new Array(e>1?e-1:0),n=1;n0?n:void 0,timeout:r.timeout||e,headers:r.headers||{},queryParameters:r.queryParameters||{},cacheable:r.cacheable}}var g={Read:1,Write:2,Any:3},v=1,b=2,P=3;function w(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:v;return r(r({},t),{},{status:e,lastUpdate:Date.now()})}function O(t){return"string"==typeof t?{protocol:"https",url:t,accept:g.Any}:{protocol:t.protocol||"https",url:t.url,accept:t.accept||g.Any}}var I="DELETE",x="GET",j="POST",D="PUT";function q(t,e){return Promise.all(e.map((function(e){return t.get(e,(function(){return Promise.resolve(w(e))}))}))).then((function(t){var r=t.filter((function(t){return function(t){return t.status===v||Date.now()-t.lastUpdate>12e4}(t)})),n=t.filter((function(t){return function(t){return t.status===P&&Date.now()-t.lastUpdate<=12e4}(t)})),a=[].concat(o(r),o(n));return{getTimeout:function(t,e){return(0===n.length&&0===t?1:n.length+3+t)*e},statelessHosts:a.length>0?a.map((function(t){return O(t)})):e}}))}function S(t,e,n,a){var i=[],u=function(t,e){if(t.method===x||void 0===t.data&&void 0===e.data)return;var n=Array.isArray(t.data)?t.data:r(r({},t.data),e.data);return JSON.stringify(n)}(n,a),s=function(t,e){var n=r(r({},t.headers),e.headers),a={};return Object.keys(n).forEach((function(t){var e=n[t];a[t.toLowerCase()]=e})),a}(t,a),c=n.method,f=n.method!==x?{}:r(r({},n.data),a.data),d=r(r(r({"x-algolia-agent":t.userAgent.value},t.queryParameters),f),a.queryParameters),l=0,p=function e(r,o){var f=r.pop();if(void 0===f)throw{name:"RetryError",message:"Unreachable hosts - your application id may be incorrect. If the error persists, contact support@algolia.com.",transporterStackTrace:R(i)};var p={data:u,headers:s,method:c,url:N(f,n.path,d),connectTimeout:o(l,t.timeouts.connect),responseTimeout:o(l,a.timeout)},h=function(t){var e={request:p,response:t,host:f,triesLeft:r.length};return i.push(e),e},m={onSuccess:function(t){return function(t){try{return JSON.parse(t.content)}catch(e){throw function(t,e){return{name:"DeserializationError",message:t,response:e}}(e.message,t)}}(t)},onRetry:function(n){var a=h(n);return n.isTimedOut&&l++,Promise.all([t.logger.info("Retryable failure",A(a)),t.hostsCache.set(f,w(f,n.isTimedOut?P:b))]).then((function(){return e(r,o)}))},onFail:function(t){throw h(t),function(t,e){var r=t.content,n=t.status,a=r;try{a=JSON.parse(r).message}catch(t){}return function(t,e,r){return{name:"ApiError",message:t,status:e,transporterStackTrace:r}}(a,n,e)}(t,R(i))}};return t.requester.send(p).then((function(t){return function(t,e){return function(t){var e=t.status;return t.isTimedOut||function(t){var e=t.isTimedOut,r=t.status;return!e&&0==~~r}(t)||2!=~~(e/100)&&4!=~~(e/100)}(t)?e.onRetry(t):2==~~(t.status/100)?e.onSuccess(t):e.onFail(t)}(t,m)}))};return q(t.hostsCache,e).then((function(t){return p(o(t.statelessHosts).reverse(),t.getTimeout)}))}function k(t){var e=t.hostsCache,r=t.logger,n=t.requester,o=t.requestsCache,i=t.responsesCache,u=t.timeouts,s=t.userAgent,c=t.hosts,f=t.queryParameters,d={hostsCache:e,logger:r,requester:n,requestsCache:o,responsesCache:i,timeouts:u,userAgent:s,headers:t.headers,queryParameters:f,hosts:c.map((function(t){return O(t)})),read:function(t,e){var r=y(e,d.timeouts.read),n=function(){return S(d,d.hosts.filter((function(t){return 0!=(t.accept&g.Read)})),t,r)};if(!0!==(void 0!==r.cacheable?r.cacheable:t.cacheable))return n();var o={request:t,mappedRequestOptions:r,transporter:{queryParameters:d.queryParameters,headers:d.headers}};return d.responsesCache.get(o,(function(){return d.requestsCache.get(o,(function(){return d.requestsCache.set(o,n()).then((function(t){return Promise.all([d.requestsCache.delete(o),t])}),(function(t){return Promise.all([d.requestsCache.delete(o),Promise.reject(t)])})).then((function(t){var e=a(t,2);e[0];return e[1]}))}))}),{miss:function(t){return d.responsesCache.set(o,t)}})},write:function(t,e){return S(d,d.hosts.filter((function(t){return 0!=(t.accept&g.Write)})),t,y(e,d.timeouts.write))}};return d}function T(t){var e={value:"Algolia for JavaScript (".concat(t,")"),add:function(t){var r="; ".concat(t.segment).concat(void 0!==t.version?" (".concat(t.version,")"):"");return-1===e.value.indexOf(r)&&(e.value="".concat(e.value).concat(r)),e}};return e}function N(t,e,r){var n=E(r),a="".concat(t.protocol,"://").concat(t.url,"/").concat("/"===e.charAt(0)?e.substr(1):e);return n.length&&(a+="?".concat(n)),a}function E(t){return Object.keys(t).map((function(e){return h("%s=%s",e,(r=t[e],"[object Object]"===Object.prototype.toString.call(r)||"[object Array]"===Object.prototype.toString.call(r)?JSON.stringify(t[e]):t[e]));var r})).join("&")}function R(t){return t.map((function(t){return A(t)}))}function A(t){var e=t.request.headers["x-algolia-api-key"]?{"x-algolia-api-key":"*****"}:{};return r(r({},t),{},{request:r(r({},t.request),{},{headers:r(r({},t.request.headers),e)})})}var C=function(t){return function(e,r){return t.transporter.write({method:j,path:"2/abtests",data:e},r)}},U=function(t){return function(e,r){return t.transporter.write({method:I,path:h("2/abtests/%s",e)},r)}},z=function(t){return function(e,r){return t.transporter.read({method:x,path:h("2/abtests/%s",e)},r)}},J=function(t){return function(e){return t.transporter.read({method:x,path:"2/abtests"},e)}},F=function(t){return function(e,r){return t.transporter.write({method:j,path:h("2/abtests/%s/stop",e)},r)}},H=function(t){return function(e){return t.transporter.read({method:x,path:"1/strategies/personalization"},e)}},M=function(t){return function(e,r){return t.transporter.write({method:j,path:"1/strategies/personalization",data:e},r)}};function K(t){return function e(r){return t.request(r).then((function(n){if(void 0!==t.batch&&t.batch(n.hits),!t.shouldStop(n))return n.cursor?e({cursor:n.cursor}):e({page:(r.page||0)+1})}))}({})}var W=function(t){return function(e,a){var o=a||{},i=o.queryParameters,u=n(o,["queryParameters"]),s=r({acl:e},void 0!==i?{queryParameters:i}:{});return d(t.transporter.write({method:j,path:"1/keys",data:s},u),(function(e,r){return f((function(n){return tt(t)(e.key,r).catch((function(t){if(404!==t.status)throw t;return n()}))}))}))}},B=function(t){return function(e,r,n){var a=y(n);return a.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:j,path:"1/clusters/mapping",data:{cluster:r}},a)}},Q=function(t){return function(e,r,n){return t.transporter.write({method:j,path:"1/clusters/mapping/batch",data:{users:e,cluster:r}},n)}},G=function(t){return function(e,r){return d(t.transporter.write({method:j,path:h("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:{action:"addEntry",body:[]}}},r),(function(e,r){return jt(t)(e.taskID,r)}))}},L=function(t){return function(e,r,n){return d(t.transporter.write({method:j,path:h("1/indexes/%s/operation",e),data:{operation:"copy",destination:r}},n),(function(r,n){return ut(t)(e,{methods:{waitTask:de}}).waitTask(r.taskID,n)}))}},V=function(t){return function(e,n,a){return L(t)(e,n,r(r({},a),{},{scope:[pe.Rules]}))}},_=function(t){return function(e,n,a){return L(t)(e,n,r(r({},a),{},{scope:[pe.Settings]}))}},X=function(t){return function(e,n,a){return L(t)(e,n,r(r({},a),{},{scope:[pe.Synonyms]}))}},Y=function(t){return function(e,r){return e.method===x?t.transporter.read(e,r):t.transporter.write(e,r)}},Z=function(t){return function(e,r){return d(t.transporter.write({method:I,path:h("1/keys/%s",e)},r),(function(r,n){return f((function(r){return tt(t)(e,n).then(r).catch((function(t){if(404!==t.status)throw t}))}))}))}},$=function(t){return function(e,r,n){var a=r.map((function(t){return{action:"deleteEntry",body:{objectID:t}}}));return d(t.transporter.write({method:j,path:h("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},n),(function(e,r){return jt(t)(e.taskID,r)}))}},tt=function(t){return function(e,r){return t.transporter.read({method:x,path:h("1/keys/%s",e)},r)}},et=function(t){return function(e,r){return t.transporter.read({method:x,path:h("1/task/%s",e.toString())},r)}},rt=function(t){return function(e){return t.transporter.read({method:x,path:"/1/dictionaries/*/settings"},e)}},nt=function(t){return function(e){return t.transporter.read({method:x,path:"1/logs"},e)}},at=function(t){return function(e){return t.transporter.read({method:x,path:"1/clusters/mapping/top"},e)}},ot=function(t){return function(e,r){return t.transporter.read({method:x,path:h("1/clusters/mapping/%s",e)},r)}},it=function(t){return function(e){var r=e||{},a=r.retrieveMappings,o=n(r,["retrieveMappings"]);return!0===a&&(o.getClusters=!0),t.transporter.read({method:x,path:"1/clusters/mapping/pending"},o)}},ut=function(t){return function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n={transporter:t.transporter,appId:t.appId,indexName:e};return p(n,r.methods)}},st=function(t){return function(e){return t.transporter.read({method:x,path:"1/keys"},e)}},ct=function(t){return function(e){return t.transporter.read({method:x,path:"1/clusters"},e)}},ft=function(t){return function(e){return t.transporter.read({method:x,path:"1/indexes"},e)}},dt=function(t){return function(e){return t.transporter.read({method:x,path:"1/clusters/mapping"},e)}},lt=function(t){return function(e,r,n){return d(t.transporter.write({method:j,path:h("1/indexes/%s/operation",e),data:{operation:"move",destination:r}},n),(function(r,n){return ut(t)(e,{methods:{waitTask:de}}).waitTask(r.taskID,n)}))}},pt=function(t){return function(e,r){return d(t.transporter.write({method:j,path:"1/indexes/*/batch",data:{requests:e}},r),(function(e,r){return Promise.all(Object.keys(e.taskID).map((function(n){return ut(t)(n,{methods:{waitTask:de}}).waitTask(e.taskID[n],r)})))}))}},ht=function(t){return function(e,r){return t.transporter.read({method:j,path:"1/indexes/*/objects",data:{requests:e}},r)}},mt=function(t){return function(e,n){var a=e.map((function(t){return r(r({},t),{},{params:E(t.params||{})})}));return t.transporter.read({method:j,path:"1/indexes/*/queries",data:{requests:a},cacheable:!0},n)}},yt=function(t){return function(e,a){return Promise.all(e.map((function(e){var o=e.params,i=o.facetName,u=o.facetQuery,s=n(o,["facetName","facetQuery"]);return ut(t)(e.indexName,{methods:{searchForFacetValues:ue}}).searchForFacetValues(i,u,r(r({},a),s))})))}},gt=function(t){return function(e,r){var n=y(r);return n.queryParameters["X-Algolia-User-ID"]=e,t.transporter.write({method:I,path:"1/clusters/mapping"},n)}},vt=function(t){return function(e,r,n){var a=r.map((function(t){return{action:"addEntry",body:t}}));return d(t.transporter.write({method:j,path:h("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!0,requests:a}},n),(function(e,r){return jt(t)(e.taskID,r)}))}},bt=function(t){return function(e,r){return d(t.transporter.write({method:j,path:h("1/keys/%s/restore",e)},r),(function(r,n){return f((function(r){return tt(t)(e,n).catch((function(t){if(404!==t.status)throw t;return r()}))}))}))}},Pt=function(t){return function(e,r,n){var a=r.map((function(t){return{action:"addEntry",body:t}}));return d(t.transporter.write({method:j,path:h("/1/dictionaries/%s/batch",e),data:{clearExistingDictionaryEntries:!1,requests:a}},n),(function(e,r){return jt(t)(e.taskID,r)}))}},wt=function(t){return function(e,r,n){return t.transporter.read({method:j,path:h("/1/dictionaries/%s/search",e),data:{query:r},cacheable:!0},n)}},Ot=function(t){return function(e,r){return t.transporter.read({method:j,path:"1/clusters/mapping/search",data:{query:e}},r)}},It=function(t){return function(e,r){return d(t.transporter.write({method:D,path:"/1/dictionaries/*/settings",data:e},r),(function(e,r){return jt(t)(e.taskID,r)}))}},xt=function(t){return function(e,r){var a=Object.assign({},r),o=r||{},i=o.queryParameters,u=n(o,["queryParameters"]),s=i?{queryParameters:i}:{},c=["acl","indexes","referers","restrictSources","queryParameters","description","maxQueriesPerIPPerHour","maxHitsPerQuery"];return d(t.transporter.write({method:D,path:h("1/keys/%s",e),data:s},u),(function(r,n){return f((function(r){return tt(t)(e,n).then((function(t){return function(t){return Object.keys(a).filter((function(t){return-1!==c.indexOf(t)})).every((function(e){return t[e]===a[e]}))}(t)?Promise.resolve():r()}))}))}))}},jt=function(t){return function(e,r){return f((function(n){return et(t)(e,r).then((function(t){return"published"!==t.status?n():void 0}))}))}},Dt=function(t){return function(e,r){return d(t.transporter.write({method:j,path:h("1/indexes/%s/batch",t.indexName),data:{requests:e}},r),(function(e,r){return de(t)(e.taskID,r)}))}},qt=function(t){return function(e){return K(r(r({shouldStop:function(t){return void 0===t.cursor}},e),{},{request:function(r){return t.transporter.read({method:j,path:h("1/indexes/%s/browse",t.indexName),data:r},e)}}))}},St=function(t){return function(e){var n=r({hitsPerPage:1e3},e);return K(r(r({shouldStop:function(t){return t.hits.length0&&void 0!==arguments[0]?arguments[0]:0,c=[];for(a=o;a=t.nbPages)throw{name:"ObjectNotFoundError",message:"Object not found."};return n()}))}()}},Wt=function(t){return function(e,r){return t.transporter.read({method:x,path:h("1/indexes/%s/%s",t.indexName,e)},r)}},Bt=function(){return function(t,e){for(var r=0,n=Object.entries(t.hits);rr.OPENED&&void 0===n&&(clearTimeout(o),n=a(t.responseTimeout,"Socket timeout"))},r.onerror=function(){0===r.status&&(clearTimeout(o),clearTimeout(n),e({content:r.responseText||"Network request failed",status:r.status,isTimedOut:!1}))},r.onload=function(){clearTimeout(o),clearTimeout(n),e({content:r.responseText,status:r.status,isTimedOut:!1})},r.send(t.data)}))}},logger:(a=ye,{debug:function(t,e){return he>=a&&console.debug(t,e),Promise.resolve()},info:function(t,e){return me>=a&&console.info(t,e),Promise.resolve()},error:function(t,e){return console.error(t,e),Promise.resolve()}}),responsesCache:s(),requestsCache:s({serializable:!1}),hostsCache:u({caches:[i({key:"".concat("4.14.2","-").concat(t)}),s()]}),userAgent:T("4.14.2").add({segment:"Browser"})},f=r(r({},o),n),d=function(){return function(t){return function(t){var e=t.region||"us",n=c(m.WithinHeaders,t.appId,t.apiKey),a=k(r(r({hosts:[{url:"personalization.".concat(e,".algolia.com")}]},t),{},{headers:r(r(r({},n.headers()),{"content-type":"application/json"}),t.headers),queryParameters:r(r({},n.queryParameters()),t.queryParameters)}));return p({appId:t.appId,transporter:a},t.methods)}(r(r(r({},o),t),{},{methods:{getPersonalizationStrategy:H,setPersonalizationStrategy:M}}))}};return function(t){var e=t.appId,n=c(void 0!==t.authMode?t.authMode:m.WithinHeaders,e,t.apiKey),a=k(r(r({hosts:[{url:"".concat(e,"-dsn.algolia.net"),accept:g.Read},{url:"".concat(e,".algolia.net"),accept:g.Write}].concat(l([{url:"".concat(e,"-1.algolianet.com")},{url:"".concat(e,"-2.algolianet.com")},{url:"".concat(e,"-3.algolianet.com")}]))},t),{},{headers:r(r(r({},n.headers()),{"content-type":"application/x-www-form-urlencoded"}),t.headers),queryParameters:r(r({},n.queryParameters()),t.queryParameters)}));return p({transporter:a,appId:e,addAlgoliaAgent:function(t,e){a.userAgent.add({segment:t,version:e})},clearCache:function(){return Promise.all([a.requestsCache.clear(),a.responsesCache.clear()]).then((function(){}))}},t.methods)}(r(r({},f),{},{methods:{search:mt,searchForFacetValues:yt,multipleBatch:pt,multipleGetObjects:ht,multipleQueries:mt,copyIndex:L,copySettings:_,copySynonyms:X,copyRules:V,moveIndex:lt,listIndices:ft,getLogs:nt,listClusters:ct,multipleSearchForFacetValues:yt,getApiKey:tt,addApiKey:W,listApiKeys:st,updateApiKey:xt,deleteApiKey:Z,restoreApiKey:bt,assignUserID:B,assignUserIDs:Q,getUserID:ot,searchUserIDs:Ot,listUserIDs:dt,getTopUserIDs:at,removeUserID:gt,hasPendingMappings:it,clearDictionaryEntries:G,deleteDictionaryEntries:$,getDictionarySettings:rt,getAppTask:et,replaceDictionaryEntries:vt,saveDictionaryEntries:Pt,searchDictionaryEntries:wt,setDictionarySettings:It,waitAppTask:jt,customRequest:Y,initIndex:function(t){return function(e){return ut(t)(e,{methods:{batch:Dt,delete:Ct,findAnswers:Mt,getObject:Wt,getObjects:Qt,saveObject:te,saveObjects:ee,search:ie,searchForFacetValues:ue,waitTask:de,setSettings:fe,getSettings:Lt,partialUpdateObject:_t,partialUpdateObjects:Xt,deleteObject:Ut,deleteObjects:zt,deleteBy:At,clearObjects:Nt,browseObjects:qt,getObjectPosition:Bt,findObject:Kt,exists:Ht,saveSynonym:ae,saveSynonyms:oe,getSynonym:Vt,searchSynonyms:ce,browseSynonyms:kt,deleteSynonym:Ft,clearSynonyms:Rt,replaceAllObjects:Yt,replaceAllSynonyms:$t,searchRules:se,getRule:Gt,deleteRule:Jt,saveRule:re,saveRules:ne,replaceAllRules:Zt,browseRules:St,clearRules:Et}})}},initAnalytics:function(){return function(t){return function(t){var e=t.region||"us",n=c(m.WithinHeaders,t.appId,t.apiKey),a=k(r(r({hosts:[{url:"analytics.".concat(e,".algolia.com")}]},t),{},{headers:r(r(r({},n.headers()),{"content-type":"application/json"}),t.headers),queryParameters:r(r({},n.queryParameters()),t.queryParameters)}));return p({appId:t.appId,transporter:a},t.methods)}(r(r(r({},o),t),{},{methods:{addABTest:C,getABTest:z,getABTests:J,stopABTest:F,deleteABTest:U}}))}},initPersonalization:d,initRecommendation:function(){return function(t){return f.logger.info("The `initRecommendation` method is deprecated. Use `initPersonalization` instead."),d()(t)}}}}))}return ge.version="4.14.2",ge}));
diff --git a/assets/algoliasearch/index.d.ts b/assets/algoliasearch/index.d.ts
new file mode 100644
index 00000000..f3e17624
--- /dev/null
+++ b/assets/algoliasearch/index.d.ts
@@ -0,0 +1,3 @@
+/* eslint-disable import/no-unresolved*/
+export * from './dist/algoliasearch';
+export { default } from './dist/algoliasearch';
diff --git a/assets/algoliasearch/index.js b/assets/algoliasearch/index.js
new file mode 100644
index 00000000..14ca1ec1
--- /dev/null
+++ b/assets/algoliasearch/index.js
@@ -0,0 +1,15 @@
+/* eslint-disable functional/immutable-data, import/no-commonjs */
+const algoliasearch = require('./dist/algoliasearch.cjs.js');
+
+/**
+ * The Common JS build is the default entry point for the Node environment. Keep in
+ * in mind, that for the browser environment, we hint the bundler to use the UMD
+ * build instead as specified on the key `browser` of our `package.json` file.
+ */
+module.exports = algoliasearch;
+
+/**
+ * In addition, we also set explicitly the default export below making
+ * this Common JS module in compliance with es6 modules specification.
+ */
+module.exports.default = algoliasearch;
diff --git a/assets/algoliasearch/lite.d.ts b/assets/algoliasearch/lite.d.ts
new file mode 100644
index 00000000..41a19612
--- /dev/null
+++ b/assets/algoliasearch/lite.d.ts
@@ -0,0 +1,3 @@
+/* eslint-disable import/no-unresolved*/
+export * from './dist/algoliasearch-lite';
+export { default } from './dist/algoliasearch-lite';
diff --git a/assets/algoliasearch/lite.js b/assets/algoliasearch/lite.js
new file mode 100644
index 00000000..cdbfa358
--- /dev/null
+++ b/assets/algoliasearch/lite.js
@@ -0,0 +1,2 @@
+// eslint-disable-next-line functional/immutable-data, import/no-commonjs
+module.exports = require('./index');
diff --git a/assets/algoliasearch/package.json b/assets/algoliasearch/package.json
new file mode 100644
index 00000000..2fdaa467
--- /dev/null
+++ b/assets/algoliasearch/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "algoliasearch",
+ "version": "4.14.2",
+ "private": false,
+ "description": "A fully-featured and blazing-fast JavaScript API client to interact with Algolia API.",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/algolia/algoliasearch-client-javascript.git"
+ },
+ "license": "MIT",
+ "sideEffects": false,
+ "main": "index.js",
+ "jsdelivr": "./dist/algoliasearch.umd.js",
+ "unpkg": "./dist/algoliasearch.umd.js",
+ "browser": {
+ "./index.js": "./dist/algoliasearch.umd.js",
+ "./lite.js": "./dist/algoliasearch-lite.umd.js"
+ },
+ "types": "index.d.ts",
+ "files": [
+ "dist",
+ "index.js",
+ "index.d.ts",
+ "lite.js",
+ "lite.d.ts"
+ ],
+ "dependencies": {
+ "@algolia/cache-browser-local-storage": "4.14.2",
+ "@algolia/cache-common": "4.14.2",
+ "@algolia/cache-in-memory": "4.14.2",
+ "@algolia/client-account": "4.14.2",
+ "@algolia/client-analytics": "4.14.2",
+ "@algolia/client-common": "4.14.2",
+ "@algolia/client-personalization": "4.14.2",
+ "@algolia/client-search": "4.14.2",
+ "@algolia/logger-common": "4.14.2",
+ "@algolia/logger-console": "4.14.2",
+ "@algolia/requester-browser-xhr": "4.14.2",
+ "@algolia/requester-common": "4.14.2",
+ "@algolia/requester-node-http": "4.14.2",
+ "@algolia/transporter": "4.14.2"
+ }
+}
diff --git a/assets/autocomplete-theme-classic/dist/theme.css b/assets/autocomplete-theme-classic/dist/theme.css
new file mode 100644
index 00000000..14666550
--- /dev/null
+++ b/assets/autocomplete-theme-classic/dist/theme.css
@@ -0,0 +1,1089 @@
+/*! @algolia/autocomplete-theme-classic 1.7.3 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
+/* ---------------- */
+/* 1. CSS Variables */
+/* 2. Dark Mode */
+/* 3. Autocomplete */
+/* 4. Panel */
+/* 5. Sources */
+/* 6. Hit Layout */
+/* 7. Panel Header */
+/* 8. Panel Footer */
+/* 9. Detached Mode */
+/* 10. Gradients */
+/* 11. Utilities */
+/* ---------------- */
+/* Note: */
+/* This theme reflects the markup structure of autocomplete with SCSS indentation. */
+/* We use the SASS `@at-root` function to keep specificity low. */
+/* ---------------- */
+/* 1. CSS Variables */
+/* ---------------- */
+:root {
+ /* Input */
+ --aa-search-input-height: 44px;
+ --aa-input-icon-size: 20px;
+ /* Size and spacing */
+ --aa-base-unit: 16;
+ --aa-spacing-factor: 1;
+ --aa-spacing: calc(var(--aa-base-unit) * var(--aa-spacing-factor) * 1px);
+ --aa-spacing-half: calc(var(--aa-spacing) / 2);
+ --aa-panel-max-height: 650px;
+ /* Z-index */
+ --aa-base-z-index: 9999;
+ /* Font */
+ --aa-font-size: calc(var(--aa-base-unit) * 1px);
+ --aa-font-family: inherit;
+ --aa-font-weight-medium: 500;
+ --aa-font-weight-semibold: 600;
+ --aa-font-weight-bold: 700;
+ /* Icons */
+ --aa-icon-size: 20px;
+ --aa-icon-stroke-width: 1.6;
+ --aa-icon-color-rgb: 119, 119, 163;
+ --aa-icon-color-alpha: 1;
+ --aa-action-icon-size: 20px;
+ /* Text colors */
+ --aa-text-color-rgb: 38, 38, 39;
+ --aa-text-color-alpha: 1;
+ --aa-primary-color-rgb: 62, 52, 211;
+ --aa-primary-color-alpha: 0.2;
+ --aa-muted-color-rgb: 128, 126, 163;
+ --aa-muted-color-alpha: 0.6;
+ /* Border colors */
+ --aa-panel-border-color-rgb: 128, 126, 163;
+ --aa-panel-border-color-alpha: 0.3;
+ --aa-input-border-color-rgb: 128, 126, 163;
+ --aa-input-border-color-alpha: 0.8;
+ /* Background colors */
+ --aa-background-color-rgb: 255, 255, 255;
+ --aa-background-color-alpha: 1;
+ --aa-input-background-color-rgb: 255, 255, 255;
+ --aa-input-background-color-alpha: 1;
+ --aa-selected-color-rgb: 179, 173, 214;
+ --aa-selected-color-alpha: 0.205;
+ --aa-description-highlight-background-color-rgb: 245, 223, 77;
+ --aa-description-highlight-background-color-alpha: 0.5;
+ /* Detached mode */
+ --aa-detached-media-query: (max-width: 680px);
+ --aa-detached-modal-media-query: (min-width: 680px);
+ --aa-detached-modal-max-width: 680px;
+ --aa-detached-modal-max-height: 500px;
+ --aa-overlay-color-rgb: 115, 114, 129;
+ --aa-overlay-color-alpha: 0.4;
+ /* Shadows */
+ --aa-panel-shadow: 0 0 0 1px rgba(35, 38, 59, .1),
+ 0 6px 16px -4px rgba(35, 38, 59, .15);
+ /* Scrollbar */
+ --aa-scrollbar-width: 13px;
+ --aa-scrollbar-track-background-color-rgb: 234, 234, 234;
+ --aa-scrollbar-track-background-color-alpha: 1;
+ --aa-scrollbar-thumb-background-color-rgb: var(--aa-background-color-rgb);
+ --aa-scrollbar-thumb-background-color-alpha: 1;
+ /* Touch screens */
+}
+@media (hover: none) and (pointer: coarse) {
+ :root {
+ --aa-spacing-factor: 1.2;
+ --aa-action-icon-size: 22px;
+ }
+}
+
+/* ---------------- */
+/* 2. Dark Mode */
+/* ---------------- */
+body {
+ /* stylelint-disable selector-no-qualifying-type, selector-class-pattern */
+ /* stylelint-enable selector-no-qualifying-type, selector-class-pattern */
+}
+body[data-theme=dark], body.dark {
+ /* Text colors */
+ --aa-text-color-rgb: 183, 192, 199;
+ --aa-primary-color-rgb: 146, 138, 255;
+ --aa-muted-color-rgb: 146, 138, 255;
+ /* Background colors */
+ --aa-input-background-color-rgb: 0, 3, 9;
+ --aa-background-color-rgb: 21, 24, 42;
+ --aa-selected-color-rgb: 146, 138, 255;
+ --aa-selected-color-alpha: 0.25;
+ --aa-description-highlight-background-color-rgb: 0 255 255;
+ --aa-description-highlight-background-color-alpha: 0.25;
+ /* Icons */
+ --aa-icon-color-rgb: 119, 119, 163;
+ /* Shadows */
+ --aa-panel-shadow: inset 1px 1px 0 0 rgb(44, 46, 64),
+ 0 3px 8px 0 rgb(0, 3, 9);
+ /* Scrollbar */
+ --aa-scrollbar-track-background-color-rgb: 44, 46, 64;
+ --aa-scrollbar-thumb-background-color-rgb: var(--aa-background-color-rgb);
+}
+
+/* Reset for `@extend` */
+.aa-Panel *, .aa-Autocomplete *,
+.aa-DetachedFormContainer * {
+ box-sizing: border-box;
+}
+
+/* Init for `@extend` */
+.aa-Panel, .aa-Autocomplete,
+.aa-DetachedFormContainer {
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ font-family: inherit;
+ font-family: var(--aa-font-family);
+ font-size: 16px;
+ font-size: var(--aa-font-size);
+ font-weight: normal;
+ line-height: 1em;
+ margin: 0;
+ padding: 0;
+ text-align: left;
+}
+
+/* ---------------- */
+/* 3. Autocomplete */
+/* ---------------- */
+.aa-Autocomplete,
+.aa-DetachedFormContainer {
+ /* Search box */
+}
+.aa-Form {
+ align-items: center;
+ background-color: white;
+ background-color: rgba(var(--aa-input-background-color-rgb), var(--aa-input-background-color-alpha));
+ border: 1px solid rgba(128, 126, 163, 0.8);
+ border: 1px solid rgba(var(--aa-input-border-color-rgb), var(--aa-input-border-color-alpha));
+ border-radius: 3px;
+ display: flex;
+ line-height: 1em;
+ margin: 0;
+ position: relative;
+ width: 100%;
+}
+.aa-Form[focus-within] {
+ border-color: #3e34d3;
+ border-color: rgba(var(--aa-primary-color-rgb), 1);
+ box-shadow: rgba(62, 52, 211, 0.2) 0 0 0 2px, inset rgba(62, 52, 211, 0.2) 0 0 0 2px;
+ box-shadow: rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 2px, inset rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 2px;
+ outline: currentColor none medium;
+}
+.aa-Form:focus-within {
+ border-color: #3e34d3;
+ border-color: rgba(var(--aa-primary-color-rgb), 1);
+ box-shadow: rgba(62, 52, 211, 0.2) 0 0 0 2px, inset rgba(62, 52, 211, 0.2) 0 0 0 2px;
+ box-shadow: rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 2px, inset rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 2px;
+ outline: currentColor none medium;
+}
+.aa-InputWrapperPrefix {
+ align-items: center;
+ display: flex;
+ flex-shrink: 0;
+ height: 44px;
+ height: var(--aa-search-input-height);
+ order: 1;
+ /* Container for search and loading icons */
+}
+.aa-Label,
+.aa-LoadingIndicator {
+ cursor: auto;
+ cursor: initial;
+ flex-shrink: 0;
+ height: 100%;
+ padding: 0;
+ text-align: left;
+}
+.aa-Label svg,
+.aa-LoadingIndicator svg {
+ color: #3e34d3;
+ color: rgba(var(--aa-primary-color-rgb), 1);
+ height: auto;
+ max-height: 20px;
+ max-height: var(--aa-input-icon-size);
+ stroke-width: 1.6;
+ stroke-width: var(--aa-icon-stroke-width);
+ width: 20px;
+ width: var(--aa-input-icon-size);
+}
+
+.aa-SubmitButton,
+.aa-LoadingIndicator {
+ height: 100%;
+ padding-left: 11px;
+ padding-left: calc(var(--aa-spacing) * 0.75 - 1px);
+ padding-right: 8px;
+ padding-right: var(--aa-spacing-half);
+ width: 47px;
+ width: calc(var(--aa-spacing) * 1.75 + var(--aa-icon-size) - 1px);
+}
+@media (hover: none) and (pointer: coarse) {
+ .aa-SubmitButton,
+.aa-LoadingIndicator {
+ padding-left: 3px;
+ padding-left: calc(var(--aa-spacing-half) / 2 - 1px);
+ width: 39px;
+ width: calc(var(--aa-icon-size) + var(--aa-spacing) * 1.25 - 1px);
+ }
+}
+
+.aa-SubmitButton {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: none;
+ border: 0;
+ margin: 0;
+}
+
+.aa-LoadingIndicator {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+}
+.aa-LoadingIndicator[hidden] {
+ display: none;
+}
+
+.aa-InputWrapper {
+ order: 3;
+ position: relative;
+ width: 100%;
+ /* Search box input (with placeholder and query) */
+}
+.aa-Input {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: none;
+ border: 0;
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ font: inherit;
+ height: 44px;
+ height: var(--aa-search-input-height);
+ padding: 0;
+ width: 100%;
+ /* Focus is set and styled on the parent, it isn't necessary here */
+ /* Remove native appearence */
+}
+.aa-Input::-moz-placeholder {
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ opacity: 1;
+}
+.aa-Input:-ms-input-placeholder {
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ opacity: 1;
+}
+.aa-Input::placeholder {
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ opacity: 1;
+}
+.aa-Input:focus {
+ border-color: none;
+ box-shadow: none;
+ outline: none;
+}
+.aa-Input::-webkit-search-decoration, .aa-Input::-webkit-search-cancel-button, .aa-Input::-webkit-search-results-button, .aa-Input::-webkit-search-results-decoration {
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+.aa-InputWrapperSuffix {
+ align-items: center;
+ display: flex;
+ height: 44px;
+ height: var(--aa-search-input-height);
+ order: 4;
+ /* Accelerator to clear the query */
+}
+.aa-ClearButton {
+ align-items: center;
+ background: none;
+ border: 0;
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ cursor: pointer;
+ display: flex;
+ height: 100%;
+ margin: 0;
+ padding: 0 12.8333333333px;
+ padding: 0 calc(var(--aa-spacing) * 0.8333333333 - 0.5px);
+}
+@media (hover: none) and (pointer: coarse) {
+ .aa-ClearButton {
+ padding: 0 10.1666666667px;
+ padding: 0 calc(var(--aa-spacing) * 0.6666666667 - 0.5px);
+ }
+}
+.aa-ClearButton:hover, .aa-ClearButton:focus {
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+}
+.aa-ClearButton[hidden] {
+ display: none;
+}
+.aa-ClearButton svg {
+ stroke-width: 1.6;
+ stroke-width: var(--aa-icon-stroke-width);
+ width: 20px;
+ width: var(--aa-icon-size);
+}
+
+/* ---------------- */
+/* 4. Panel */
+/* ---------------- */
+.aa-Panel {
+ background-color: white;
+ background-color: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ border-radius: 4px;
+ border-radius: calc(var(--aa-spacing) / 4);
+ box-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1), 0 6px 16px -4px rgba(35, 38, 59, 0.15);
+ box-shadow: var(--aa-panel-shadow);
+ margin: 8px 0 0;
+ overflow: hidden;
+ position: absolute;
+ transition: opacity 200ms ease-in, filter 200ms ease-in;
+ /* When a request isn't resolved yet */
+}
+@media screen and (prefers-reduced-motion) {
+ .aa-Panel {
+ transition: none;
+ }
+}
+.aa-Panel button {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background: none;
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+.aa-PanelLayout {
+ height: 100%;
+ margin: 0;
+ max-height: 650px;
+ max-height: var(--aa-panel-max-height);
+ overflow-y: auto;
+ padding: 0;
+ position: relative;
+ text-align: left;
+}
+.aa-PanelLayoutColumns--twoGolden {
+ display: grid;
+ grid-template-columns: 39.2% auto;
+ overflow: hidden;
+ padding: 0;
+}
+
+.aa-PanelLayoutColumns--two {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ overflow: hidden;
+ padding: 0;
+}
+
+.aa-PanelLayoutColumns--three {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ overflow: hidden;
+ padding: 0;
+}
+
+.aa-Panel--stalled .aa-Source {
+ filter: grayscale(1);
+ opacity: 0.8;
+}
+
+.aa-Panel--scrollable {
+ margin: 0;
+ max-height: 650px;
+ max-height: var(--aa-panel-max-height);
+ overflow-x: hidden;
+ overflow-y: auto;
+ padding: 8px;
+ padding: var(--aa-spacing-half);
+ scrollbar-color: white #eaeaea;
+ scrollbar-color: rgba(var(--aa-scrollbar-thumb-background-color-rgb), var(--aa-scrollbar-thumb-background-color-alpha)) rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha));
+ scrollbar-width: thin;
+}
+.aa-Panel--scrollable::-webkit-scrollbar {
+ width: 13px;
+ width: var(--aa-scrollbar-width);
+}
+.aa-Panel--scrollable::-webkit-scrollbar-track {
+ background-color: #eaeaea;
+ background-color: rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha));
+}
+.aa-Panel--scrollable::-webkit-scrollbar-thumb {
+ background-color: white;
+ background-color: rgba(var(--aa-scrollbar-thumb-background-color-rgb), var(--aa-scrollbar-thumb-background-color-alpha));
+ border-color: #eaeaea;
+ border-color: rgba(var(--aa-scrollbar-track-background-color-rgb), var(--aa-scrollbar-track-background-color-alpha));
+ border-radius: 9999px;
+ border-style: solid;
+ border-width: 3px 2px 3px 3px;
+}
+
+/* ---------------- */
+/* 5. Sources */
+/* Each source can be styled independently */
+/* ---------------- */
+.aa-Source {
+ margin: 0;
+ padding: 0;
+ position: relative;
+ width: 100%;
+ /* List of results inside the source */
+ /* Source title */
+ /* See all button */
+}
+.aa-Source:empty {
+ /* Hide empty section */
+ display: none;
+}
+.aa-SourceNoResults {
+ font-size: 1em;
+ margin: 0;
+ padding: 16px;
+ padding: var(--aa-spacing);
+}
+
+.aa-List {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ position: relative;
+}
+
+.aa-SourceHeader {
+ margin: 8px 0.5em 8px 0;
+ margin: var(--aa-spacing-half) 0.5em var(--aa-spacing-half) 0;
+ padding: 0;
+ position: relative;
+ /* Hide empty header */
+ /* Title typography */
+ /* Line separator */
+}
+.aa-SourceHeader:empty {
+ display: none;
+}
+.aa-SourceHeaderTitle {
+ background: white;
+ background: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ color: #3e34d3;
+ color: rgba(var(--aa-primary-color-rgb), 1);
+ display: inline-block;
+ font-size: 0.8em;
+ font-weight: 600;
+ font-weight: var(--aa-font-weight-semibold);
+ margin: 0;
+ padding: 0 8px 0 0;
+ padding: 0 var(--aa-spacing-half) 0 0;
+ position: relative;
+ z-index: 9999;
+ z-index: var(--aa-base-z-index);
+}
+
+.aa-SourceHeaderLine {
+ border-bottom: solid 1px #3e34d3;
+ border-bottom: solid 1px rgba(var(--aa-primary-color-rgb), 1);
+ display: block;
+ height: 2px;
+ left: 0;
+ margin: 0;
+ opacity: 0.3;
+ padding: 0;
+ position: absolute;
+ right: 0;
+ top: 8px;
+ top: var(--aa-spacing-half);
+ z-index: 9998;
+ z-index: calc(var(--aa-base-z-index) - 1);
+}
+
+.aa-SourceFooterSeeAll {
+ background: linear-gradient(180deg, white, rgba(128, 126, 163, 0.14));
+ background: linear-gradient(180deg, rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha)), rgba(128, 126, 163, 0.14));
+ border: 1px solid rgba(128, 126, 163, 0.6);
+ border: 1px solid rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ border-radius: 5px;
+ box-shadow: inset 0 0 2px #fff, 0 2px 2px -1px rgba(76, 69, 88, 0.15);
+ color: inherit;
+ font-size: 0.95em;
+ font-weight: 500;
+ font-weight: var(--aa-font-weight-medium);
+ padding: 0.475em 1em 0.6em;
+ text-decoration: none;
+}
+.aa-SourceFooterSeeAll:focus, .aa-SourceFooterSeeAll:hover {
+ border: 1px solid #3e34d3;
+ border: 1px solid rgba(var(--aa-primary-color-rgb), 1);
+ color: #3e34d3;
+ color: rgba(var(--aa-primary-color-rgb), 1);
+}
+
+/* ---------------- */
+/* 6. Hit Layout */
+/* ---------------- */
+.aa-Item {
+ align-items: center;
+ border-radius: 3px;
+ cursor: pointer;
+ display: grid;
+ min-height: 40px;
+ min-height: calc(var(--aa-spacing) * 2.5);
+ padding: 4px;
+ padding: calc(var(--aa-spacing-half) / 2);
+ /* When the result is active */
+ /* The result type icon inlined SVG or image */
+ /* wrap hit with url but we don't need to see it */
+ /* Secondary click actions */
+}
+.aa-Item[aria-selected=true] {
+ background-color: rgba(179, 173, 214, 0.205);
+ background-color: rgba(var(--aa-selected-color-rgb), var(--aa-selected-color-alpha));
+}
+.aa-Item[aria-selected=true] .aa-ItemActionButton,
+.aa-Item[aria-selected=true] .aa-ActiveOnly {
+ visibility: visible;
+}
+.aa-ItemIcon {
+ align-items: center;
+ background: white;
+ background: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ border-radius: 3px;
+ box-shadow: inset 0 0 0 1px rgba(128, 126, 163, 0.3);
+ box-shadow: inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha));
+ color: #7777a3;
+ color: rgba(var(--aa-icon-color-rgb), var(--aa-icon-color-alpha));
+ display: flex;
+ flex-shrink: 0;
+ font-size: 0.7em;
+ height: 28px;
+ height: calc(var(--aa-icon-size) + var(--aa-spacing-half));
+ justify-content: center;
+ overflow: hidden;
+ stroke-width: 1.6;
+ stroke-width: var(--aa-icon-stroke-width);
+ text-align: center;
+ width: 28px;
+ width: calc(var(--aa-icon-size) + var(--aa-spacing-half));
+}
+.aa-ItemIcon img {
+ height: auto;
+ max-height: 20px;
+ max-height: calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);
+ max-width: 20px;
+ max-width: calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);
+ width: auto;
+}
+.aa-ItemIcon svg {
+ height: 20px;
+ height: var(--aa-icon-size);
+ width: 20px;
+ width: var(--aa-icon-size);
+}
+.aa-ItemIcon--alignTop {
+ align-self: flex-start;
+}
+
+.aa-ItemIcon--noBorder {
+ background: none;
+ box-shadow: none;
+}
+
+.aa-ItemIcon--picture {
+ height: 96px;
+ width: 96px;
+}
+.aa-ItemIcon--picture img {
+ max-height: 100%;
+ max-width: 100%;
+ padding: 8px;
+ padding: var(--aa-spacing-half);
+}
+
+.aa-ItemContent {
+ align-items: center;
+ cursor: pointer;
+ display: grid;
+ grid-gap: 8px;
+ gap: 8px;
+ grid-gap: var(--aa-spacing-half);
+ gap: var(--aa-spacing-half);
+ grid-auto-flow: column;
+ line-height: 1.25em;
+ overflow: hidden;
+}
+.aa-ItemContent:empty {
+ display: none;
+}
+.aa-ItemContent mark {
+ background: none;
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ font-style: normal;
+ font-weight: 700;
+ font-weight: var(--aa-font-weight-bold);
+}
+.aa-ItemContent--dual {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ text-align: left;
+}
+.aa-ItemContent--dual .aa-ItemContentTitle,
+.aa-ItemContent--dual .aa-ItemContentSubtitle {
+ display: block;
+}
+
+.aa-ItemContent--indented {
+ padding-left: 36px;
+ padding-left: calc(var(--aa-icon-size) + var(--aa-spacing));
+}
+
+.aa-ItemContentBody {
+ display: grid;
+ grid-gap: 4px;
+ gap: 4px;
+ grid-gap: calc(var(--aa-spacing-half) / 2);
+ gap: calc(var(--aa-spacing-half) / 2);
+}
+
+.aa-ItemContentTitle {
+ display: inline-block;
+ margin: 0 0.5em 0 0;
+ max-width: 100%;
+ overflow: hidden;
+ padding: 0;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.aa-ItemContentSubtitle {
+ font-size: 0.92em;
+}
+.aa-ItemContentSubtitleIcon::before {
+ border-color: rgba(128, 126, 163, 0.64);
+ border-color: rgba(var(--aa-muted-color-rgb), 0.64);
+ border-style: solid;
+ content: "";
+ display: inline-block;
+ left: 1px;
+ position: relative;
+ top: -3px;
+}
+
+.aa-ItemContentSubtitle--inline .aa-ItemContentSubtitleIcon::before {
+ border-width: 0 0 1.5px;
+ margin-left: 8px;
+ margin-left: var(--aa-spacing-half);
+ margin-right: 4px;
+ margin-right: calc(var(--aa-spacing-half) / 2);
+ width: 10px;
+ width: calc(var(--aa-spacing-half) + 2px);
+}
+
+.aa-ItemContentSubtitle--standalone {
+ align-items: center;
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ display: grid;
+ grid-gap: 8px;
+ gap: 8px;
+ grid-gap: var(--aa-spacing-half);
+ gap: var(--aa-spacing-half);
+ grid-auto-flow: column;
+ justify-content: start;
+}
+.aa-ItemContentSubtitle--standalone .aa-ItemContentSubtitleIcon::before {
+ border-radius: 0 0 0 3px;
+ border-width: 0 0 1.5px 1.5px;
+ height: 8px;
+ height: var(--aa-spacing-half);
+ width: 8px;
+ width: var(--aa-spacing-half);
+}
+
+.aa-ItemContentSubtitleCategory {
+ color: #807ea3;
+ color: rgba(var(--aa-muted-color-rgb), 1);
+ font-weight: 500;
+}
+
+.aa-ItemContentDescription {
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ font-size: 0.85em;
+ max-width: 100%;
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+}
+.aa-ItemContentDescription:empty {
+ display: none;
+}
+.aa-ItemContentDescription mark {
+ background: rgba(245, 223, 77, 0.5);
+ background: rgba(var(--aa-description-highlight-background-color-rgb), var(--aa-description-highlight-background-color-alpha));
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ font-style: normal;
+ font-weight: 500;
+ font-weight: var(--aa-font-weight-medium);
+}
+
+.aa-ItemContentDash {
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ display: none;
+ opacity: 0.4;
+}
+
+.aa-ItemContentTag {
+ background-color: rgba(62, 52, 211, 0.2);
+ background-color: rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha));
+ border-radius: 3px;
+ margin: 0 0.4em 0 0;
+ padding: 0.08em 0.3em;
+}
+
+.aa-ItemWrapper,
+.aa-ItemLink {
+ align-items: center;
+ color: inherit;
+ display: grid;
+ grid-gap: 4px;
+ gap: 4px;
+ grid-gap: calc(var(--aa-spacing-half) / 2);
+ gap: calc(var(--aa-spacing-half) / 2);
+ grid-auto-flow: column;
+ justify-content: space-between;
+ width: 100%;
+}
+
+.aa-ItemLink {
+ color: inherit;
+ text-decoration: none;
+}
+
+.aa-ItemActions {
+ display: grid;
+ grid-auto-flow: column;
+ height: 100%;
+ justify-self: end;
+ margin: 0 -5.3333333333px;
+ margin: 0 calc(var(--aa-spacing) / -3);
+ padding: 0 2px 0 0;
+}
+
+.aa-ItemActionButton {
+ align-items: center;
+ background: none;
+ border: 0;
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ cursor: pointer;
+ display: flex;
+ flex-shrink: 0;
+ padding: 0;
+}
+.aa-ItemActionButton:hover svg, .aa-ItemActionButton:focus svg {
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+}
+@media (hover: none) and (pointer: coarse) {
+ .aa-ItemActionButton:hover svg, .aa-ItemActionButton:focus svg {
+ color: inherit;
+ }
+}
+.aa-ItemActionButton svg {
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ margin: 0;
+ margin: 5.3333333333px;
+ margin: calc(var(--aa-spacing) / 3);
+ stroke-width: 1.6;
+ stroke-width: var(--aa-icon-stroke-width);
+ width: 20px;
+ width: var(--aa-action-icon-size);
+}
+
+.aa-ActiveOnly {
+ visibility: hidden;
+}
+
+/*---------------- */
+/* 7. Panel Header */
+/*---------------- */
+.aa-PanelHeader {
+ align-items: center;
+ background: #3e34d3;
+ background: rgba(var(--aa-primary-color-rgb), 1);
+ color: #fff;
+ display: grid;
+ height: var(--aa-modal-header-height);
+ margin: 0;
+ padding: 8px 16px;
+ padding: var(--aa-spacing-half) var(--aa-spacing);
+ position: relative;
+}
+.aa-PanelHeader::after {
+ background-image: linear-gradient(white, rgba(255, 255, 255, 0));
+ background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 1), rgba(var(--aa-background-color-rgb), 0));
+ bottom: -8px;
+ bottom: calc(var(--aa-spacing-half) * -1);
+ content: "";
+ height: 8px;
+ height: var(--aa-spacing-half);
+ left: 0;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ z-index: 9999;
+ z-index: var(--aa-base-z-index);
+}
+
+/*---------------- */
+/* 8. Panel Footer */
+/*---------------- */
+.aa-PanelFooter {
+ background-color: white;
+ background-color: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ box-shadow: inset 0 1px 0 rgba(128, 126, 163, 0.3);
+ box-shadow: inset 0 1px 0 rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha));
+ display: flex;
+ justify-content: space-between;
+ margin: 0;
+ padding: 16px;
+ padding: var(--aa-spacing);
+ position: relative;
+ z-index: 9999;
+ z-index: var(--aa-base-z-index);
+}
+.aa-PanelFooter::after {
+ background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(128, 126, 163, 0.6));
+ background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 0), rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha)));
+ content: "";
+ height: 16px;
+ height: var(--aa-spacing);
+ left: 0;
+ opacity: 0.12;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ top: -16px;
+ top: calc(var(--aa-spacing) * -1);
+ z-index: 9998;
+ z-index: calc(var(--aa-base-z-index) - 1);
+}
+
+/*---------------- */
+/* 9. Detached Mode */
+/*---------------- */
+.aa-DetachedContainer {
+ background: white;
+ background: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ bottom: 0;
+ box-shadow: 0 0 0 1px rgba(35, 38, 59, 0.1), 0 6px 16px -4px rgba(35, 38, 59, 0.15);
+ box-shadow: var(--aa-panel-shadow);
+ display: flex;
+ flex-direction: column;
+ left: 0;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 9999;
+ z-index: var(--aa-base-z-index);
+}
+.aa-DetachedContainer::after {
+ height: 32px;
+}
+.aa-DetachedContainer .aa-SourceHeader {
+ margin: 8px 0 8px 2px;
+ margin: var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px;
+}
+.aa-DetachedContainer .aa-Panel {
+ background-color: white;
+ background-color: rgba(var(--aa-background-color-rgb), var(--aa-background-color-alpha));
+ border-radius: 0;
+ box-shadow: none;
+ flex-grow: 1;
+ margin: 0;
+ padding: 0;
+ position: relative;
+}
+.aa-DetachedContainer .aa-PanelLayout {
+ bottom: 0;
+ box-shadow: none;
+ left: 0;
+ margin: 0;
+ max-height: none;
+ overflow-y: auto;
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 100%;
+}
+.aa-DetachedFormContainer {
+ border-bottom: solid 1px rgba(128, 126, 163, 0.3);
+ border-bottom: solid 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha));
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ margin: 0;
+ padding: 8px;
+ padding: var(--aa-spacing-half);
+}
+.aa-DetachedCancelButton {
+ background: none;
+ border: 0;
+ border-radius: 3px;
+ color: inherit;
+ color: #262627;
+ color: rgba(var(--aa-text-color-rgb), var(--aa-text-color-alpha));
+ cursor: pointer;
+ font: inherit;
+ margin: 0 0 0 8px;
+ margin: 0 0 0 var(--aa-spacing-half);
+ padding: 0 8px;
+ padding: 0 var(--aa-spacing-half);
+}
+.aa-DetachedCancelButton:hover, .aa-DetachedCancelButton:focus {
+ box-shadow: inset 0 0 0 1px rgba(128, 126, 163, 0.3);
+ box-shadow: inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb), var(--aa-panel-border-color-alpha));
+}
+
+.aa-DetachedContainer--modal {
+ border-radius: 6px;
+ bottom: inherit;
+ height: auto;
+ margin: 0 auto;
+ max-width: 680px;
+ max-width: var(--aa-detached-modal-max-width);
+ position: absolute;
+ top: 3%;
+}
+.aa-DetachedContainer--modal .aa-PanelLayout {
+ max-height: 500px;
+ max-height: var(--aa-detached-modal-max-height);
+ padding-bottom: 8px;
+ padding-bottom: var(--aa-spacing-half);
+ position: static;
+}
+
+/* Search Button */
+.aa-DetachedSearchButton {
+ align-items: center;
+ background-color: white;
+ background-color: rgba(var(--aa-input-background-color-rgb), var(--aa-input-background-color-alpha));
+ border: 1px solid rgba(128, 126, 163, 0.8);
+ border: 1px solid rgba(var(--aa-input-border-color-rgb), var(--aa-input-border-color-alpha));
+ border-radius: 3px;
+ color: rgba(128, 126, 163, 0.6);
+ color: rgba(var(--aa-muted-color-rgb), var(--aa-muted-color-alpha));
+ cursor: pointer;
+ display: flex;
+ font: inherit;
+ font-family: inherit;
+ font-family: var(--aa-font-family);
+ font-size: 16px;
+ font-size: var(--aa-font-size);
+ height: 44px;
+ height: var(--aa-search-input-height);
+ margin: 0;
+ padding: 0 5.5px;
+ padding: 0 calc(var(--aa-search-input-height) / 8);
+ position: relative;
+ text-align: left;
+ width: 100%;
+}
+.aa-DetachedSearchButton:focus {
+ border-color: #3e34d3;
+ border-color: rgba(var(--aa-primary-color-rgb), 1);
+ box-shadow: rgba(62, 52, 211, 0.2) 0 0 0 3px, inset rgba(62, 52, 211, 0.2) 0 0 0 2px;
+ box-shadow: rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 3px, inset rgba(var(--aa-primary-color-rgb), var(--aa-primary-color-alpha)) 0 0 0 2px;
+ outline: currentColor none medium;
+}
+.aa-DetachedSearchButtonIcon {
+ align-items: center;
+ color: #3e34d3;
+ color: rgba(var(--aa-primary-color-rgb), 1);
+ cursor: auto;
+ cursor: initial;
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ width: 36px;
+ width: calc(var(--aa-icon-size) + var(--aa-spacing));
+}
+
+/* Remove scroll on `body` */
+.aa-Detached {
+ height: 100vh;
+ overflow: hidden;
+}
+
+.aa-DetachedOverlay {
+ background-color: rgba(115, 114, 129, 0.4);
+ background-color: rgba(var(--aa-overlay-color-rgb), var(--aa-overlay-color-alpha));
+ height: 100vh;
+ left: 0;
+ margin: 0;
+ padding: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 9998;
+ z-index: calc(var(--aa-base-z-index) - 1);
+}
+
+/*---------------- */
+/* 10. Gradients */
+/*---------------- */
+.aa-GradientTop,
+.aa-GradientBottom {
+ height: 8px;
+ height: var(--aa-spacing-half);
+ left: 0;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ z-index: 9999;
+ z-index: var(--aa-base-z-index);
+}
+
+.aa-GradientTop {
+ background-image: linear-gradient(white, rgba(255, 255, 255, 0));
+ background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 1), rgba(var(--aa-background-color-rgb), 0));
+ top: 0;
+}
+
+.aa-GradientBottom {
+ background-image: linear-gradient(rgba(255, 255, 255, 0), white);
+ background-image: linear-gradient(rgba(var(--aa-background-color-rgb), 0), rgba(var(--aa-background-color-rgb), 1));
+ border-bottom-left-radius: 4px;
+ border-bottom-left-radius: calc(var(--aa-spacing) / 4);
+ border-bottom-right-radius: 4px;
+ border-bottom-right-radius: calc(var(--aa-spacing) / 4);
+ bottom: 0;
+}
+
+/*---------------- */
+/* 11. Utilities */
+/*---------------- */
+@media (hover: none) and (pointer: coarse) {
+ .aa-DesktopOnly {
+ display: none;
+ }
+}
+
+@media (hover: hover) {
+ .aa-TouchOnly {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/assets/autocomplete-theme-classic/dist/theme.min.css b/assets/autocomplete-theme-classic/dist/theme.min.css
new file mode 100644
index 00000000..a8cf2dbc
--- /dev/null
+++ b/assets/autocomplete-theme-classic/dist/theme.min.css
@@ -0,0 +1,2 @@
+/*! @algolia/autocomplete-theme-classic 1.7.3 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
+:root{--aa-search-input-height:44px;--aa-input-icon-size:20px;--aa-base-unit:16;--aa-spacing-factor:1;--aa-spacing:calc(var(--aa-base-unit)*var(--aa-spacing-factor)*1px);--aa-spacing-half:calc(var(--aa-spacing)/2);--aa-panel-max-height:650px;--aa-base-z-index:9999;--aa-font-size:calc(var(--aa-base-unit)*1px);--aa-font-family:inherit;--aa-font-weight-medium:500;--aa-font-weight-semibold:600;--aa-font-weight-bold:700;--aa-icon-size:20px;--aa-icon-stroke-width:1.6;--aa-icon-color-rgb:119,119,163;--aa-icon-color-alpha:1;--aa-action-icon-size:20px;--aa-text-color-rgb:38,38,39;--aa-text-color-alpha:1;--aa-primary-color-rgb:62,52,211;--aa-primary-color-alpha:0.2;--aa-muted-color-rgb:128,126,163;--aa-muted-color-alpha:0.6;--aa-panel-border-color-rgb:128,126,163;--aa-panel-border-color-alpha:0.3;--aa-input-border-color-rgb:128,126,163;--aa-input-border-color-alpha:0.8;--aa-background-color-rgb:255,255,255;--aa-background-color-alpha:1;--aa-input-background-color-rgb:255,255,255;--aa-input-background-color-alpha:1;--aa-selected-color-rgb:179,173,214;--aa-selected-color-alpha:0.205;--aa-description-highlight-background-color-rgb:245,223,77;--aa-description-highlight-background-color-alpha:0.5;--aa-detached-media-query:(max-width:680px);--aa-detached-modal-media-query:(min-width:680px);--aa-detached-modal-max-width:680px;--aa-detached-modal-max-height:500px;--aa-overlay-color-rgb:115,114,129;--aa-overlay-color-alpha:0.4;--aa-panel-shadow:0 0 0 1px rgba(35,38,59,0.1),0 6px 16px -4px rgba(35,38,59,0.15);--aa-scrollbar-width:13px;--aa-scrollbar-track-background-color-rgb:234,234,234;--aa-scrollbar-track-background-color-alpha:1;--aa-scrollbar-thumb-background-color-rgb:var(--aa-background-color-rgb);--aa-scrollbar-thumb-background-color-alpha:1}@media (hover:none) and (pointer:coarse){:root{--aa-spacing-factor:1.2;--aa-action-icon-size:22px}}body.dark,body[data-theme=dark]{--aa-text-color-rgb:183,192,199;--aa-primary-color-rgb:146,138,255;--aa-muted-color-rgb:146,138,255;--aa-input-background-color-rgb:0,3,9;--aa-background-color-rgb:21,24,42;--aa-selected-color-rgb:146,138,255;--aa-selected-color-alpha:0.25;--aa-description-highlight-background-color-rgb:0 255 255;--aa-description-highlight-background-color-alpha:0.25;--aa-icon-color-rgb:119,119,163;--aa-panel-shadow:inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309;--aa-scrollbar-track-background-color-rgb:44,46,64;--aa-scrollbar-thumb-background-color-rgb:var(--aa-background-color-rgb)}.aa-Autocomplete *,.aa-DetachedFormContainer *,.aa-Panel *{box-sizing:border-box}.aa-Autocomplete,.aa-DetachedFormContainer,.aa-Panel{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-family:inherit;font-family:var(--aa-font-family);font-size:16px;font-size:var(--aa-font-size);font-weight:400;line-height:1em;margin:0;padding:0;text-align:left}.aa-Form{align-items:center;background-color:#fff;background-color:rgba(var(--aa-input-background-color-rgb),var(--aa-input-background-color-alpha));border:1px solid rgba(128,126,163,.8);border:1px solid rgba(var(--aa-input-border-color-rgb),var(--aa-input-border-color-alpha));border-radius:3px;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Form[focus-within]{border-color:#3e34d3;border-color:rgba(var(--aa-primary-color-rgb),1);box-shadow:0 0 0 2px rgba(62,52,211,.2),inset 0 0 0 2px rgba(62,52,211,.2);box-shadow:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px,inset rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px;outline:medium none currentColor}.aa-Form:focus-within{border-color:#3e34d3;border-color:rgba(var(--aa-primary-color-rgb),1);box-shadow:0 0 0 2px rgba(62,52,211,.2),inset 0 0 0 2px rgba(62,52,211,.2);box-shadow:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px,inset rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px;outline:medium none currentColor}.aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;height:44px;height:var(--aa-search-input-height);order:1}.aa-Label,.aa-LoadingIndicator{cursor:auto;flex-shrink:0;height:100%;padding:0;text-align:left}.aa-Label svg,.aa-LoadingIndicator svg{color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);height:auto;max-height:20px;max-height:var(--aa-input-icon-size);stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-input-icon-size)}.aa-LoadingIndicator,.aa-SubmitButton{height:100%;padding-left:11px;padding-left:calc(var(--aa-spacing)*0.75 - 1px);padding-right:8px;padding-right:var(--aa-spacing-half);width:47px;width:calc(var(--aa-spacing)*1.75 + var(--aa-icon-size) - 1px)}@media (hover:none) and (pointer:coarse){.aa-LoadingIndicator,.aa-SubmitButton{padding-left:3px;padding-left:calc(var(--aa-spacing-half)/2 - 1px);width:39px;width:calc(var(--aa-icon-size) + var(--aa-spacing)*1.25 - 1px)}}.aa-SubmitButton{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;margin:0}.aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-LoadingIndicator[hidden]{display:none}.aa-InputWrapper{order:3;position:relative;width:100%}.aa-Input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font:inherit;height:44px;height:var(--aa-search-input-height);padding:0;width:100%}.aa-Input::-moz-placeholder{color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));opacity:1}.aa-Input:-ms-input-placeholder{color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));opacity:1}.aa-Input::placeholder{color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));opacity:1}.aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Input::-webkit-search-cancel-button,.aa-Input::-webkit-search-decoration,.aa-Input::-webkit-search-results-button,.aa-Input::-webkit-search-results-decoration{-webkit-appearance:none;appearance:none}.aa-InputWrapperSuffix{align-items:center;display:flex;height:44px;height:var(--aa-search-input-height);order:4}.aa-ClearButton{align-items:center;background:none;border:0;color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;height:100%;margin:0;padding:0 12.8333333333px;padding:0 calc(var(--aa-spacing)*0.83333 - .5px)}@media (hover:none) and (pointer:coarse){.aa-ClearButton{padding:0 10.1666666667px;padding:0 calc(var(--aa-spacing)*0.66667 - .5px)}}.aa-ClearButton:focus,.aa-ClearButton:hover{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha))}.aa-ClearButton[hidden]{display:none}.aa-ClearButton svg{stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-icon-size)}.aa-Panel{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));border-radius:4px;border-radius:calc(var(--aa-spacing)/4);box-shadow:0 0 0 1px rgba(35,38,59,.1),0 6px 16px -4px rgba(35,38,59,.15);box-shadow:var(--aa-panel-shadow);margin:8px 0 0;overflow:hidden;position:absolute;transition:opacity .2s ease-in,filter .2s ease-in}@media screen and (prefers-reduced-motion){.aa-Panel{transition:none}}.aa-Panel button{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;margin:0;padding:0}.aa-PanelLayout{height:100%;margin:0;max-height:650px;max-height:var(--aa-panel-max-height);overflow-y:auto;padding:0;position:relative;text-align:left}.aa-PanelLayoutColumns--twoGolden{display:grid;grid-template-columns:39.2% auto;overflow:hidden;padding:0}.aa-PanelLayoutColumns--two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));overflow:hidden;padding:0}.aa-PanelLayoutColumns--three{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));overflow:hidden;padding:0}.aa-Panel--stalled .aa-Source{filter:grayscale(1);opacity:.8}.aa-Panel--scrollable{margin:0;max-height:650px;max-height:var(--aa-panel-max-height);overflow-x:hidden;overflow-y:auto;padding:8px;padding:var(--aa-spacing-half);scrollbar-color:#fff #eaeaea;scrollbar-color:rgba(var(--aa-scrollbar-thumb-background-color-rgb),var(--aa-scrollbar-thumb-background-color-alpha)) rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha));scrollbar-width:thin}.aa-Panel--scrollable::-webkit-scrollbar{width:13px;width:var(--aa-scrollbar-width)}.aa-Panel--scrollable::-webkit-scrollbar-track{background-color:#eaeaea;background-color:rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha))}.aa-Panel--scrollable::-webkit-scrollbar-thumb{background-color:#fff;background-color:rgba(var(--aa-scrollbar-thumb-background-color-rgb),var(--aa-scrollbar-thumb-background-color-alpha));border-radius:9999px;border:3px solid #eaeaea;border-color:rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha));border-right:2px solid rgba(var(--aa-scrollbar-track-background-color-rgb),var(--aa-scrollbar-track-background-color-alpha))}.aa-Source{margin:0;padding:0;position:relative;width:100%}.aa-Source:empty{display:none}.aa-SourceNoResults{font-size:1em;margin:0;padding:16px;padding:var(--aa-spacing)}.aa-List{list-style:none;margin:0}.aa-List,.aa-SourceHeader{padding:0;position:relative}.aa-SourceHeader{margin:8px .5em 8px 0;margin:var(--aa-spacing-half) .5em var(--aa-spacing-half) 0}.aa-SourceHeader:empty{display:none}.aa-SourceHeaderTitle{background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);display:inline-block;font-size:.8em;font-weight:600;font-weight:var(--aa-font-weight-semibold);margin:0;padding:0 8px 0 0;padding:0 var(--aa-spacing-half) 0 0;position:relative;z-index:9999;z-index:var(--aa-base-z-index)}.aa-SourceHeaderLine{border-bottom:1px solid #3e34d3;border-bottom:1px solid rgba(var(--aa-primary-color-rgb),1);display:block;height:2px;left:0;margin:0;opacity:.3;padding:0;position:absolute;right:0;top:8px;top:var(--aa-spacing-half);z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-SourceFooterSeeAll{background:linear-gradient(180deg,#fff,rgba(128,126,163,.14));background:linear-gradient(180deg,rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha)),rgba(128,126,163,.14));border:1px solid rgba(128,126,163,.6);border:1px solid rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));border-radius:5px;box-shadow:inset 0 0 2px #fff,0 2px 2px -1px rgba(76,69,88,.15);color:inherit;font-size:.95em;font-weight:500;font-weight:var(--aa-font-weight-medium);padding:.475em 1em .6em;text-decoration:none}.aa-SourceFooterSeeAll:focus,.aa-SourceFooterSeeAll:hover{border:1px solid #3e34d3;border:1px solid rgba(var(--aa-primary-color-rgb),1);color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1)}.aa-Item{align-items:center;border-radius:3px;cursor:pointer;display:grid;min-height:40px;min-height:calc(var(--aa-spacing)*2.5);padding:4px;padding:calc(var(--aa-spacing-half)/2)}.aa-Item[aria-selected=true]{background-color:rgba(179,173,214,.205);background-color:rgba(var(--aa-selected-color-rgb),var(--aa-selected-color-alpha))}.aa-Item[aria-selected=true] .aa-ActiveOnly,.aa-Item[aria-selected=true] .aa-ItemActionButton{visibility:visible}.aa-ItemIcon{align-items:center;background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));border-radius:3px;box-shadow:inset 0 0 0 1px rgba(128,126,163,.3);box-shadow:inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));color:#7777a3;color:rgba(var(--aa-icon-color-rgb),var(--aa-icon-color-alpha));display:flex;flex-shrink:0;font-size:.7em;height:28px;height:calc(var(--aa-icon-size) + var(--aa-spacing-half));justify-content:center;overflow:hidden;stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);text-align:center;width:28px;width:calc(var(--aa-icon-size) + var(--aa-spacing-half))}.aa-ItemIcon img{height:auto;max-height:20px;max-height:calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);max-width:20px;max-width:calc(var(--aa-icon-size) + var(--aa-spacing-half) - 8px);width:auto}.aa-ItemIcon svg{height:20px;height:var(--aa-icon-size);width:20px;width:var(--aa-icon-size)}.aa-ItemIcon--alignTop{align-self:flex-start}.aa-ItemIcon--noBorder{background:none;box-shadow:none}.aa-ItemIcon--picture{height:96px;width:96px}.aa-ItemIcon--picture img{max-height:100%;max-width:100%;padding:8px;padding:var(--aa-spacing-half)}.aa-ItemContent{align-items:center;cursor:pointer;display:grid;grid-gap:8px;gap:8px;grid-gap:var(--aa-spacing-half);gap:var(--aa-spacing-half);grid-auto-flow:column;line-height:1.25em;overflow:hidden}.aa-ItemContent:empty{display:none}.aa-ItemContent mark{background:none;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-style:normal;font-weight:700;font-weight:var(--aa-font-weight-bold)}.aa-ItemContent--dual{display:flex;flex-direction:column;justify-content:space-between;text-align:left}.aa-ItemContent--dual .aa-ItemContentSubtitle,.aa-ItemContent--dual .aa-ItemContentTitle{display:block}.aa-ItemContent--indented{padding-left:36px;padding-left:calc(var(--aa-icon-size) + var(--aa-spacing))}.aa-ItemContentBody{display:grid;grid-gap:4px;gap:4px;grid-gap:calc(var(--aa-spacing-half)/2);gap:calc(var(--aa-spacing-half)/2)}.aa-ItemContentTitle{display:inline-block;margin:0 .5em 0 0;max-width:100%;overflow:hidden;padding:0;text-overflow:ellipsis;white-space:nowrap}.aa-ItemContentSubtitle{font-size:.92em}.aa-ItemContentSubtitleIcon:before{border-color:rgba(128,126,163,.64);border-color:rgba(var(--aa-muted-color-rgb),.64);border-style:solid;content:"";display:inline-block;left:1px;position:relative;top:-3px}.aa-ItemContentSubtitle--inline .aa-ItemContentSubtitleIcon:before{border-width:0 0 1.5px;margin-left:8px;margin-left:var(--aa-spacing-half);margin-right:4px;margin-right:calc(var(--aa-spacing-half)/2);width:10px;width:calc(var(--aa-spacing-half) + 2px)}.aa-ItemContentSubtitle--standalone{align-items:center;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));display:grid;grid-gap:8px;gap:8px;grid-gap:var(--aa-spacing-half);gap:var(--aa-spacing-half);grid-auto-flow:column;justify-content:start}.aa-ItemContentSubtitle--standalone .aa-ItemContentSubtitleIcon:before{border-radius:0 0 0 3px;border-width:0 0 1.5px 1.5px;height:8px;height:var(--aa-spacing-half);width:8px;width:var(--aa-spacing-half)}.aa-ItemContentSubtitleCategory{color:#807ea3;color:rgba(var(--aa-muted-color-rgb),1);font-weight:500}.aa-ItemContentDescription{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-size:.85em;max-width:100%;overflow-x:hidden;text-overflow:ellipsis}.aa-ItemContentDescription:empty{display:none}.aa-ItemContentDescription mark{background:rgba(245,223,77,.5);background:rgba(var(--aa-description-highlight-background-color-rgb),var(--aa-description-highlight-background-color-alpha));color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));font-style:normal;font-weight:500;font-weight:var(--aa-font-weight-medium)}.aa-ItemContentDash{color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));display:none;opacity:.4}.aa-ItemContentTag{background-color:rgba(62,52,211,.2);background-color:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha));border-radius:3px;margin:0 .4em 0 0;padding:.08em .3em}.aa-ItemLink,.aa-ItemWrapper{align-items:center;color:inherit;display:grid;grid-gap:4px;gap:4px;grid-gap:calc(var(--aa-spacing-half)/2);gap:calc(var(--aa-spacing-half)/2);grid-auto-flow:column;justify-content:space-between;width:100%}.aa-ItemLink{color:inherit;text-decoration:none}.aa-ItemActions{display:grid;grid-auto-flow:column;height:100%;justify-self:end;margin:0 -5.3333333333px;margin:0 calc(var(--aa-spacing)/-3);padding:0 2px 0 0}.aa-ItemActionButton{align-items:center;background:none;border:0;color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;flex-shrink:0;padding:0}.aa-ItemActionButton:focus svg,.aa-ItemActionButton:hover svg{color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha))}@media (hover:none) and (pointer:coarse){.aa-ItemActionButton:focus svg,.aa-ItemActionButton:hover svg{color:inherit}}.aa-ItemActionButton svg{color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));margin:5.3333333333px;margin:calc(var(--aa-spacing)/3);stroke-width:1.6;stroke-width:var(--aa-icon-stroke-width);width:20px;width:var(--aa-action-icon-size)}.aa-ActiveOnly{visibility:hidden}.aa-PanelHeader{align-items:center;background:#3e34d3;background:rgba(var(--aa-primary-color-rgb),1);color:#fff;display:grid;height:var(--aa-modal-header-height);margin:0;padding:8px 16px;padding:var(--aa-spacing-half) var(--aa-spacing);position:relative}.aa-PanelHeader:after{background-image:linear-gradient(#fff,hsla(0,0%,100%,0));background-image:linear-gradient(rgba(var(--aa-background-color-rgb),1),rgba(var(--aa-background-color-rgb),0));bottom:-8px;bottom:calc(var(--aa-spacing-half)*-1);content:"";height:8px;height:var(--aa-spacing-half);left:0;pointer-events:none;position:absolute;right:0}.aa-PanelFooter,.aa-PanelHeader:after{z-index:9999;z-index:var(--aa-base-z-index)}.aa-PanelFooter{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));box-shadow:inset 0 1px 0 rgba(128,126,163,.3);box-shadow:inset 0 1px 0 rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));display:flex;justify-content:space-between;margin:0;padding:16px;padding:var(--aa-spacing);position:relative}.aa-PanelFooter:after{background-image:linear-gradient(hsla(0,0%,100%,0),rgba(128,126,163,.6));background-image:linear-gradient(rgba(var(--aa-background-color-rgb),0),rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha)));content:"";height:16px;height:var(--aa-spacing);left:0;opacity:.12;pointer-events:none;position:absolute;right:0;top:-16px;top:calc(var(--aa-spacing)*-1);z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-DetachedContainer{background:#fff;background:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));bottom:0;box-shadow:0 0 0 1px rgba(35,38,59,.1),0 6px 16px -4px rgba(35,38,59,.15);box-shadow:var(--aa-panel-shadow);display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:9999;z-index:var(--aa-base-z-index)}.aa-DetachedContainer:after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:8px 0 8px 2px;margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;background-color:rgba(var(--aa-background-color-rgb),var(--aa-background-color-alpha));border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{border-bottom:1px solid rgba(128,126,163,.3);border-bottom:1px solid rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha));display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:8px;padding:var(--aa-spacing-half)}.aa-DetachedCancelButton{background:none;border:0;border-radius:3px;color:inherit;color:#262627;color:rgba(var(--aa-text-color-rgb),var(--aa-text-color-alpha));cursor:pointer;font:inherit;margin:0 0 0 8px;margin:0 0 0 var(--aa-spacing-half);padding:0 8px;padding:0 var(--aa-spacing-half)}.aa-DetachedCancelButton:focus,.aa-DetachedCancelButton:hover{box-shadow:inset 0 0 0 1px rgba(128,126,163,.3);box-shadow:inset 0 0 0 1px rgba(var(--aa-panel-border-color-rgb),var(--aa-panel-border-color-alpha))}.aa-DetachedContainer--modal{border-radius:6px;bottom:inherit;height:auto;margin:0 auto;max-width:680px;max-width:var(--aa-detached-modal-max-width);position:absolute;top:3%}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:500px;max-height:var(--aa-detached-modal-max-height);padding-bottom:8px;padding-bottom:var(--aa-spacing-half);position:static}.aa-DetachedSearchButton{align-items:center;background-color:#fff;background-color:rgba(var(--aa-input-background-color-rgb),var(--aa-input-background-color-alpha));border:1px solid rgba(128,126,163,.8);border:1px solid rgba(var(--aa-input-border-color-rgb),var(--aa-input-border-color-alpha));border-radius:3px;color:rgba(128,126,163,.6);color:rgba(var(--aa-muted-color-rgb),var(--aa-muted-color-alpha));cursor:pointer;display:flex;font:inherit;font-family:inherit;font-family:var(--aa-font-family);font-size:16px;font-size:var(--aa-font-size);height:44px;height:var(--aa-search-input-height);margin:0;padding:0 5.5px;padding:0 calc(var(--aa-search-input-height)/8);position:relative;text-align:left;width:100%}.aa-DetachedSearchButton:focus{border-color:#3e34d3;border-color:rgba(var(--aa-primary-color-rgb),1);box-shadow:0 0 0 3px rgba(62,52,211,.2),inset 0 0 0 2px rgba(62,52,211,.2);box-shadow:rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 3px,inset rgba(var(--aa-primary-color-rgb),var(--aa-primary-color-alpha)) 0 0 0 2px;outline:medium none currentColor}.aa-DetachedSearchButtonIcon{align-items:center;color:#3e34d3;color:rgba(var(--aa-primary-color-rgb),1);cursor:auto;display:flex;height:100%;justify-content:center;width:36px;width:calc(var(--aa-icon-size) + var(--aa-spacing))}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(115,114,129,.4);background-color:rgba(var(--aa-overlay-color-rgb),var(--aa-overlay-color-alpha));height:100vh;left:0;margin:0;padding:0;position:fixed;right:0;top:0;z-index:9998;z-index:calc(var(--aa-base-z-index) - 1)}.aa-GradientBottom,.aa-GradientTop{height:8px;height:var(--aa-spacing-half);left:0;pointer-events:none;position:absolute;right:0;z-index:9999;z-index:var(--aa-base-z-index)}.aa-GradientTop{background-image:linear-gradient(#fff,hsla(0,0%,100%,0));background-image:linear-gradient(rgba(var(--aa-background-color-rgb),1),rgba(var(--aa-background-color-rgb),0));top:0}.aa-GradientBottom{background-image:linear-gradient(hsla(0,0%,100%,0),#fff);background-image:linear-gradient(rgba(var(--aa-background-color-rgb),0),rgba(var(--aa-background-color-rgb),1));border-bottom-left-radius:4px;border-bottom-left-radius:calc(var(--aa-spacing)/4);border-bottom-right-radius:4px;border-bottom-right-radius:calc(var(--aa-spacing)/4);bottom:0}@media (hover:none) and (pointer:coarse){.aa-DesktopOnly{display:none}}@media (hover:hover){.aa-TouchOnly{display:none}}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/autocomplete.d.ts b/assets/autocomplete.js/dist/esm/autocomplete.d.ts
new file mode 100644
index 00000000..fabd6c3b
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/autocomplete.d.ts
@@ -0,0 +1,3 @@
+import { BaseItem } from '@algolia/autocomplete-core';
+import { AutocompleteApi, AutocompleteOptions } from './types';
+export declare function autocomplete(options: AutocompleteOptions): AutocompleteApi;
diff --git a/assets/autocomplete.js/dist/esm/autocomplete.js b/assets/autocomplete.js/dist/esm/autocomplete.js
new file mode 100644
index 00000000..a76f2f22
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/autocomplete.js
@@ -0,0 +1,331 @@
+var _excluded = ["components"];
+
+function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
+
+function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
+
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+import { createAutocomplete } from '@algolia/autocomplete-core';
+import { createRef, debounce, getItemsCount } from '@algolia/autocomplete-shared';
+import htm from 'htm';
+import { createAutocompleteDom } from './createAutocompleteDom';
+import { createEffectWrapper } from './createEffectWrapper';
+import { createReactiveWrapper } from './createReactiveWrapper';
+import { getDefaultOptions } from './getDefaultOptions';
+import { getPanelPlacementStyle } from './getPanelPlacementStyle';
+import { renderPanel, renderSearchBox } from './render';
+import { userAgents } from './userAgents';
+import { mergeDeep, pickBy, setProperties } from './utils';
+export function autocomplete(options) {
+ var _createEffectWrapper = createEffectWrapper(),
+ runEffect = _createEffectWrapper.runEffect,
+ cleanupEffects = _createEffectWrapper.cleanupEffects,
+ runEffects = _createEffectWrapper.runEffects;
+
+ var _createReactiveWrappe = createReactiveWrapper(),
+ reactive = _createReactiveWrappe.reactive,
+ runReactives = _createReactiveWrappe.runReactives;
+
+ var hasNoResultsSourceTemplateRef = createRef(false);
+ var optionsRef = createRef(options);
+ var onStateChangeRef = createRef(undefined);
+ var props = reactive(function () {
+ return getDefaultOptions(optionsRef.current);
+ });
+ var isDetached = reactive(function () {
+ return props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
+ });
+ var autocomplete = reactive(function () {
+ return createAutocomplete(_objectSpread(_objectSpread({}, props.value.core), {}, {
+ onStateChange: function onStateChange(params) {
+ var _onStateChangeRef$cur, _props$value$core$onS, _props$value$core;
+
+ hasNoResultsSourceTemplateRef.current = params.state.collections.some(function (collection) {
+ return collection.source.templates.noResults;
+ });
+ (_onStateChangeRef$cur = onStateChangeRef.current) === null || _onStateChangeRef$cur === void 0 ? void 0 : _onStateChangeRef$cur.call(onStateChangeRef, params);
+ (_props$value$core$onS = (_props$value$core = props.value.core).onStateChange) === null || _props$value$core$onS === void 0 ? void 0 : _props$value$core$onS.call(_props$value$core, params);
+ },
+ shouldPanelOpen: optionsRef.current.shouldPanelOpen || function (_ref) {
+ var state = _ref.state;
+
+ if (isDetached.value) {
+ return true;
+ }
+
+ var hasItems = getItemsCount(state) > 0;
+
+ if (!props.value.core.openOnFocus && !state.query) {
+ return hasItems;
+ }
+
+ var hasNoResultsTemplate = Boolean(hasNoResultsSourceTemplateRef.current || props.value.renderer.renderNoResults);
+ return !hasItems && hasNoResultsTemplate || hasItems;
+ },
+ __autocomplete_metadata: {
+ userAgents: userAgents,
+ options: options
+ }
+ }));
+ });
+ var lastStateRef = createRef(_objectSpread({
+ collections: [],
+ completion: null,
+ context: {},
+ isOpen: false,
+ query: '',
+ activeItemId: null,
+ status: 'idle'
+ }, props.value.core.initialState));
+ var propGetters = {
+ getEnvironmentProps: props.value.renderer.getEnvironmentProps,
+ getFormProps: props.value.renderer.getFormProps,
+ getInputProps: props.value.renderer.getInputProps,
+ getItemProps: props.value.renderer.getItemProps,
+ getLabelProps: props.value.renderer.getLabelProps,
+ getListProps: props.value.renderer.getListProps,
+ getPanelProps: props.value.renderer.getPanelProps,
+ getRootProps: props.value.renderer.getRootProps
+ };
+ var autocompleteScopeApi = {
+ setActiveItemId: autocomplete.value.setActiveItemId,
+ setQuery: autocomplete.value.setQuery,
+ setCollections: autocomplete.value.setCollections,
+ setIsOpen: autocomplete.value.setIsOpen,
+ setStatus: autocomplete.value.setStatus,
+ setContext: autocomplete.value.setContext,
+ refresh: autocomplete.value.refresh
+ };
+ var html = reactive(function () {
+ return htm.bind(props.value.renderer.renderer.createElement);
+ });
+ var dom = reactive(function () {
+ return createAutocompleteDom({
+ autocomplete: autocomplete.value,
+ autocompleteScopeApi: autocompleteScopeApi,
+ classNames: props.value.renderer.classNames,
+ environment: props.value.core.environment,
+ isDetached: isDetached.value,
+ placeholder: props.value.core.placeholder,
+ propGetters: propGetters,
+ setIsModalOpen: setIsModalOpen,
+ state: lastStateRef.current,
+ translations: props.value.renderer.translations
+ });
+ });
+
+ function setPanelPosition() {
+ setProperties(dom.value.panel, {
+ style: isDetached.value ? {} : getPanelPlacementStyle({
+ panelPlacement: props.value.renderer.panelPlacement,
+ container: dom.value.root,
+ form: dom.value.form,
+ environment: props.value.core.environment
+ })
+ });
+ }
+
+ function scheduleRender(state) {
+ lastStateRef.current = state;
+ var renderProps = {
+ autocomplete: autocomplete.value,
+ autocompleteScopeApi: autocompleteScopeApi,
+ classNames: props.value.renderer.classNames,
+ components: props.value.renderer.components,
+ container: props.value.renderer.container,
+ html: html.value,
+ dom: dom.value,
+ panelContainer: isDetached.value ? dom.value.detachedContainer : props.value.renderer.panelContainer,
+ propGetters: propGetters,
+ state: lastStateRef.current,
+ renderer: props.value.renderer.renderer
+ };
+ var render = !getItemsCount(state) && !hasNoResultsSourceTemplateRef.current && props.value.renderer.renderNoResults || props.value.renderer.render;
+ renderSearchBox(renderProps);
+ renderPanel(render, renderProps);
+ }
+
+ runEffect(function () {
+ var environmentProps = autocomplete.value.getEnvironmentProps({
+ formElement: dom.value.form,
+ panelElement: dom.value.panel,
+ inputElement: dom.value.input
+ });
+ setProperties(props.value.core.environment, environmentProps);
+ return function () {
+ setProperties(props.value.core.environment, Object.keys(environmentProps).reduce(function (acc, key) {
+ return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, key, undefined));
+ }, {}));
+ };
+ });
+ runEffect(function () {
+ var panelContainerElement = isDetached.value ? props.value.core.environment.document.body : props.value.renderer.panelContainer;
+ var panelElement = isDetached.value ? dom.value.detachedOverlay : dom.value.panel;
+
+ if (isDetached.value && lastStateRef.current.isOpen) {
+ setIsModalOpen(true);
+ }
+
+ scheduleRender(lastStateRef.current);
+ return function () {
+ if (panelContainerElement.contains(panelElement)) {
+ panelContainerElement.removeChild(panelElement);
+ }
+ };
+ });
+ runEffect(function () {
+ var containerElement = props.value.renderer.container;
+ containerElement.appendChild(dom.value.root);
+ return function () {
+ containerElement.removeChild(dom.value.root);
+ };
+ });
+ runEffect(function () {
+ var debouncedRender = debounce(function (_ref2) {
+ var state = _ref2.state;
+ scheduleRender(state);
+ }, 0);
+
+ onStateChangeRef.current = function (_ref3) {
+ var state = _ref3.state,
+ prevState = _ref3.prevState;
+
+ if (isDetached.value && prevState.isOpen !== state.isOpen) {
+ setIsModalOpen(state.isOpen);
+ } // The outer DOM might have changed since the last time the panel was
+ // positioned. The layout might have shifted vertically for instance.
+ // It's therefore safer to re-calculate the panel position before opening
+ // it again.
+
+
+ if (!isDetached.value && state.isOpen && !prevState.isOpen) {
+ setPanelPosition();
+ } // We scroll to the top of the panel whenever the query changes (i.e. new
+ // results come in) so that users don't have to.
+
+
+ if (state.query !== prevState.query) {
+ var scrollablePanels = props.value.core.environment.document.querySelectorAll('.aa-Panel--scrollable');
+ scrollablePanels.forEach(function (scrollablePanel) {
+ if (scrollablePanel.scrollTop !== 0) {
+ scrollablePanel.scrollTop = 0;
+ }
+ });
+ }
+
+ debouncedRender({
+ state: state
+ });
+ };
+
+ return function () {
+ onStateChangeRef.current = undefined;
+ };
+ });
+ runEffect(function () {
+ var onResize = debounce(function () {
+ var previousIsDetached = isDetached.value;
+ isDetached.value = props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
+
+ if (previousIsDetached !== isDetached.value) {
+ update({});
+ } else {
+ requestAnimationFrame(setPanelPosition);
+ }
+ }, 20);
+ props.value.core.environment.addEventListener('resize', onResize);
+ return function () {
+ props.value.core.environment.removeEventListener('resize', onResize);
+ };
+ });
+ runEffect(function () {
+ if (!isDetached.value) {
+ return function () {};
+ }
+
+ function toggleModalClassname(isActive) {
+ dom.value.detachedContainer.classList.toggle('aa-DetachedContainer--modal', isActive);
+ }
+
+ function onChange(event) {
+ toggleModalClassname(event.matches);
+ }
+
+ var isModalDetachedMql = props.value.core.environment.matchMedia(getComputedStyle(props.value.core.environment.document.documentElement).getPropertyValue('--aa-detached-modal-media-query'));
+ toggleModalClassname(isModalDetachedMql.matches); // Prior to Safari 14, `MediaQueryList` isn't based on `EventTarget`,
+ // so we must use `addListener` and `removeListener` to observe media query lists.
+ // See https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener
+
+ var hasModernEventListener = Boolean(isModalDetachedMql.addEventListener);
+ hasModernEventListener ? isModalDetachedMql.addEventListener('change', onChange) : isModalDetachedMql.addListener(onChange);
+ return function () {
+ hasModernEventListener ? isModalDetachedMql.removeEventListener('change', onChange) : isModalDetachedMql.removeListener(onChange);
+ };
+ });
+ runEffect(function () {
+ requestAnimationFrame(setPanelPosition);
+ return function () {};
+ });
+
+ function destroy() {
+ cleanupEffects();
+ }
+
+ function update() {
+ var updatedOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+ cleanupEffects();
+
+ var _props$value$renderer = props.value.renderer,
+ components = _props$value$renderer.components,
+ rendererProps = _objectWithoutProperties(_props$value$renderer, _excluded);
+
+ optionsRef.current = mergeDeep(rendererProps, props.value.core, {
+ // We need to filter out default components so they can be replaced with
+ // a new `renderer`, without getting rid of user components.
+ // @MAJOR Deal with registering components with the same name as the
+ // default ones. If we disallow overriding default components, we'd just
+ // need to pass all `components` here.
+ components: pickBy(components, function (_ref4) {
+ var value = _ref4.value;
+ return !value.hasOwnProperty('__autocomplete_componentName');
+ }),
+ initialState: lastStateRef.current
+ }, updatedOptions);
+ runReactives();
+ runEffects();
+ autocomplete.value.refresh().then(function () {
+ scheduleRender(lastStateRef.current);
+ });
+ }
+
+ function setIsModalOpen(value) {
+ requestAnimationFrame(function () {
+ var prevValue = props.value.core.environment.document.body.contains(dom.value.detachedOverlay);
+
+ if (value === prevValue) {
+ return;
+ }
+
+ if (value) {
+ props.value.core.environment.document.body.appendChild(dom.value.detachedOverlay);
+ props.value.core.environment.document.body.classList.add('aa-Detached');
+ dom.value.input.focus();
+ } else {
+ props.value.core.environment.document.body.removeChild(dom.value.detachedOverlay);
+ props.value.core.environment.document.body.classList.remove('aa-Detached');
+ autocomplete.value.setQuery('');
+ autocomplete.value.refresh();
+ }
+ });
+ }
+
+ return _objectSpread(_objectSpread({}, autocompleteScopeApi), {}, {
+ update: update,
+ destroy: destroy
+ });
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/components/Highlight.d.ts b/assets/autocomplete.js/dist/esm/components/Highlight.d.ts
new file mode 100644
index 00000000..214dbdda
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/Highlight.d.ts
@@ -0,0 +1,6 @@
+///
+import { AutocompleteRenderer, HighlightHitParams } from '../types';
+export declare function createHighlightComponent({ createElement, Fragment, }: AutocompleteRenderer): {
+ ({ hit, attribute, tagName, }: HighlightHitParams): JSX.Element;
+ __autocomplete_componentName: string;
+};
diff --git a/assets/autocomplete.js/dist/esm/components/Highlight.js b/assets/autocomplete.js/dist/esm/components/Highlight.js
new file mode 100644
index 00000000..f3a17d4c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/Highlight.js
@@ -0,0 +1,23 @@
+import { parseAlgoliaHitHighlight } from '@algolia/autocomplete-preset-algolia';
+export function createHighlightComponent(_ref) {
+ var createElement = _ref.createElement,
+ Fragment = _ref.Fragment;
+
+ function Highlight(_ref2) {
+ var hit = _ref2.hit,
+ attribute = _ref2.attribute,
+ _ref2$tagName = _ref2.tagName,
+ tagName = _ref2$tagName === void 0 ? 'mark' : _ref2$tagName;
+ return createElement(Fragment, {}, parseAlgoliaHitHighlight({
+ hit: hit,
+ attribute: attribute
+ }).map(function (x, index) {
+ return x.isHighlighted ? createElement(tagName, {
+ key: index
+ }, x.value) : x.value;
+ }));
+ }
+
+ Highlight.__autocomplete_componentName = 'Highlight';
+ return Highlight;
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/components/ReverseHighlight.d.ts b/assets/autocomplete.js/dist/esm/components/ReverseHighlight.d.ts
new file mode 100644
index 00000000..bb5937f5
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/ReverseHighlight.d.ts
@@ -0,0 +1,6 @@
+///
+import { AutocompleteRenderer, HighlightHitParams } from '../types';
+export declare function createReverseHighlightComponent({ createElement, Fragment, }: AutocompleteRenderer): {
+ ({ hit, attribute, tagName, }: HighlightHitParams): JSX.Element;
+ __autocomplete_componentName: string;
+};
diff --git a/assets/autocomplete.js/dist/esm/components/ReverseHighlight.js b/assets/autocomplete.js/dist/esm/components/ReverseHighlight.js
new file mode 100644
index 00000000..bca45bb6
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/ReverseHighlight.js
@@ -0,0 +1,23 @@
+import { parseAlgoliaHitReverseHighlight } from '@algolia/autocomplete-preset-algolia';
+export function createReverseHighlightComponent(_ref) {
+ var createElement = _ref.createElement,
+ Fragment = _ref.Fragment;
+
+ function ReverseHighlight(_ref2) {
+ var hit = _ref2.hit,
+ attribute = _ref2.attribute,
+ _ref2$tagName = _ref2.tagName,
+ tagName = _ref2$tagName === void 0 ? 'mark' : _ref2$tagName;
+ return createElement(Fragment, {}, parseAlgoliaHitReverseHighlight({
+ hit: hit,
+ attribute: attribute
+ }).map(function (x, index) {
+ return x.isHighlighted ? createElement(tagName, {
+ key: index
+ }, x.value) : x.value;
+ }));
+ }
+
+ ReverseHighlight.__autocomplete_componentName = 'ReverseHighlight';
+ return ReverseHighlight;
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/components/ReverseSnippet.d.ts b/assets/autocomplete.js/dist/esm/components/ReverseSnippet.d.ts
new file mode 100644
index 00000000..c4bbd509
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/ReverseSnippet.d.ts
@@ -0,0 +1,6 @@
+///
+import { AutocompleteRenderer, HighlightHitParams } from '../types';
+export declare function createReverseSnippetComponent({ createElement, Fragment, }: AutocompleteRenderer): {
+ ({ hit, attribute, tagName, }: HighlightHitParams): JSX.Element;
+ __autocomplete_componentName: string;
+};
diff --git a/assets/autocomplete.js/dist/esm/components/ReverseSnippet.js b/assets/autocomplete.js/dist/esm/components/ReverseSnippet.js
new file mode 100644
index 00000000..7d22aad0
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/ReverseSnippet.js
@@ -0,0 +1,23 @@
+import { parseAlgoliaHitReverseSnippet } from '@algolia/autocomplete-preset-algolia';
+export function createReverseSnippetComponent(_ref) {
+ var createElement = _ref.createElement,
+ Fragment = _ref.Fragment;
+
+ function ReverseSnippet(_ref2) {
+ var hit = _ref2.hit,
+ attribute = _ref2.attribute,
+ _ref2$tagName = _ref2.tagName,
+ tagName = _ref2$tagName === void 0 ? 'mark' : _ref2$tagName;
+ return createElement(Fragment, {}, parseAlgoliaHitReverseSnippet({
+ hit: hit,
+ attribute: attribute
+ }).map(function (x, index) {
+ return x.isHighlighted ? createElement(tagName, {
+ key: index
+ }, x.value) : x.value;
+ }));
+ }
+
+ ReverseSnippet.__autocomplete_componentName = 'ReverseSnippet';
+ return ReverseSnippet;
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/components/Snippet.d.ts b/assets/autocomplete.js/dist/esm/components/Snippet.d.ts
new file mode 100644
index 00000000..7b478583
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/Snippet.d.ts
@@ -0,0 +1,6 @@
+///
+import { AutocompleteRenderer, HighlightHitParams } from '../types';
+export declare function createSnippetComponent({ createElement, Fragment, }: AutocompleteRenderer): {
+ ({ hit, attribute, tagName, }: HighlightHitParams): JSX.Element;
+ __autocomplete_componentName: string;
+};
diff --git a/assets/autocomplete.js/dist/esm/components/Snippet.js b/assets/autocomplete.js/dist/esm/components/Snippet.js
new file mode 100644
index 00000000..9065a0dc
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/Snippet.js
@@ -0,0 +1,23 @@
+import { parseAlgoliaHitSnippet } from '@algolia/autocomplete-preset-algolia';
+export function createSnippetComponent(_ref) {
+ var createElement = _ref.createElement,
+ Fragment = _ref.Fragment;
+
+ function Snippet(_ref2) {
+ var hit = _ref2.hit,
+ attribute = _ref2.attribute,
+ _ref2$tagName = _ref2.tagName,
+ tagName = _ref2$tagName === void 0 ? 'mark' : _ref2$tagName;
+ return createElement(Fragment, {}, parseAlgoliaHitSnippet({
+ hit: hit,
+ attribute: attribute
+ }).map(function (x, index) {
+ return x.isHighlighted ? createElement(tagName, {
+ key: index
+ }, x.value) : x.value;
+ }));
+ }
+
+ Snippet.__autocomplete_componentName = 'Snippet';
+ return Snippet;
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/components/index.d.ts b/assets/autocomplete.js/dist/esm/components/index.d.ts
new file mode 100644
index 00000000..2f1cf316
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/index.d.ts
@@ -0,0 +1,4 @@
+export * from './Highlight';
+export * from './ReverseHighlight';
+export * from './ReverseSnippet';
+export * from './Snippet';
diff --git a/assets/autocomplete.js/dist/esm/components/index.js b/assets/autocomplete.js/dist/esm/components/index.js
new file mode 100644
index 00000000..4222ba60
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/components/index.js
@@ -0,0 +1,4 @@
+export * from './Highlight';
+export * from './ReverseHighlight';
+export * from './ReverseSnippet';
+export * from './Snippet';
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/createAutocompleteDom.d.ts b/assets/autocomplete.js/dist/esm/createAutocompleteDom.d.ts
new file mode 100644
index 00000000..c263bddf
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createAutocompleteDom.d.ts
@@ -0,0 +1,16 @@
+import { AutocompleteApi as AutocompleteCoreApi, AutocompleteEnvironment, AutocompleteScopeApi, BaseItem } from '@algolia/autocomplete-core';
+import { AutocompleteClassNames, AutocompleteDom, AutocompletePropGetters, AutocompleteState, AutocompleteTranslations } from './types';
+declare type CreateDomProps = {
+ autocomplete: AutocompleteCoreApi;
+ autocompleteScopeApi: AutocompleteScopeApi;
+ classNames: AutocompleteClassNames;
+ environment: AutocompleteEnvironment;
+ isDetached: boolean;
+ placeholder?: string;
+ propGetters: AutocompletePropGetters;
+ setIsModalOpen(value: boolean): void;
+ state: AutocompleteState;
+ translations: AutocompleteTranslations;
+};
+export declare function createAutocompleteDom({ autocomplete, autocompleteScopeApi, classNames, environment, isDetached, placeholder, propGetters, setIsModalOpen, state, translations, }: CreateDomProps): AutocompleteDom;
+export {};
diff --git a/assets/autocomplete.js/dist/esm/createAutocompleteDom.js b/assets/autocomplete.js/dist/esm/createAutocompleteDom.js
new file mode 100644
index 00000000..77b5040d
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createAutocompleteDom.js
@@ -0,0 +1,175 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+import { ClearIcon, Input, LoadingIcon, SearchIcon } from './elements';
+import { getCreateDomElement } from './getCreateDomElement';
+import { setProperties } from './utils';
+export function createAutocompleteDom(_ref) {
+ var autocomplete = _ref.autocomplete,
+ autocompleteScopeApi = _ref.autocompleteScopeApi,
+ classNames = _ref.classNames,
+ environment = _ref.environment,
+ isDetached = _ref.isDetached,
+ _ref$placeholder = _ref.placeholder,
+ placeholder = _ref$placeholder === void 0 ? 'Search' : _ref$placeholder,
+ propGetters = _ref.propGetters,
+ setIsModalOpen = _ref.setIsModalOpen,
+ state = _ref.state,
+ translations = _ref.translations;
+ var createDomElement = getCreateDomElement(environment);
+ var rootProps = propGetters.getRootProps(_objectSpread({
+ state: state,
+ props: autocomplete.getRootProps({})
+ }, autocompleteScopeApi));
+ var root = createDomElement('div', _objectSpread({
+ class: classNames.root
+ }, rootProps));
+ var detachedContainer = createDomElement('div', {
+ class: classNames.detachedContainer,
+ onMouseDown: function onMouseDown(event) {
+ event.stopPropagation();
+ }
+ });
+ var detachedOverlay = createDomElement('div', {
+ class: classNames.detachedOverlay,
+ children: [detachedContainer],
+ onMouseDown: function onMouseDown() {
+ setIsModalOpen(false);
+ autocomplete.setIsOpen(false);
+ }
+ });
+ var labelProps = propGetters.getLabelProps(_objectSpread({
+ state: state,
+ props: autocomplete.getLabelProps({})
+ }, autocompleteScopeApi));
+ var submitButton = createDomElement('button', {
+ class: classNames.submitButton,
+ type: 'submit',
+ title: translations.submitButtonTitle,
+ children: [SearchIcon({
+ environment: environment
+ })]
+ });
+ var label = createDomElement('label', _objectSpread({
+ class: classNames.label,
+ children: [submitButton]
+ }, labelProps));
+ var clearButton = createDomElement('button', {
+ class: classNames.clearButton,
+ type: 'reset',
+ title: translations.clearButtonTitle,
+ children: [ClearIcon({
+ environment: environment
+ })]
+ });
+ var loadingIndicator = createDomElement('div', {
+ class: classNames.loadingIndicator,
+ children: [LoadingIcon({
+ environment: environment
+ })]
+ });
+ var input = Input({
+ class: classNames.input,
+ environment: environment,
+ state: state,
+ getInputProps: propGetters.getInputProps,
+ getInputPropsCore: autocomplete.getInputProps,
+ autocompleteScopeApi: autocompleteScopeApi,
+ isDetached: isDetached
+ });
+ var inputWrapperPrefix = createDomElement('div', {
+ class: classNames.inputWrapperPrefix,
+ children: [label, loadingIndicator]
+ });
+ var inputWrapperSuffix = createDomElement('div', {
+ class: classNames.inputWrapperSuffix,
+ children: [clearButton]
+ });
+ var inputWrapper = createDomElement('div', {
+ class: classNames.inputWrapper,
+ children: [input]
+ });
+ var formProps = propGetters.getFormProps(_objectSpread({
+ state: state,
+ props: autocomplete.getFormProps({
+ inputElement: input
+ })
+ }, autocompleteScopeApi));
+ var form = createDomElement('form', _objectSpread({
+ class: classNames.form,
+ children: [inputWrapperPrefix, inputWrapper, inputWrapperSuffix]
+ }, formProps));
+ var panelProps = propGetters.getPanelProps(_objectSpread({
+ state: state,
+ props: autocomplete.getPanelProps({})
+ }, autocompleteScopeApi));
+ var panel = createDomElement('div', _objectSpread({
+ class: classNames.panel
+ }, panelProps));
+
+ if (process.env.NODE_ENV === 'test') {
+ setProperties(panel, {
+ 'data-testid': 'panel'
+ });
+ }
+
+ if (isDetached) {
+ var detachedSearchButtonIcon = createDomElement('div', {
+ class: classNames.detachedSearchButtonIcon,
+ children: [SearchIcon({
+ environment: environment
+ })]
+ });
+ var detachedSearchButtonPlaceholder = createDomElement('div', {
+ class: classNames.detachedSearchButtonPlaceholder,
+ textContent: placeholder
+ });
+ var detachedSearchButton = createDomElement('button', {
+ type: 'button',
+ class: classNames.detachedSearchButton,
+ onClick: function onClick() {
+ setIsModalOpen(true);
+ },
+ children: [detachedSearchButtonIcon, detachedSearchButtonPlaceholder]
+ });
+ var detachedCancelButton = createDomElement('button', {
+ type: 'button',
+ class: classNames.detachedCancelButton,
+ textContent: translations.detachedCancelButtonText,
+ // Prevent `onTouchStart` from closing the panel
+ // since it should be initiated by `onClick` only
+ onTouchStart: function onTouchStart(event) {
+ event.stopPropagation();
+ },
+ onClick: function onClick() {
+ autocomplete.setIsOpen(false);
+ setIsModalOpen(false);
+ }
+ });
+ var detachedFormContainer = createDomElement('div', {
+ class: classNames.detachedFormContainer,
+ children: [form, detachedCancelButton]
+ });
+ detachedContainer.appendChild(detachedFormContainer);
+ root.appendChild(detachedSearchButton);
+ } else {
+ root.appendChild(form);
+ }
+
+ return {
+ detachedContainer: detachedContainer,
+ detachedOverlay: detachedOverlay,
+ inputWrapper: inputWrapper,
+ input: input,
+ root: root,
+ form: form,
+ label: label,
+ submitButton: submitButton,
+ clearButton: clearButton,
+ loadingIndicator: loadingIndicator,
+ panel: panel
+ };
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/createEffectWrapper.d.ts b/assets/autocomplete.js/dist/esm/createEffectWrapper.d.ts
new file mode 100644
index 00000000..e3335834
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createEffectWrapper.d.ts
@@ -0,0 +1,9 @@
+declare type Effect = () => void;
+declare type EffectFn = () => Effect;
+declare type EffectWrapper = {
+ runEffect(fn: EffectFn): void;
+ cleanupEffects(): void;
+ runEffects(): void;
+};
+export declare function createEffectWrapper(): EffectWrapper;
+export {};
diff --git a/assets/autocomplete.js/dist/esm/createEffectWrapper.js b/assets/autocomplete.js/dist/esm/createEffectWrapper.js
new file mode 100644
index 00000000..14032c10
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createEffectWrapper.js
@@ -0,0 +1,28 @@
+export function createEffectWrapper() {
+ var effects = [];
+ var cleanups = [];
+
+ function runEffect(fn) {
+ effects.push(fn);
+ var effectCleanup = fn();
+ cleanups.push(effectCleanup);
+ }
+
+ return {
+ runEffect: runEffect,
+ cleanupEffects: function cleanupEffects() {
+ var currentCleanups = cleanups;
+ cleanups = [];
+ currentCleanups.forEach(function (cleanup) {
+ cleanup();
+ });
+ },
+ runEffects: function runEffects() {
+ var currentEffects = effects;
+ effects = [];
+ currentEffects.forEach(function (effect) {
+ runEffect(effect);
+ });
+ }
+ };
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/createReactiveWrapper.d.ts b/assets/autocomplete.js/dist/esm/createReactiveWrapper.d.ts
new file mode 100644
index 00000000..b87d293a
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createReactiveWrapper.d.ts
@@ -0,0 +1,19 @@
+declare type ReactiveValue = () => TValue;
+export declare type Reactive = {
+ value: TValue;
+ /**
+ * @private
+ */
+ _fn: ReactiveValue;
+ /**
+ * @private
+ */
+ _ref: {
+ current: TValue;
+ };
+};
+export declare function createReactiveWrapper(): {
+ reactive(value: ReactiveValue): Reactive;
+ runReactives(): void;
+};
+export {};
diff --git a/assets/autocomplete.js/dist/esm/createReactiveWrapper.js b/assets/autocomplete.js/dist/esm/createReactiveWrapper.js
new file mode 100644
index 00000000..e695ea77
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/createReactiveWrapper.js
@@ -0,0 +1,30 @@
+export function createReactiveWrapper() {
+ var reactives = [];
+ return {
+ reactive: function reactive(value) {
+ var current = value();
+ var reactive = {
+ _fn: value,
+ _ref: {
+ current: current
+ },
+
+ get value() {
+ return this._ref.current;
+ },
+
+ set value(value) {
+ this._ref.current = value;
+ }
+
+ };
+ reactives.push(reactive);
+ return reactive;
+ },
+ runReactives: function runReactives() {
+ reactives.forEach(function (value) {
+ value._ref.current = value._fn();
+ });
+ }
+ };
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/elements/ClearIcon.d.ts b/assets/autocomplete.js/dist/esm/elements/ClearIcon.d.ts
new file mode 100644
index 00000000..d57c6110
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/ClearIcon.d.ts
@@ -0,0 +1,5 @@
+import { AutocompleteEnvironment } from '@algolia/autocomplete-core';
+import { AutocompleteElement } from '../types/AutocompleteElement';
+export declare const ClearIcon: AutocompleteElement<{
+ environment: AutocompleteEnvironment;
+}, SVGSVGElement>;
diff --git a/assets/autocomplete.js/dist/esm/elements/ClearIcon.js b/assets/autocomplete.js/dist/esm/elements/ClearIcon.js
new file mode 100644
index 00000000..a46aff9b
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/ClearIcon.js
@@ -0,0 +1,13 @@
+export var ClearIcon = function ClearIcon(_ref) {
+ var environment = _ref.environment;
+ var element = environment.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ element.setAttribute('class', 'aa-ClearIcon');
+ element.setAttribute('viewBox', '0 0 24 24');
+ element.setAttribute('width', '18');
+ element.setAttribute('height', '18');
+ element.setAttribute('fill', 'currentColor');
+ var path = environment.document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ path.setAttribute('d', 'M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z');
+ element.appendChild(path);
+ return element;
+};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/elements/Input.d.ts b/assets/autocomplete.js/dist/esm/elements/Input.d.ts
new file mode 100644
index 00000000..b9731e98
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/Input.d.ts
@@ -0,0 +1,13 @@
+import { AutocompleteApi as AutocompleteCoreApi, AutocompleteEnvironment, AutocompleteScopeApi } from '@algolia/autocomplete-core';
+import { AutocompletePropGetters, AutocompleteState } from '../types';
+import { AutocompleteElement } from '../types/AutocompleteElement';
+declare type InputProps = {
+ autocompleteScopeApi: AutocompleteScopeApi;
+ environment: AutocompleteEnvironment;
+ getInputProps: AutocompletePropGetters['getInputProps'];
+ getInputPropsCore: AutocompleteCoreApi['getInputProps'];
+ isDetached: boolean;
+ state: AutocompleteState;
+};
+export declare const Input: AutocompleteElement;
+export {};
diff --git a/assets/autocomplete.js/dist/esm/elements/Input.js b/assets/autocomplete.js/dist/esm/elements/Input.js
new file mode 100644
index 00000000..4e3641f7
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/Input.js
@@ -0,0 +1,45 @@
+var _excluded = ["autocompleteScopeApi", "environment", "classNames", "getInputProps", "getInputPropsCore", "isDetached", "state"];
+
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
+
+function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
+
+import { getCreateDomElement } from '../getCreateDomElement';
+import { setProperties } from '../utils';
+export var Input = function Input(_ref) {
+ var autocompleteScopeApi = _ref.autocompleteScopeApi,
+ environment = _ref.environment,
+ classNames = _ref.classNames,
+ getInputProps = _ref.getInputProps,
+ getInputPropsCore = _ref.getInputPropsCore,
+ isDetached = _ref.isDetached,
+ state = _ref.state,
+ props = _objectWithoutProperties(_ref, _excluded);
+
+ var createDomElement = getCreateDomElement(environment);
+ var element = createDomElement('input', props);
+ var inputProps = getInputProps(_objectSpread({
+ state: state,
+ props: getInputPropsCore({
+ inputElement: element
+ }),
+ inputElement: element
+ }, autocompleteScopeApi));
+ setProperties(element, _objectSpread(_objectSpread({}, inputProps), {}, {
+ onKeyDown: function onKeyDown(event) {
+ // In detached mode we don't want to close the panel when hittin `Tab`.
+ if (isDetached && event.key === 'Tab') {
+ return;
+ }
+
+ inputProps.onKeyDown(event);
+ }
+ }));
+ return element;
+};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/elements/LoadingIcon.d.ts b/assets/autocomplete.js/dist/esm/elements/LoadingIcon.d.ts
new file mode 100644
index 00000000..c3b094ac
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/LoadingIcon.d.ts
@@ -0,0 +1,5 @@
+import { AutocompleteEnvironment } from '@algolia/autocomplete-core';
+import { AutocompleteElement } from '../types/AutocompleteElement';
+export declare const LoadingIcon: AutocompleteElement<{
+ environment: AutocompleteEnvironment;
+}, SVGSVGElement>;
diff --git a/assets/autocomplete.js/dist/esm/elements/LoadingIcon.js b/assets/autocomplete.js/dist/esm/elements/LoadingIcon.js
new file mode 100644
index 00000000..c56dff7f
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/LoadingIcon.js
@@ -0,0 +1,10 @@
+export var LoadingIcon = function LoadingIcon(_ref) {
+ var environment = _ref.environment;
+ var element = environment.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ element.setAttribute('class', 'aa-LoadingIcon');
+ element.setAttribute('viewBox', '0 0 100 100');
+ element.setAttribute('width', '20');
+ element.setAttribute('height', '20');
+ element.innerHTML = "\n \n";
+ return element;
+};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/elements/SearchIcon.d.ts b/assets/autocomplete.js/dist/esm/elements/SearchIcon.d.ts
new file mode 100644
index 00000000..a3f269a3
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/SearchIcon.d.ts
@@ -0,0 +1,5 @@
+import { AutocompleteEnvironment } from '@algolia/autocomplete-core';
+import { AutocompleteElement } from '../types/AutocompleteElement';
+export declare const SearchIcon: AutocompleteElement<{
+ environment: AutocompleteEnvironment;
+}, SVGSVGElement>;
diff --git a/assets/autocomplete.js/dist/esm/elements/SearchIcon.js b/assets/autocomplete.js/dist/esm/elements/SearchIcon.js
new file mode 100644
index 00000000..fe13f4db
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/SearchIcon.js
@@ -0,0 +1,13 @@
+export var SearchIcon = function SearchIcon(_ref) {
+ var environment = _ref.environment;
+ var element = environment.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ element.setAttribute('class', 'aa-SubmitIcon');
+ element.setAttribute('viewBox', '0 0 24 24');
+ element.setAttribute('width', '20');
+ element.setAttribute('height', '20');
+ element.setAttribute('fill', 'currentColor');
+ var path = environment.document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ path.setAttribute('d', 'M16.041 15.856c-0.034 0.026-0.067 0.055-0.099 0.087s-0.060 0.064-0.087 0.099c-1.258 1.213-2.969 1.958-4.855 1.958-1.933 0-3.682-0.782-4.95-2.050s-2.050-3.017-2.050-4.95 0.782-3.682 2.050-4.95 3.017-2.050 4.95-2.050 3.682 0.782 4.95 2.050 2.050 3.017 2.050 4.95c0 1.886-0.745 3.597-1.959 4.856zM21.707 20.293l-3.675-3.675c1.231-1.54 1.968-3.493 1.968-5.618 0-2.485-1.008-4.736-2.636-6.364s-3.879-2.636-6.364-2.636-4.736 1.008-6.364 2.636-2.636 3.879-2.636 6.364 1.008 4.736 2.636 6.364 3.879 2.636 6.364 2.636c2.125 0 4.078-0.737 5.618-1.968l3.675 3.675c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414z');
+ element.appendChild(path);
+ return element;
+};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/elements/index.d.ts b/assets/autocomplete.js/dist/esm/elements/index.d.ts
new file mode 100644
index 00000000..7bc3d23a
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/index.d.ts
@@ -0,0 +1,4 @@
+export * from './ClearIcon';
+export * from './Input';
+export * from './LoadingIcon';
+export * from './SearchIcon';
diff --git a/assets/autocomplete.js/dist/esm/elements/index.js b/assets/autocomplete.js/dist/esm/elements/index.js
new file mode 100644
index 00000000..9a6b6a2c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/elements/index.js
@@ -0,0 +1,4 @@
+export * from './ClearIcon';
+export * from './Input';
+export * from './LoadingIcon';
+export * from './SearchIcon';
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/getCreateDomElement.d.ts b/assets/autocomplete.js/dist/esm/getCreateDomElement.d.ts
new file mode 100644
index 00000000..6ee88876
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getCreateDomElement.d.ts
@@ -0,0 +1,6 @@
+import { AutocompleteEnvironment } from '@algolia/autocomplete-core';
+declare type CreateDomElementProps = Record & {
+ children?: Node[];
+};
+export declare function getCreateDomElement(environment: AutocompleteEnvironment): (tagName: KParam, { children, ...props }: CreateDomElementProps) => HTMLElementTagNameMap[KParam];
+export {};
diff --git a/assets/autocomplete.js/dist/esm/getCreateDomElement.js b/assets/autocomplete.js/dist/esm/getCreateDomElement.js
new file mode 100644
index 00000000..e48ba815
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getCreateDomElement.js
@@ -0,0 +1,31 @@
+var _excluded = ["children"];
+
+function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
+
+function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
+
+function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
+
+function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
+
+function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
+
+function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
+
+function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
+
+function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
+
+import { setProperties } from './utils';
+export function getCreateDomElement(environment) {
+ return function createDomElement(tagName, _ref) {
+ var _ref$children = _ref.children,
+ children = _ref$children === void 0 ? [] : _ref$children,
+ props = _objectWithoutProperties(_ref, _excluded);
+
+ var element = environment.document.createElement(tagName);
+ setProperties(element, props);
+ element.append.apply(element, _toConsumableArray(children));
+ return element;
+ };
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/getDefaultOptions.d.ts b/assets/autocomplete.js/dist/esm/getDefaultOptions.d.ts
new file mode 100644
index 00000000..6691997c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getDefaultOptions.d.ts
@@ -0,0 +1,201 @@
+///
+import { BaseItem } from '@algolia/autocomplete-core';
+import { AutocompleteClassNames, AutocompleteOptions, AutocompleteRender } from './types';
+export declare function getDefaultOptions(options: AutocompleteOptions): {
+ renderer: {
+ classNames: AutocompleteClassNames;
+ container: HTMLElement;
+ getEnvironmentProps: (params: {
+ props: {
+ onTouchStart(event: TouchEvent): void;
+ onTouchMove(event: TouchEvent): void;
+ onMouseDown(event: MouseEvent): void;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ onTouchStart(event: TouchEvent): void;
+ onTouchMove(event: TouchEvent): void;
+ onMouseDown(event: MouseEvent): void;
+ };
+ getFormProps: (params: {
+ props: {
+ action: "";
+ noValidate: true;
+ role: "search";
+ onSubmit(event: Event): void;
+ onReset(event: Event): void;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ action: "";
+ noValidate: true;
+ role: "search";
+ onSubmit(event: Event): void;
+ onReset(event: Event): void;
+ };
+ getInputProps: (params: {
+ props: {
+ id: string;
+ value: string;
+ autoFocus: boolean;
+ placeholder: string;
+ autoComplete: "off" | "on";
+ autoCorrect: "off" | "on";
+ autoCapitalize: "off" | "on";
+ enterKeyHint: "search" | "go";
+ spellCheck: "false";
+ maxLength: number;
+ type: "search";
+ 'aria-autocomplete': "list" | "none" | "inline" | "both";
+ 'aria-activedescendant': string | undefined;
+ 'aria-controls': string | undefined;
+ 'aria-labelledby': string;
+ onChange(event: Event): void;
+ onKeyDown(event: KeyboardEvent): void;
+ onFocus(event: Event): void;
+ onBlur(): void;
+ onClick(event: MouseEvent): void;
+ };
+ inputElement: HTMLInputElement;
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ id: string;
+ value: string;
+ autoFocus: boolean;
+ placeholder: string;
+ autoComplete: "off" | "on";
+ autoCorrect: "off" | "on";
+ autoCapitalize: "off" | "on";
+ enterKeyHint: "search" | "go";
+ spellCheck: "false";
+ maxLength: number;
+ type: "search";
+ 'aria-autocomplete': "list" | "none" | "inline" | "both";
+ 'aria-activedescendant': string | undefined;
+ 'aria-controls': string | undefined;
+ 'aria-labelledby': string;
+ onChange(event: Event): void;
+ onKeyDown(event: KeyboardEvent): void;
+ onFocus(event: Event): void;
+ onBlur(): void;
+ onClick(event: MouseEvent): void;
+ };
+ getItemProps: (params: {
+ props: {
+ id: string;
+ role: string;
+ 'aria-selected': boolean;
+ onMouseMove(event: MouseEvent): void;
+ onMouseDown(event: MouseEvent): void;
+ onClick(event: MouseEvent): void;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ id: string;
+ role: string;
+ 'aria-selected': boolean;
+ onMouseMove(event: MouseEvent): void;
+ onMouseDown(event: MouseEvent): void;
+ onClick(event: MouseEvent): void;
+ };
+ getLabelProps: (params: {
+ props: {
+ htmlFor: string;
+ id: string;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ htmlFor: string;
+ id: string;
+ };
+ getListProps: (params: {
+ props: {
+ role: string;
+ 'aria-labelledby': string;
+ id: string;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ role: string;
+ 'aria-labelledby': string;
+ id: string;
+ };
+ getPanelProps: (params: {
+ props: {
+ onMouseDown(event: MouseEvent): void;
+ onMouseLeave(): void;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ onMouseDown(event: MouseEvent): void;
+ onMouseLeave(): void;
+ };
+ getRootProps: (params: {
+ props: {
+ role: string;
+ 'aria-expanded': boolean;
+ 'aria-haspopup': boolean | "dialog" | "menu" | "true" | "false" | "grid" | "listbox" | "tree" | undefined;
+ 'aria-owns': string | undefined;
+ 'aria-labelledby': string;
+ };
+ } & {
+ state: import("./types").AutocompleteState;
+ } & import("@algolia/autocomplete-core").AutocompleteScopeApi) => {
+ role: string;
+ 'aria-expanded': boolean;
+ 'aria-haspopup': boolean | "dialog" | "menu" | "true" | "false" | "grid" | "listbox" | "tree" | undefined;
+ 'aria-owns': string | undefined;
+ 'aria-labelledby': string;
+ };
+ panelContainer: HTMLElement;
+ panelPlacement: "start" | "end" | "full-width" | "input-wrapper-width";
+ render: AutocompleteRender | AutocompleteRender;
+ renderNoResults: AutocompleteRender | undefined;
+ renderer: {
+ createElement: import("./types").Pragma;
+ Fragment: any;
+ render: import("./types").Render;
+ };
+ detachedMediaQuery: string;
+ components: {
+ [x: string]: (props: any) => JSX.Element;
+ Highlight: ({ hit, attribute, tagName, }: import("./types").HighlightHitParams) => JSX.Element;
+ ReverseHighlight: ({ hit, attribute, tagName, }: import("./types").HighlightHitParams) => JSX.Element;
+ ReverseSnippet: ({ hit, attribute, tagName, }: import("./types").HighlightHitParams) => JSX.Element;
+ Snippet: ({ hit, attribute, tagName, }: import("./types").HighlightHitParams) => JSX.Element;
+ };
+ translations: {
+ detachedCancelButtonText: string;
+ clearButtonTitle: string;
+ submitButtonTitle: string;
+ };
+ };
+ core: {
+ id: string;
+ environment: Window;
+ getSources?: import("./types").GetSources | undefined;
+ initialState?: Partial> | undefined;
+ onStateChange?(props: import("./types").OnStateChangeProps): void;
+ plugins?: import("./types").AutocompletePlugin[] | undefined;
+ debug?: boolean | undefined;
+ placeholder?: string | undefined;
+ autoFocus?: boolean | undefined;
+ defaultActiveItemId?: number | null | undefined;
+ openOnFocus?: boolean | undefined;
+ stallThreshold?: number | undefined;
+ navigator?: Partial> | undefined;
+ shouldPanelOpen?(params: {
+ state: import("@algolia/autocomplete-core").AutocompleteState;
+ }): boolean;
+ onSubmit?(params: import("@algolia/autocomplete-core").OnSubmitParams): void;
+ onReset?(params: import("@algolia/autocomplete-core").OnResetParams): void;
+ reshape?: import("@algolia/autocomplete-core").Reshape> | undefined;
+ };
+};
diff --git a/assets/autocomplete.js/dist/esm/getDefaultOptions.js b/assets/autocomplete.js/dist/esm/getDefaultOptions.js
new file mode 100644
index 00000000..25c9e5d5
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getDefaultOptions.js
@@ -0,0 +1,152 @@
+var _excluded = ["classNames", "container", "getEnvironmentProps", "getFormProps", "getInputProps", "getItemProps", "getLabelProps", "getListProps", "getPanelProps", "getRootProps", "panelContainer", "panelPlacement", "render", "renderNoResults", "renderer", "detachedMediaQuery", "components", "translations"];
+
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
+
+function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
+
+import { generateAutocompleteId, invariant, warn } from '@algolia/autocomplete-shared';
+import { createElement as preactCreateElement, Fragment as PreactFragment, render } from 'preact';
+import { createHighlightComponent, createReverseHighlightComponent, createReverseSnippetComponent, createSnippetComponent } from './components';
+import { getHTMLElement, mergeClassNames } from './utils';
+var defaultClassNames = {
+ clearButton: 'aa-ClearButton',
+ detachedCancelButton: 'aa-DetachedCancelButton',
+ detachedContainer: 'aa-DetachedContainer',
+ detachedFormContainer: 'aa-DetachedFormContainer',
+ detachedOverlay: 'aa-DetachedOverlay',
+ detachedSearchButton: 'aa-DetachedSearchButton',
+ detachedSearchButtonIcon: 'aa-DetachedSearchButtonIcon',
+ detachedSearchButtonPlaceholder: 'aa-DetachedSearchButtonPlaceholder',
+ form: 'aa-Form',
+ input: 'aa-Input',
+ inputWrapper: 'aa-InputWrapper',
+ inputWrapperPrefix: 'aa-InputWrapperPrefix',
+ inputWrapperSuffix: 'aa-InputWrapperSuffix',
+ item: 'aa-Item',
+ label: 'aa-Label',
+ list: 'aa-List',
+ loadingIndicator: 'aa-LoadingIndicator',
+ panel: 'aa-Panel',
+ panelLayout: 'aa-PanelLayout aa-Panel--scrollable',
+ root: 'aa-Autocomplete',
+ source: 'aa-Source',
+ sourceFooter: 'aa-SourceFooter',
+ sourceHeader: 'aa-SourceHeader',
+ sourceNoResults: 'aa-SourceNoResults',
+ submitButton: 'aa-SubmitButton'
+};
+
+var defaultRender = function defaultRender(_ref, root) {
+ var children = _ref.children,
+ render = _ref.render;
+ render(children, root);
+};
+
+var defaultRenderer = {
+ createElement: preactCreateElement,
+ Fragment: PreactFragment,
+ render: render
+};
+export function getDefaultOptions(options) {
+ var _core$id;
+
+ var classNames = options.classNames,
+ container = options.container,
+ getEnvironmentProps = options.getEnvironmentProps,
+ getFormProps = options.getFormProps,
+ getInputProps = options.getInputProps,
+ getItemProps = options.getItemProps,
+ getLabelProps = options.getLabelProps,
+ getListProps = options.getListProps,
+ getPanelProps = options.getPanelProps,
+ getRootProps = options.getRootProps,
+ panelContainer = options.panelContainer,
+ panelPlacement = options.panelPlacement,
+ render = options.render,
+ renderNoResults = options.renderNoResults,
+ renderer = options.renderer,
+ detachedMediaQuery = options.detachedMediaQuery,
+ components = options.components,
+ translations = options.translations,
+ core = _objectWithoutProperties(options, _excluded);
+ /* eslint-disable no-restricted-globals */
+
+
+ var environment = typeof window !== 'undefined' ? window : {};
+ /* eslint-enable no-restricted-globals */
+
+ var containerElement = getHTMLElement(environment, container);
+ invariant(containerElement.tagName !== 'INPUT', 'The `container` option does not support `input` elements. You need to change the container to a `div`.');
+ process.env.NODE_ENV !== 'production' ? warn(!(render && renderer && !(renderer !== null && renderer !== void 0 && renderer.render)), "You provided the `render` option but did not provide a `renderer.render`. Since v1.6.0, you can provide a `render` function directly in `renderer`." + "\nTo get rid of this warning, do any of the following depending on your use case." + "\n- If you are using the `render` option only to override Autocomplete's default `render` function, pass the `render` function into `renderer` and remove the `render` option." + '\n- If you are using the `render` option to customize the layout, pass your `render` function into `renderer` and use it from the provided parameters of the `render` option.' + '\n- If you are using the `render` option to work with React 18, pass an empty `render` function into `renderer`.' + '\nSee https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-render') : void 0;
+ process.env.NODE_ENV !== 'production' ? warn(!renderer || render || renderer.Fragment && renderer.createElement && renderer.render, "You provided an incomplete `renderer` (missing: ".concat([!(renderer !== null && renderer !== void 0 && renderer.createElement) && '`renderer.createElement`', !(renderer !== null && renderer !== void 0 && renderer.Fragment) && '`renderer.Fragment`', !(renderer !== null && renderer !== void 0 && renderer.render) && '`renderer.render`'].filter(Boolean).join(', '), "). This can cause rendering issues.") + '\nSee https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-renderer') : void 0;
+
+ var defaultedRenderer = _objectSpread(_objectSpread({}, defaultRenderer), renderer);
+
+ var defaultComponents = {
+ Highlight: createHighlightComponent(defaultedRenderer),
+ ReverseHighlight: createReverseHighlightComponent(defaultedRenderer),
+ ReverseSnippet: createReverseSnippetComponent(defaultedRenderer),
+ Snippet: createSnippetComponent(defaultedRenderer)
+ };
+ var defaultTranslations = {
+ clearButtonTitle: 'Clear',
+ detachedCancelButtonText: 'Cancel',
+ submitButtonTitle: 'Submit'
+ };
+ return {
+ renderer: {
+ classNames: mergeClassNames(defaultClassNames, classNames !== null && classNames !== void 0 ? classNames : {}),
+ container: containerElement,
+ getEnvironmentProps: getEnvironmentProps !== null && getEnvironmentProps !== void 0 ? getEnvironmentProps : function (_ref2) {
+ var props = _ref2.props;
+ return props;
+ },
+ getFormProps: getFormProps !== null && getFormProps !== void 0 ? getFormProps : function (_ref3) {
+ var props = _ref3.props;
+ return props;
+ },
+ getInputProps: getInputProps !== null && getInputProps !== void 0 ? getInputProps : function (_ref4) {
+ var props = _ref4.props;
+ return props;
+ },
+ getItemProps: getItemProps !== null && getItemProps !== void 0 ? getItemProps : function (_ref5) {
+ var props = _ref5.props;
+ return props;
+ },
+ getLabelProps: getLabelProps !== null && getLabelProps !== void 0 ? getLabelProps : function (_ref6) {
+ var props = _ref6.props;
+ return props;
+ },
+ getListProps: getListProps !== null && getListProps !== void 0 ? getListProps : function (_ref7) {
+ var props = _ref7.props;
+ return props;
+ },
+ getPanelProps: getPanelProps !== null && getPanelProps !== void 0 ? getPanelProps : function (_ref8) {
+ var props = _ref8.props;
+ return props;
+ },
+ getRootProps: getRootProps !== null && getRootProps !== void 0 ? getRootProps : function (_ref9) {
+ var props = _ref9.props;
+ return props;
+ },
+ panelContainer: panelContainer ? getHTMLElement(environment, panelContainer) : environment.document.body,
+ panelPlacement: panelPlacement !== null && panelPlacement !== void 0 ? panelPlacement : 'input-wrapper-width',
+ render: render !== null && render !== void 0 ? render : defaultRender,
+ renderNoResults: renderNoResults,
+ renderer: defaultedRenderer,
+ detachedMediaQuery: detachedMediaQuery !== null && detachedMediaQuery !== void 0 ? detachedMediaQuery : getComputedStyle(environment.document.documentElement).getPropertyValue('--aa-detached-media-query'),
+ components: _objectSpread(_objectSpread({}, defaultComponents), components),
+ translations: _objectSpread(_objectSpread({}, defaultTranslations), translations)
+ },
+ core: _objectSpread(_objectSpread({}, core), {}, {
+ id: (_core$id = core.id) !== null && _core$id !== void 0 ? _core$id : generateAutocompleteId(),
+ environment: environment
+ })
+ };
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.d.ts b/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.d.ts
new file mode 100644
index 00000000..94d1d2cf
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.d.ts
@@ -0,0 +1,25 @@
+import { AutocompleteOptions } from './types';
+declare type GetPanelPlacementStyleParams = Pick>, 'panelPlacement' | 'environment'> & {
+ container: HTMLElement;
+ form: HTMLElement;
+};
+export declare function getPanelPlacementStyle({ panelPlacement, container, form, environment, }: GetPanelPlacementStyleParams): {
+ top: number;
+ left: number;
+ right?: undefined;
+ width?: undefined;
+ maxWidth?: undefined;
+} | {
+ top: number;
+ right: number;
+ left?: undefined;
+ width?: undefined;
+ maxWidth?: undefined;
+} | {
+ top: number;
+ left: number;
+ right: number;
+ width: string;
+ maxWidth: string;
+};
+export {};
diff --git a/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.js b/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.js
new file mode 100644
index 00000000..a015a6d5
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/getPanelPlacementStyle.js
@@ -0,0 +1,57 @@
+export function getPanelPlacementStyle(_ref) {
+ var panelPlacement = _ref.panelPlacement,
+ container = _ref.container,
+ form = _ref.form,
+ environment = _ref.environment;
+ var containerRect = container.getBoundingClientRect(); // Some browsers have specificities to retrieve the document scroll position.
+ // See https://stackoverflow.com/a/28633515/9940315
+
+ var scrollTop = environment.pageYOffset || environment.document.documentElement.scrollTop || environment.document.body.scrollTop || 0;
+ var top = scrollTop + containerRect.top + containerRect.height;
+
+ switch (panelPlacement) {
+ case 'start':
+ {
+ return {
+ top: top,
+ left: containerRect.left
+ };
+ }
+
+ case 'end':
+ {
+ return {
+ top: top,
+ right: environment.document.documentElement.clientWidth - (containerRect.left + containerRect.width)
+ };
+ }
+
+ case 'full-width':
+ {
+ return {
+ top: top,
+ left: 0,
+ right: 0,
+ width: 'unset',
+ maxWidth: 'unset'
+ };
+ }
+
+ case 'input-wrapper-width':
+ {
+ var formRect = form.getBoundingClientRect();
+ return {
+ top: top,
+ left: formRect.left,
+ right: environment.document.documentElement.clientWidth - (formRect.left + formRect.width),
+ width: 'unset',
+ maxWidth: 'unset'
+ };
+ }
+
+ default:
+ {
+ throw new Error("[Autocomplete] The `panelPlacement` value ".concat(JSON.stringify(panelPlacement), " is not valid."));
+ }
+ }
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/index.d.ts b/assets/autocomplete.js/dist/esm/index.d.ts
new file mode 100644
index 00000000..05dd16bb
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/index.d.ts
@@ -0,0 +1,3 @@
+export * from './autocomplete';
+export * from './requesters';
+export * from './types';
diff --git a/assets/autocomplete.js/dist/esm/index.js b/assets/autocomplete.js/dist/esm/index.js
new file mode 100644
index 00000000..02979738
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/index.js
@@ -0,0 +1,3 @@
+export * from './autocomplete';
+export * from './requesters';
+export * from './types';
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/render.d.ts b/assets/autocomplete.js/dist/esm/render.d.ts
new file mode 100644
index 00000000..1c0865fc
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/render.d.ts
@@ -0,0 +1,18 @@
+/** @jsx renderer.createElement */
+import { AutocompleteApi as AutocompleteCoreApi, AutocompleteScopeApi, BaseItem } from '@algolia/autocomplete-core';
+import { AutocompleteClassNames, AutocompleteComponents, AutocompleteDom, AutocompletePropGetters, AutocompleteRender, AutocompleteRenderer, AutocompleteState, HTMLTemplate } from './types';
+declare type RenderProps = {
+ autocomplete: AutocompleteCoreApi;
+ autocompleteScopeApi: AutocompleteScopeApi;
+ classNames: AutocompleteClassNames;
+ components: AutocompleteComponents;
+ html: HTMLTemplate;
+ dom: AutocompleteDom;
+ panelContainer: HTMLElement;
+ propGetters: AutocompletePropGetters;
+ state: AutocompleteState;
+ renderer: Required;
+};
+export declare function renderSearchBox({ autocomplete, autocompleteScopeApi, dom, propGetters, state, }: RenderProps): void;
+export declare function renderPanel(render: AutocompleteRender, { autocomplete, autocompleteScopeApi, classNames, html, dom, panelContainer, propGetters, state, components, renderer, }: RenderProps): void;
+export {};
diff --git a/assets/autocomplete.js/dist/esm/render.js b/assets/autocomplete.js/dist/esm/render.js
new file mode 100644
index 00000000..e9594082
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/render.js
@@ -0,0 +1,149 @@
+function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
+
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+/** @jsx renderer.createElement */
+import { setProperties, setPropertiesWithoutEvents } from './utils';
+export function renderSearchBox(_ref) {
+ var autocomplete = _ref.autocomplete,
+ autocompleteScopeApi = _ref.autocompleteScopeApi,
+ dom = _ref.dom,
+ propGetters = _ref.propGetters,
+ state = _ref.state;
+ setPropertiesWithoutEvents(dom.root, propGetters.getRootProps(_objectSpread({
+ state: state,
+ props: autocomplete.getRootProps({})
+ }, autocompleteScopeApi)));
+ setPropertiesWithoutEvents(dom.input, propGetters.getInputProps(_objectSpread({
+ state: state,
+ props: autocomplete.getInputProps({
+ inputElement: dom.input
+ }),
+ inputElement: dom.input
+ }, autocompleteScopeApi)));
+ setProperties(dom.label, {
+ hidden: state.status === 'stalled'
+ });
+ setProperties(dom.loadingIndicator, {
+ hidden: state.status !== 'stalled'
+ });
+ setProperties(dom.clearButton, {
+ hidden: !state.query
+ });
+}
+export function renderPanel(render, _ref2) {
+ var autocomplete = _ref2.autocomplete,
+ autocompleteScopeApi = _ref2.autocompleteScopeApi,
+ classNames = _ref2.classNames,
+ html = _ref2.html,
+ dom = _ref2.dom,
+ panelContainer = _ref2.panelContainer,
+ propGetters = _ref2.propGetters,
+ state = _ref2.state,
+ components = _ref2.components,
+ renderer = _ref2.renderer;
+
+ if (!state.isOpen) {
+ if (panelContainer.contains(dom.panel)) {
+ panelContainer.removeChild(dom.panel);
+ }
+
+ return;
+ } // We add the panel element to the DOM when it's not yet appended and that the
+ // items are fetched.
+
+
+ if (!panelContainer.contains(dom.panel) && state.status !== 'loading') {
+ panelContainer.appendChild(dom.panel);
+ }
+
+ dom.panel.classList.toggle('aa-Panel--stalled', state.status === 'stalled');
+ var sections = state.collections.filter(function (_ref3) {
+ var source = _ref3.source,
+ items = _ref3.items;
+ return source.templates.noResults || items.length > 0;
+ }).map(function (_ref4, sourceIndex) {
+ var source = _ref4.source,
+ items = _ref4.items;
+ return renderer.createElement("section", {
+ key: sourceIndex,
+ className: classNames.source,
+ "data-autocomplete-source-id": source.sourceId
+ }, source.templates.header && renderer.createElement("div", {
+ className: classNames.sourceHeader
+ }, source.templates.header({
+ components: components,
+ createElement: renderer.createElement,
+ Fragment: renderer.Fragment,
+ items: items,
+ source: source,
+ state: state,
+ html: html
+ })), source.templates.noResults && items.length === 0 ? renderer.createElement("div", {
+ className: classNames.sourceNoResults
+ }, source.templates.noResults({
+ components: components,
+ createElement: renderer.createElement,
+ Fragment: renderer.Fragment,
+ source: source,
+ state: state,
+ html: html
+ })) : renderer.createElement("ul", _extends({
+ className: classNames.list
+ }, propGetters.getListProps(_objectSpread({
+ state: state,
+ props: autocomplete.getListProps({})
+ }, autocompleteScopeApi))), items.map(function (item) {
+ var itemProps = autocomplete.getItemProps({
+ item: item,
+ source: source
+ });
+ return renderer.createElement("li", _extends({
+ key: itemProps.id,
+ className: classNames.item
+ }, propGetters.getItemProps(_objectSpread({
+ state: state,
+ props: itemProps
+ }, autocompleteScopeApi))), source.templates.item({
+ components: components,
+ createElement: renderer.createElement,
+ Fragment: renderer.Fragment,
+ item: item,
+ state: state,
+ html: html
+ }));
+ })), source.templates.footer && renderer.createElement("div", {
+ className: classNames.sourceFooter
+ }, source.templates.footer({
+ components: components,
+ createElement: renderer.createElement,
+ Fragment: renderer.Fragment,
+ items: items,
+ source: source,
+ state: state,
+ html: html
+ })));
+ });
+ var children = renderer.createElement(renderer.Fragment, null, renderer.createElement("div", {
+ className: classNames.panelLayout
+ }, sections), renderer.createElement("div", {
+ className: "aa-GradientBottom"
+ }));
+ var elements = sections.reduce(function (acc, current) {
+ acc[current.props['data-autocomplete-source-id']] = current;
+ return acc;
+ }, {});
+ render(_objectSpread(_objectSpread({
+ children: children,
+ state: state,
+ sections: sections,
+ elements: elements
+ }, renderer), {}, {
+ components: components,
+ html: html
+ }, autocompleteScopeApi), dom.panel);
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.d.ts b/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.d.ts
new file mode 100644
index 00000000..62f9af75
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.d.ts
@@ -0,0 +1 @@
+export declare const createAlgoliaRequester: (requesterParams: import("@algolia/autocomplete-preset-algolia").RequesterParams) => (requestParams: import("@algolia/autocomplete-preset-algolia").RequestParams) => import("@algolia/autocomplete-preset-algolia").RequesterDescription;
diff --git a/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.js b/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.js
new file mode 100644
index 00000000..25788e5d
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/createAlgoliaRequester.js
@@ -0,0 +1,13 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+import { createRequester, fetchAlgoliaResults } from '@algolia/autocomplete-preset-algolia';
+import { userAgents } from '../userAgents';
+export var createAlgoliaRequester = createRequester(function (params) {
+ return fetchAlgoliaResults(_objectSpread(_objectSpread({}, params), {}, {
+ userAgents: userAgents
+ }));
+}, 'algolia');
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.d.ts b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.d.ts
new file mode 100644
index 00000000..b6173c18
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.d.ts
@@ -0,0 +1,5 @@
+import { RequestParams } from '@algolia/autocomplete-preset-algolia';
+/**
+ * Retrieves Algolia facet hits from multiple indices.
+ */
+export declare function getAlgoliaFacets(requestParams: RequestParams): import("@algolia/autocomplete-preset-algolia").RequesterDescription;
diff --git a/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.js b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.js
new file mode 100644
index 00000000..45bb38be
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaFacets.js
@@ -0,0 +1,26 @@
+function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
+
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+import { createAlgoliaRequester } from './createAlgoliaRequester';
+/**
+ * Retrieves Algolia facet hits from multiple indices.
+ */
+
+export function getAlgoliaFacets(requestParams) {
+ var requester = createAlgoliaRequester({
+ transformResponse: function transformResponse(response) {
+ return response.facetHits;
+ }
+ });
+ var queries = requestParams.queries.map(function (query) {
+ return _objectSpread(_objectSpread({}, query), {}, {
+ type: 'facet'
+ });
+ });
+ return requester(_objectSpread(_objectSpread({}, requestParams), {}, {
+ queries: queries
+ }));
+}
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.d.ts b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.d.ts
new file mode 100644
index 00000000..42635065
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.d.ts
@@ -0,0 +1,4 @@
+/**
+ * Retrieves Algolia results from multiple indices.
+ */
+export declare const getAlgoliaResults: (requestParams: import("@algolia/autocomplete-preset-algolia").RequestParams) => import("@algolia/autocomplete-preset-algolia").RequesterDescription;
diff --git a/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.js b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.js
new file mode 100644
index 00000000..c4c12ddc
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/getAlgoliaResults.js
@@ -0,0 +1,10 @@
+import { createAlgoliaRequester } from './createAlgoliaRequester';
+/**
+ * Retrieves Algolia results from multiple indices.
+ */
+
+export var getAlgoliaResults = createAlgoliaRequester({
+ transformResponse: function transformResponse(response) {
+ return response.hits;
+ }
+});
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/requesters/index.d.ts b/assets/autocomplete.js/dist/esm/requesters/index.d.ts
new file mode 100644
index 00000000..347d3128
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/index.d.ts
@@ -0,0 +1,2 @@
+export * from './getAlgoliaFacets';
+export * from './getAlgoliaResults';
diff --git a/assets/autocomplete.js/dist/esm/requesters/index.js b/assets/autocomplete.js/dist/esm/requesters/index.js
new file mode 100644
index 00000000..62e340c2
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/requesters/index.js
@@ -0,0 +1,2 @@
+export * from './getAlgoliaFacets';
+export * from './getAlgoliaResults';
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteApi.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteApi.d.ts
new file mode 100644
index 00000000..3291e3fe
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteApi.d.ts
@@ -0,0 +1,12 @@
+import { AutocompleteScopeApi as AutocompleteCoreScopeApi, BaseItem } from '@algolia/autocomplete-core';
+import { AutocompleteOptions } from './AutocompleteOptions';
+export interface AutocompleteApi extends AutocompleteCoreScopeApi {
+ /**
+ * Updates the Autocomplete experience.
+ */
+ update(updatedOptions: Partial>): void;
+ /**
+ * Cleans up the DOM mutations and event listeners.
+ */
+ destroy(): void;
+}
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteApi.js b/assets/autocomplete.js/dist/esm/types/AutocompleteApi.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteApi.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.d.ts
new file mode 100644
index 00000000..53fbf426
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.d.ts
@@ -0,0 +1,27 @@
+export declare type AutocompleteClassNames = {
+ detachedCancelButton: string;
+ detachedFormContainer: string;
+ detachedContainer: string;
+ detachedOverlay: string;
+ detachedSearchButton: string;
+ detachedSearchButtonIcon: string;
+ detachedSearchButtonPlaceholder: string;
+ form: string;
+ input: string;
+ inputWrapper: string;
+ inputWrapperPrefix: string;
+ inputWrapperSuffix: string;
+ item: string;
+ label: string;
+ list: string;
+ loadingIndicator: string;
+ panel: string;
+ panelLayout: string;
+ clearButton: string;
+ root: string;
+ source: string;
+ sourceFooter: string;
+ sourceHeader: string;
+ sourceNoResults: string;
+ submitButton: string;
+};
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.js b/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteClassNames.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.d.ts
new file mode 100644
index 00000000..0459e89f
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.d.ts
@@ -0,0 +1,6 @@
+import { BaseItem } from '@algolia/autocomplete-core';
+import { InternalAutocompleteSource } from './AutocompleteSource';
+export interface AutocompleteCollection {
+ source: InternalAutocompleteSource;
+ items: TItem[];
+}
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.js b/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteCollection.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.d.ts
new file mode 100644
index 00000000..cc127283
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.d.ts
@@ -0,0 +1,23 @@
+///
+import { HighlightHitParams } from '.';
+declare type AutocompleteHighlightComponent = ({ hit, attribute, tagName, }: HighlightHitParams) => JSX.Element;
+export declare type PublicAutocompleteComponents = Record JSX.Element>;
+export interface AutocompleteComponents extends PublicAutocompleteComponents {
+ /**
+ * Highlight matches in an Algolia hit.
+ */
+ Highlight: AutocompleteHighlightComponent;
+ /**
+ * Reverse-highlight matches in an Algolia hit.
+ */
+ ReverseHighlight: AutocompleteHighlightComponent;
+ /**
+ * Reverse-highlight and snippets matches in an Algolia hit.
+ */
+ ReverseSnippet: AutocompleteHighlightComponent;
+ /**
+ * Highlight and snippet matches in an Algolia hit.
+ */
+ Snippet: AutocompleteHighlightComponent;
+}
+export {};
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.js b/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteComponents.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteDom.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteDom.d.ts
new file mode 100644
index 00000000..35df059b
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteDom.d.ts
@@ -0,0 +1,13 @@
+export declare type AutocompleteDom = {
+ inputWrapper: HTMLDivElement;
+ input: HTMLInputElement;
+ root: HTMLDivElement;
+ form: HTMLFormElement;
+ label: HTMLLabelElement;
+ submitButton: HTMLButtonElement;
+ clearButton: HTMLButtonElement;
+ loadingIndicator: HTMLDivElement;
+ panel: HTMLDivElement;
+ detachedContainer: HTMLDivElement;
+ detachedOverlay: HTMLDivElement;
+};
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteDom.js b/assets/autocomplete.js/dist/esm/types/AutocompleteDom.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteDom.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteElement.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteElement.d.ts
new file mode 100644
index 00000000..dbc5d1ce
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteElement.d.ts
@@ -0,0 +1,5 @@
+declare type WithElementProps = TProps & Record & {
+ children?: Node[];
+};
+export declare type AutocompleteElement = (props: WithElementProps) => TElement;
+export {};
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteElement.js b/assets/autocomplete.js/dist/esm/types/AutocompleteElement.js
new file mode 100644
index 00000000..8cec2e9c
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteElement.js
@@ -0,0 +1 @@
+export {};
\ No newline at end of file
diff --git a/assets/autocomplete.js/dist/esm/types/AutocompleteOptions.d.ts b/assets/autocomplete.js/dist/esm/types/AutocompleteOptions.d.ts
new file mode 100644
index 00000000..e54d3bdd
--- /dev/null
+++ b/assets/autocomplete.js/dist/esm/types/AutocompleteOptions.d.ts
@@ -0,0 +1,106 @@
+import { AutocompleteScopeApi, AutocompleteOptions as AutocompleteCoreOptions, BaseItem, GetSourcesParams } from '@algolia/autocomplete-core';
+import { MaybePromise } from '@algolia/autocomplete-shared';
+import { AutocompleteClassNames } from './AutocompleteClassNames';
+import { PublicAutocompleteComponents } from './AutocompleteComponents';
+import { AutocompletePlugin } from './AutocompletePlugin';
+import { AutocompletePropGetters } from './AutocompletePropGetters';
+import { AutocompleteRender } from './AutocompleteRender';
+import { AutocompleteRenderer } from './AutocompleteRenderer';
+import { AutocompleteSource } from './AutocompleteSource';
+import { AutocompleteState } from './AutocompleteState';
+import { AutocompleteTranslations } from './AutocompleteTranslations';
+export interface OnStateChangeProps extends AutocompleteScopeApi {
+ /**
+ * The current Autocomplete state.
+ */
+ state: AutocompleteState;
+ /**
+ * The previous Autocomplete state.
+ */
+ prevState: AutocompleteState;
+}
+export declare type GetSources = (params: GetSourcesParams) => MaybePromise | boolean | undefined>>;
+export interface AutocompleteOptions extends AutocompleteCoreOptions, Partial> {
+ /**
+ * The container for the Autocomplete search box.
+ *
+ * You can either pass a [CSS selector](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors) or an [Element](https://developer.mozilla.org/docs/Web/API/HTMLElement). If there are several containers matching the selector, Autocomplete picks up the first one.
+ *
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-container
+ */
+ container: string | HTMLElement;
+ /**
+ * The container for the Autocomplete panel.
+ *
+ * You can either pass a [CSS selector](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors) or an [Element](https://developer.mozilla.org/docs/Web/API/HTMLElement). If there are several containers matching the selector, Autocomplete picks up the first one.
+ *
+ * @default document.body
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-panelcontainer
+ */
+ panelContainer?: string | HTMLElement;
+ /**
+ * The Media Query to turn Autocomplete into a detached experience.
+ *
+ * @default "(max-width: 680px)"
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-detachedmediaquery
+ * @link https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries
+ */
+ detachedMediaQuery?: string;
+ getSources?: GetSources;
+ /**
+ * The panel's horizontal position.
+ *
+ * @default "input-wrapper-width"
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-panelplacement
+ */
+ panelPlacement?: 'start' | 'end' | 'full-width' | 'input-wrapper-width';
+ /**
+ * Class names to inject for each created DOM element.
+ *
+ * This is useful to style your autocomplete with external CSS frameworks.
+ *
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-classnames
+ */
+ classNames?: Partial