@rokmohar/medusa-plugin-meilisearch
Version:
Meilisearch plugin for Medusa 2
207 lines • 19 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MeiliSearchService = void 0;
const meilisearch_1 = require("meilisearch");
const utils_1 = require("@medusajs/utils");
const types_1 = require("../types");
const embedder_1 = require("../utils/embedder");
const transformer_1 = require("../utils/transformer");
class MeiliSearchService extends utils_1.SearchUtils.AbstractSearchService {
static identifier = 'index-meilisearch';
isDefault = false;
config_;
client_;
embedder_;
// First arg is the awilix cradle for this module's local container, not a MedusaContainer.
// Calls like `.resolve()` on it fail. Callers must supply the real container via AddDocumentsOptions.
constructor(cradle, options) {
super(cradle, options);
this.config_ = options;
if (!options.config.apiKey) {
throw Error('Meilisearch API key is missing in plugin config. See https://github.com/rokmohar/medusa-plugin-meilisearch');
}
if (!options.config.host) {
throw Error('Meilisearch host is missing in plugin config. See https://github.com/rokmohar/medusa-plugin-meilisearch');
}
this.client_ = new meilisearch_1.Meilisearch(options.config);
this.embedder_ = new embedder_1.MeiliSearchEmbedder(options, this.client_);
}
getLanguageIndexName(baseKey, language) {
const { i18n } = this.config_;
if (i18n?.strategy !== 'separate-index' || !language) {
return baseKey;
}
return `${baseKey}_${language}`;
}
getFieldsForType(type) {
const fields = new Set();
Object.values(this.config_.settings ?? {})
.filter((config) => {
return config.type === type && config.enabled !== false;
})
.forEach((config) => {
if (Array.isArray(config.fields)) {
config.fields.forEach((field) => {
return fields.add(field);
});
}
});
if (!fields.size) {
fields.add('*');
}
return Array.from(fields);
}
getIndexesByType(type) {
const { i18n } = this.config_;
const baseIndexes = Object.entries(this.config_.settings ?? {})
.filter(([, config]) => {
return config.type === type && config.enabled !== false;
})
.map(([key]) => {
return key;
});
if (i18n?.strategy === 'separate-index') {
const { languages } = i18n;
return baseIndexes.flatMap((baseIndex) => {
return languages.map((lang) => {
return this.getLanguageIndexName(baseIndex, lang);
});
});
}
return baseIndexes;
}
async createIndex(indexName, options = { primaryKey: 'id' }) {
return this.client_.createIndex(indexName, options);
}
getIndex(indexName) {
return this.client_.index(indexName);
}
async addDocuments(indexName, documents, _type, options) {
const { language, container } = options ?? {};
const { i18n } = this.config_;
const i18nOptions = {
i18n,
language,
container,
};
const records = documents.filter((d) => {
return typeof d === 'object' && d !== null && !Array.isArray(d);
});
if (i18n?.strategy === 'separate-index') {
const langIndexName = this.getLanguageIndexName(indexName, language ?? i18n.defaultLanguage);
const transformedDocuments = await this.getTransformedDocuments(indexName, records, i18nOptions);
return this.client_.index(langIndexName).addDocuments(transformedDocuments, { primaryKey: 'id' });
}
else {
const transformedDocuments = await this.getTransformedDocuments(indexName, records, i18nOptions);
return this.client_.index(indexName).addDocuments(transformedDocuments, { primaryKey: 'id' });
}
}
async replaceDocuments(indexName, documents, type, options) {
return this.addDocuments(indexName, documents, type, options);
}
async deleteDocument(indexName, documentId, language) {
const actualIndexName = this.getLanguageIndexName(indexName, language);
return this.client_.index(actualIndexName).deleteDocument(documentId);
}
async deleteDocuments(indexName, documents, language) {
const actualIndexName = this.getLanguageIndexName(indexName, language);
return this.client_.index(actualIndexName).deleteDocuments(documents);
}
async deleteAllDocuments(indexName, language) {
const actualIndexName = this.getLanguageIndexName(indexName, language);
return this.client_.index(actualIndexName).deleteAllDocuments();
}
async search(indexName, query, options) {
const { language, paginationOptions, filter, additionalOptions, semanticSearch = false, semanticRatio = 0.5, attributesToRetrieve, } = options;
const actualIndexName = this.getLanguageIndexName(indexName, language);
// Build base search options
let searchOptions = {
filter,
attributesToRetrieve,
...paginationOptions,
...additionalOptions,
};
// Enhance with vector search if needed
searchOptions = this.embedder_.enhanceSearchOptions(searchOptions, semanticSearch, semanticRatio);
// Perform search
return this.client_.index(actualIndexName).search(query, searchOptions);
}
async updateSettings(indexName, settings) {
const indexConfig = this.config_.settings?.[indexName];
if (indexConfig?.enabled === false) {
return;
}
const { i18n } = this.config_;
if (i18n?.strategy === 'separate-index') {
const { languages } = i18n;
return Promise.all(languages.map(async (lang) => {
const langIndexName = this.getLanguageIndexName(indexName, lang);
await this.upsertIndex(langIndexName, settings);
await this.updateIndexSettings(langIndexName, settings.indexSettings);
// Configure embedders for vector search
if (this.embedder_.isVectorSearchEnabled()) {
await this.embedder_.configureEmbedders(langIndexName);
}
}));
}
else {
await this.upsertIndex(indexName, settings);
await this.updateIndexSettings(indexName, settings.indexSettings);
// Configure embedders for vector search
if (this.embedder_.isVectorSearchEnabled()) {
await this.embedder_.configureEmbedders(indexName);
}
return;
}
}
async updateIndexSettings(indexName, indexSettings) {
return this.client_.index(indexName).updateSettings(indexSettings);
}
async upsertIndex(indexName, settings) {
const indexConfig = this.config_.settings?.[indexName];
if (indexConfig?.enabled === false) {
return;
}
try {
await this.client_.getIndex(indexName);
}
catch (error) {
if (typeof error === 'object' &&
error !== null &&
'code' in error &&
error.code === types_1.meilisearchErrorCodes.INDEX_NOT_FOUND) {
await this.createIndex(indexName, {
primaryKey: settings.primaryKey ?? 'id',
});
}
}
}
async getTransformedDocuments(indexName, documents, options) {
if (!documents.length) {
return [];
}
const indexConfig = this.config_.settings?.[indexName];
switch (indexConfig?.type) {
case utils_1.SearchUtils.indexTypes.PRODUCTS:
return Promise.all(documents.map(async (doc) => {
return indexConfig.transformer?.(doc, transformer_1.transformProduct, { ...options }) ?? (0, transformer_1.transformProduct)(doc, options);
}));
case 'categories':
return Promise.all(documents.map(async (doc) => {
return indexConfig.transformer?.(doc, transformer_1.transformCategory, { ...options }) ?? (0, transformer_1.transformCategory)(doc, options);
}));
default:
return documents;
}
}
/**
* Get embedder configuration status for admin panel
* Delegates to the embedder service
*/
getVectorSearchStatus() {
return this.embedder_.getVectorSearchStatus();
}
}
exports.MeiliSearchService = MeiliSearchService;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVpbGlzZWFyY2guanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9tZWlsaXNlYXJjaC9zZXJ2aWNlcy9tZWlsaXNlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBeUY7QUFFekYsMkNBQTZDO0FBQzdDLG9DQUErRjtBQUMvRixnREFBdUQ7QUFDdkQsc0RBQTRGO0FBRTVGLE1BQWEsa0JBQW1CLFNBQVEsbUJBQVcsQ0FBQyxxQkFBcUI7SUFDaEUsTUFBTSxDQUFDLFVBQVUsR0FBRyxtQkFBbUIsQ0FBQTtJQUV2QyxTQUFTLEdBQUcsS0FBSyxDQUFBO0lBRUwsT0FBTyxDQUEwQjtJQUNqQyxPQUFPLENBQWE7SUFDcEIsU0FBUyxDQUFxQjtJQUVqRCwyRkFBMkY7SUFDM0Ysc0dBQXNHO0lBQ3RHLFlBQVksTUFBZSxFQUFFLE9BQWlDO1FBQzVELEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFFdEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFFdEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDM0IsTUFBTSxLQUFLLENBQ1QsNEdBQTRHLENBQzdHLENBQUE7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDekIsTUFBTSxLQUFLLENBQ1QseUdBQXlHLENBQzFHLENBQUE7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLHlCQUFXLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBQzlDLElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSw4QkFBbUIsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ2pFLENBQUM7SUFFUyxvQkFBb0IsQ0FBQyxPQUFlLEVBQUUsUUFBaUI7UUFDL0Qs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