UNPKG

meilisearch

Version:

The Meilisearch JS client for Node.js and the browser.

1 lines 151 kB
{"version":3,"file":"index.cjs","sources":["../../src/errors/meilisearch-error.ts","../../src/errors/meilisearch-api-error.ts","../../src/errors/meilisearch-request-error.ts","../../src/errors/meilisearch-timeout-error.ts","../../src/errors/version-hint-message.ts","../../src/package-version.ts","../../src/utils.ts","../../src/http-requests.ts","../../src/enqueued-task.ts","../../src/task.ts","../../src/batch.ts","../../src/types.ts","../../src/indexes.ts","../../src/meilisearch.ts","../../src/index.ts"],"sourcesContent":["export class MeiliSearchError extends Error {\n override name = \"MeiliSearchError\";\n\n constructor(...params: ConstructorParameters<typeof Error>) {\n super(...params);\n }\n}\n","import type { MeiliSearchErrorResponse } from \"../types.js\";\nimport { MeiliSearchError } from \"./meilisearch-error.js\";\n\nexport class MeiliSearchApiError extends MeiliSearchError {\n override name = \"MeiliSearchApiError\";\n override cause?: MeiliSearchErrorResponse;\n readonly response: Response;\n\n constructor(response: Response, responseBody?: MeiliSearchErrorResponse) {\n super(\n responseBody?.message ?? `${response.status}: ${response.statusText}`,\n );\n\n this.response = response;\n\n if (responseBody !== undefined) {\n this.cause = responseBody;\n }\n }\n}\n","import { MeiliSearchError } from \"./meilisearch-error.js\";\n\nexport class MeiliSearchRequestError extends MeiliSearchError {\n override name = \"MeiliSearchRequestError\";\n\n constructor(url: string, cause: unknown) {\n super(`Request to ${url} has failed`, { cause });\n }\n}\n","import { MeiliSearchError } from \"./meilisearch-error.js\";\n\nexport class MeiliSearchTimeOutError extends MeiliSearchError {\n override name = \"MeiliSearchTimeOutError\";\n\n constructor(message: string) {\n super(message);\n }\n}\n","export function versionErrorHintMessage(message: string, method: string) {\n return `${message}\\nHint: It might not be working because maybe you're not up to date with the Meilisearch version that ${method} call requires.`;\n}\n","export const PACKAGE_VERSION = \"0.49.0\";\n","/** Removes undefined entries from object */\nfunction removeUndefinedFromObject(obj: Record<string, any>): object {\n return Object.entries(obj).reduce(\n (acc, curEntry) => {\n const [key, val] = curEntry;\n if (val !== undefined) acc[key] = val;\n return acc;\n },\n {} as Record<string, any>,\n );\n}\n\nasync function sleep(ms: number): Promise<void> {\n return await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction addProtocolIfNotPresent(host: string): string {\n if (!(host.startsWith(\"https://\") || host.startsWith(\"http://\"))) {\n return `http://${host}`;\n }\n return host;\n}\n\nfunction addTrailingSlash(url: string): string {\n if (!url.endsWith(\"/\")) {\n url += \"/\";\n }\n return url;\n}\n\nexport {\n sleep,\n removeUndefinedFromObject,\n addProtocolIfNotPresent,\n addTrailingSlash,\n};\n","import type { Config, EnqueuedTaskObject } from \"./types.js\";\nimport { PACKAGE_VERSION } from \"./package-version.js\";\n\nimport {\n MeiliSearchError,\n MeiliSearchApiError,\n MeiliSearchRequestError,\n} from \"./errors/index.js\";\n\nimport { addTrailingSlash, addProtocolIfNotPresent } from \"./utils.js\";\n\ntype queryParams<T> = { [key in keyof T]: string };\n\nfunction toQueryParams<T extends object>(parameters: T): queryParams<T> {\n const params = Object.keys(parameters) as Array<keyof T>;\n\n const queryParams = params.reduce<queryParams<T>>((acc, key) => {\n const value = parameters[key];\n if (value === undefined) {\n return acc;\n } else if (Array.isArray(value)) {\n return { ...acc, [key]: value.join(\",\") };\n } else if (value instanceof Date) {\n return { ...acc, [key]: value.toISOString() };\n }\n return { ...acc, [key]: value };\n }, {} as queryParams<T>);\n return queryParams;\n}\n\nfunction constructHostURL(host: string): string {\n try {\n host = addProtocolIfNotPresent(host);\n host = addTrailingSlash(host);\n return host;\n } catch {\n throw new MeiliSearchError(\"The provided host is not valid.\");\n }\n}\n\nfunction cloneAndParseHeaders(headers: HeadersInit): Record<string, string> {\n if (Array.isArray(headers)) {\n return headers.reduce(\n (acc, headerPair) => {\n acc[headerPair[0]] = headerPair[1];\n return acc;\n },\n {} as Record<string, string>,\n );\n } else if (\"has\" in headers) {\n const clonedHeaders: Record<string, string> = {};\n (headers as Headers).forEach((value, key) => (clonedHeaders[key] = value));\n return clonedHeaders;\n } else {\n return Object.assign({}, headers);\n }\n}\n\nfunction createHeaders(config: Config): Record<string, any> {\n const agentHeader = \"X-Meilisearch-Client\";\n const packageAgent = `Meilisearch JavaScript (v${PACKAGE_VERSION})`;\n const contentType = \"Content-Type\";\n const authorization = \"Authorization\";\n const headers = cloneAndParseHeaders(config.requestConfig?.headers ?? {});\n\n // do not override if user provided the header\n if (config.apiKey && !headers[authorization]) {\n headers[authorization] = `Bearer ${config.apiKey}`;\n }\n\n if (!headers[contentType]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n // Creates the custom user agent with information on the package used.\n if (config.clientAgents && Array.isArray(config.clientAgents)) {\n const clients = config.clientAgents.concat(packageAgent);\n\n headers[agentHeader] = clients.join(\" ; \");\n } else if (config.clientAgents && !Array.isArray(config.clientAgents)) {\n // If the header is defined but not an array\n throw new MeiliSearchError(\n `Meilisearch: The header \"${agentHeader}\" should be an array of string(s).\\n`,\n );\n } else {\n headers[agentHeader] = packageAgent;\n }\n\n return headers;\n}\n\nclass HttpRequests {\n headers: Record<string, any>;\n url: URL;\n requestConfig?: Config[\"requestConfig\"];\n httpClient?: Required<Config>[\"httpClient\"];\n requestTimeout?: number;\n\n constructor(config: Config) {\n this.headers = createHeaders(config);\n this.requestConfig = config.requestConfig;\n this.httpClient = config.httpClient;\n this.requestTimeout = config.timeout;\n\n try {\n const host = constructHostURL(config.host);\n this.url = new URL(host);\n } catch {\n throw new MeiliSearchError(\"The provided host is not valid.\");\n }\n }\n\n async request({\n method,\n url,\n params,\n body,\n config = {},\n }: {\n method: string;\n url: string;\n params?: { [key: string]: any };\n body?: any;\n config?: Record<string, any>;\n }) {\n const constructURL = new URL(url, this.url);\n if (params) {\n const queryParams = new URLSearchParams();\n Object.keys(params)\n .filter((x: string) => params[x] !== null)\n .map((x: string) => queryParams.set(x, params[x]));\n constructURL.search = queryParams.toString();\n }\n\n // in case a custom content-type is provided\n // do not stringify body\n if (!config.headers?.[\"Content-Type\"]) {\n body = JSON.stringify(body);\n }\n\n const headers = { ...this.headers, ...config.headers };\n const responsePromise = this.fetchWithTimeout(\n constructURL.toString(),\n {\n ...config,\n ...this.requestConfig,\n method,\n body,\n headers,\n },\n this.requestTimeout,\n );\n\n const response = await responsePromise.catch((error: unknown) => {\n throw new MeiliSearchRequestError(constructURL.toString(), error);\n });\n\n // When using a custom HTTP client, the response is returned to allow the user to parse/handle it as they see fit\n if (this.httpClient !== undefined) {\n return response;\n }\n\n const responseBody = await response.text();\n const parsedResponse =\n responseBody === \"\" ? undefined : JSON.parse(responseBody);\n\n if (!response.ok) {\n throw new MeiliSearchApiError(response, parsedResponse);\n }\n\n return parsedResponse;\n }\n\n async fetchWithTimeout(\n url: string,\n options: Record<string, any> | RequestInit | undefined,\n timeout: HttpRequests[\"requestTimeout\"],\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n const fetchFn = this.httpClient ? this.httpClient : fetch;\n\n const fetchPromise = fetchFn(url, options);\n\n const promises: Array<Promise<any>> = [fetchPromise];\n\n // TimeoutPromise will not run if undefined or zero\n let timeoutId: ReturnType<typeof setTimeout>;\n if (timeout) {\n const timeoutPromise = new Promise((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(\"Error: Request Timed Out\"));\n }, timeout);\n });\n\n promises.push(timeoutPromise);\n }\n\n Promise.race(promises)\n .then(resolve)\n .catch(reject)\n .finally(() => {\n clearTimeout(timeoutId);\n });\n });\n }\n\n async get(\n url: string,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<void>;\n\n async get<T = any>(\n url: string,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<T>;\n\n async get(\n url: string,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<any> {\n return await this.request({\n method: \"GET\",\n url,\n params,\n config,\n });\n }\n\n async post<T = any, R = EnqueuedTaskObject>(\n url: string,\n data?: T,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<R>;\n\n async post(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<any> {\n return await this.request({\n method: \"POST\",\n url,\n body: data,\n params,\n config,\n });\n }\n\n async put<T = any, R = EnqueuedTaskObject>(\n url: string,\n data?: T,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<R>;\n\n async put(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<any> {\n return await this.request({\n method: \"PUT\",\n url,\n body: data,\n params,\n config,\n });\n }\n\n async patch(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<any> {\n return await this.request({\n method: \"PATCH\",\n url,\n body: data,\n params,\n config,\n });\n }\n\n async delete(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<EnqueuedTaskObject>;\n async delete<T>(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<T>;\n async delete(\n url: string,\n data?: any,\n params?: { [key: string]: any },\n config?: Record<string, any>,\n ): Promise<any> {\n return await this.request({\n method: \"DELETE\",\n url,\n body: data,\n params,\n config,\n });\n }\n}\n\nexport { HttpRequests, toQueryParams };\n","import type { EnqueuedTaskObject } from \"./types.js\";\n\nclass EnqueuedTask {\n taskUid: EnqueuedTaskObject[\"taskUid\"];\n indexUid: EnqueuedTaskObject[\"indexUid\"];\n status: EnqueuedTaskObject[\"status\"];\n type: EnqueuedTaskObject[\"type\"];\n enqueuedAt: Date;\n\n constructor(task: EnqueuedTaskObject) {\n this.taskUid = task.taskUid;\n this.indexUid = task.indexUid;\n this.status = task.status;\n this.type = task.type;\n this.enqueuedAt = new Date(task.enqueuedAt);\n }\n}\n\nexport { EnqueuedTask };\n","import { MeiliSearchTimeOutError } from \"./errors/index.js\";\nimport type {\n Config,\n WaitOptions,\n TasksQuery,\n TasksResults,\n TaskObject,\n CancelTasksQuery,\n TasksResultsObject,\n DeleteTasksQuery,\n} from \"./types.js\";\nimport { TaskStatus } from \"./types.js\";\nimport { HttpRequests, toQueryParams } from \"./http-requests.js\";\nimport { sleep } from \"./utils.js\";\nimport { EnqueuedTask } from \"./enqueued-task.js\";\n\nclass Task {\n indexUid: TaskObject[\"indexUid\"];\n status: TaskObject[\"status\"];\n type: TaskObject[\"type\"];\n uid: TaskObject[\"uid\"];\n batchUid: TaskObject[\"batchUid\"];\n canceledBy: TaskObject[\"canceledBy\"];\n details: TaskObject[\"details\"];\n error: TaskObject[\"error\"];\n duration: TaskObject[\"duration\"];\n startedAt: Date;\n enqueuedAt: Date;\n finishedAt: Date;\n\n constructor(task: TaskObject) {\n this.indexUid = task.indexUid;\n this.status = task.status;\n this.type = task.type;\n this.uid = task.uid;\n this.batchUid = task.batchUid;\n this.details = task.details;\n this.canceledBy = task.canceledBy;\n this.error = task.error;\n this.duration = task.duration;\n\n this.startedAt = new Date(task.startedAt);\n this.enqueuedAt = new Date(task.enqueuedAt);\n this.finishedAt = new Date(task.finishedAt);\n }\n}\n\nclass TaskClient {\n httpRequest: HttpRequests;\n\n constructor(config: Config) {\n this.httpRequest = new HttpRequests(config);\n }\n\n /**\n * Get one task\n *\n * @param uid - Unique identifier of the task\n * @returns\n */\n async getTask(uid: number): Promise<Task> {\n const url = `tasks/${uid}`;\n const taskItem = await this.httpRequest.get<TaskObject>(url);\n return new Task(taskItem);\n }\n\n /**\n * Get tasks\n *\n * @param parameters - Parameters to browse the tasks\n * @returns Promise containing all tasks\n */\n async getTasks(parameters: TasksQuery = {}): Promise<TasksResults> {\n const url = `tasks`;\n\n const tasks = await this.httpRequest.get<Promise<TasksResultsObject>>(\n url,\n toQueryParams<TasksQuery>(parameters),\n );\n\n return {\n ...tasks,\n results: tasks.results.map((task) => new Task(task)),\n };\n }\n\n /**\n * Wait for a task to be processed.\n *\n * @param taskUid - Task identifier\n * @param options - Additional configuration options\n * @returns Promise returning a task after it has been processed\n */\n async waitForTask(\n taskUid: number,\n { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {},\n ): Promise<Task> {\n const startingTime = Date.now();\n while (Date.now() - startingTime < timeOutMs) {\n const response = await this.getTask(taskUid);\n if (\n !(\n [\n TaskStatus.TASK_ENQUEUED,\n TaskStatus.TASK_PROCESSING,\n ] as readonly string[]\n ).includes(response.status)\n )\n return response;\n await sleep(intervalMs);\n }\n throw new MeiliSearchTimeOutError(\n `timeout of ${timeOutMs}ms has exceeded on process ${taskUid} when waiting a task to be resolved.`,\n );\n }\n\n /**\n * Waits for multiple tasks to be processed\n *\n * @param taskUids - Tasks identifier list\n * @param options - Wait options\n * @returns Promise returning a list of tasks after they have been processed\n */\n async waitForTasks(\n taskUids: number[],\n { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {},\n ): Promise<Task[]> {\n const tasks: Task[] = [];\n for (const taskUid of taskUids) {\n const task = await this.waitForTask(taskUid, {\n timeOutMs,\n intervalMs,\n });\n tasks.push(task);\n }\n return tasks;\n }\n\n /**\n * Cancel a list of enqueued or processing tasks.\n *\n * @param parameters - Parameters to filter the tasks.\n * @returns Promise containing an EnqueuedTask\n */\n async cancelTasks(parameters: CancelTasksQuery = {}): Promise<EnqueuedTask> {\n const url = `tasks/cancel`;\n\n const task = await this.httpRequest.post(\n url,\n {},\n toQueryParams<CancelTasksQuery>(parameters),\n );\n\n return new EnqueuedTask(task);\n }\n\n /**\n * Delete a list tasks.\n *\n * @param parameters - Parameters to filter the tasks.\n * @returns Promise containing an EnqueuedTask\n */\n async deleteTasks(parameters: DeleteTasksQuery = {}): Promise<EnqueuedTask> {\n const url = `tasks`;\n\n const task = await this.httpRequest.delete(\n url,\n {},\n toQueryParams<DeleteTasksQuery>(parameters),\n );\n return new EnqueuedTask(task);\n }\n}\n\nexport { TaskClient, Task };\n","import type {\n Config,\n BatchObject,\n BatchesQuery,\n BatchesResults,\n BatchesResultsObject,\n} from \"./types.js\";\nimport { HttpRequests, toQueryParams } from \"./http-requests.js\";\n\nclass Batch {\n uid: BatchObject[\"uid\"];\n details: BatchObject[\"details\"];\n stats: BatchObject[\"stats\"];\n startedAt: BatchObject[\"startedAt\"];\n finishedAt: BatchObject[\"finishedAt\"];\n duration: BatchObject[\"duration\"];\n progress: BatchObject[\"progress\"];\n\n constructor(batch: BatchObject) {\n this.uid = batch.uid;\n this.details = batch.details;\n this.stats = batch.stats;\n this.startedAt = batch.startedAt;\n this.finishedAt = batch.finishedAt;\n this.duration = batch.duration;\n this.progress = batch.progress;\n }\n}\n\nclass BatchClient {\n httpRequest: HttpRequests;\n\n constructor(config: Config) {\n this.httpRequest = new HttpRequests(config);\n }\n\n /**\n * Get one batch\n *\n * @param uid - Unique identifier of the batch\n * @returns\n */\n async getBatch(uid: number): Promise<Batch> {\n const url = `batches/${uid}`;\n const batch = await this.httpRequest.get<BatchObject>(url);\n return new Batch(batch);\n }\n\n /**\n * Get batches\n *\n * @param parameters - Parameters to browse the batches\n * @returns Promise containing all batches\n */\n async getBatches(parameters: BatchesQuery = {}): Promise<BatchesResults> {\n const url = `batches`;\n\n const batches = await this.httpRequest.get<Promise<BatchesResultsObject>>(\n url,\n toQueryParams<BatchesQuery>(parameters),\n );\n\n return {\n ...batches,\n results: batches.results.map((batch) => new Batch(batch)),\n };\n }\n}\n\nexport { BatchClient, Batch };\n","// Type definitions for meilisearch\n// Project: https://github.com/meilisearch/meilisearch-js\n// Definitions by: qdequele <quentin@meilisearch.com> <https://github.com/meilisearch>\n// Definitions: https://github.com/meilisearch/meilisearch-js\n// TypeScript Version: ^3.8.3\n\nimport { Task } from \"./task.js\";\nimport { Batch } from \"./batch.js\";\n\nexport type Config = {\n host: string;\n apiKey?: string;\n clientAgents?: string[];\n requestConfig?: Partial<Omit<RequestInit, \"body\" | \"method\">>;\n httpClient?: (input: string, init?: RequestInit) => Promise<any>;\n timeout?: number;\n};\n\n///\n/// Resources\n///\n\nexport type Pagination = {\n offset?: number;\n limit?: number;\n};\n\nexport type ResourceQuery = Pagination & {};\n\nexport type ResourceResults<T> = Pagination & {\n results: T;\n total: number;\n};\n\n///\n/// Indexes\n///\n\nexport type IndexOptions = {\n primaryKey?: string;\n};\n\nexport type IndexObject = {\n uid: string;\n primaryKey?: string;\n createdAt: Date;\n updatedAt: Date;\n};\n\nexport type IndexesQuery = ResourceQuery & {};\n\nexport type IndexesResults<T> = ResourceResults<T> & {};\n\n/*\n * SEARCH PARAMETERS\n */\n\nexport const MatchingStrategies = {\n ALL: \"all\",\n LAST: \"last\",\n FREQUENCY: \"frequency\",\n} as const;\n\nexport type MatchingStrategies =\n (typeof MatchingStrategies)[keyof typeof MatchingStrategies];\n\nexport type Filter = string | Array<string | string[]>;\n\nexport type Query = {\n q?: string | null;\n};\n\nexport type Highlight = {\n attributesToHighlight?: string[];\n highlightPreTag?: string;\n highlightPostTag?: string;\n};\n\nexport type Crop = {\n attributesToCrop?: string[];\n cropLength?: number;\n cropMarker?: string;\n};\n\n// `facetName` becomes mandatory when using `searchForFacetValues`\nexport type SearchForFacetValuesParams = Omit<SearchParams, \"facetName\"> & {\n facetName: string;\n};\n\nexport type FacetHit = {\n value: string;\n count: number;\n};\n\nexport type SearchForFacetValuesResponse = {\n facetHits: FacetHit[];\n facetQuery: string | null;\n processingTimeMs: number;\n};\n\nexport type HybridSearch = {\n embedder: string;\n semanticRatio?: number;\n};\n\n// https://www.meilisearch.com/docs/reference/api/settings#localized-attributes\nexport type Locale = string;\n\nexport type SearchParams = Query &\n Pagination &\n Highlight &\n Crop & {\n filter?: Filter;\n sort?: string[];\n facets?: string[];\n attributesToRetrieve?: string[];\n showMatchesPosition?: boolean;\n matchingStrategy?: MatchingStrategies;\n hitsPerPage?: number;\n page?: number;\n facetName?: string;\n facetQuery?: string;\n vector?: number[] | null;\n showRankingScore?: boolean;\n showRankingScoreDetails?: boolean;\n rankingScoreThreshold?: number;\n attributesToSearchOn?: string[] | null;\n hybrid?: HybridSearch;\n distinct?: string;\n retrieveVectors?: boolean;\n locales?: Locale[];\n };\n\n// Search parameters for searches made with the GET method\n// Are different than the parameters for the POST method\nexport type SearchRequestGET = Pagination &\n Query &\n Omit<Highlight, \"attributesToHighlight\"> &\n Omit<Crop, \"attributesToCrop\"> & {\n filter?: string;\n sort?: string;\n facets?: string;\n attributesToRetrieve?: string;\n attributesToHighlight?: string;\n attributesToCrop?: string;\n showMatchesPosition?: boolean;\n vector?: string | null;\n attributesToSearchOn?: string | null;\n hybridEmbedder?: string;\n hybridSemanticRatio?: number;\n rankingScoreThreshold?: number;\n distinct?: string;\n retrieveVectors?: boolean;\n locales?: Locale[];\n };\n\nexport type MergeFacets = {\n maxValuesPerFacet?: number | null;\n};\n\nexport type FederationOptions = { weight: number };\nexport type MultiSearchFederation = {\n limit?: number;\n offset?: number;\n facetsByIndex?: Record<string, string[]>;\n mergeFacets?: MergeFacets | null;\n};\n\nexport type MultiSearchQuery = SearchParams & { indexUid: string };\nexport type MultiSearchQueryWithFederation = MultiSearchQuery & {\n federationOptions?: FederationOptions;\n};\n\nexport type MultiSearchParams = {\n queries: MultiSearchQuery[];\n};\nexport type FederatedMultiSearchParams = {\n federation: MultiSearchFederation;\n queries: MultiSearchQueryWithFederation[];\n};\n\nexport type CategoriesDistribution = {\n [category: string]: number;\n};\n\nexport type Facet = string;\nexport type FacetDistribution = Record<Facet, CategoriesDistribution>;\nexport type MatchesPosition<T> = Partial<\n Record<keyof T, Array<{ start: number; length: number; indices?: number[] }>>\n>;\n\nexport type RankingScoreDetails = {\n words?: {\n order: number;\n matchingWords: number;\n maxMatchingWords: number;\n score: number;\n };\n typo?: {\n order: number;\n typoCount: number;\n maxTypoCount: number;\n score: number;\n };\n proximity?: {\n order: number;\n score: number;\n };\n attribute?: {\n order: number;\n attributes_ranking_order: number;\n attributes_query_word_order: number;\n score: number;\n };\n exactness?: {\n order: number;\n matchType: string;\n score: number;\n };\n [key: string]: Record<string, any> | undefined;\n};\n\nexport type FederationDetails = {\n indexUid: string;\n queriesPosition: number;\n weightedRankingScore: number;\n};\n\nexport type Hit<T = Record<string, any>> = T & {\n _formatted?: Partial<T>;\n _matchesPosition?: MatchesPosition<T>;\n _rankingScore?: number;\n _rankingScoreDetails?: RankingScoreDetails;\n _federation?: FederationDetails;\n};\n\nexport type Hits<T = Record<string, any>> = Array<Hit<T>>;\n\nexport type FacetStat = { min: number; max: number };\nexport type FacetStats = Record<string, FacetStat>;\n\nexport type FacetsByIndex = Record<\n string,\n {\n distribution: FacetDistribution;\n stats: FacetStats;\n }\n>;\n\nexport type SearchResponse<\n T = Record<string, any>,\n S extends SearchParams | undefined = undefined,\n> = {\n hits: Hits<T>;\n processingTimeMs: number;\n query: string;\n facetDistribution?: FacetDistribution;\n facetStats?: FacetStats;\n facetsByIndex?: FacetsByIndex;\n} & (undefined extends S\n ? Partial<FinitePagination & InfinitePagination>\n : true extends IsFinitePagination<NonNullable<S>>\n ? FinitePagination\n : InfinitePagination);\n\ntype FinitePagination = {\n totalHits: number;\n hitsPerPage: number;\n page: number;\n totalPages: number;\n};\ntype InfinitePagination = {\n offset: number;\n limit: number;\n estimatedTotalHits: number;\n};\n\ntype IsFinitePagination<S extends SearchParams> = Or<\n HasHitsPerPage<S>,\n HasPage<S>\n>;\n\ntype Or<A extends boolean, B extends boolean> = true extends A\n ? true\n : true extends B\n ? true\n : false;\n\ntype HasHitsPerPage<S extends SearchParams> = undefined extends S[\"hitsPerPage\"]\n ? false\n : true;\n\ntype HasPage<S extends SearchParams> = undefined extends S[\"page\"]\n ? false\n : true;\n\nexport type MultiSearchResult<T> = SearchResponse<T> & { indexUid: string };\n\nexport type MultiSearchResponse<T = Record<string, any>> = {\n results: Array<MultiSearchResult<T>>;\n};\n\nexport type MultiSearchResponseOrSearchResponse<\n T1 extends FederatedMultiSearchParams | MultiSearchParams,\n T2 extends Record<string, unknown> = Record<string, any>,\n> = T1 extends FederatedMultiSearchParams\n ? SearchResponse<T2>\n : MultiSearchResponse<T2>;\n\nexport type FieldDistribution = {\n [field: string]: number;\n};\n\nexport type SearchSimilarDocumentsParams = {\n id: string | number;\n offset?: number;\n limit?: number;\n filter?: Filter;\n embedder?: string;\n attributesToRetrieve?: string[];\n showRankingScore?: boolean;\n showRankingScoreDetails?: boolean;\n rankingScoreThreshold?: number;\n};\n\n/*\n ** Documents\n */\n\ntype Fields<T = Record<string, any>> =\n | Array<Extract<keyof T, string>>\n | Extract<keyof T, string>;\n\nexport type DocumentOptions = {\n primaryKey?: string;\n};\n\nexport const ContentTypeEnum: Readonly<Record<string, ContentType>> = {\n JSON: \"application/json\",\n CSV: \"text/csv\",\n NDJSON: \"application/x-ndjson\",\n};\n\nexport type ContentType =\n | \"text/csv\"\n | \"application/x-ndjson\"\n | \"application/json\";\n\nexport type RawDocumentAdditionOptions = DocumentOptions & {\n csvDelimiter?: string;\n};\n\nexport type DocumentsQuery<T = Record<string, any>> = ResourceQuery & {\n fields?: Fields<T>;\n filter?: Filter;\n limit?: number;\n offset?: number;\n retrieveVectors?: boolean;\n};\n\nexport type DocumentQuery<T = Record<string, any>> = {\n fields?: Fields<T>;\n};\n\nexport type DocumentsDeletionQuery = {\n filter: Filter;\n};\n\nexport type DocumentsIds = string[] | number[];\n\nexport type UpdateDocumentsByFunctionOptions = {\n function: string;\n filter?: string | string[];\n context?: Record<string, any>;\n};\n\n/*\n ** Settings\n */\n\nexport type FilterableAttributes = string[] | null;\nexport type DistinctAttribute = string | null;\nexport type SearchableAttributes = string[] | null;\nexport type SortableAttributes = string[] | null;\nexport type DisplayedAttributes = string[] | null;\nexport type RankingRules = string[] | null;\nexport type StopWords = string[] | null;\nexport type Synonyms = {\n [field: string]: string[];\n} | null;\nexport type TypoTolerance = {\n enabled?: boolean | null;\n disableOnAttributes?: string[] | null;\n disableOnWords?: string[] | null;\n minWordSizeForTypos?: {\n oneTypo?: number | null;\n twoTypos?: number | null;\n };\n} | null;\nexport type SeparatorTokens = string[] | null;\nexport type NonSeparatorTokens = string[] | null;\nexport type Dictionary = string[] | null;\nexport type ProximityPrecision = \"byWord\" | \"byAttribute\";\n\nexport type Distribution = {\n mean: number;\n sigma: number;\n};\n\nexport type OpenAiEmbedder = {\n source: \"openAi\";\n model?: string;\n apiKey?: string;\n documentTemplate?: string;\n dimensions?: number;\n distribution?: Distribution;\n url?: string;\n documentTemplateMaxBytes?: number;\n binaryQuantized?: boolean;\n};\n\nexport type HuggingFaceEmbedder = {\n source: \"huggingFace\";\n model?: string;\n revision?: string;\n documentTemplate?: string;\n distribution?: Distribution;\n documentTemplateMaxBytes?: number;\n binaryQuantized?: boolean;\n};\n\nexport type UserProvidedEmbedder = {\n source: \"userProvided\";\n dimensions: number;\n distribution?: Distribution;\n binaryQuantized?: boolean;\n};\n\nexport type RestEmbedder = {\n source: \"rest\";\n url: string;\n apiKey?: string;\n dimensions?: number;\n documentTemplate?: string;\n distribution?: Distribution;\n request: Record<string, any>;\n response: Record<string, any>;\n headers?: Record<string, string>;\n documentTemplateMaxBytes?: number;\n binaryQuantized?: boolean;\n};\n\nexport type OllamaEmbedder = {\n source: \"ollama\";\n url?: string;\n apiKey?: string;\n model?: string;\n documentTemplate?: string;\n distribution?: Distribution;\n dimensions?: number;\n documentTemplateMaxBytes?: number;\n binaryQuantized?: boolean;\n};\n\nexport type Embedder =\n | OpenAiEmbedder\n | HuggingFaceEmbedder\n | UserProvidedEmbedder\n | RestEmbedder\n | OllamaEmbedder\n | null;\n\nexport type Embedders = Record<string, Embedder> | null;\n\nexport type FacetOrder = \"alpha\" | \"count\";\n\nexport type Faceting = {\n maxValuesPerFacet?: number | null;\n sortFacetValuesBy?: Record<string, FacetOrder> | null;\n};\n\nexport type PaginationSettings = {\n maxTotalHits?: number | null;\n};\n\nexport type SearchCutoffMs = number | null;\n\nexport type LocalizedAttribute = {\n attributePatterns: string[];\n locales: Locale[];\n};\n\nexport type LocalizedAttributes = LocalizedAttribute[] | null;\n\nexport type PrefixSearch = \"indexingTime\" | \"disabled\";\n\nexport type Settings = {\n filterableAttributes?: FilterableAttributes;\n distinctAttribute?: DistinctAttribute;\n sortableAttributes?: SortableAttributes;\n searchableAttributes?: SearchableAttributes;\n displayedAttributes?: DisplayedAttributes;\n rankingRules?: RankingRules;\n stopWords?: StopWords;\n synonyms?: Synonyms;\n typoTolerance?: TypoTolerance;\n faceting?: Faceting;\n pagination?: PaginationSettings;\n separatorTokens?: SeparatorTokens;\n nonSeparatorTokens?: NonSeparatorTokens;\n dictionary?: Dictionary;\n proximityPrecision?: ProximityPrecision;\n embedders?: Embedders;\n searchCutoffMs?: SearchCutoffMs;\n localizedAttributes?: LocalizedAttributes;\n\n /**\n * Enable facet searching on all the filters of an index (requires Meilisearch\n * 1.12.0 or later)\n */\n facetSearch?: boolean;\n /**\n * Enable the ability to search a word by prefix on an index (requires\n * Meilisearch 1.12.0 or later)\n */\n prefixSearch?: \"indexingTime\" | \"disabled\";\n};\n\n/*\n ** TASKS\n */\n\nexport const TaskStatus = {\n TASK_SUCCEEDED: \"succeeded\",\n TASK_PROCESSING: \"processing\",\n TASK_FAILED: \"failed\",\n TASK_ENQUEUED: \"enqueued\",\n TASK_CANCELED: \"canceled\",\n} as const;\n\nexport type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];\n\nexport const TaskTypes = {\n DOCUMENTS_ADDITION_OR_UPDATE: \"documentAdditionOrUpdate\",\n DOCUMENT_DELETION: \"documentDeletion\",\n DUMP_CREATION: \"dumpCreation\",\n INDEX_CREATION: \"indexCreation\",\n INDEX_DELETION: \"indexDeletion\",\n INDEXES_SWAP: \"indexSwap\",\n INDEX_UPDATE: \"indexUpdate\",\n SETTINGS_UPDATE: \"settingsUpdate\",\n SNAPSHOT_CREATION: \"snapshotCreation\",\n TASK_CANCELATION: \"taskCancelation\",\n TASK_DELETION: \"taskDeletion\",\n} as const;\n\nexport type TaskTypes = (typeof TaskTypes)[keyof typeof TaskTypes];\n\nexport type TasksQuery = {\n indexUids?: string[];\n uids?: number[];\n types?: TaskTypes[];\n statuses?: TaskStatus[];\n canceledBy?: number[];\n beforeEnqueuedAt?: Date;\n afterEnqueuedAt?: Date;\n beforeStartedAt?: Date;\n afterStartedAt?: Date;\n beforeFinishedAt?: Date;\n afterFinishedAt?: Date;\n limit?: number;\n from?: number;\n /**\n * If true, the tasks are returned in reverse order (requires Meilisearch\n * 1.12.0 or later)\n */\n reverse?: boolean;\n};\n\nexport type CancelTasksQuery = Omit<TasksQuery, \"limit\" | \"from\"> & {};\n\nexport type DeleteTasksQuery = Omit<TasksQuery, \"limit\" | \"from\"> & {};\n\nexport type EnqueuedTaskObject = {\n taskUid: number;\n indexUid?: string;\n status: TaskStatus;\n type: TaskTypes;\n enqueuedAt: string;\n canceledBy: number;\n};\n\nexport type TaskObject = Omit<EnqueuedTaskObject, \"taskUid\"> & {\n uid: number;\n /** The UID of the batch that the task belongs to (`null` for enqueued tasks) */\n batchUid: number | null;\n details: {\n // Number of documents sent\n receivedDocuments?: number;\n\n // Number of documents successfully indexed/updated in Meilisearch\n indexedDocuments?: number;\n\n // Number of deleted documents\n deletedDocuments?: number;\n\n // Number of documents found on a batch-delete\n providedIds?: number;\n\n // Primary key on index creation\n primaryKey?: string;\n\n // Ranking rules on settings actions\n rankingRules?: RankingRules;\n\n // Searchable attributes on settings actions\n searchableAttributes?: SearchableAttributes;\n\n // Displayed attributes on settings actions\n displayedAttributes?: DisplayedAttributes;\n\n // Filterable attributes on settings actions\n filterableAttributes?: FilterableAttributes;\n\n // Sortable attributes on settings actions\n sortableAttributes?: SortableAttributes;\n\n // Stop words on settings actions\n stopWords?: StopWords;\n\n // Stop words on settings actions\n synonyms?: Synonyms;\n\n // Distinct attribute on settings actions\n distinctAttribute?: DistinctAttribute;\n\n // Object containing the payload originating the `indexSwap` task creation\n swaps?: SwapIndexesParams;\n\n // Number of tasks that matched the originalQuery filter\n matchedTasks?: number;\n\n // Number of tasks that were canceled\n canceledTasks?: number;\n\n // Number of tasks that were deleted\n deletedTasks?: number;\n\n // Query parameters used to filter the tasks\n originalFilter?: string;\n };\n error: MeiliSearchErrorResponse | null;\n duration: string;\n startedAt: string;\n finishedAt: string;\n};\n\nexport type SwapIndexesParams = Array<{\n indexes: string[];\n}>;\n\ntype CursorResults<T> = {\n results: T[];\n limit: number;\n from: number;\n next: number;\n total: number;\n};\n\nexport type TasksResults = CursorResults<Task>;\nexport type TasksResultsObject = CursorResults<TaskObject>;\n\nexport type WaitOptions = {\n timeOutMs?: number;\n intervalMs?: number;\n};\n\n/*\n ** BATCHES\n */\n\n/**\n * Represents a batch operation object containing information about tasks\n * processing\n */\nexport type BatchObject = {\n /** Unique identifier for the batch */\n uid: number;\n\n /** Details about document processing */\n details: {\n /** Number of documents received in the batch */\n receivedDocuments?: number;\n /** Number of documents successfully indexed */\n indexedDocuments?: number;\n /** Number of documents deleted in the batch */\n deletedDocuments?: number;\n };\n\n /** Progress and indexing step of the batch, null if the batch is finished */\n progress: null | {\n /** An array of all the steps currently being processed */\n steps: Array<{\n /**\n * A string representing the name of the current step NOT stable. Only use\n * for debugging purposes.\n */\n currentStep: string;\n /** Number of finished tasks */\n finished: number;\n /** Total number of tasks to finish before moving to the next step */\n total: number;\n }>;\n /** Percentage of progression of all steps currently being processed */\n percentage: number;\n };\n\n /** Statistics about tasks within the batch */\n stats: {\n /** Total number of tasks in the batch */\n totalNbTasks: number;\n /** Count of tasks in each status */\n status: {\n /** Number of successfully completed tasks */\n succeeded: number;\n /** Number of failed tasks */\n failed: number;\n /** Number of canceled tasks */\n canceled: number;\n /** Number of tasks currently processing */\n processing: number;\n /** Number of tasks waiting to be processed */\n enqueued: number;\n };\n /** Count of tasks by type */\n types: Record<TaskTypes, number>;\n /** Count of tasks by index UID */\n indexUids: Record<string, number>;\n };\n\n /** Timestamp when the batch started processing (rfc3339 format) */\n startedAt: string;\n /** Timestamp when the batch finished processing (rfc3339 format) */\n finishedAt: string;\n /** Duration of batch processing */\n duration: string;\n};\n\nexport type BatchesQuery = {\n /** The batch should contain the specified task UIDs */\n uids?: number[];\n batchUids?: number[];\n types?: TaskTypes[];\n statuses?: TaskStatus[];\n indexUids?: string[];\n canceledBy?: number[];\n beforeEnqueuedAt?: Date;\n afterEnqueuedAt?: Date;\n beforeStartedAt?: Date;\n afterStartedAt?: Date;\n beforeFinishedAt?: Date;\n afterFinishedAt?: Date;\n limit?: number;\n from?: number;\n};\n\nexport type BatchesResults = CursorResults<Batch>;\nexport type BatchesResultsObject = CursorResults<BatchObject>;\n\n/*\n *** HEALTH\n */\n\nexport type Health = {\n status: \"available\";\n};\n\n/*\n *** STATS\n */\n\nexport type IndexStats = {\n numberOfDocuments: number;\n isIndexing: boolean;\n fieldDistribution: FieldDistribution;\n};\n\nexport type Stats = {\n databaseSize: number;\n lastUpdate: string;\n indexes: {\n [index: string]: IndexStats;\n };\n};\n\n/*\n ** Keys\n */\n\nexport type Key = {\n uid: string;\n description: string;\n name: string | null;\n key: string;\n actions: string[];\n indexes: string[];\n expiresAt: Date;\n createdAt: Date;\n updatedAt: Date;\n};\n\nexport type KeyCreation = {\n uid?: string;\n name?: string;\n description?: string;\n actions: string[];\n indexes: string[];\n expiresAt: Date | null;\n};\n\nexport type KeyUpdate = {\n name?: string;\n description?: string;\n};\n\nexport type KeysQuery = ResourceQuery & {};\n\nexport type KeysResults = ResourceResults<Key[]> & {};\n\n/*\n ** version\n */\nexport type Version = {\n commitSha: string;\n commitDate: string;\n pkgVersion: string;\n};\n\n/*\n ** ERROR HANDLER\n */\n\nexport interface FetchError extends Error {\n type: string;\n errno: string;\n code: string;\n}\n\nexport type MeiliSearchErrorResponse = {\n message: string;\n // https://www.meilisearch.com/docs/reference/errors/error_codes\n code: string;\n // https://www.meilisearch.com/docs/reference/errors/overview#errors\n type: string;\n link: string;\n};\n\n// @TODO: This doesn't seem to be up to date, and its usefullness comes into question.\nexport const ErrorStatusCode = {\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_creation_failed */\n INDEX_CREATION_FAILED: \"index_creation_failed\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_index_uid */\n MISSING_INDEX_UID: \"missing_index_uid\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_already_exists */\n INDEX_ALREADY_EXISTS: \"index_already_exists\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_not_found */\n INDEX_NOT_FOUND: \"index_not_found\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_uid */\n INVALID_INDEX_UID: \"invalid_index_uid\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_not_accessible */\n INDEX_NOT_ACCESSIBLE: \"index_not_accessible\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_offset */\n INVALID_INDEX_OFFSET: \"invalid_index_offset\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_limit */\n INVALID_INDEX_LIMIT: \"invalid_index_limit\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_state */\n INVALID_STATE: \"invalid_state\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#primary_key_inference_failed */\n PRIMARY_KEY_INFERENCE_FAILED: \"primary_key_inference_failed\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_primary_key_already_exists */\n INDEX_PRIMARY_KEY_ALREADY_EXISTS: \"index_primary_key_already_exists\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_primary_key */\n INVALID_INDEX_PRIMARY_KEY: \"invalid_index_primary_key\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#max_fields_limit_exceeded */\n DOCUMENTS_FIELDS_LIMIT_REACHED: \"document_fields_limit_reached\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_id */\n MISSING_DOCUMENT_ID: \"missing_document_id\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_id */\n INVALID_DOCUMENT_ID: \"invalid_document_id\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_content_type */\n INVALID_CONTENT_TYPE: \"invalid_content_type\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_content_type */\n MISSING_CONTENT_TYPE: \"missing_content_type\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_fields */\n INVALID_DOCUMENT_FIELDS: \"invalid_document_fields\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_limit */\n INVALID_DOCUMENT_LIMIT: \"invalid_document_limit\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_offset */\n INVALID_DOCUMENT_OFFSET: \"invalid_document_offset\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_filter */\n INVALID_DOCUMENT_FILTER: \"invalid_document_filter\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_filter */\n MISSING_DOCUMENT_FILTER: \"missing_document_filter\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_vectors_field */\n INVALID_DOCUMENT_VECTORS_FIELD: \"invalid_document_vectors_field\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#payload_too_large */\n PAYLOAD_TOO_LARGE: \"payload_too_large\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_payload */\n MISSING_PAYLOAD: \"missing_payload\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#malformed_payload */\n MALFORMED_PAYLOAD: \"malformed_payload\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#no_space_left_on_device */\n NO_SPACE_LEFT_ON_DEVICE: \"no_space_left_on_device\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_store_file */\n INVALID_STORE_FILE: \"invalid_store_file\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_ranking_rules */\n INVALID_RANKING_RULES: \"missing_document_id\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_request */\n INVALID_REQUEST: \"invalid_request\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_geo_field */\n INVALID_DOCUMENT_GEO_FIELD: \"invalid_document_geo_field\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_q */\n INVALID_SEARCH_Q: \"invalid_search_q\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_offset */\n INVALID_SEARCH_OFFSET: \"invalid_search_offset\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_limit */\n INVALID_SEARCH_LIMIT: \"invalid_search_limit\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_page */\n INVALID_SEARCH_PAGE: \"invalid_search_page\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_hits_per_page */\n INVALID_SEARCH_HITS_PER_PAGE: \"invalid_search_hits_per_page\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_retrieve */\n INVALID_SEARCH_ATTRIBUTES_TO_RETRIEVE:\n \"invalid_search_attributes_to_retrieve\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_crop */\n INVALID_SEARCH_ATTRIBUTES_TO_CROP: \"invalid_search_attributes_to_crop\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_crop_length */\n INVALID_SEARCH_CROP_LENGTH: \"invalid_search_crop_length\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_highlight */\n INVALID_SEARCH_ATTRIBUTES_TO_HIGHLIGHT:\n \"invalid_search_attributes_to_highlight\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_show_matches_position */\n INVALID_SEARCH_SHOW_MATCHES_POSITION: \"invalid_search_show_matches_position\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_filter */\n INVALID_SEARCH_FILTER: \"invalid_search_filter\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_sort */\n INVALID_SEARCH_SORT: \"invalid_search_sort\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_facets */\n INVALID_SEARCH_FACETS: \"invalid_search_facets\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_highlight_pre_tag */\n INVALID_SEARCH_HIGHLIGHT_PRE_TAG: \"invalid_search_highlight_pre_tag\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_highlight_post_tag */\n INVALID_SEARCH_HIGHLIGHT_POST_TAG: \"invalid_search_highlight_post_tag\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_crop_marker */\n INVALID_SEARCH_CROP_MARKER: \"invalid_search_crop_marker\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_matching_strategy */\n INVALID_SEARCH_MATCHING_STRATEGY: \"invalid_search_matching_strategy\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_vector */\n INVALID_SEARCH_VECTOR: \"invalid_search_vector\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_search_on */\n INVALID_SEARCH_ATTRIBUTES_TO_SEARCH_ON:\n \"invalid_search_attributes_to_search_on\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#bad_request */\n BAD_REQUEST: \"bad_request\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#document_not_found */\n DOCUMENT_NOT_FOUND: \"document_not_found\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#internal */\n INTERNAL: \"internal\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key */\n INVALID_API_KEY: \"invalid_api_key\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_description */\n INVALID_API_KEY_DESCRIPTION: \"invalid_api_key_description\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_actions */\n INVALID_API_KEY_ACTIONS: \"invalid_api_key_actions\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_indexes */\n INVALID_API_KEY_INDEXES: \"invalid_api_key_indexes\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_expires_at */\n INVALID_API_KEY_EXPIRES_AT: \"invalid_api_key_expires_at\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#api_key_not_found */\n API_KEY_NOT_FOUND: \"api_key_not_found\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_uid */\n IMMUTABLE_API_KEY_UID: \"immutable_api_key_uid\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_actions */\n IMMUTABLE_API_KEY_ACTIONS: \"immutable_api_key_actions\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_indexes */\n IMMUTABLE_API_KEY_INDEXES: \"immutable_api_key_indexes\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_expires_at */\n IMMUTABLE_API_KEY_EXPIRES_AT: \"immutable_api_key_expires_at\",\n\n /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_created_at */\n IMMUTABLE_API_KEY_CREATE