UNPKG

medusa-plugin-meilisearch-variants-v3

Version:

Meilisearch plugin for Medusa 2 Product Variants

473 lines 38.9 kB
"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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