meilisearch
Version:
The Meilisearch JS client for Node.js and the browser.
1,338 lines • 76.9 kB
JavaScript
"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
class MeiliSearchError extends Error {
name = "MeiliSearchError";
constructor(...params) {
super(...params);
}
}
class MeiliSearchApiError extends MeiliSearchError {
name = "MeiliSearchApiError";
cause;
response;
constructor(response, responseBody) {
super(
responseBody?.message ?? `${response.status}: ${response.statusText}`
);
this.response = response;
if (responseBody !== void 0) {
this.cause = responseBody;
}
}
}
class MeiliSearchRequestError extends MeiliSearchError {
name = "MeiliSearchRequestError";
constructor(url, cause) {
super(`Request to ${url} has failed`, { cause });
}
}
class MeiliSearchTimeOutError extends MeiliSearchError {
name = "MeiliSearchTimeOutError";
constructor(message) {
super(message);
}
}
function versionErrorHintMessage(message, method) {
return `${message}
Hint: It might not be working because maybe you're not up to date with the Meilisearch version that ${method} call requires.`;
}
const PACKAGE_VERSION = "0.49.0";
function removeUndefinedFromObject(obj) {
return Object.entries(obj).reduce(
(acc, curEntry) => {
const [key, val] = curEntry;
if (val !== void 0) acc[key] = val;
return acc;
},
{}
);
}
async function sleep(ms) {
return await new Promise((resolve) => setTimeout(resolve, ms));
}
function addProtocolIfNotPresent(host) {
if (!(host.startsWith("https://") || host.startsWith("http://"))) {
return `http://${host}`;
}
return host;
}
function addTrailingSlash(url) {
if (!url.endsWith("/")) {
url += "/";
}
return url;
}
function toQueryParams(parameters) {
const params = Object.keys(parameters);
const queryParams = params.reduce((acc, key) => {
const value = parameters[key];
if (value === void 0) {
return acc;
} else if (Array.isArray(value)) {
return { ...acc, [key]: value.join(",") };
} else if (value instanceof Date) {
return { ...acc, [key]: value.toISOString() };
}
return { ...acc, [key]: value };
}, {});
return queryParams;
}
function constructHostURL(host) {
try {
host = addProtocolIfNotPresent(host);
host = addTrailingSlash(host);
return host;
} catch {
throw new MeiliSearchError("The provided host is not valid.");
}
}
function cloneAndParseHeaders(headers) {
if (Array.isArray(headers)) {
return headers.reduce(
(acc, headerPair) => {
acc[headerPair[0]] = headerPair[1];
return acc;
},
{}
);
} else if ("has" in headers) {
const clonedHeaders = {};
headers.forEach((value, key) => clonedHeaders[key] = value);
return clonedHeaders;
} else {
return Object.assign({}, headers);
}
}
function createHeaders(config) {
const agentHeader = "X-Meilisearch-Client";
const packageAgent = `Meilisearch JavaScript (v${PACKAGE_VERSION})`;
const contentType = "Content-Type";
const authorization = "Authorization";
const headers = cloneAndParseHeaders(config.requestConfig?.headers ?? {});
if (config.apiKey && !headers[authorization]) {
headers[authorization] = `Bearer ${config.apiKey}`;
}
if (!headers[contentType]) {
headers["Content-Type"] = "application/json";
}
if (config.clientAgents && Array.isArray(config.clientAgents)) {
const clients = config.clientAgents.concat(packageAgent);
headers[agentHeader] = clients.join(" ; ");
} else if (config.clientAgents && !Array.isArray(config.clientAgents)) {
throw new MeiliSearchError(
`Meilisearch: The header "${agentHeader}" should be an array of string(s).
`
);
} else {
headers[agentHeader] = packageAgent;
}
return headers;
}
class HttpRequests {
headers;
url;
requestConfig;
httpClient;
requestTimeout;
constructor(config) {
this.headers = createHeaders(config);
this.requestConfig = config.requestConfig;
this.httpClient = config.httpClient;
this.requestTimeout = config.timeout;
try {
const host = constructHostURL(config.host);
this.url = new URL(host);
} catch {
throw new MeiliSearchError("The provided host is not valid.");
}
}
async request({
method,
url,
params,
body,
config = {}
}) {
const constructURL = new URL(url, this.url);
if (params) {
const queryParams = new URLSearchParams();
Object.keys(params).filter((x) => params[x] !== null).map((x) => queryParams.set(x, params[x]));
constructURL.search = queryParams.toString();
}
if (!config.headers?.["Content-Type"]) {
body = JSON.stringify(body);
}
const headers = { ...this.headers, ...config.headers };
const responsePromise = this.fetchWithTimeout(
constructURL.toString(),
{
...config,
...this.requestConfig,
method,
body,
headers
},
this.requestTimeout
);
const response = await responsePromise.catch((error) => {
throw new MeiliSearchRequestError(constructURL.toString(), error);
});
if (this.httpClient !== void 0) {
return response;
}
const responseBody = await response.text();
const parsedResponse = responseBody === "" ? void 0 : JSON.parse(responseBody);
if (!response.ok) {
throw new MeiliSearchApiError(response, parsedResponse);
}
return parsedResponse;
}
async fetchWithTimeout(url, options, timeout) {
return new Promise((resolve, reject) => {
const fetchFn = this.httpClient ? this.httpClient : fetch;
const fetchPromise = fetchFn(url, options);
const promises = [fetchPromise];
let timeoutId;
if (timeout) {
const timeoutPromise = new Promise((_, reject2) => {
timeoutId = setTimeout(() => {
reject2(new Error("Error: Request Timed Out"));
}, timeout);
});
promises.push(timeoutPromise);
}
Promise.race(promises).then(resolve).catch(reject).finally(() => {
clearTimeout(timeoutId);
});
});
}
async get(url, params, config) {
return await this.request({
method: "GET",
url,
params,
config
});
}
async post(url, data, params, config) {
return await this.request({
method: "POST",
url,
body: data,
params,
config
});
}
async put(url, data, params, config) {
return await this.request({
method: "PUT",
url,
body: data,
params,
config
});
}
async patch(url, data, params, config) {
return await this.request({
method: "PATCH",
url,
body: data,
params,
config
});
}
async delete(url, data, params, config) {
return await this.request({
method: "DELETE",
url,
body: data,
params,
config
});
}
}
class EnqueuedTask {
taskUid;
indexUid;
status;
type;
enqueuedAt;
constructor(task) {
this.taskUid = task.taskUid;
this.indexUid = task.indexUid;
this.status = task.status;
this.type = task.type;
this.enqueuedAt = new Date(task.enqueuedAt);
}
}
class Task {
indexUid;
status;
type;
uid;
batchUid;
canceledBy;
details;
error;
duration;
startedAt;
enqueuedAt;
finishedAt;
constructor(task) {
this.indexUid = task.indexUid;
this.status = task.status;
this.type = task.type;
this.uid = task.uid;
this.batchUid = task.batchUid;
this.details = task.details;
this.canceledBy = task.canceledBy;
this.error = task.error;
this.duration = task.duration;
this.startedAt = new Date(task.startedAt);
this.enqueuedAt = new Date(task.enqueuedAt);
this.finishedAt = new Date(task.finishedAt);
}
}
class TaskClient {
httpRequest;
constructor(config) {
this.httpRequest = new HttpRequests(config);
}
/**
* Get one task
*
* @param uid - Unique identifier of the task
* @returns
*/
async getTask(uid) {
const url = `tasks/${uid}`;
const taskItem = await this.httpRequest.get(url);
return new Task(taskItem);
}
/**
* Get tasks
*
* @param parameters - Parameters to browse the tasks
* @returns Promise containing all tasks
*/
async getTasks(parameters = {}) {
const url = `tasks`;
const tasks = await this.httpRequest.get(
url,
toQueryParams(parameters)
);
return {
...tasks,
results: tasks.results.map((task) => new Task(task))
};
}
/**
* Wait for a task to be processed.
*
* @param taskUid - Task identifier
* @param options - Additional configuration options
* @returns Promise returning a task after it has been processed
*/
async waitForTask(taskUid, { timeOutMs = 5e3, intervalMs = 50 } = {}) {
const startingTime = Date.now();
while (Date.now() - startingTime < timeOutMs) {
const response = await this.getTask(taskUid);
if (![
TaskStatus.TASK_ENQUEUED,
TaskStatus.TASK_PROCESSING
].includes(response.status))
return response;
await sleep(intervalMs);
}
throw new MeiliSearchTimeOutError(
`timeout of ${timeOutMs}ms has exceeded on process ${taskUid} when waiting a task to be resolved.`
);
}
/**
* Waits for multiple tasks to be processed
*
* @param taskUids - Tasks identifier list
* @param options - Wait options
* @returns Promise returning a list of tasks after they have been processed
*/
async waitForTasks(taskUids, { timeOutMs = 5e3, intervalMs = 50 } = {}) {
const tasks = [];
for (const taskUid of taskUids) {
const task = await this.waitForTask(taskUid, {
timeOutMs,
intervalMs
});
tasks.push(task);
}
return tasks;
}
/**
* Cancel a list of enqueued or processing tasks.
*
* @param parameters - Parameters to filter the tasks.
* @returns Promise containing an EnqueuedTask
*/
async cancelTasks(parameters = {}) {
const url = `tasks/cancel`;
const task = await this.httpRequest.post(
url,
{},
toQueryParams(parameters)
);
return new EnqueuedTask(task);
}
/**
* Delete a list tasks.
*
* @param parameters - Parameters to filter the tasks.
* @returns Promise containing an EnqueuedTask
*/
async deleteTasks(parameters = {}) {
const url = `tasks`;
const task = await this.httpRequest.delete(
url,
{},
toQueryParams(parameters)
);
return new EnqueuedTask(task);
}
}
class Batch {
uid;
details;
stats;
startedAt;
finishedAt;
duration;
progress;
constructor(batch) {
this.uid = batch.uid;
this.details = batch.details;
this.stats = batch.stats;
this.startedAt = batch.startedAt;
this.finishedAt = batch.finishedAt;
this.duration = batch.duration;
this.progress = batch.progress;
}
}
class BatchClient {
httpRequest;
constructor(config) {
this.httpRequest = new HttpRequests(config);
}
/**
* Get one batch
*
* @param uid - Unique identifier of the batch
* @returns
*/
async getBatch(uid) {
const url = `batches/${uid}`;
const batch = await this.httpRequest.get(url);
return new Batch(batch);
}
/**
* Get batches
*
* @param parameters - Parameters to browse the batches
* @returns Promise containing all batches
*/
async getBatches(parameters = {}) {
const url = `batches`;
const batches = await this.httpRequest.get(
url,
toQueryParams(parameters)
);
return {
...batches,
results: batches.results.map((batch) => new Batch(batch))
};
}
}
const MatchingStrategies = {
ALL: "all",
LAST: "last",
FREQUENCY: "frequency"
};
const ContentTypeEnum = {
JSON: "application/json",
CSV: "text/csv",
NDJSON: "application/x-ndjson"
};
const TaskStatus = {
TASK_SUCCEEDED: "succeeded",
TASK_PROCESSING: "processing",
TASK_FAILED: "failed",
TASK_ENQUEUED: "enqueued",
TASK_CANCELED: "canceled"
};
const TaskTypes = {
DOCUMENTS_ADDITION_OR_UPDATE: "documentAdditionOrUpdate",
DOCUMENT_DELETION: "documentDeletion",
DUMP_CREATION: "dumpCreation",
INDEX_CREATION: "indexCreation",
INDEX_DELETION: "indexDeletion",
INDEXES_SWAP: "indexSwap",
INDEX_UPDATE: "indexUpdate",
SETTINGS_UPDATE: "settingsUpdate",
SNAPSHOT_CREATION: "snapshotCreation",
TASK_CANCELATION: "taskCancelation",
TASK_DELETION: "taskDeletion"
};
const ErrorStatusCode = {
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_creation_failed */
INDEX_CREATION_FAILED: "index_creation_failed",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_index_uid */
MISSING_INDEX_UID: "missing_index_uid",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_already_exists */
INDEX_ALREADY_EXISTS: "index_already_exists",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_not_found */
INDEX_NOT_FOUND: "index_not_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_uid */
INVALID_INDEX_UID: "invalid_index_uid",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_not_accessible */
INDEX_NOT_ACCESSIBLE: "index_not_accessible",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_offset */
INVALID_INDEX_OFFSET: "invalid_index_offset",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_limit */
INVALID_INDEX_LIMIT: "invalid_index_limit",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_state */
INVALID_STATE: "invalid_state",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#primary_key_inference_failed */
PRIMARY_KEY_INFERENCE_FAILED: "primary_key_inference_failed",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#index_primary_key_already_exists */
INDEX_PRIMARY_KEY_ALREADY_EXISTS: "index_primary_key_already_exists",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_index_primary_key */
INVALID_INDEX_PRIMARY_KEY: "invalid_index_primary_key",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#max_fields_limit_exceeded */
DOCUMENTS_FIELDS_LIMIT_REACHED: "document_fields_limit_reached",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_id */
MISSING_DOCUMENT_ID: "missing_document_id",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_id */
INVALID_DOCUMENT_ID: "invalid_document_id",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_content_type */
INVALID_CONTENT_TYPE: "invalid_content_type",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_content_type */
MISSING_CONTENT_TYPE: "missing_content_type",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_fields */
INVALID_DOCUMENT_FIELDS: "invalid_document_fields",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_limit */
INVALID_DOCUMENT_LIMIT: "invalid_document_limit",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_offset */
INVALID_DOCUMENT_OFFSET: "invalid_document_offset",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_filter */
INVALID_DOCUMENT_FILTER: "invalid_document_filter",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_document_filter */
MISSING_DOCUMENT_FILTER: "missing_document_filter",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_vectors_field */
INVALID_DOCUMENT_VECTORS_FIELD: "invalid_document_vectors_field",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#payload_too_large */
PAYLOAD_TOO_LARGE: "payload_too_large",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_payload */
MISSING_PAYLOAD: "missing_payload",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#malformed_payload */
MALFORMED_PAYLOAD: "malformed_payload",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#no_space_left_on_device */
NO_SPACE_LEFT_ON_DEVICE: "no_space_left_on_device",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_store_file */
INVALID_STORE_FILE: "invalid_store_file",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_ranking_rules */
INVALID_RANKING_RULES: "missing_document_id",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_request */
INVALID_REQUEST: "invalid_request",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_document_geo_field */
INVALID_DOCUMENT_GEO_FIELD: "invalid_document_geo_field",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_q */
INVALID_SEARCH_Q: "invalid_search_q",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_offset */
INVALID_SEARCH_OFFSET: "invalid_search_offset",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_limit */
INVALID_SEARCH_LIMIT: "invalid_search_limit",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_page */
INVALID_SEARCH_PAGE: "invalid_search_page",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_hits_per_page */
INVALID_SEARCH_HITS_PER_PAGE: "invalid_search_hits_per_page",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_retrieve */
INVALID_SEARCH_ATTRIBUTES_TO_RETRIEVE: "invalid_search_attributes_to_retrieve",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_crop */
INVALID_SEARCH_ATTRIBUTES_TO_CROP: "invalid_search_attributes_to_crop",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_crop_length */
INVALID_SEARCH_CROP_LENGTH: "invalid_search_crop_length",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_highlight */
INVALID_SEARCH_ATTRIBUTES_TO_HIGHLIGHT: "invalid_search_attributes_to_highlight",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_show_matches_position */
INVALID_SEARCH_SHOW_MATCHES_POSITION: "invalid_search_show_matches_position",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_filter */
INVALID_SEARCH_FILTER: "invalid_search_filter",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_sort */
INVALID_SEARCH_SORT: "invalid_search_sort",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_facets */
INVALID_SEARCH_FACETS: "invalid_search_facets",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_highlight_pre_tag */
INVALID_SEARCH_HIGHLIGHT_PRE_TAG: "invalid_search_highlight_pre_tag",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_highlight_post_tag */
INVALID_SEARCH_HIGHLIGHT_POST_TAG: "invalid_search_highlight_post_tag",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_crop_marker */
INVALID_SEARCH_CROP_MARKER: "invalid_search_crop_marker",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_matching_strategy */
INVALID_SEARCH_MATCHING_STRATEGY: "invalid_search_matching_strategy",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_vector */
INVALID_SEARCH_VECTOR: "invalid_search_vector",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_attributes_to_search_on */
INVALID_SEARCH_ATTRIBUTES_TO_SEARCH_ON: "invalid_search_attributes_to_search_on",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#bad_request */
BAD_REQUEST: "bad_request",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#document_not_found */
DOCUMENT_NOT_FOUND: "document_not_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#internal */
INTERNAL: "internal",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key */
INVALID_API_KEY: "invalid_api_key",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_description */
INVALID_API_KEY_DESCRIPTION: "invalid_api_key_description",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_actions */
INVALID_API_KEY_ACTIONS: "invalid_api_key_actions",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_indexes */
INVALID_API_KEY_INDEXES: "invalid_api_key_indexes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_expires_at */
INVALID_API_KEY_EXPIRES_AT: "invalid_api_key_expires_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#api_key_not_found */
API_KEY_NOT_FOUND: "api_key_not_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_uid */
IMMUTABLE_API_KEY_UID: "immutable_api_key_uid",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_actions */
IMMUTABLE_API_KEY_ACTIONS: "immutable_api_key_actions",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_indexes */
IMMUTABLE_API_KEY_INDEXES: "immutable_api_key_indexes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_expires_at */
IMMUTABLE_API_KEY_EXPIRES_AT: "immutable_api_key_expires_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_created_at */
IMMUTABLE_API_KEY_CREATED_AT: "immutable_api_key_created_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_api_key_updated_at */
IMMUTABLE_API_KEY_UPDATED_AT: "immutable_api_key_updated_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_authorization_header */
MISSING_AUTHORIZATION_HEADER: "missing_authorization_header",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#unretrievable_document */
UNRETRIEVABLE_DOCUMENT: "unretrievable_document",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#database_size_limit_reached */
MAX_DATABASE_SIZE_LIMIT_REACHED: "database_size_limit_reached",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#task_not_found */
TASK_NOT_FOUND: "task_not_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#dump_process_failed */
DUMP_PROCESS_FAILED: "dump_process_failed",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#dump_not_found */
DUMP_NOT_FOUND: "dump_not_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_swap_duplicate_index_found */
INVALID_SWAP_DUPLICATE_INDEX_FOUND: "invalid_swap_duplicate_index_found",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_swap_indexes */
INVALID_SWAP_INDEXES: "invalid_swap_indexes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_swap_indexes */
MISSING_SWAP_INDEXES: "missing_swap_indexes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_master_key */
MISSING_MASTER_KEY: "missing_master_key",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_types */
INVALID_TASK_TYPES: "invalid_task_types",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_uids */
INVALID_TASK_UIDS: "invalid_task_uids",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_statuses */
INVALID_TASK_STATUSES: "invalid_task_statuses",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_limit */
INVALID_TASK_LIMIT: "invalid_task_limit",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_from */
INVALID_TASK_FROM: "invalid_task_from",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_canceled_by */
INVALID_TASK_CANCELED_BY: "invalid_task_canceled_by",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_task_filters */
MISSING_TASK_FILTERS: "missing_task_filters",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#too_many_open_files */
TOO_MANY_OPEN_FILES: "too_many_open_files",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#io_error */
IO_ERROR: "io_error",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_index_uids */
INVALID_TASK_INDEX_UIDS: "invalid_task_index_uids",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_index_uid */
IMMUTABLE_INDEX_UID: "immutable_index_uid",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_index_created_at */
IMMUTABLE_INDEX_CREATED_AT: "immutable_index_created_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#immutable_index_updated_at */
IMMUTABLE_INDEX_UPDATED_AT: "immutable_index_updated_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_displayed_attributes */
INVALID_SETTINGS_DISPLAYED_ATTRIBUTES: "invalid_settings_displayed_attributes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_searchable_attributes */
INVALID_SETTINGS_SEARCHABLE_ATTRIBUTES: "invalid_settings_searchable_attributes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_filterable_attributes */
INVALID_SETTINGS_FILTERABLE_ATTRIBUTES: "invalid_settings_filterable_attributes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_sortable_attributes */
INVALID_SETTINGS_SORTABLE_ATTRIBUTES: "invalid_settings_sortable_attributes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_ranking_rules */
INVALID_SETTINGS_RANKING_RULES: "invalid_settings_ranking_rules",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_stop_words */
INVALID_SETTINGS_STOP_WORDS: "invalid_settings_stop_words",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_synonyms */
INVALID_SETTINGS_SYNONYMS: "invalid_settings_synonyms",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_distinct_attribute */
INVALID_SETTINGS_DISTINCT_ATTRIBUTE: "invalid_settings_distinct_attribute",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_typo_tolerance */
INVALID_SETTINGS_TYPO_TOLERANCE: "invalid_settings_typo_tolerance",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_faceting */
INVALID_SETTINGS_FACETING: "invalid_settings_faceting",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_pagination */
INVALID_SETTINGS_PAGINATION: "invalid_settings_pagination",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_search_cutoff_ms */
INVALID_SETTINGS_SEARCH_CUTOFF_MS: "invalid_settings_search_cutoff_ms",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_settings_search_cutoff_ms */
INVALID_SETTINGS_LOCALIZED_ATTRIBUTES: "invalid_settings_localized_attributes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_before_enqueued_at */
INVALID_TASK_BEFORE_ENQUEUED_AT: "invalid_task_before_enqueued_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_after_enqueued_at */
INVALID_TASK_AFTER_ENQUEUED_AT: "invalid_task_after_enqueued_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_before_started_at */
INVALID_TASK_BEFORE_STARTED_AT: "invalid_task_before_started_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_after_started_at */
INVALID_TASK_AFTER_STARTED_AT: "invalid_task_after_started_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_before_finished_at */
INVALID_TASK_BEFORE_FINISHED_AT: "invalid_task_before_finished_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_task_after_finished_at */
INVALID_TASK_AFTER_FINISHED_AT: "invalid_task_after_finished_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_api_key_actions */
MISSING_API_KEY_ACTIONS: "missing_api_key_actions",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_api_key_indexes */
MISSING_API_KEY_INDEXES: "missing_api_key_indexes",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_api_key_expires_at */
MISSING_API_KEY_EXPIRES_AT: "missing_api_key_expires_at",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_limit */
INVALID_API_KEY_LIMIT: "invalid_api_key_limit",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_offset */
INVALID_API_KEY_OFFSET: "invalid_api_key_offset",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_facet_name */
INVALID_FACET_SEARCH_FACET_NAME: "invalid_facet_search_facet_name",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_facet_search_facet_name */
MISSING_FACET_SEARCH_FACET_NAME: "missing_facet_search_facet_name",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_facet_query */
INVALID_FACET_SEARCH_FACET_QUERY: "invalid_facet_search_facet_query",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_ranking_score_threshold */
INVALID_SEARCH_RANKING_SCORE_THRESHOLD: "invalid_search_ranking_score_threshold",
/** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_similar_ranking_score_threshold */
INVALID_SIMILAR_RANKING_SCORE_THRESHOLD: "invalid_similar_ranking_score_threshold"
};
class Index {
uid;
primaryKey;
createdAt;
updatedAt;
httpRequest;
tasks;
/**
* @param config - Request configuration options
* @param uid - UID of the index
* @param primaryKey - Primary Key of the index
*/
constructor(config, uid, primaryKey) {
this.uid = uid;
this.primaryKey = primaryKey;
this.httpRequest = new HttpRequests(config);
this.tasks = new TaskClient(config);
}
///
/// SEARCH
///
/**
* Search for documents into an index
*
* @param query - Query string
* @param options - Search options
* @param config - Additional request configuration options
* @returns Promise containing the search response
*/
async search(query, options, config) {
const url = `indexes/${this.uid}/search`;
return await this.httpRequest.post(
url,
removeUndefinedFromObject({ q: query, ...options }),
void 0,
config
);
}
/**
* Search for documents into an index using the GET method
*
* @param query - Query string
* @param options - Search options
* @param config - Additional request configuration options
* @returns Promise containing the search response
*/
async searchGet(query, options, config) {
const url = `indexes/${this.uid}/search`;
const parseFilter = (filter) => {
if (typeof filter === "string") return filter;
else if (Array.isArray(filter))
throw new MeiliSearchError(
"The filter query parameter should be in string format when using searchGet"
);
else return void 0;
};
const getParams = {
q: query,
...options,
filter: parseFilter(options?.filter),
sort: options?.sort?.join(","),
facets: options?.facets?.join(","),
attributesToRetrieve: options?.attributesToRetrieve?.join(","),
attributesToCrop: options?.attributesToCrop?.join(","),
attributesToHighlight: options?.attributesToHighlight?.join(","),
vector: options?.vector?.join(","),
attributesToSearchOn: options?.attributesToSearchOn?.join(",")
};
return await this.httpRequest.get(
url,
removeUndefinedFromObject(getParams),
config
);
}
/**
* Search for facet values
*
* @param params - Parameters used to search on the facets
* @param config - Additional request configuration options
* @returns Promise containing the search response
*/
async searchForFacetValues(params, config) {
const url = `indexes/${this.uid}/facet-search`;
return await this.httpRequest.post(
url,
removeUndefinedFromObject(params),
void 0,
config
);
}
/**
* Search for similar documents
*
* @param params - Parameters used to search for similar documents
* @returns Promise containing the search response
*/
async searchSimilarDocuments(params) {
const url = `indexes/${this.uid}/similar`;
return await this.httpRequest.post(
url,
removeUndefinedFromObject(params),
void 0
);
}
///
/// INDEX
///
/**
* Get index information.
*
* @returns Promise containing index information
*/
async getRawInfo() {
const url = `indexes/${this.uid}`;
const res = await this.httpRequest.get(url);
this.primaryKey = res.primaryKey;
this.updatedAt = new Date(res.updatedAt);
this.createdAt = new Date(res.createdAt);
return res;
}
/**
* Fetch and update Index information.
*
* @returns Promise to the current Index object with updated information
*/
async fetchInfo() {
await this.getRawInfo();
return this;
}
/**
* Get Primary Key.
*
* @returns Promise containing the Primary Key of the index
*/
async fetchPrimaryKey() {
this.primaryKey = (await this.getRawInfo()).primaryKey;
return this.primaryKey;
}
/**
* Create an index.
*
* @param uid - Unique identifier of the Index
* @param options - Index options
* @param config - Request configuration options
* @returns Newly created Index object
*/
static async create(uid, options = {}, config) {
const url = `indexes`;
const req = new HttpRequests(config);
const task = await req.post(url, { ...options, uid });
return new EnqueuedTask(task);
}
/**
* Update an index.
*
* @param data - Data to update
* @returns Promise to the current Index object with updated information
*/
async update(data) {
const url = `indexes/${this.uid}`;
const task = await this.httpRequest.patch(url, data);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
/**
* Delete an index.
*
* @returns Promise which resolves when index is deleted successfully
*/
async delete() {
const url = `indexes/${this.uid}`;
const task = await this.httpRequest.delete(url);
return new EnqueuedTask(task);
}
///
/// TASKS
///
/**
* Get the list of all the tasks of the index.
*
* @param parameters - Parameters to browse the tasks
* @returns Promise containing all tasks
*/
async getTasks(parameters = {}) {
return await this.tasks.getTasks({ ...parameters, indexUids: [this.uid] });
}
/**
* Get one task of the index.
*
* @param taskUid - Task identifier
* @returns Promise containing a task
*/
async getTask(taskUid) {
return await this.tasks.getTask(taskUid);
}
/**
* Wait for multiple tasks to be processed.
*
* @param taskUids - Tasks identifier
* @param waitOptions - Options on timeout and interval
* @returns Promise containing an array of tasks
*/
async waitForTasks(taskUids, { timeOutMs = 5e3, intervalMs = 50 } = {}) {
return await this.tasks.waitForTasks(taskUids, {
timeOutMs,
intervalMs
});
}
/**
* Wait for a task to be processed.
*
* @param taskUid - Task identifier
* @param waitOptions - Options on timeout and interval
* @returns Promise containing an array of tasks
*/
async waitForTask(taskUid, { timeOutMs = 5e3, intervalMs = 50 } = {}) {
return await this.tasks.waitForTask(taskUid, {
timeOutMs,
intervalMs
});
}
///
/// STATS
///
/**
* Get stats of an index
*
* @returns Promise containing object with stats of the index
*/
async getStats() {
const url = `indexes/${this.uid}/stats`;
return await this.httpRequest.get(url);
}
///
/// DOCUMENTS
///
/**
* Get documents of an index.
*
* @param parameters - Parameters to browse the documents. Parameters can
* contain the `filter` field only available in Meilisearch v1.2 and newer
* @returns Promise containing the returned documents
*/
async getDocuments(parameters = {}) {
parameters = removeUndefinedFromObject(parameters);
if (parameters.filter !== void 0) {
try {
const url = `indexes/${this.uid}/documents/fetch`;
return await this.httpRequest.post(url, parameters);
} catch (e) {
if (e instanceof MeiliSearchRequestError) {
e.message = versionErrorHintMessage(e.message, "getDocuments");
} else if (e instanceof MeiliSearchApiError) {
e.message = versionErrorHintMessage(e.message, "getDocuments");
}
throw e;
}
} else {
const url = `indexes/${this.uid}/documents`;
const fields = Array.isArray(parameters?.fields) ? { fields: parameters?.fields?.join(",") } : {};
return await this.httpRequest.get(url, {
...parameters,
...fields
});
}
}
/**
* Get one document
*
* @param documentId - Document ID
* @param parameters - Parameters applied on a document
* @returns Promise containing Document response
*/
async getDocument(documentId, parameters) {
const url = `indexes/${this.uid}/documents/${documentId}`;
const fields = (() => {
if (Array.isArray(parameters?.fields)) {
return parameters?.fields?.join(",");
}
return void 0;
})();
return await this.httpRequest.get(
url,
removeUndefinedFromObject({
...parameters,
fields
})
);
}
/**
* Add or replace multiples documents to an index
*
* @param documents - Array of Document objects to add/replace
* @param options - Options on document addition
* @returns Promise containing an EnqueuedTask
*/
async addDocuments(documents, options) {
const url = `indexes/${this.uid}/documents`;
const task = await this.httpRequest.post(url, documents, options);
return new EnqueuedTask(task);
}
/**
* Add or replace multiples documents in a string format to an index. It only
* supports csv, ndjson and json formats.
*
* @param documents - Documents provided in a string to add/replace
* @param contentType - Content type of your document:
* 'text/csv'|'application/x-ndjson'|'application/json'
* @param options - Options on document addition
* @returns Promise containing an EnqueuedTask
*/
async addDocumentsFromString(documents, contentType, queryParams) {
const url = `indexes/${this.uid}/documents`;
const task = await this.httpRequest.post(url, documents, queryParams, {
headers: {
"Content-Type": contentType
}
});
return new EnqueuedTask(task);
}
/**
* Add or replace multiples documents to an index in batches
*
* @param documents - Array of Document objects to add/replace
* @param batchSize - Size of the batch
* @param options - Options on document addition
* @returns Promise containing array of enqueued task objects for each batch
*/
async addDocumentsInBatches(documents, batchSize = 1e3, options) {
const updates = [];
for (let i = 0; i < documents.length; i += batchSize) {
updates.push(
await this.addDocuments(documents.slice(i, i + batchSize), options)
);
}
return updates;
}
/**
* Add or update multiples documents to an index
*
* @param documents - Array of Document objects to add/update
* @param options - Options on document update
* @returns Promise containing an EnqueuedTask
*/
async updateDocuments(documents, options) {
const url = `indexes/${this.uid}/documents`;
const task = await this.httpRequest.put(url, documents, options);
return new EnqueuedTask(task);
}
/**
* Add or update multiples documents to an index in batches
*
* @param documents - Array of Document objects to add/update
* @param batchSize - Size of the batch
* @param options - Options on document update
* @returns Promise containing array of enqueued task objects for each batch
*/
async updateDocumentsInBatches(documents, batchSize = 1e3, options) {
const updates = [];
for (let i = 0; i < documents.length; i += batchSize) {
updates.push(
await this.updateDocuments(documents.slice(i, i + batchSize), options)
);
}
return updates;
}
/**
* Add or update multiples documents in a string format to an index. It only
* supports csv, ndjson and json formats.
*
* @param documents - Documents provided in a string to add/update
* @param contentType - Content type of your document:
* 'text/csv'|'application/x-ndjson'|'application/json'
* @param queryParams - Options on raw document addition
* @returns Promise containing an EnqueuedTask
*/
async updateDocumentsFromString(documents, contentType, queryParams) {
const url = `indexes/${this.uid}/documents`;
const task = await this.httpRequest.put(url, documents, queryParams, {
headers: {
"Content-Type": contentType
}
});
return new EnqueuedTask(task);
}
/**
* Delete one document
*
* @param documentId - Id of Document to delete
* @returns Promise containing an EnqueuedTask
*/
async deleteDocument(documentId) {
const url = `indexes/${this.uid}/documents/${documentId}`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
/**
* Delete multiples documents of an index.
*
* @param params - Params value can be:
*
* - DocumentsDeletionQuery: An object containing the parameters to customize
* your document deletion. Only available in Meilisearch v1.2 and newer
* - DocumentsIds: An array of document ids to delete
*
* @returns Promise containing an EnqueuedTask
*/
async deleteDocuments(params) {
const isDocumentsDeletionQuery = !Array.isArray(params) && typeof params === "object";
const endpoint = isDocumentsDeletionQuery ? "documents/delete" : "documents/delete-batch";
const url = `indexes/${this.uid}/${endpoint}`;
try {
const task = await this.httpRequest.post(url, params);
return new EnqueuedTask(task);
} catch (e) {
if (e instanceof MeiliSearchRequestError && isDocumentsDeletionQuery) {
e.message = versionErrorHintMessage(e.message, "deleteDocuments");
} else if (e instanceof MeiliSearchApiError) {
e.message = versionErrorHintMessage(e.message, "deleteDocuments");
}
throw e;
}
}
/**
* Delete all documents of an index
*
* @returns Promise containing an EnqueuedTask
*/
async deleteAllDocuments() {
const url = `indexes/${this.uid}/documents`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
/**
* This is an EXPERIMENTAL feature, which may break without a major version.
* It's available after Meilisearch v1.10.
*
* More info about the feature:
* https://github.com/orgs/meilisearch/discussions/762 More info about
* experimental features in general:
* https://www.meilisearch.com/docs/reference/api/experimental-features
*
* @param options - Object containing the function string and related options
* @returns Promise containing an EnqueuedTask
*/
async updateDocumentsByFunction(options) {
const url = `indexes/${this.uid}/documents/edit`;
const task = await this.httpRequest.post(url, options);
return new EnqueuedTask(task);
}
///
/// SETTINGS
///
/**
* Retrieve all settings
*
* @returns Promise containing Settings object
*/
async getSettings() {
const url = `indexes/${this.uid}/settings`;
return await this.httpRequest.get(url);
}
/**
* Update all settings Any parameters not provided will be left unchanged.
*
* @param settings - Object containing parameters with their updated values
* @returns Promise containing an EnqueuedTask
*/
async updateSettings(settings) {
const url = `indexes/${this.uid}/settings`;
const task = await this.httpRequest.patch(url, settings);
task.enqueued = new Date(task.enqueuedAt);
return task;
}
/**
* Reset settings.
*
* @returns Promise containing an EnqueuedTask
*/
async resetSettings() {
const url = `indexes/${this.uid}/settings`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
///
/// PAGINATION SETTINGS
///
/**
* Get the pagination settings.
*
* @returns Promise containing object of pagination settings
*/
async getPagination() {
const url = `indexes/${this.uid}/settings/pagination`;
return await this.httpRequest.get(url);
}
/**
* Update the pagination settings.
*
* @param pagination - Pagination object
* @returns Promise containing an EnqueuedTask
*/
async updatePagination(pagination) {
const url = `indexes/${this.uid}/settings/pagination`;
const task = await this.httpRequest.patch(url, pagination);
return new EnqueuedTask(task);
}
/**
* Reset the pagination settings.
*
* @returns Promise containing an EnqueuedTask
*/
async resetPagination() {
const url = `indexes/${this.uid}/settings/pagination`;
const task = await this.httpRequest.delete(url);
return new EnqueuedTask(task);
}
///
/// SYNONYMS
///
/**
* Get the list of all synonyms
*
* @returns Promise containing object of synonym mappings
*/
async getSynonyms() {
const url = `indexes/${this.uid}/settings/synonyms`;
return await this.httpRequest.get(url);
}
/**
* Update the list of synonyms. Overwrite the old list.
*
* @param synonyms - Mapping of synonyms with their associated words
* @returns Promise containing an EnqueuedTask
*/
async updateSynonyms(synonyms) {
const url = `indexes/${this.uid}/settings/synonyms`;
const task = await this.httpRequest.put(url, synonyms);
return new EnqueuedTask(task);
}
/**
* Reset the synonym list to be empty again
*
* @returns Promise containing an EnqueuedTask
*/
async resetSynonyms() {
const url = `indexes/${this.uid}/settings/synonyms`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
///
/// STOP WORDS
///
/**
* Get the list of all stop-words
*
* @returns Promise containing array of stop-words
*/
async getStopWords() {
const url = `indexes/${this.uid}/settings/stop-words`;
return await this.httpRequest.get(url);
}
/**
* Update the list of stop-words. Overwrite the old list.
*
* @param stopWords - Array of strings that contains the stop-words.
* @returns Promise containing an EnqueuedTask
*/
async updateStopWords(stopWords) {
const url = `indexes/${this.uid}/settings/stop-words`;
const task = await this.httpRequest.put(url, stopWords);
return new EnqueuedTask(task);
}
/**
* Reset the stop-words list to be empty again
*
* @returns Promise containing an EnqueuedTask
*/
async resetStopWords() {
const url = `indexes/${this.uid}/settings/stop-words`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(task.enqueuedAt);
return task;
}
///
/// RANKING RULES
///
/**
* Get the list of all ranking-rules
*
* @returns Promise containing array of ranking-rules
*/
async getRankingRules() {
const url = `indexes/${this.uid}/settings/ranking-rules`;
return await this.httpRequest.get(url);
}
/**
* Update the list of ranking-rules. Overwrite the old list.
*
* @param rankingRules - Array that contain ranking rules sorted by order of
* importance.
* @returns Promise containing an EnqueuedTask
*/
async updateRankingRules(rankingRules) {
const url = `indexes/${this.uid}/settings/ranking-rules`;
const task = await this.httpRequest.put(url, rankingRules);
return new EnqueuedTask(task);
}
/**
* Reset the ranking rules list to its default value
*
* @returns Promise containing an EnqueuedTask
*/
async resetRankingRules() {
const url = `indexes/${this.uid}/settings/ranking-rules`;
const task = await this.httpRequest.delete(url);
task.enqueuedAt = new Date(t