medusa-plugin-meilisearch-variants-v3
Version:
Meilisearch plugin for Medusa 2 Product Variants
473 lines • 38.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MeiliSearchVariantsService = void 0;
const utils_1 = require("@medusajs/utils");
const meilisearch_1 = require("meilisearch");
const types_1 = require("../types");
const transformer_1 = require("../utils/transformer");
class MeiliSearchVariantsService extends utils_1.SearchUtils.AbstractSearchService {
constructor(container, options) {
super(container, options);
this.isDefault = false;
this.config_ = options;
console.log("🔧 [SERVICE] MeiliSearchVariantsService: Initializing service", {
config: {
host: options.config?.host,
apiKey: options.config?.apiKey ? "[REDACTED]" : "missing",
i18n: options.i18n,
},
});
if (!options.config?.apiKey) {
throw Error("Meilisearch API key is missing in plugin config. See https://github.com/rokmohar/medusa-plugin-meilisearch-variants");
}
if (!options.config?.host) {
throw Error("Meilisearch host is missing in plugin config. See https://github.com/rokmohar/medusa-plugin-meilisearch-variants");
}
this.client_ = new meilisearch_1.MeiliSearch(options.config);
console.log("✅ [SERVICE] MeiliSearchVariantsService: Service initialized successfully");
}
getLanguageIndexKey(baseKey, language) {
const { i18n } = this.config_;
if (!i18n || i18n.strategy !== "separate-index" || !language) {
return baseKey;
}
return `${baseKey}_${language}`;
}
async getFieldsForType(type) {
console.log("🔍 [SERVICE] getFieldsForType: Getting fields for type", {
type: type,
settings: this.config_.settings,
});
const fields = new Set();
Object.values(this.config_.settings || {})
.filter((config) => config.type === type && config.enabled !== false)
.forEach((config) => {
if (Array.isArray(config.fields)) {
config.fields.forEach((field) => fields.add(field));
}
});
if (!fields.size) {
fields.add("*");
}
const result = Array.from(fields);
console.log("📋 [SERVICE] getFieldsForType: Fields retrieved", {
type: type,
fields: result,
});
return result;
}
async getIndexesByType(type) {
console.log("🔍 [SERVICE] getIndexesByType: Getting indexes for type", {
type: type,
settings: Object.keys(this.config_.settings || {}),
});
const { i18n } = this.config_;
const baseIndexes = Object.entries(this.config_.settings || {})
.filter(([, config]) => config.type === type && config.enabled !== false)
.map(([key]) => key);
console.log("📋 [SERVICE] getIndexesByType: Base indexes found", {
type: type,
baseIndexes: baseIndexes,
i18nStrategy: i18n?.strategy,
});
if (i18n?.strategy === "separate-index") {
const { languages } = i18n;
const result = baseIndexes.flatMap((baseIndex) => languages.map((lang) => this.getLanguageIndexKey(baseIndex, lang)));
console.log("🌐 [SERVICE] getIndexesByType: Language-specific indexes created", {
type: type,
languages: languages,
indexes: result,
});
return result;
}
console.log("📋 [SERVICE] getIndexesByType: Returning base indexes", {
type: type,
indexes: baseIndexes,
});
return baseIndexes;
}
async createIndex(indexKey, options = { primaryKey: "id" }) {
console.log("🏗️ [SERVICE] createIndex: Creating new index", {
indexKey: indexKey,
options: options,
});
try {
const result = await this.client_.createIndex(indexKey, options);
console.log("✅ [SERVICE] createIndex: Index created successfully", {
indexKey: indexKey,
result: result,
});
return result;
}
catch (error) {
console.error("❌ [SERVICE] createIndex: Failed to create index", {
indexKey: indexKey,
error: error.message,
});
throw error;
}
}
getIndex(indexKey) {
console.log("📋 [SERVICE] getIndex: Getting index reference", {
indexKey: indexKey,
});
return this.client_.index(indexKey);
}
async addDocuments(indexKey, documents, language) {
console.log("📤 [SERVICE] addDocuments: Adding documents to index", {
indexKey: indexKey,
documentsCount: documents.length,
language: language,
i18nStrategy: this.config_.i18n?.strategy,
});
const { i18n } = this.config_;
const i18nOptions = {
i18n,
language,
};
try {
if (i18n?.strategy === "separate-index") {
const langIndexKey = this.getLanguageIndexKey(indexKey, language || i18n.defaultLanguage);
console.log("🌐 [SERVICE] addDocuments: Using language-specific index", {
originalIndexKey: indexKey,
languageIndexKey: langIndexKey,
language: language || i18n.defaultLanguage,
});
const transformedDocuments = await this.getTransformedDocuments(indexKey, documents, i18nOptions);
console.log("🔄 [SERVICE] addDocuments: Documents transformed for separate-index strategy", {
indexKey: langIndexKey,
originalCount: documents.length,
transformedCount: transformedDocuments.length,
});
const result = await this.client_
.index(langIndexKey)
.addDocuments(transformedDocuments, { primaryKey: "id" });
console.log("✅ [SERVICE] addDocuments: Documents added to language-specific index", {
indexKey: langIndexKey,
result: result,
});
return result;
}
else {
const transformedDocuments = await this.getTransformedDocuments(indexKey, documents, i18nOptions);
console.log("🔄 [SERVICE] addDocuments: Documents transformed for single index", {
indexKey: indexKey,
originalCount: documents.length,
transformedCount: transformedDocuments.length,
});
const result = await this.client_
.index(indexKey)
.addDocuments(transformedDocuments, { primaryKey: "id" });
console.log("✅ [SERVICE] addDocuments: Documents added to single index", {
indexKey: indexKey,
result: result,
});
return result;
}
}
catch (error) {
console.error("❌ [SERVICE] addDocuments: Failed to add documents", {
indexKey: indexKey,
language: language,
error: error.message,
stack: error.stack,
});
throw error;
}
}
async replaceDocuments(indexKey, documents, language) {
console.log("🔄 [SERVICE] replaceDocuments: Replacing documents in index", {
indexKey: indexKey,
documentsCount: documents.length,
language: language,
});
return this.addDocuments(indexKey, documents, language);
}
async deleteDocument(indexKey, documentId, language) {
const actualIndexKey = this.getLanguageIndexKey(indexKey, language);
console.log("🗑️ [SERVICE] deleteDocument: Deleting document from index", {
originalIndexKey: indexKey,
actualIndexKey: actualIndexKey,
documentId: documentId,
language: language,
});
try {
const result = await this.client_
.index(actualIndexKey)
.deleteDocument(documentId);
console.log("✅ [SERVICE] deleteDocument: Document deleted successfully", {
indexKey: actualIndexKey,
documentId: documentId,
result: result,
});
return result;
}
catch (error) {
console.error("❌ [SERVICE] deleteDocument: Failed to delete document", {
indexKey: actualIndexKey,
documentId: documentId,
error: error.message,
});
throw error;
}
}
async deleteDocuments(indexKey, documentIds, language) {
const actualIndexKey = this.getLanguageIndexKey(indexKey, language);
console.log("🗑️ [SERVICE] deleteDocuments: Deleting multiple documents from index", {
originalIndexKey: indexKey,
actualIndexKey: actualIndexKey,
documentIds: documentIds,
language: language,
});
try {
const result = await this.client_
.index(actualIndexKey)
.deleteDocuments(documentIds);
console.log("✅ [SERVICE] deleteDocuments: Documents deleted successfully", {
indexKey: actualIndexKey,
documentIdsCount: documentIds.length,
result: result,
});
return result;
}
catch (error) {
console.error("❌ [SERVICE] deleteDocuments: Failed to delete documents", {
indexKey: actualIndexKey,
documentIds: documentIds,
error: error.message,
});
throw error;
}
}
async deleteAllDocuments(indexKey, language) {
const actualIndexKey = this.getLanguageIndexKey(indexKey, language);
console.log("🗑️ [SERVICE] deleteAllDocuments: Deleting all documents from index", {
originalIndexKey: indexKey,
actualIndexKey: actualIndexKey,
language: language,
});
try {
const result = await this.client_
.index(actualIndexKey)
.deleteAllDocuments();
console.log("✅ [SERVICE] deleteAllDocuments: All documents deleted successfully", {
indexKey: actualIndexKey,
result: result,
});
return result;
}
catch (error) {
console.error("❌ [SERVICE] deleteAllDocuments: Failed to delete all documents", {
indexKey: actualIndexKey,
error: error.message,
});
throw error;
}
}
async search(indexKey, query, options) {
const { language, paginationOptions, filter, additionalOptions } = options;
const actualIndexKey = this.getLanguageIndexKey(indexKey, language);
console.log("🔍 [SERVICE] search: Performing search", {
originalIndexKey: indexKey,
actualIndexKey: actualIndexKey,
query: query,
language: language,
options: { paginationOptions, filter, additionalOptions },
});
try {
const result = await this.client_
.index(actualIndexKey)
.search(query, { filter, ...paginationOptions, ...additionalOptions });
console.log("✅ [SERVICE] search: Search completed", {
indexKey: actualIndexKey,
query: query,
hitsCount: result.hits?.length || 0,
estimatedTotalHits: result.estimatedTotalHits,
});
return result;
}
catch (error) {
console.error("❌ [SERVICE] search: Search failed", {
indexKey: actualIndexKey,
query: query,
error: error.message,
});
throw error;
}
}
async updateSettings(indexKey, settings) {
console.log("⚙️ [SERVICE] updateSettings: Updating index settings", {
indexKey: indexKey,
settings: settings,
});
const indexConfig = this.config_.settings?.[indexKey];
if (indexConfig?.enabled === false) {
console.log("⚠️ [SERVICE] updateSettings: Index is disabled, skipping", {
indexKey: indexKey,
});
return;
}
const { i18n } = this.config_;
try {
if (i18n?.strategy === "separate-index") {
const { languages } = i18n;
console.log("🌐 [SERVICE] updateSettings: Updating settings for all languages", {
indexKey: indexKey,
languages: languages,
});
const result = await Promise.all(languages.map(async (lang) => {
const langIndexKey = this.getLanguageIndexKey(indexKey, lang);
console.log("🌐 [SERVICE] updateSettings: Updating language-specific index", {
originalIndexKey: indexKey,
languageIndexKey: langIndexKey,
language: lang,
});
await this.upsertIndex(langIndexKey, settings);
const updateResult = await this.client_
.index(langIndexKey)
.updateSettings(settings.indexSettings ?? {});
console.log("✅ [SERVICE] updateSettings: Language-specific index updated", {
languageIndexKey: langIndexKey,
result: updateResult,
});
return updateResult;
}));
console.log("✅ [SERVICE] updateSettings: All language-specific indexes updated", {
indexKey: indexKey,
languagesCount: languages.length,
});
return result;
}
else {
console.log("📋 [SERVICE] updateSettings: Updating single index", {
indexKey: indexKey,
});
await this.upsertIndex(indexKey, settings);
const result = await this.client_
.index(indexKey)
.updateSettings(settings.indexSettings ?? {});
console.log("✅ [SERVICE] updateSettings: Single index updated", {
indexKey: indexKey,
result: result,
});
return result;
}
}
catch (error) {
console.error("❌ [SERVICE] updateSettings: Failed to update settings", {
indexKey: indexKey,
error: error.message,
code: error.code,
});
// Если индекс не найден, пробрасываем ошибку для обработки в loaders
if (error.code === "index_not_found" ||
error.message?.includes("not found")) {
throw error;
}
// Для других ошибок логируем и пробрасываем
throw error;
}
}
async upsertIndex(indexKey, settings) {
console.log("🔄 [SERVICE] upsertIndex: Upserting index", {
indexKey: indexKey,
settings: settings,
});
const indexConfig = this.config_.settings?.[indexKey];
if (indexConfig?.enabled === false) {
console.log("⚠️ [SERVICE] upsertIndex: Index is disabled, skipping", {
indexKey: indexKey,
});
return;
}
try {
await this.client_.getIndex(indexKey);
console.log("✅ [SERVICE] upsertIndex: Index already exists", {
indexKey: indexKey,
});
}
catch (error) {
if (error.code === types_1.meilisearchVariantsErrorCodes.INDEX_NOT_FOUND) {
console.log("🏗️ [SERVICE] upsertIndex: Index not found, creating new one", {
indexKey: indexKey,
primaryKey: settings.primaryKey ?? "id",
});
await this.createIndex(indexKey, {
primaryKey: settings.primaryKey ?? "id",
});
}
else {
console.error("❌ [SERVICE] upsertIndex: Unexpected error checking index", {
indexKey: indexKey,
error: error.message,
});
throw error;
}
}
}
async getTransformedDocuments(indexKey, documents, options) {
console.log("🔄 [SERVICE] getTransformedDocuments: Transforming documents", {
indexKey: indexKey,
documentsCount: documents.length,
options: options,
});
if (!documents?.length) {
console.log("⚠️ [SERVICE] getTransformedDocuments: No documents to transform", {
indexKey: indexKey,
});
return [];
}
const indexConfig = (this.config_.settings || {})[indexKey];
console.log("📋 [SERVICE] getTransformedDocuments: Index configuration", {
indexKey: indexKey,
indexConfig: indexConfig,
});
try {
switch (indexConfig?.type) {
case "variants":
console.log("🔄 [SERVICE] getTransformedDocuments: Transforming variants", {
indexKey: indexKey,
documentsCount: documents.length,
});
const transformedDocuments = await Promise.all(documents.map((doc) => indexConfig.transformer?.(doc, transformer_1.transformVariant, {
...options,
fields: indexConfig.fields, // Передаем поля из конфига
}) ??
(0, transformer_1.transformVariant)(doc, {
...options,
fields: indexConfig.fields, // Передаем поля из конфига
})));
console.log("✅ [SERVICE] getTransformedDocuments: Variants transformed successfully", {
indexKey: indexKey,
originalCount: documents.length,
transformedCount: transformedDocuments.length,
sampleTransformed: transformedDocuments[0]
? {
id: transformedDocuments[0].id,
sku: transformedDocuments[0].sku,
title: transformedDocuments[0].title,
}
: null,
});
return transformedDocuments;
default:
console.log("📋 [SERVICE] getTransformedDocuments: No transformation needed, returning original documents", {
indexKey: indexKey,
type: indexConfig?.type,
});
return documents;
}
}
catch (error) {
console.error("❌ [SERVICE] getTransformedDocuments: Failed to transform documents", {
indexKey: indexKey,
error: error.message,
stack: error.stack,
});
throw error;
}
}
}
exports.MeiliSearchVariantsService = MeiliSearchVariantsService;
MeiliSearchVariantsService.identifier = "index-meilisearch-variants";
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVpbGlzZWFyY2gtdmFyaWFudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9tZWlsaXNlYXJjaC12YXJpYW50cy9zZXJ2aWNlcy9tZWlsaXNlYXJjaC12YXJpYW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSwyQ0FBOEM7QUFDOUMsNkNBQTBDO0FBQzFDLG9DQUdrQjtBQUNsQixzREFBMEU7QUFFMUUsTUFBYSwwQkFBMkIsU0FBUSxtQkFBVyxDQUFDLHFCQUFxQjtJQVEvRSxZQUFZLFNBQWMsRUFBRSxPQUF5QztRQUNuRSxLQUFLLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBTjVCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFRaEIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFdkIsT0FBTyxDQUFDLEdBQUcsQ0FDVCwrREFBK0QsRUFDL0Q7WUFDRSxNQUFNLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsSUFBSTtnQkFDMUIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLFNBQVM7Z0JBQ3pELElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTthQUNuQjtTQUNGLENBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDO1lBQzVCLE1BQU0sS0FBSyxDQUNULHFIQUFxSCxDQUN0SCxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDO1lBQzFCLE1BQU0sS0FBSyxDQUNULGtIQUFrSCxDQUNuSCxDQUFDO1FBQ0osQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSx5QkFBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FB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