strapi-content-embeddings 0.1.9 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/App-ByRBbkZn.js +1 -0
- package/dist/_chunks/App-ByRBbkZn.js.map +1 -0
- package/dist/_chunks/App-MjsTrWRS.mjs +1 -0
- package/dist/_chunks/App-MjsTrWRS.mjs.map +1 -0
- package/dist/_chunks/en-B4KWt_jN.js +1 -0
- package/dist/_chunks/en-B4KWt_jN.js.map +1 -0
- package/dist/_chunks/en-Byx4XI2L.mjs +1 -0
- package/dist/_chunks/en-Byx4XI2L.mjs.map +1 -0
- package/dist/_chunks/index-TWbcT-zJ.js +1 -0
- package/dist/_chunks/index-TWbcT-zJ.js.map +1 -0
- package/dist/_chunks/index-ifqYByO5.mjs +1 -0
- package/dist/_chunks/index-ifqYByO5.mjs.map +1 -0
- package/dist/admin/index.js +1 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/index.mjs +1 -0
- package/dist/admin/index.mjs.map +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +1 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../server/src/config/index.ts","../../server/src/plugin-manager.ts","../../server/src/mcp/schemas/index.ts","../../server/src/mcp/tools/semantic-search.ts","../../server/src/mcp/tools/rag-query.ts","../../server/src/mcp/tools/list-embeddings.ts","../../server/src/mcp/tools/get-embedding.ts","../../server/src/mcp/tools/create-embedding.ts","../../server/src/mcp/tools/index.ts","../../server/src/mcp/server.ts","../../server/src/bootstrap.ts","../../server/src/destroy.ts","../../server/src/register.ts","../../server/src/content-types/embedding/index.ts","../../server/src/content-types/index.ts","../../server/src/controllers/controller.ts","../../server/src/controllers/mcp.ts","../../server/src/controllers/index.ts","../../server/src/middlewares/index.ts","../../server/src/policies/index.ts","../../server/src/routes/content-api.ts","../../server/src/routes/admin.ts","../../server/src/routes/index.ts","../../server/src/utils/chunking.ts","../../server/src/utils/preprocessing.ts","../../server/src/services/embeddings.ts","../../server/src/services/sync.ts","../../server/src/services/index.ts","../../server/src/index.ts"],"sourcesContent":["// Available OpenAI embedding models and their dimensions\nexport const EMBEDDING_MODELS = {\n \"text-embedding-3-small\": { dimensions: 1536 },\n \"text-embedding-3-large\": { dimensions: 3072 },\n \"text-embedding-ada-002\": { dimensions: 1536 },\n} as const;\n\nexport type EmbeddingModelName = keyof typeof EMBEDDING_MODELS;\n\nexport interface PluginConfigSchema {\n openAIApiKey?: string;\n neonConnectionString?: string;\n embeddingModel?: EmbeddingModelName;\n /** Maximum characters per chunk (default: 4000, roughly ~1000 tokens) */\n chunkSize?: number;\n /** Number of characters to overlap between chunks (default: 200) */\n chunkOverlap?: number;\n /** Automatically chunk content that exceeds chunkSize (default: false) */\n autoChunk?: boolean;\n /** Preprocess content before embedding - strips HTML/Markdown (default: true) */\n preprocessContent?: boolean;\n}\n\nexport default {\n default: {\n openAIApiKey: \"\",\n neonConnectionString: \"\",\n embeddingModel: \"text-embedding-3-small\" as EmbeddingModelName,\n chunkSize: 4000,\n chunkOverlap: 200,\n autoChunk: false,\n preprocessContent: true,\n },\n validator(config: PluginConfigSchema) {\n if (!config.openAIApiKey) {\n console.warn(\n \"strapi-content-embeddings: openAIApiKey is not configured. Plugin features will be disabled.\"\n );\n }\n if (!config.neonConnectionString) {\n console.warn(\n \"strapi-content-embeddings: neonConnectionString is not configured. Plugin features will be disabled.\"\n );\n }\n if (config.embeddingModel && !EMBEDDING_MODELS[config.embeddingModel]) {\n console.warn(\n `strapi-content-embeddings: Invalid embeddingModel \"${config.embeddingModel}\". ` +\n `Valid options: ${Object.keys(EMBEDDING_MODELS).join(\", \")}. ` +\n `Defaulting to \"text-embedding-3-small\".`\n );\n }\n if (config.chunkSize && (config.chunkSize < 100 || config.chunkSize > 8000)) {\n console.warn(\n `strapi-content-embeddings: chunkSize ${config.chunkSize} is outside recommended range (100-8000). ` +\n `Using default value of 4000.`\n );\n }\n },\n};\n","import { OpenAIEmbeddings, ChatOpenAI } from \"@langchain/openai\";\nimport { PGVectorStore } from \"@langchain/community/vectorstores/pgvector\";\nimport { Document } from \"@langchain/core/documents\";\nimport { StringOutputParser } from \"@langchain/core/output_parsers\";\nimport { ChatPromptTemplate } from \"@langchain/core/prompts\";\nimport {\n RunnableSequence,\n RunnablePassthrough,\n} from \"@langchain/core/runnables\";\nimport { Pool, PoolConfig } from \"pg\";\nimport {\n EMBEDDING_MODELS,\n type EmbeddingModelName,\n} from \"./config\";\n\ninterface PluginConfig {\n openAIApiKey: string;\n neonConnectionString: string;\n embeddingModel?: EmbeddingModelName;\n}\n\ninterface EmbeddingDocument {\n id: string;\n title: string;\n content: string;\n collectionType?: string;\n fieldName?: string;\n}\n\ninterface CreateEmbeddingResult {\n embeddingId: string;\n embedding: number[];\n}\n\ninterface QueryResponse {\n text: string;\n sourceDocuments: Document[];\n}\n\nclass PluginManager {\n private embeddings: OpenAIEmbeddings | null = null;\n private chat: ChatOpenAI | null = null;\n private pool: Pool | null = null;\n private embeddingModel: EmbeddingModelName = \"text-embedding-3-small\";\n private dimensions: number = 1536;\n private vectorStoreConfig: {\n pool: Pool;\n tableName: string;\n columns: {\n idColumnName: string;\n vectorColumnName: string;\n contentColumnName: string;\n metadataColumnName: string;\n };\n distanceStrategy: \"cosine\" | \"innerProduct\" | \"euclidean\";\n } | null = null;\n\n async initializePool(connectionString: string): Promise<Pool> {\n console.log(\"Initializing Neon DB Pool\");\n\n if (this.pool) return this.pool;\n\n try {\n const poolConfig: PoolConfig = {\n connectionString,\n ssl: { rejectUnauthorized: false },\n max: 10,\n };\n\n this.pool = new Pool(poolConfig);\n\n // Test the connection\n const client = await this.pool.connect();\n await client.query(\"SELECT 1\");\n client.release();\n\n // Initialize the vector store table if it doesn't exist\n await this.initializeVectorTable();\n\n console.log(\"Neon DB Pool initialized successfully\");\n return this.pool;\n } catch (error) {\n console.error(`Failed to initialize Neon DB Pool: ${error}`);\n throw new Error(`Failed to initialize Neon DB Pool: ${error}`);\n }\n }\n\n private async initializeVectorTable(): Promise<void> {\n if (!this.pool) throw new Error(\"Pool not initialized\");\n\n const client = await this.pool.connect();\n try {\n // Enable the pgvector extension\n await client.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n\n // Create the documents table if it doesn't exist\n // Note: If you change embedding models with different dimensions,\n // you may need to drop and recreate this table\n await client.query(`\n CREATE TABLE IF NOT EXISTS embeddings_documents (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n content TEXT,\n metadata JSONB,\n embedding vector(${this.dimensions})\n )\n `);\n\n // Drop any IVFFlat indexes that may have been created (they cause issues with small datasets)\n await client.query(`\n DROP INDEX IF EXISTS embeddings_documents_embedding_idx\n `);\n\n // Create HNSW index for similarity search (works better with any dataset size)\n await client.query(`\n CREATE INDEX IF NOT EXISTS embeddings_documents_embedding_hnsw_idx\n ON embeddings_documents\n USING hnsw (embedding vector_cosine_ops)\n `);\n\n // Create GIN index on metadata for faster lookups\n await client.query(`\n CREATE INDEX IF NOT EXISTS embeddings_documents_metadata_idx\n ON embeddings_documents\n USING gin (metadata)\n `);\n\n console.log(`Vector table initialized (dimensions: ${this.dimensions})`);\n } catch (error) {\n // Index creation might fail if not enough rows, that's okay\n console.log(\"Note: Index creation may require more data\");\n } finally {\n client.release();\n }\n }\n\n async initializeEmbeddings(openAIApiKey: string): Promise<OpenAIEmbeddings> {\n console.log(`Initializing OpenAI Embeddings (model: ${this.embeddingModel})`);\n\n if (this.embeddings) return this.embeddings;\n\n try {\n this.embeddings = new OpenAIEmbeddings({\n openAIApiKey,\n modelName: this.embeddingModel,\n dimensions: this.dimensions,\n });\n\n return this.embeddings;\n } catch (error) {\n console.error(`Failed to initialize Embeddings: ${error}`);\n throw new Error(`Failed to initialize Embeddings: ${error}`);\n }\n }\n\n async initializeChat(openAIApiKey: string): Promise<ChatOpenAI> {\n console.log(\"Initializing Chat Model\");\n\n if (this.chat) return this.chat;\n\n try {\n this.chat = new ChatOpenAI({\n modelName: \"gpt-4o-mini\",\n temperature: 0.7,\n openAIApiKey,\n });\n\n return this.chat;\n } catch (error) {\n console.error(`Failed to initialize Chat: ${error}`);\n throw new Error(`Failed to initialize Chat: ${error}`);\n }\n }\n\n async initialize(config: PluginConfig): Promise<void> {\n // Set embedding model and dimensions from config\n const model = config.embeddingModel || \"text-embedding-3-small\";\n if (EMBEDDING_MODELS[model]) {\n this.embeddingModel = model;\n this.dimensions = EMBEDDING_MODELS[model].dimensions;\n } else {\n console.warn(`Invalid embedding model \"${model}\", using default`);\n this.embeddingModel = \"text-embedding-3-small\";\n this.dimensions = EMBEDDING_MODELS[\"text-embedding-3-small\"].dimensions;\n }\n\n console.log(`Using embedding model: ${this.embeddingModel} (${this.dimensions} dimensions)`);\n\n await this.initializePool(config.neonConnectionString);\n await this.initializeEmbeddings(config.openAIApiKey);\n await this.initializeChat(config.openAIApiKey);\n\n if (this.pool) {\n this.vectorStoreConfig = {\n pool: this.pool,\n tableName: \"embeddings_documents\",\n columns: {\n idColumnName: \"id\",\n vectorColumnName: \"embedding\",\n contentColumnName: \"content\",\n metadataColumnName: \"metadata\",\n },\n distanceStrategy: \"cosine\",\n };\n }\n\n console.log(\"Plugin Manager Initialization Complete\");\n }\n\n async createEmbedding(docData: EmbeddingDocument): Promise<CreateEmbeddingResult> {\n if (!this.embeddings || !this.vectorStoreConfig || !this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n const maxRetries = 3;\n const retryDelay = 2000; // 2 seconds\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n // Generate the embedding vector (single API call)\n const embeddingVector = await this.embeddings.embedQuery(docData.content);\n\n // Insert directly into DB with pre-computed embedding (no second API call)\n const metadata = {\n id: docData.id,\n title: docData.title,\n collectionType: docData.collectionType || \"standalone\",\n fieldName: docData.fieldName || \"content\",\n };\n\n const vectorString = `[${embeddingVector.join(\",\")}]`;\n\n const result = await this.pool.query(\n `INSERT INTO embeddings_documents (content, metadata, embedding)\n VALUES ($1, $2::jsonb, $3::vector)\n RETURNING id`,\n [docData.content, JSON.stringify(metadata), vectorString]\n );\n\n return {\n embeddingId: result.rows[0]?.id || \"\",\n embedding: embeddingVector,\n };\n } catch (error: any) {\n const isRateLimit = error.message?.includes(\"429\") || error.message?.includes(\"rate\");\n const isLastAttempt = attempt === maxRetries;\n\n if (isRateLimit && !isLastAttempt) {\n console.log(`[createEmbedding] Rate limited, waiting ${retryDelay}ms before retry ${attempt + 1}/${maxRetries}...`);\n await new Promise(resolve => setTimeout(resolve, retryDelay * attempt));\n continue;\n }\n\n console.error(`[createEmbedding] Failed (attempt ${attempt}/${maxRetries}):`, error.message || error);\n if (isLastAttempt) {\n throw new Error(`Failed to create embedding after ${maxRetries} attempts: ${error.message || error}`);\n }\n }\n }\n\n throw new Error(\"Failed to create embedding: unexpected error\");\n }\n\n async deleteEmbedding(strapiId: string): Promise<void> {\n if (!this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n await this.pool.query(\n `DELETE FROM embeddings_documents WHERE metadata->>'id' = $1`,\n [strapiId]\n );\n } catch (error) {\n console.error(`Failed to delete embedding: ${error}`);\n throw new Error(`Failed to delete embedding: ${error}`);\n }\n }\n\n async queryEmbedding(query: string): Promise<QueryResponse> {\n if (!this.embeddings || !this.chat || !this.vectorStoreConfig) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n const vectorStore = await PGVectorStore.initialize(\n this.embeddings,\n this.vectorStoreConfig\n );\n\n // Use similaritySearchWithScore to get relevance scores\n // Retrieve more documents initially, then filter by score\n const resultsWithScores = await vectorStore.similaritySearchWithScore(query, 6);\n\n console.log(`[queryEmbedding] Query: \"${query}\"`);\n console.log(`[queryEmbedding] Found ${resultsWithScores.length} results:`);\n resultsWithScores.forEach(([doc, score], i) => {\n console.log(` ${i + 1}. Score: ${score.toFixed(4)}, Title: ${doc.metadata?.title || 'N/A'}`);\n });\n\n // Filter by similarity threshold (cosine distance: 0 = identical, higher = more different)\n // Increase threshold to allow more results\n const SIMILARITY_THRESHOLD = 1.0;\n const relevantResults = resultsWithScores.filter(([_, score]) => score < SIMILARITY_THRESHOLD);\n\n console.log(`[queryEmbedding] ${relevantResults.length} results passed threshold (< ${SIMILARITY_THRESHOLD})`);\n\n // Take top 3 most relevant documents for context\n const topResults = relevantResults.slice(0, 3);\n const sourceDocuments = topResults.map(([doc]) => doc);\n\n // Only show the single best matching source to the user\n const bestMatchForDisplay = topResults.length > 0 ? [topResults[0][0]] : [];\n\n // Format documents for context - include title from metadata\n const formatDocs = (docs: Document[]): string => {\n return docs.map((doc) => {\n const title = doc.metadata?.title ? `Title: ${doc.metadata.title}\\n` : '';\n return `${title}${doc.pageContent}`;\n }).join(\"\\n\\n\");\n };\n\n // Create RAG prompt\n const ragPrompt = ChatPromptTemplate.fromMessages([\n [\n \"system\",\n `You are a helpful assistant that answers questions based on the provided context.\nIf you cannot find the answer in the context, say so. Be concise and accurate.\n\nContext:\n{context}`,\n ],\n [\"human\", \"{question}\"],\n ]);\n\n // Build LCEL chain - use all relevant docs for context\n const ragChain = RunnableSequence.from([\n {\n context: async () => formatDocs(sourceDocuments),\n question: new RunnablePassthrough(),\n },\n ragPrompt,\n this.chat,\n new StringOutputParser(),\n ]);\n\n const text = await ragChain.invoke(query);\n\n return {\n text,\n sourceDocuments: bestMatchForDisplay, // Only return best match to display\n };\n } catch (error) {\n console.error(`Failed to query embeddings: ${error}`);\n throw new Error(`Failed to query embeddings: ${error}`);\n }\n }\n\n async similaritySearch(\n query: string,\n k: number = 4\n ): Promise<Document[]> {\n if (!this.embeddings || !this.vectorStoreConfig) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n const vectorStore = await PGVectorStore.initialize(\n this.embeddings,\n this.vectorStoreConfig\n );\n\n return await vectorStore.similaritySearch(query, k);\n } catch (error) {\n console.error(`Failed to perform similarity search: ${error}`);\n throw new Error(`Failed to perform similarity search: ${error}`);\n }\n }\n\n isInitialized(): boolean {\n return !!(this.embeddings && this.chat && this.pool);\n }\n\n /**\n * Get all embeddings from Neon DB\n * Returns the metadata (including Strapi documentId) for each embedding\n */\n async getAllNeonEmbeddings(): Promise<Array<{\n id: string;\n strapiId: string;\n title: string;\n content: string;\n collectionType: string;\n fieldName: string;\n }>> {\n if (!this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n const result = await this.pool.query(`\n SELECT\n id,\n content,\n metadata->>'id' as strapi_id,\n metadata->>'title' as title,\n metadata->>'collectionType' as collection_type,\n metadata->>'fieldName' as field_name\n FROM embeddings_documents\n ORDER BY id\n `);\n\n return result.rows.map((row) => ({\n id: row.id,\n strapiId: row.strapi_id,\n title: row.title || '',\n content: row.content || '',\n collectionType: row.collection_type || 'standalone',\n fieldName: row.field_name || 'content',\n }));\n } catch (error) {\n console.error(`Failed to get Neon embeddings: ${error}`);\n throw new Error(`Failed to get Neon embeddings: ${error}`);\n }\n }\n\n /**\n * Delete an embedding from Neon by its Neon UUID (not Strapi ID)\n */\n async deleteNeonEmbeddingById(neonId: string): Promise<void> {\n if (!this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n await this.pool.query(\n `DELETE FROM embeddings_documents WHERE id = $1`,\n [neonId]\n );\n } catch (error) {\n console.error(`Failed to delete Neon embedding: ${error}`);\n throw new Error(`Failed to delete Neon embedding: ${error}`);\n }\n }\n\n async destroy(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = null;\n }\n this.embeddings = null;\n this.chat = null;\n this.vectorStoreConfig = null;\n }\n\n /**\n * Clear all embeddings from Neon DB\n * Returns the number of deleted rows\n */\n async clearAllNeonEmbeddings(): Promise<number> {\n if (!this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n const result = await this.pool.query(`\n DELETE FROM embeddings_documents\n RETURNING id\n `);\n\n console.log(`[clearAllNeonEmbeddings] Deleted ${result.rowCount} embeddings from Neon`);\n return result.rowCount || 0;\n } catch (error) {\n console.error(`Failed to clear Neon embeddings: ${error}`);\n throw new Error(`Failed to clear Neon embeddings: ${error}`);\n }\n }\n\n /**\n * Debug method to inspect raw data in Neon DB\n */\n async debugNeonEmbeddings(): Promise<Array<{\n id: string;\n content: string;\n metadata: any;\n metadataType: string;\n hasEmbedding: boolean;\n embeddingLength: number;\n }>> {\n if (!this.pool) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n try {\n const result = await this.pool.query(`\n SELECT\n id,\n content,\n metadata,\n pg_typeof(metadata) as metadata_type,\n embedding IS NOT NULL as has_embedding,\n CASE WHEN embedding IS NOT NULL THEN array_length(embedding::float[], 1) ELSE 0 END as embedding_length\n FROM embeddings_documents\n ORDER BY id\n LIMIT 20\n `);\n\n return result.rows.map((row) => ({\n id: row.id,\n content: row.content?.substring(0, 200) + (row.content?.length > 200 ? '...' : ''),\n metadata: row.metadata,\n metadataType: row.metadata_type,\n hasEmbedding: row.has_embedding,\n embeddingLength: row.embedding_length || 0,\n }));\n } catch (error) {\n console.error(`Failed to debug Neon embeddings: ${error}`);\n throw new Error(`Failed to debug Neon embeddings: ${error}`);\n }\n }\n}\n\nexport const pluginManager = new PluginManager();\nexport type { PluginConfig, EmbeddingDocument, QueryResponse, CreateEmbeddingResult };\n","/**\n * Zod Schemas for MCP Tool Input Validation\n */\n\nimport { z } from 'zod';\n\n// Semantic Search Schema\nexport const SemanticSearchSchema = z.object({\n query: z.string().min(1, 'Query is required'),\n limit: z.number().min(1).max(20).optional().default(5),\n});\n\n// RAG Query Schema\nexport const RagQuerySchema = z.object({\n query: z.string().min(1, 'Query is required'),\n includeSourceDocuments: z.boolean().optional().default(true),\n});\n\n// List Embeddings Schema\nexport const ListEmbeddingsSchema = z.object({\n page: z.number().min(1).optional().default(1),\n pageSize: z.number().min(1).max(50).optional().default(25),\n search: z.string().optional(),\n});\n\n// Get Embedding Schema\nexport const GetEmbeddingSchema = z.object({\n documentId: z.string().min(1, 'Document ID is required'),\n includeContent: z.boolean().optional().default(true),\n});\n\n// Create Embedding Schema\nexport const CreateEmbeddingSchema = z.object({\n title: z.string().min(1, 'Title is required'),\n content: z.string().min(1, 'Content is required'),\n metadata: z.record(z.any()).optional(),\n});\n\n// Schema registry\nexport const ToolSchemas: Record<string, z.ZodSchema> = {\n semantic_search: SemanticSearchSchema,\n rag_query: RagQuerySchema,\n list_embeddings: ListEmbeddingsSchema,\n get_embedding: GetEmbeddingSchema,\n create_embedding: CreateEmbeddingSchema,\n};\n\n/**\n * Validate tool input against its schema\n */\nexport function validateToolInput<T = unknown>(\n toolName: string,\n input: unknown\n): T {\n const schema = ToolSchemas[toolName];\n\n if (!schema) {\n throw new Error(`No schema defined for tool: ${toolName}`);\n }\n\n const result = schema.safeParse(input);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => `${e.path.join('.')}: ${e.message}`)\n .join(', ');\n throw new Error(`Validation failed for ${toolName}: ${errors}`);\n }\n\n return result.data as T;\n}\n","/**\n * Semantic Search Tool\n *\n * Performs vector similarity search to find relevant content.\n */\n\nimport type { Core } from '@strapi/strapi';\n\nexport const semanticSearchTool = {\n name: 'semantic_search',\n description:\n 'TRIGGER: Use when user types \"/rag\" or asks to search embeddings/content. Search for semantically similar content using vector embeddings. Returns the most relevant documents matching your query based on meaning, not just keywords.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'The search query text to find similar content',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results to return (default: 5, max: 20)',\n default: 5,\n },\n },\n required: ['query'],\n },\n};\n\nexport async function handleSemanticSearch(\n strapi: Core.Strapi,\n args: { query: string; limit?: number }\n) {\n const { query, limit = 5 } = args;\n const maxLimit = Math.min(limit, 20);\n\n try {\n // Get the plugin manager for vector operations\n const pluginManager = (strapi as any).contentEmbeddingsManager;\n\n if (!pluginManager) {\n throw new Error('Content embeddings plugin not initialized');\n }\n\n // Perform similarity search\n const results = await pluginManager.similaritySearch(query, maxLimit);\n\n // Format results\n const formattedResults = results.map((doc: any, index: number) => ({\n rank: index + 1,\n content: doc.pageContent,\n metadata: doc.metadata,\n score: doc.score || null,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n query,\n resultCount: formattedResults.length,\n results: formattedResults,\n },\n null,\n 2\n ),\n },\n ],\n };\n } catch (error) {\n throw new Error(\n `Semantic search failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n","/**\n * RAG Query Tool\n *\n * Performs Retrieval-Augmented Generation to answer questions using embedded content.\n */\n\nimport type { Core } from '@strapi/strapi';\n\nexport const ragQueryTool = {\n name: 'rag_query',\n description:\n 'TRIGGER: Use when user types \"/rag\" followed by a question. Ask a question and get an AI-generated answer based on your embedded content. Uses RAG (Retrieval-Augmented Generation) to find relevant documents and generate a contextual response. This is the PRIMARY tool for /rag queries.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'The question or query to answer using embedded content',\n },\n includeSourceDocuments: {\n type: 'boolean',\n description: 'Include the source documents used to generate the answer (default: true)',\n default: true,\n },\n },\n required: ['query'],\n },\n};\n\nexport async function handleRagQuery(\n strapi: Core.Strapi,\n args: { query: string; includeSourceDocuments?: boolean }\n) {\n const { query, includeSourceDocuments = true } = args;\n\n try {\n // Get the embeddings service\n const embeddingsService = strapi\n .plugin('strapi-content-embeddings')\n .service('embeddings');\n\n // Perform RAG query\n const result = await embeddingsService.queryEmbeddings(query);\n\n // Format response\n const response: any = {\n query,\n answer: result.text,\n };\n\n if (includeSourceDocuments && result.sourceDocuments) {\n response.sourceDocuments = result.sourceDocuments.map((doc: any, index: number) => ({\n rank: index + 1,\n content: doc.pageContent?.substring(0, 500) + (doc.pageContent?.length > 500 ? '...' : ''),\n metadata: doc.metadata,\n }));\n response.sourceCount = result.sourceDocuments.length;\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(response, null, 2),\n },\n ],\n };\n } catch (error) {\n throw new Error(\n `RAG query failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n","/**\n * List Embeddings Tool\n *\n * Lists all embeddings stored in the database.\n */\n\nimport type { Core } from '@strapi/strapi';\n\nexport const listEmbeddingsTool = {\n name: 'list_embeddings',\n description:\n 'List all embeddings stored in the database. Returns metadata without the full content to avoid context overflow.',\n inputSchema: {\n type: 'object',\n properties: {\n page: {\n type: 'number',\n description: 'Page number (starts at 1)',\n default: 1,\n },\n pageSize: {\n type: 'number',\n description: 'Number of items per page (max: 50)',\n default: 25,\n },\n search: {\n type: 'string',\n description: 'Search filter for title',\n },\n },\n required: [],\n },\n};\n\nexport async function handleListEmbeddings(\n strapi: Core.Strapi,\n args: { page?: number; pageSize?: number; search?: string }\n) {\n const { page = 1, pageSize = 25, search } = args;\n const limit = Math.min(pageSize, 50);\n\n try {\n // Get the embeddings service\n const embeddingsService = strapi\n .plugin('strapi-content-embeddings')\n .service('embeddings');\n\n // Build filters\n const filters: any = {};\n if (search) {\n filters.title = { $containsi: search };\n }\n\n // Fetch embeddings\n const result = await embeddingsService.getEmbeddings({\n page,\n pageSize: limit,\n filters,\n });\n\n // Format response - exclude large fields\n const embeddings = (result.results || []).map((emb: any) => ({\n id: emb.id,\n documentId: emb.documentId,\n title: emb.title,\n collectionType: emb.collectionType,\n fieldName: emb.fieldName,\n metadata: emb.metadata,\n contentPreview: emb.content?.substring(0, 200) + (emb.content?.length > 200 ? '...' : ''),\n createdAt: emb.createdAt,\n updatedAt: emb.updatedAt,\n }));\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n embeddings,\n pagination: result.pagination || {\n page,\n pageSize: limit,\n total: embeddings.length,\n },\n },\n null,\n 2\n ),\n },\n ],\n };\n } catch (error) {\n throw new Error(\n `Failed to list embeddings: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n","/**\n * Get Embedding Tool\n *\n * Retrieves a single embedding by ID.\n */\n\nimport type { Core } from '@strapi/strapi';\n\nexport const getEmbeddingTool = {\n name: 'get_embedding',\n description:\n 'Get a specific embedding by its document ID. Returns the full content and metadata.',\n inputSchema: {\n type: 'object',\n properties: {\n documentId: {\n type: 'string',\n description: 'The document ID of the embedding to retrieve',\n },\n includeContent: {\n type: 'boolean',\n description: 'Include the full content text (default: true)',\n default: true,\n },\n },\n required: ['documentId'],\n },\n};\n\nexport async function handleGetEmbedding(\n strapi: Core.Strapi,\n args: { documentId: string; includeContent?: boolean }\n) {\n const { documentId, includeContent = true } = args;\n\n try {\n // Get the embeddings service\n const embeddingsService = strapi\n .plugin('strapi-content-embeddings')\n .service('embeddings');\n\n // Fetch the embedding\n const embedding = await embeddingsService.getEmbedding(documentId);\n\n if (!embedding) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: true,\n message: `Embedding not found with documentId: ${documentId}`,\n }),\n },\n ],\n };\n }\n\n // Format response\n const result: any = {\n id: embedding.id,\n documentId: embedding.documentId,\n title: embedding.title,\n collectionType: embedding.collectionType,\n fieldName: embedding.fieldName,\n metadata: embedding.metadata,\n embeddingId: embedding.embeddingId,\n createdAt: embedding.createdAt,\n updatedAt: embedding.updatedAt,\n };\n\n if (includeContent) {\n result.content = embedding.content;\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (error) {\n throw new Error(\n `Failed to get embedding: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n","/**\n * Create Embedding Tool\n *\n * Creates a new embedding from text content.\n * Supports automatic chunking for large content.\n */\n\nimport type { Core } from '@strapi/strapi';\n\nexport const createEmbeddingTool = {\n name: 'create_embedding',\n description:\n 'Create a new embedding from text content. The content will be vectorized and stored for semantic search. For large content (over 4000 characters), enable autoChunk to automatically split into multiple embeddings.',\n inputSchema: {\n type: 'object',\n properties: {\n title: {\n type: 'string',\n description: 'A descriptive title for the embedding',\n },\n content: {\n type: 'string',\n description: 'The text content to embed (will be vectorized)',\n },\n metadata: {\n type: 'object',\n description: 'Optional metadata to associate with the embedding (tags, source, etc.)',\n },\n autoChunk: {\n type: 'boolean',\n description:\n 'Automatically split large content into chunks (default: false). When enabled, content over 4000 characters will be split into multiple embeddings with overlap for context preservation.',\n },\n },\n required: ['title', 'content'],\n },\n};\n\nexport async function handleCreateEmbedding(\n strapi: Core.Strapi,\n args: {\n title: string;\n content: string;\n metadata?: Record<string, any>;\n autoChunk?: boolean;\n }\n) {\n const { title, content, metadata, autoChunk } = args;\n\n try {\n // Get the embeddings service\n const embeddingsService = strapi\n .plugin('strapi-content-embeddings')\n .service('embeddings');\n\n // Check if we should use chunked embedding\n if (autoChunk) {\n const result = await embeddingsService.createChunkedEmbedding({\n data: {\n title,\n content,\n metadata: metadata || {},\n collectionType: 'standalone',\n fieldName: 'content',\n },\n });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: result.wasChunked\n ? `Content chunked into ${result.totalChunks} embeddings`\n : 'Embedding created successfully (no chunking needed)',\n wasChunked: result.wasChunked,\n totalChunks: result.totalChunks,\n primaryEmbedding: {\n id: result.entity.id,\n documentId: result.entity.documentId,\n title: result.entity.title,\n embeddingId: result.entity.embeddingId,\n },\n chunks: result.chunks.map((chunk: any) => ({\n documentId: chunk.documentId,\n title: chunk.title,\n contentLength: chunk.content?.length || 0,\n })),\n contentLength: content.length,\n estimatedTokens: Math.ceil(content.length / 4),\n },\n null,\n 2\n ),\n },\n ],\n };\n }\n\n // Create single embedding (original behavior)\n const embedding = await embeddingsService.createEmbedding({\n data: {\n title,\n content,\n metadata: metadata || {},\n collectionType: 'standalone',\n fieldName: 'content',\n },\n });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Embedding created successfully',\n embedding: {\n id: embedding.id,\n documentId: embedding.documentId,\n title: embedding.title,\n embeddingId: embedding.embeddingId,\n contentLength: content.length,\n metadata: embedding.metadata,\n createdAt: embedding.createdAt,\n },\n hint:\n content.length > 4000\n ? 'Content is large. Consider using autoChunk: true for better search results.'\n : undefined,\n },\n null,\n 2\n ),\n },\n ],\n };\n } catch (error) {\n throw new Error(\n `Failed to create embedding: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n","/**\n * MCP Tools for Content Embeddings\n *\n * Exposes vector search, RAG queries, and embedding management tools.\n */\n\nimport type { Core } from '@strapi/strapi';\nimport { validateToolInput } from '../schemas';\n\n// Import tool handlers\nimport { semanticSearchTool, handleSemanticSearch } from './semantic-search';\nimport { ragQueryTool, handleRagQuery } from './rag-query';\nimport { listEmbeddingsTool, handleListEmbeddings } from './list-embeddings';\nimport { getEmbeddingTool, handleGetEmbedding } from './get-embedding';\nimport { createEmbeddingTool, handleCreateEmbedding } from './create-embedding';\n\n// Export all tool definitions\nexport const tools = [\n semanticSearchTool,\n ragQueryTool,\n listEmbeddingsTool,\n getEmbeddingTool,\n createEmbeddingTool,\n];\n\n// Tool handler registry\nconst toolHandlers: Record<\n string,\n (strapi: Core.Strapi, args: unknown) => Promise<any>\n> = {\n semantic_search: handleSemanticSearch,\n rag_query: handleRagQuery,\n list_embeddings: handleListEmbeddings,\n get_embedding: handleGetEmbedding,\n create_embedding: handleCreateEmbedding,\n};\n\n/**\n * Handle MCP tool calls\n */\nexport async function handleToolCall(\n strapi: Core.Strapi,\n request: { params: { name: string; arguments?: unknown } }\n) {\n const { name, arguments: args } = request.params;\n\n const handler = toolHandlers[name];\n if (!handler) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: true,\n message: `Unknown tool: ${name}`,\n availableTools: Object.keys(toolHandlers),\n }),\n },\n ],\n };\n }\n\n try {\n // Validate input using Zod schemas\n const validatedArgs = validateToolInput(name, args || {});\n const result = await handler(strapi, validatedArgs);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n strapi.log.error(`[strapi-content-embeddings] Tool ${name} error:`, { error: errorMessage });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: true,\n tool: name,\n message: errorMessage,\n }, null, 2),\n },\n ],\n };\n }\n}\n","/**\n * MCP Server Factory for Content Embeddings\n *\n * Creates an MCP server that exposes vector search and RAG tools.\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type { Core } from '@strapi/strapi';\nimport { tools, handleToolCall } from './tools';\n\nexport function createMcpServer(strapi: Core.Strapi): Server {\n const server = new Server(\n {\n name: 'strapi-content-embeddings-mcp',\n version: '1.0.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Handle tool listing\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return { tools };\n });\n\n // Handle tool execution\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n return handleToolCall(strapi, request);\n });\n\n return server;\n}\n","import type { Core } from \"@strapi/strapi\";\nimport { pluginManager } from \"./plugin-manager\";\nimport { createMcpServer } from \"./mcp/server\";\n\nconst PLUGIN_ID = \"strapi-content-embeddings\";\nconst OAUTH_PLUGIN_ID = \"strapi-oauth-mcp-manager\";\n\n/**\n * Fallback auth middleware for when OAuth manager plugin is not installed.\n * Requires Bearer token (Strapi API token) for MCP endpoints.\n */\nfunction createFallbackAuthMiddleware(strapi: Core.Strapi) {\n const mcpPath = `/api/${PLUGIN_ID}/mcp`;\n\n return async (ctx: any, next: () => Promise<void>) => {\n // Only apply to this plugin's MCP endpoint\n if (!ctx.path.startsWith(mcpPath)) {\n return next();\n }\n\n const authHeader = ctx.request.headers.authorization;\n\n if (!authHeader?.startsWith(\"Bearer \")) {\n ctx.status = 401;\n ctx.body = {\n error: \"Unauthorized\",\n message: \"Bearer token required. Provide a Strapi API token.\",\n };\n return;\n }\n\n // Extract token and set it for the controller\n const token = authHeader.slice(7);\n ctx.state.strapiToken = token;\n ctx.state.authMethod = \"api-token\";\n\n return next();\n };\n}\n\nconst bootstrap = async ({ strapi }: { strapi: Core.Strapi }) => {\n // Register RBAC actions for the plugin\n const actions = [\n {\n section: \"plugins\",\n displayName: \"Read\",\n uid: \"read\",\n pluginName: PLUGIN_ID,\n },\n {\n section: \"plugins\",\n displayName: \"Update\",\n uid: \"update\",\n pluginName: PLUGIN_ID,\n },\n {\n section: \"plugins\",\n displayName: \"Create\",\n uid: \"create\",\n pluginName: PLUGIN_ID,\n },\n {\n section: \"plugins\",\n displayName: \"Delete\",\n uid: \"delete\",\n pluginName: PLUGIN_ID,\n },\n {\n section: \"plugins\",\n displayName: \"Chat\",\n uid: \"chat\",\n pluginName: PLUGIN_ID,\n },\n ];\n\n await strapi.admin.services.permission.actionProvider.registerMany(actions);\n\n // Initialize the plugin manager with configuration\n const pluginConfig = strapi.config.get(`plugin::${PLUGIN_ID}`) as {\n openAIApiKey?: string;\n neonConnectionString?: string;\n embeddingModel?: string;\n };\n\n if (pluginConfig?.openAIApiKey && pluginConfig?.neonConnectionString) {\n try {\n await pluginManager.initialize({\n openAIApiKey: pluginConfig.openAIApiKey,\n neonConnectionString: pluginConfig.neonConnectionString,\n embeddingModel: pluginConfig.embeddingModel as any,\n });\n\n // Store plugin manager on strapi for MCP tools to access\n (strapi as any).contentEmbeddingsManager = pluginManager;\n\n strapi.log.info(`[${PLUGIN_ID}] Plugin initialized successfully`);\n } catch (error) {\n strapi.log.error(`[${PLUGIN_ID}] Failed to initialize:`, error);\n }\n } else {\n strapi.log.warn(\n `[${PLUGIN_ID}] Missing configuration. Set openAIApiKey and neonConnectionString in plugin config.`\n );\n }\n\n // Initialize MCP server\n const plugin = strapi.plugin(PLUGIN_ID) as any;\n plugin.createMcpServer = () => createMcpServer(strapi);\n plugin.sessions = new Map();\n\n // Check if OAuth manager is installed\n const oauthPlugin = strapi.plugin(OAUTH_PLUGIN_ID);\n\n if (oauthPlugin) {\n strapi.log.info(`[${PLUGIN_ID}] OAuth manager detected - OAuth + API token auth enabled`);\n } else {\n // No OAuth manager - use fallback auth\n const fallbackMiddleware = createFallbackAuthMiddleware(strapi);\n strapi.server.use(fallbackMiddleware);\n strapi.log.info(`[${PLUGIN_ID}] Using API token authentication (OAuth manager not installed)`);\n }\n\n strapi.log.info(`[${PLUGIN_ID}] MCP endpoint available at: /api/${PLUGIN_ID}/mcp`);\n};\n\nexport default bootstrap;\n","import type { Core } from \"@strapi/strapi\";\nimport { pluginManager } from \"./plugin-manager\";\n\nconst destroy = async ({ strapi }: { strapi: Core.Strapi }) => {\n // Clean up the plugin manager (close DB connections)\n await pluginManager.destroy();\n console.log(\"Content Embeddings plugin destroyed\");\n};\n\nexport default destroy;\n","import type { Core } from \"@strapi/strapi\";\n\nconst PLUGIN_ID = \"strapi-content-embeddings\";\n\nconst register = ({ strapi }: { strapi: Core.Strapi }) => {\n // Add embedding relation to all content types\n Object.values(strapi.contentTypes).forEach((contentType: any) => {\n // Skip internal content types and the embedding content type itself\n if (\n contentType.uid.startsWith(\"admin::\") ||\n contentType.uid.startsWith(\"strapi::\") ||\n contentType.uid === `plugin::${PLUGIN_ID}.embedding`\n ) {\n return;\n }\n\n // Add morphOne relation to content type\n contentType.attributes.embedding = {\n type: \"relation\",\n relation: \"morphOne\",\n target: `plugin::${PLUGIN_ID}.embedding`,\n morphBy: \"related\",\n private: false,\n configurable: false,\n };\n });\n};\n\nexport default register;\n","import schema from './schema.json';\n\nexport default {\n schema,\n};","import embedding from './embedding';\n\nexport default {\n embedding,\n}","import type { Core } from \"@strapi/strapi\";\n\nconst PLUGIN_ID = \"strapi-content-embeddings\";\n\nconst controller = ({ strapi }: { strapi: Core.Strapi }) => ({\n async createEmbedding(ctx: any) {\n try {\n console.log(\"[createEmbedding] Starting, autoChunk:\", ctx.request.body?.data?.autoChunk);\n\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .createEmbedding(ctx.request.body);\n\n console.log(\"[createEmbedding] Completed, documentId:\", result?.documentId);\n\n ctx.body = result;\n } catch (error: any) {\n console.error(\"[createEmbedding] Error:\", error.message);\n ctx.throw(500, error.message || \"Failed to create embedding\");\n }\n },\n\n async deleteEmbedding(ctx: any) {\n try {\n const { id } = ctx.params;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .deleteEmbedding(id);\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to delete embedding\");\n }\n },\n\n async updateEmbedding(ctx: any) {\n try {\n const { id } = ctx.params;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .updateEmbedding(id, ctx.request.body);\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to update embedding\");\n }\n },\n\n async getEmbeddings(ctx: any) {\n try {\n const { page, pageSize, filters } = ctx.query;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .getEmbeddings({\n page: page ? parseInt(page, 10) : 1,\n pageSize: pageSize ? parseInt(pageSize, 10) : 10,\n filters,\n });\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to get embeddings\");\n }\n },\n\n async getEmbedding(ctx: any) {\n try {\n const { id } = ctx.params;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .getEmbedding(id);\n\n if (!result) {\n ctx.throw(404, \"Embedding not found\");\n }\n\n ctx.body = result;\n } catch (error: any) {\n if (error.status === 404) {\n ctx.throw(404, error.message);\n }\n ctx.throw(500, error.message || \"Failed to get embedding\");\n }\n },\n\n async queryEmbeddings(ctx: any) {\n try {\n const { query } = ctx.query;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .queryEmbeddings(query);\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to query embeddings\");\n }\n },\n\n /**\n * Get all chunks related to a document\n * GET /api/strapi-content-embeddings/embeddings/related-chunks/:id\n */\n async getRelatedChunks(ctx: any) {\n try {\n const { id } = ctx.params;\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"embeddings\")\n .findRelatedChunks(id);\n\n console.log(`[getRelatedChunks] Found ${result.length} chunks for document ${id}`);\n\n ctx.body = {\n data: result,\n count: result.length,\n };\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to get related chunks\");\n }\n },\n\n /**\n * Sync embeddings from Neon DB to Strapi DB\n * GET /api/strapi-content-embeddings/sync\n *\n * Query params:\n * - removeOrphans: boolean (default: false) - Remove Strapi entries that don't exist in Neon\n * - dryRun: boolean (default: false) - Preview changes without applying them\n */\n async syncFromNeon(ctx: any) {\n try {\n const { removeOrphans, dryRun } = ctx.query;\n\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"sync\")\n .syncFromNeon({\n removeOrphans: removeOrphans === \"true\",\n dryRun: dryRun === \"true\",\n });\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to sync embeddings\");\n }\n },\n\n /**\n * Get sync status - compare Neon and Strapi without making changes\n * GET /api/strapi-content-embeddings/sync/status\n */\n async getSyncStatus(ctx: any) {\n try {\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"sync\")\n .getSyncStatus();\n\n ctx.body = result;\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to get sync status\");\n }\n },\n\n /**\n * Debug endpoint to inspect Neon DB contents\n * GET /api/strapi-content-embeddings/debug/neon\n */\n async debugNeon(ctx: any) {\n try {\n const { pluginManager } = require(\"../plugin-manager\");\n const result = await pluginManager.debugNeonEmbeddings();\n\n ctx.body = {\n count: result.length,\n embeddings: result,\n };\n } catch (error: any) {\n ctx.throw(500, error.message || \"Failed to debug Neon\");\n }\n },\n\n /**\n * Recreate all embeddings in Neon from Strapi data\n * POST /api/strapi-content-embeddings/recreate\n *\n * Use this when embeddings were created with incorrect metadata format\n * WARNING: This will delete ALL existing Neon embeddings and recreate them\n */\n async recreateEmbeddings(ctx: any) {\n try {\n console.log(\"[recreateEmbeddings] Starting recreation of all embeddings...\");\n\n const result = await strapi\n .plugin(PLUGIN_ID)\n .service(\"sync\")\n .recreateAllEmbeddings();\n\n ctx.body = result;\n } catch (error: any) {\n console.error(\"[recreateEmbeddings] Error:\", error.message);\n ctx.throw(500, error.message || \"Failed to recreate embeddings\");\n }\n },\n});\n\nexport default controller;\n","/**\n * MCP Controller for Content Embeddings\n *\n * Handles MCP (Model Context Protocol) requests with session management.\n */\n\nimport type { Core } from '@strapi/strapi';\nimport { randomUUID } from 'node:crypto';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\n\nconst PLUGIN_ID = 'strapi-content-embeddings';\n\n// Session timeout: 4 hours\nconst SESSION_TIMEOUT_MS = 4 * 60 * 60 * 1000;\n\ninterface McpSession {\n server: any;\n transport: StreamableHTTPServerTransport;\n createdAt: number;\n strapiToken?: string;\n}\n\ninterface ContentEmbeddingsPlugin {\n createMcpServer: () => any;\n sessions: Map<string, McpSession>;\n}\n\n/**\n * Check if a session has expired\n */\nfunction isSessionExpired(session: { createdAt: number }): boolean {\n return Date.now() - session.createdAt > SESSION_TIMEOUT_MS;\n}\n\n/**\n * Clean up expired sessions\n */\nfunction cleanupExpiredSessions(plugin: ContentEmbeddingsPlugin, strapi: Core.Strapi): void {\n let cleaned = 0;\n for (const [sessionId, session] of plugin.sessions.entries()) {\n if (isSessionExpired(session)) {\n try {\n session.server.close();\n } catch {\n // Ignore close errors\n }\n plugin.sessions.delete(sessionId);\n cleaned++;\n }\n }\n if (cleaned > 0) {\n strapi.log.debug(`[${PLUGIN_ID}] Cleaned up ${cleaned} expired MCP sessions`);\n }\n}\n\n/**\n * MCP Controller\n */\nconst mcpController = ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Handle MCP requests (POST, GET, DELETE)\n */\n async handle(ctx: any) {\n const plugin = strapi.plugin(PLUGIN_ID) as unknown as ContentEmbeddingsPlugin;\n\n if (!plugin.createMcpServer) {\n ctx.status = 503;\n ctx.body = {\n error: 'MCP not initialized',\n message: 'The MCP server is not available. Check plugin configuration.',\n };\n return;\n }\n\n // Periodically clean up expired sessions\n if (Math.random() < 0.01) {\n cleanupExpiredSessions(plugin, strapi);\n }\n\n try {\n // Get session ID from header\n const requestedSessionId = ctx.request.headers['mcp-session-id'];\n let session = requestedSessionId ? plugin.sessions.get(requestedSessionId) : null;\n\n // Check if session exists and is not expired\n if (session && isSessionExpired(session)) {\n strapi.log.debug(`[${PLUGIN_ID}] Session expired, removing: ${requestedSessionId}`);\n try {\n session.server.close();\n } catch {\n // Ignore close errors\n }\n plugin.sessions.delete(requestedSessionId);\n session = null;\n }\n\n // If client sent a session ID but session doesn't exist, return error to force re-init\n if (requestedSessionId && !session) {\n ctx.status = 400;\n ctx.body = {\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Session expired or invalid. Please reinitialize the connection.',\n },\n id: null,\n };\n return;\n }\n\n // Create new session if none exists\n if (!session) {\n const sessionId = randomUUID();\n const server = plugin.createMcpServer();\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => sessionId,\n });\n\n await server.connect(transport);\n\n session = {\n server,\n transport,\n createdAt: Date.now(),\n strapiToken: ctx.state.strapiToken,\n };\n plugin.sessions.set(sessionId, session);\n\n strapi.log.debug(\n `[${PLUGIN_ID}] New MCP session created: ${sessionId} (auth: ${ctx.state.authMethod || 'unknown'})`\n );\n }\n\n // Handle the request - wrap in try/catch to handle transport errors\n try {\n await session.transport.handleRequest(ctx.req, ctx.res, ctx.request.body);\n } catch (transportError) {\n strapi.log.warn(`[${PLUGIN_ID}] Transport error, cleaning up session: ${requestedSessionId}`, {\n error: transportError instanceof Error ? transportError.message : String(transportError),\n });\n\n try {\n session.server.close();\n } catch {\n // Ignore close errors\n }\n plugin.sessions.delete(requestedSessionId!);\n\n if (!ctx.res.headersSent) {\n ctx.status = 400;\n ctx.body = {\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Session transport error. Please reinitialize the connection.',\n },\n id: null,\n };\n }\n return;\n }\n\n // Prevent Koa from handling response\n ctx.respond = false;\n } catch (error) {\n strapi.log.error(`[${PLUGIN_ID}] Error handling MCP request`, {\n error: error instanceof Error ? error.message : String(error),\n method: ctx.method,\n path: ctx.path,\n });\n\n if (!ctx.res.headersSent) {\n ctx.status = 500;\n ctx.body = {\n error: 'MCP request failed',\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n },\n});\n\nexport default mcpController;\n","import controller from './controller';\nimport mcp from './mcp';\n\nexport default {\n controller,\n mcp,\n};\n","export default {};\n","export default {};\n","export default [\n {\n method: 'GET',\n path: '/embeddings-query',\n handler: 'controller.queryEmbeddings',\n },\n // Sync routes - for cron jobs or manual triggering\n // Use API token for authentication\n {\n method: 'GET',\n path: '/sync',\n handler: 'controller.syncFromNeon',\n config: {\n description: 'Sync embeddings from Neon DB to Strapi. Query params: removeOrphans=true, dryRun=true',\n },\n },\n {\n method: 'POST',\n path: '/sync',\n handler: 'controller.syncFromNeon',\n config: {\n description: 'Sync embeddings from Neon DB to Strapi. Query params: removeOrphans=true, dryRun=true',\n },\n },\n {\n method: 'GET',\n path: '/sync/status',\n handler: 'controller.getSyncStatus',\n config: {\n description: 'Get sync status between Neon and Strapi without making changes',\n },\n },\n // MCP routes - auth handled by middleware\n {\n method: 'POST',\n path: '/mcp',\n handler: 'mcp.handle',\n config: {\n auth: false,\n policies: [],\n },\n },\n {\n method: 'GET',\n path: '/mcp',\n handler: 'mcp.handle',\n config: {\n auth: false,\n policies: [],\n },\n },\n {\n method: 'DELETE',\n path: '/mcp',\n handler: 'mcp.handle',\n config: {\n auth: false,\n policies: [],\n },\n },\n]","export default [\n{\n method: 'POST',\n path: '/embeddings/create-embedding',\n handler: 'controller.createEmbedding',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.create'] }\n },\n ]\n },\n},\n{\n method: 'DELETE',\n path: '/embeddings/delete-embedding/:id',\n handler: 'controller.deleteEmbedding',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.delete'] }\n },\n ]\n },\n},\n{\n method: 'PUT',\n path: '/embeddings/update-embedding/:id',\n handler: 'controller.updateEmbedding',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.update'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/embeddings/embeddings-query',\n handler: 'controller.queryEmbeddings',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.chat'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/embeddings/find/:id',\n handler: 'controller.getEmbedding',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.read'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/embeddings/find',\n handler: 'controller.getEmbeddings',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.read'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/embeddings/related-chunks/:id',\n handler: 'controller.getRelatedChunks',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.read'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/debug/neon',\n handler: 'controller.debugNeon',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.read'] }\n },\n ]\n },\n},\n{\n method: 'POST',\n path: '/recreate',\n handler: 'controller.recreateEmbeddings',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.update'] }\n },\n ]\n },\n},\n{\n method: 'GET',\n path: '/sync/status',\n handler: 'controller.getSyncStatus',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.read'] }\n },\n ]\n },\n},\n{\n method: 'POST',\n path: '/sync',\n handler: 'controller.syncFromNeon',\n config: {\n policies: [\n {\n name: 'admin::hasPermissions',\n config: { actions: ['plugin::strapi-content-embeddings.update'] }\n },\n ]\n },\n},]","\"use strict\";\n\nimport contentApi from './content-api';\nimport admin from './admin';\n\nexport default {\n \"content-api\": {\n type: \"content-api\",\n routes: [...contentApi],\n },\n admin: {\n type: \"admin\",\n routes: [...admin],\n },\n}; \n","/**\n * Text chunking utilities for splitting large content into embeddable chunks\n */\n\nexport interface ChunkOptions {\n /** Maximum characters per chunk (default: 4000, roughly ~1000 tokens) */\n chunkSize?: number;\n /** Number of characters to overlap between chunks (default: 200) */\n chunkOverlap?: number;\n /** Separator to use when splitting (default: splits on paragraphs, sentences, then words) */\n separators?: string[];\n}\n\nexport interface TextChunk {\n /** The chunk text content */\n text: string;\n /** Zero-based chunk index */\n chunkIndex: number;\n /** Total number of chunks */\n totalChunks: number;\n /** Character offset in original text */\n startOffset: number;\n /** Character end offset in original text */\n endOffset: number;\n}\n\nconst DEFAULT_SEPARATORS = [\n \"\\n\\n\", // Paragraphs\n \"\\n\", // Lines\n \". \", // Sentences\n \"! \", // Exclamations\n \"? \", // Questions\n \"; \", // Semicolons\n \", \", // Commas\n \" \", // Words\n \"\", // Characters (last resort)\n];\n\n/**\n * Estimate token count from character count\n * OpenAI models average ~4 characters per token for English text\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Check if content exceeds the recommended chunk size\n */\nexport function needsChunking(content: string, maxChars: number = 4000): boolean {\n return content.length > maxChars;\n}\n\n/**\n * Split text by a separator, keeping the separator at the end of each piece\n */\nfunction splitWithSeparator(text: string, separator: string): string[] {\n if (separator === \"\") {\n return text.split(\"\");\n }\n\n const parts = text.split(separator);\n const result: string[] = [];\n\n for (let i = 0; i < parts.length; i++) {\n if (i < parts.length - 1) {\n result.push(parts[i] + separator);\n } else if (parts[i]) {\n result.push(parts[i]);\n }\n }\n\n return result;\n}\n\n/**\n * Recursively split text into chunks that fit within the size limit\n */\nfunction splitText(\n text: string,\n chunkSize: number,\n separators: string[]\n): string[] {\n if (text.length <= chunkSize) {\n return [text];\n }\n\n // Find the best separator to use\n let bestSeparator = separators[separators.length - 1]; // Default to last (smallest)\n\n for (const sep of separators) {\n if (text.includes(sep)) {\n bestSeparator = sep;\n break;\n }\n }\n\n const splits = splitWithSeparator(text, bestSeparator);\n const chunks: string[] = [];\n let currentChunk = \"\";\n\n for (const split of splits) {\n if ((currentChunk + split).length <= chunkSize) {\n currentChunk += split;\n } else {\n if (currentChunk) {\n chunks.push(currentChunk);\n }\n\n // If single split is too large, recursively split it\n if (split.length > chunkSize) {\n const remainingSeparators = separators.slice(separators.indexOf(bestSeparator) + 1);\n if (remainingSeparators.length > 0) {\n chunks.push(...splitText(split, chunkSize, remainingSeparators));\n } else {\n // Force split at chunkSize if no separators left\n for (let i = 0; i < split.length; i += chunkSize) {\n chunks.push(split.slice(i, i + chunkSize));\n }\n }\n currentChunk = \"\";\n } else {\n currentChunk = split;\n }\n }\n }\n\n if (currentChunk) {\n chunks.push(currentChunk);\n }\n\n return chunks;\n}\n\n/**\n * Add overlap between chunks for better context preservation\n */\nfunction addOverlap(chunks: string[], overlap: number): string[] {\n if (overlap <= 0 || chunks.length <= 1) {\n return chunks;\n }\n\n const result: string[] = [];\n\n for (let i = 0; i < chunks.length; i++) {\n let chunk = chunks[i];\n\n // Add overlap from previous chunk\n if (i > 0) {\n const prevChunk = chunks[i - 1];\n const overlapText = prevChunk.slice(-overlap);\n chunk = overlapText + chunk;\n }\n\n result.push(chunk);\n }\n\n return result;\n}\n\n/**\n * Split content into chunks suitable for embedding\n *\n * @param content - The text content to split\n * @param options - Chunking options\n * @returns Array of TextChunk objects\n */\nexport function chunkContent(\n content: string,\n options: ChunkOptions = {}\n): TextChunk[] {\n const {\n chunkSize = 4000,\n chunkOverlap = 200,\n separators = DEFAULT_SEPARATORS,\n } = options;\n\n // Clean the content\n const cleanContent = content.trim();\n\n if (!cleanContent) {\n return [];\n }\n\n // If content fits in one chunk, return as single chunk\n if (cleanContent.length <= chunkSize) {\n return [{\n text: cleanContent,\n chunkIndex: 0,\n totalChunks: 1,\n startOffset: 0,\n endOffset: cleanContent.length,\n }];\n }\n\n // Split into initial chunks\n const rawChunks = splitText(cleanContent, chunkSize - chunkOverlap, separators);\n\n // Add overlap\n const chunksWithOverlap = addOverlap(rawChunks, chunkOverlap);\n\n // Calculate offsets and build result\n const result: TextChunk[] = [];\n let currentOffset = 0;\n\n for (let i = 0; i < chunksWithOverlap.length; i++) {\n const text = chunksWithOverlap[i].trim();\n\n if (text) {\n result.push({\n text,\n chunkIndex: i,\n totalChunks: chunksWithOverlap.length,\n startOffset: currentOffset,\n endOffset: currentOffset + rawChunks[i].length,\n });\n }\n\n currentOffset += rawChunks[i].length;\n }\n\n // Update totalChunks after filtering empty chunks\n const totalChunks = result.length;\n result.forEach((chunk, idx) => {\n chunk.chunkIndex = idx;\n chunk.totalChunks = totalChunks;\n });\n\n return result;\n}\n\n/**\n * Format chunk title with index information\n */\nexport function formatChunkTitle(\n baseTitle: string,\n chunkIndex: number,\n totalChunks: number\n): string {\n if (totalChunks === 1) {\n return baseTitle;\n }\n return `${baseTitle} [Part ${chunkIndex + 1}/${totalChunks}]`;\n}\n","/**\n * Content preprocessing utilities for cleaning text before embedding\n * Handles HTML stripping, markdown conversion, and text normalization\n */\n\nimport { convert } from \"html-to-text\";\nimport removeMarkdown from \"remove-markdown\";\n\nexport interface PreprocessOptions {\n /** Strip HTML tags from content (default: true) */\n stripHtml?: boolean;\n /** Strip markdown syntax from content (default: true) */\n stripMarkdown?: boolean;\n /** Normalize whitespace (collapse multiple spaces/newlines) (default: true) */\n normalizeWhitespace?: boolean;\n}\n\nconst DEFAULT_OPTIONS: PreprocessOptions = {\n stripHtml: true,\n stripMarkdown: true,\n normalizeWhitespace: true,\n};\n\n/**\n * Detect if content likely contains HTML\n */\nfunction containsHtml(content: string): boolean {\n // Look for common HTML patterns\n return /<[a-z][\\s\\S]*>/i.test(content);\n}\n\n/**\n * Detect if content likely contains Markdown\n */\nfunction containsMarkdown(content: string): boolean {\n // Look for common markdown patterns\n const markdownPatterns = [\n /^#{1,6}\\s/m, // Headers: # ## ### etc\n /\\*\\*[^*]+\\*\\*/, // Bold: **text**\n /\\*[^*]+\\*/, // Italic: *text*\n /__[^_]+__/, // Bold: __text__\n /_[^_]+_/, // Italic: _text_\n /\\[.+\\]\\(.+\\)/, // Links: [text](url)\n /^[-*+]\\s/m, // Unordered lists: - * +\n /^\\d+\\.\\s/m, // Ordered lists: 1. 2. etc\n /^>\\s/m, // Blockquotes: >\n /`[^`]+`/, // Inline code: `code`\n /```[\\s\\S]*?```/, // Code blocks: ```code```\n /^\\|.+\\|$/m, // Tables: |col|col|\n ];\n\n return markdownPatterns.some(pattern => pattern.test(content));\n}\n\n/**\n * Strip HTML tags and convert to plain text\n */\nfunction stripHtml(content: string): string {\n if (!containsHtml(content)) {\n return content;\n }\n\n return convert(content, {\n wordwrap: false,\n preserveNewlines: true,\n selectors: [\n // Convert headings to plain text with colon\n { selector: \"h1\", options: { uppercase: false, trailingLineBreaks: 1 } },\n { selector: \"h2\", options: { uppercase: false, trailingLineBreaks: 1 } },\n { selector: \"h3\", options: { uppercase: false, trailingLineBreaks: 1 } },\n { selector: \"h4\", options: { uppercase: false, trailingLineBreaks: 1 } },\n { selector: \"h5\", options: { uppercase: false, trailingLineBreaks: 1 } },\n { selector: \"h6\", options: { uppercase: false, trailingLineBreaks: 1 } },\n // Remove images but keep alt text\n { selector: \"img\", format: \"skip\" },\n // Remove scripts and styles completely\n { selector: \"script\", format: \"skip\" },\n { selector: \"style\", format: \"skip\" },\n // Keep link text, remove URLs\n { selector: \"a\", options: { ignoreHref: true } },\n ],\n });\n}\n\n/**\n * Strip markdown syntax and convert to plain text\n */\nfunction stripMarkdownSyntax(content: string): string {\n if (!containsMarkdown(content)) {\n return content;\n }\n\n // Use remove-markdown library\n let result = removeMarkdown(content, {\n stripListLeaders: true,\n listUnicodeChar: \"\",\n gfm: true,\n useImgAltText: true,\n });\n\n // Additional cleanup for edge cases the library might miss\n result = result\n // Remove any remaining code block markers\n .replace(/```[\\s\\S]*?```/g, (match) => {\n // Extract code content without markers\n return match.replace(/```\\w*\\n?/g, \"\").replace(/```/g, \"\");\n })\n // Remove inline code backticks\n .replace(/`([^`]+)`/g, \"$1\")\n // Clean up horizontal rules\n .replace(/^[-*_]{3,}$/gm, \"\");\n\n return result;\n}\n\n/**\n * Normalize whitespace in content\n */\nfunction normalizeWhitespace(content: string): string {\n return content\n // Replace multiple newlines with double newline (preserve paragraphs)\n .replace(/\\n{3,}/g, \"\\n\\n\")\n // Replace multiple spaces with single space\n .replace(/[ \\t]+/g, \" \")\n // Trim each line\n .split(\"\\n\")\n .map(line => line.trim())\n .join(\"\\n\")\n // Final trim\n .trim();\n}\n\n/**\n * Preprocess content for embedding\n * Strips HTML, markdown, and normalizes whitespace\n *\n * @param content - The raw content to preprocess\n * @param options - Preprocessing options\n * @returns Cleaned plain text ready for embedding\n */\nexport function preprocessContent(\n content: string,\n options: PreprocessOptions = {}\n): string {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n if (!content || typeof content !== \"string\") {\n return \"\";\n }\n\n let result = content;\n\n // Step 1: Strip HTML if present\n if (opts.stripHtml) {\n result = stripHtml(result);\n }\n\n // Step 2: Strip Markdown if present\n if (opts.stripMarkdown) {\n result = stripMarkdownSyntax(result);\n }\n\n // Step 3: Normalize whitespace\n if (opts.normalizeWhitespace) {\n result = normalizeWhitespace(result);\n }\n\n return result;\n}\n\n/**\n * Check if content needs preprocessing\n * Returns true if content contains HTML or Markdown\n */\nexport function needsPreprocessing(content: string): boolean {\n return containsHtml(content) || containsMarkdown(content);\n}\n","import type { Core } from \"@strapi/strapi\";\nimport { pluginManager } from \"../plugin-manager\";\nimport {\n chunkContent,\n formatChunkTitle,\n needsChunking,\n estimateTokens,\n} from \"../utils/chunking\";\nimport { preprocessContent } from \"../utils/preprocessing\";\nimport type { PluginConfigSchema } from \"../config\";\n\nconst PLUGIN_ID = \"strapi-content-embeddings\";\nconst CONTENT_TYPE_UID = `plugin::${PLUGIN_ID}.embedding` as const;\n\nexport interface CreateEmbeddingData {\n data: {\n title: string;\n content: string;\n collectionType?: string;\n fieldName?: string;\n metadata?: Record<string, any>;\n related?: {\n __type: string;\n id: number;\n };\n /** Enable chunking for large content (overrides config.autoChunk) */\n autoChunk?: boolean;\n };\n}\n\nexport interface UpdateEmbeddingData {\n data: {\n title?: string;\n content?: string;\n metadata?: Record<string, any>;\n /** Enable chunking for large content on update (overrides config.autoChunk) */\n autoChunk?: boolean;\n };\n}\n\nexport interface ChunkedEmbeddingResult {\n /** The parent/first embedding entity */\n entity: any;\n /** All chunk entities created */\n chunks: any[];\n /** Total number of chunks created */\n totalChunks: number;\n /** Whether content was chunked */\n wasChunked: boolean;\n}\n\nconst embeddings = ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Get plugin config with defaults\n */\n getConfig(): PluginConfigSchema {\n const config = strapi.config.get(\"plugin::strapi-content-embeddings\") as PluginConfigSchema || {};\n return {\n chunkSize: config.chunkSize || 4000,\n chunkOverlap: config.chunkOverlap || 200,\n autoChunk: config.autoChunk || false,\n preprocessContent: config.preprocessContent !== false, // Default true\n ...config,\n };\n },\n\n /**\n * Create a single embedding (no chunking)\n */\n async createEmbedding(data: CreateEmbeddingData) {\n const { title, content: rawContent, collectionType, fieldName, metadata, related, autoChunk } = data.data;\n const config = this.getConfig();\n\n // Preprocess content (strip HTML/Markdown) if enabled\n const content = config.preprocessContent\n ? preprocessContent(rawContent)\n : rawContent;\n\n // Check if chunking should be applied\n const shouldChunk = autoChunk ?? config.autoChunk;\n const chunkSize = config.chunkSize || 4000;\n\n if (shouldChunk && needsChunking(content, chunkSize)) {\n // Delegate to chunked embedding creation\n const result = await this.createChunkedEmbedding(data);\n // Return the first chunk as the primary entity for backwards compatibility\n return result.entity;\n }\n\n // Build entity data - only include related if it has valid __type and id\n const entityData: Record<string, any> = {\n title,\n content,\n collectionType: collectionType || \"standalone\",\n fieldName: fieldName || \"content\",\n metadata: metadata || null,\n };\n\n // Only add related if both __type and id are provided\n if (related && related.__type && related.id) {\n entityData.related = related;\n }\n\n // First create the entity in Strapi DB\n const entity = await strapi.documents(CONTENT_TYPE_UID).create({\n data: entityData,\n });\n\n if (!pluginManager.isInitialized()) {\n console.warn(\"Plugin manager not initialized, skipping vector embedding\");\n return entity;\n }\n\n try {\n // Create embedding in vector store and get the vector\n const result = await pluginManager.createEmbedding({\n id: entity.documentId,\n title,\n content,\n collectionType: collectionType || \"standalone\",\n fieldName: fieldName || \"content\",\n });\n\n // Update entity with embedding ID and vector\n const updatedEntity = await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: entity.documentId,\n data: {\n embeddingId: result.embeddingId,\n embedding: result.embedding,\n } as any,\n });\n\n return updatedEntity;\n } catch (error) {\n console.error(\"Failed to create embedding in vector store:\", error);\n // Return the entity even if embedding failed\n return entity;\n }\n },\n\n /**\n * Create embeddings with automatic chunking for large content\n * Creates multiple embedding entities, one per chunk\n */\n async createChunkedEmbedding(data: CreateEmbeddingData): Promise<ChunkedEmbeddingResult> {\n const { title, content: rawContent, collectionType, fieldName, metadata, related } = data.data;\n const config = this.getConfig();\n\n // Preprocess content (strip HTML/Markdown) if enabled\n const content = config.preprocessContent\n ? preprocessContent(rawContent)\n : rawContent;\n\n const chunkSize = config.chunkSize || 4000;\n const chunkOverlap = config.chunkOverlap || 200;\n\n // Split content into chunks\n const chunks = chunkContent(content, { chunkSize, chunkOverlap });\n\n if (chunks.length === 0) {\n throw new Error(\"Content is empty or could not be chunked\");\n }\n\n // If only one chunk, create normally\n if (chunks.length === 1) {\n const entity = await this.createEmbedding({\n data: {\n ...data.data,\n autoChunk: false, // Prevent recursive chunking\n },\n });\n return {\n entity,\n chunks: [entity],\n totalChunks: 1,\n wasChunked: false,\n };\n }\n\n console.log(`[createChunkedEmbedding] Chunking content into ${chunks.length} parts (chunkSize: ${chunkSize}, overlap: ${chunkOverlap})`);\n\n const createdChunks: any[] = [];\n let parentDocumentId: string | null = null;\n\n for (const chunk of chunks) {\n console.log(`[createChunkedEmbedding] Processing chunk ${chunk.chunkIndex + 1}/${chunks.length}`);\n const chunkTitle = formatChunkTitle(title, chunk.chunkIndex, chunk.totalChunks);\n\n // Build chunk metadata\n const chunkMetadata = {\n ...metadata,\n isChunk: true,\n chunkIndex: chunk.chunkIndex,\n totalChunks: chunk.totalChunks,\n startOffset: chunk.startOffset,\n endOffset: chunk.endOffset,\n originalTitle: title,\n parentDocumentId: parentDocumentId,\n estimatedTokens: estimateTokens(chunk.text),\n };\n\n // Build entity data\n const entityData: Record<string, any> = {\n title: chunkTitle,\n content: chunk.text,\n collectionType: collectionType || \"standalone\",\n fieldName: fieldName || \"content\",\n metadata: chunkMetadata,\n };\n\n // Only add related to first chunk\n if (chunk.chunkIndex === 0 && related && related.__type && related.id) {\n entityData.related = related;\n }\n\n // Create entity in Strapi DB\n console.log(`[chunk ${chunk.chunkIndex + 1}] Creating entity in DB...`);\n const entity = await strapi.documents(CONTENT_TYPE_UID).create({\n data: entityData,\n });\n console.log(`[chunk ${chunk.chunkIndex + 1}] Entity created: ${entity.documentId}`);\n\n // Store first chunk's documentId as parent reference\n if (chunk.chunkIndex === 0) {\n parentDocumentId = entity.documentId;\n } else {\n // Update metadata with parent reference\n console.log(`[chunk ${chunk.chunkIndex + 1}] Updating metadata with parent ref...`);\n await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: entity.documentId,\n data: {\n metadata: {\n ...chunkMetadata,\n parentDocumentId,\n },\n } as any,\n });\n console.log(`[chunk ${chunk.chunkIndex + 1}] Metadata updated`);\n }\n\n // Create vector embedding if plugin is initialized\n if (pluginManager.isInitialized()) {\n try {\n console.log(`[chunk ${chunk.chunkIndex + 1}] Creating OpenAI embedding...`);\n const result = await pluginManager.createEmbedding({\n id: entity.documentId,\n title: chunkTitle,\n content: chunk.text,\n collectionType: collectionType || \"standalone\",\n fieldName: fieldName || \"content\",\n });\n console.log(`[chunk ${chunk.chunkIndex + 1}] OpenAI embedding created`);\n\n // Update entity with embedding ID and vector\n console.log(`[chunk ${chunk.chunkIndex + 1}] Saving embedding to DB...`);\n const updatedEntity = await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: entity.documentId,\n data: {\n embeddingId: result.embeddingId,\n embedding: result.embedding,\n } as any,\n });\n console.log(`[chunk ${chunk.chunkIndex + 1}] Chunk complete`);\n\n createdChunks.push(updatedEntity);\n } catch (error: any) {\n console.error(`[chunk ${chunk.chunkIndex + 1}] FAILED:`, error.message || error);\n createdChunks.push(entity);\n }\n } else {\n createdChunks.push(entity);\n }\n }\n\n console.log(`[createChunkedEmbedding] Completed, created ${createdChunks.length} chunks, first documentId: ${createdChunks[0]?.documentId}`);\n\n return {\n entity: createdChunks[0],\n chunks: createdChunks,\n totalChunks: createdChunks.length,\n wasChunked: true,\n };\n },\n\n async deleteEmbedding(id: number | string) {\n const currentEntry = await strapi.documents(CONTENT_TYPE_UID).findOne({\n documentId: String(id),\n });\n\n if (!currentEntry) {\n throw new Error(`Embedding with id ${id} not found`);\n }\n\n // Delete from vector store if plugin is initialized\n if (pluginManager.isInitialized()) {\n try {\n await pluginManager.deleteEmbedding(String(id));\n } catch (error) {\n console.error(\"Failed to delete from vector store:\", error);\n }\n }\n\n // Delete from Strapi DB\n const deletedEntry = await strapi.documents(CONTENT_TYPE_UID).delete({\n documentId: String(id),\n });\n\n return deletedEntry;\n },\n\n /**\n * Find all chunks related to a parent document\n * Returns chunks including the parent itself\n */\n async findRelatedChunks(documentId: string): Promise<any[]> {\n const entry = await strapi.documents(CONTENT_TYPE_UID).findOne({\n documentId,\n });\n\n if (!entry) {\n return [];\n }\n\n const metadata = entry.metadata as Record<string, any> | null;\n\n // Determine the parent document ID\n // If this entry has a parentDocumentId, use that; otherwise this is the parent\n const parentId = metadata?.parentDocumentId || documentId;\n const isChunked = metadata?.isChunk === true;\n\n // If not a chunked document, return just this entry\n if (!isChunked && !metadata?.parentDocumentId) {\n // Check if this document has children (is a parent)\n const children = await strapi.documents(CONTENT_TYPE_UID).findMany({\n filters: {\n metadata: {\n $containsi: `\"parentDocumentId\":\"${documentId}\"`,\n },\n },\n limit: -1, // No limit - get all\n });\n\n console.log(`[findRelatedChunks] Found ${children.length} children for parent ${documentId}`);\n\n if (children.length === 0) {\n return [entry];\n }\n // This is a parent with children\n return [entry, ...children];\n }\n\n // Find all chunks with the same parentDocumentId (including the parent)\n const allChunks = await strapi.documents(CONTENT_TYPE_UID).findMany({\n filters: {\n $or: [\n { documentId: parentId },\n {\n metadata: {\n $containsi: `\"parentDocumentId\":\"${parentId}\"`,\n },\n },\n ],\n },\n limit: -1, // No limit - get all\n });\n\n console.log(`[findRelatedChunks] Found ${allChunks.length} total chunks for parent ${parentId}`);\n\n // Sort by chunk index\n return allChunks.sort((a, b) => {\n const aIndex = (a.metadata as any)?.chunkIndex ?? 0;\n const bIndex = (b.metadata as any)?.chunkIndex ?? 0;\n return aIndex - bIndex;\n });\n },\n\n /**\n * Delete all chunks related to a parent document\n */\n async deleteRelatedChunks(documentId: string): Promise<number> {\n const chunks = await this.findRelatedChunks(documentId);\n\n for (const chunk of chunks) {\n // Delete from vector store\n if (pluginManager.isInitialized()) {\n try {\n await pluginManager.deleteEmbedding(chunk.documentId);\n } catch (error) {\n console.error(`Failed to delete chunk ${chunk.documentId} from vector store:`, error);\n }\n }\n\n // Delete from Strapi DB\n await strapi.documents(CONTENT_TYPE_UID).delete({\n documentId: chunk.documentId,\n });\n }\n\n return chunks.length;\n },\n\n /**\n * Update a single chunk's content and embedding\n * Updates only the specified chunk without affecting other chunks in the group\n */\n async updateChunkedEmbedding(\n id: string,\n data: UpdateEmbeddingData\n ): Promise<ChunkedEmbeddingResult> {\n const { title, content, metadata } = data.data;\n const config = this.getConfig();\n\n // Find the current entry\n const currentEntry = await strapi.documents(CONTENT_TYPE_UID).findOne({\n documentId: id,\n });\n\n if (!currentEntry) {\n throw new Error(`Embedding with id ${id} not found`);\n }\n\n const currentMetadata = currentEntry.metadata as Record<string, any> | null;\n const contentChanged = content !== undefined && content !== currentEntry.content;\n\n console.log(`[updateChunkedEmbedding] Updating single chunk ${id}, contentChanged: ${contentChanged}`);\n\n // Build update data for Strapi\n const updateData: Record<string, any> = {};\n\n if (title !== undefined) {\n // Update title but preserve [Part X/Y] suffix if present\n const currentTitle = currentEntry.title || \"\";\n const partMatch = currentTitle.match(/\\s*\\[Part \\d+\\/\\d+\\]$/);\n updateData.title = partMatch ? `${title}${partMatch[0]}` : title;\n }\n\n if (content !== undefined) {\n // Content should already be preprocessed by updateEmbedding if needed\n updateData.content = content;\n }\n\n if (metadata !== undefined) {\n // Merge with existing metadata, preserving chunk-specific fields\n updateData.metadata = {\n ...currentMetadata,\n ...metadata,\n };\n\n // Update estimatedTokens if content changed\n if (contentChanged) {\n updateData.metadata.estimatedTokens = estimateTokens(updateData.content || currentEntry.content);\n }\n }\n\n // Update Strapi entry\n const updatedEntity = await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: id,\n data: updateData,\n });\n\n // Update embedding in Neon if content or title changed\n if (pluginManager.isInitialized() && (contentChanged || title !== undefined)) {\n try {\n console.log(`[updateChunkedEmbedding] Updating embedding in Neon for chunk ${id}`);\n\n // Delete old embedding from vector store\n await pluginManager.deleteEmbedding(id);\n\n // Create new embedding with updated content\n const newContent = updateData.content || currentEntry.content;\n const result = await pluginManager.createEmbedding({\n id,\n title: updatedEntity.title || currentEntry.title,\n content: newContent,\n collectionType: currentEntry.collectionType || \"standalone\",\n fieldName: currentEntry.fieldName || \"content\",\n });\n\n // Update Strapi with new embedding data\n await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: id,\n data: {\n embeddingId: result.embeddingId,\n embedding: result.embedding,\n } as any,\n });\n\n console.log(`[updateChunkedEmbedding] Successfully updated embedding for chunk ${id}`);\n } catch (error) {\n console.error(`Failed to update vector store for ${id}:`, error);\n }\n }\n\n // Return this chunk and all related chunks\n const allChunks = await this.findRelatedChunks(id);\n return {\n entity: updatedEntity,\n chunks: allChunks,\n totalChunks: allChunks.length,\n wasChunked: allChunks.length > 1,\n };\n },\n\n async updateEmbedding(id: string, data: UpdateEmbeddingData) {\n const { title, content: rawContent, metadata, autoChunk } = data.data;\n const config = this.getConfig();\n\n // Preprocess content if provided and preprocessing is enabled\n const content = rawContent !== undefined && config.preprocessContent\n ? preprocessContent(rawContent)\n : rawContent;\n\n const currentEntry = await strapi.documents(CONTENT_TYPE_UID).findOne({\n documentId: id,\n });\n\n if (!currentEntry) {\n throw new Error(`Embedding with id ${id} not found`);\n }\n\n const currentMetadata = currentEntry.metadata as Record<string, any> | null;\n const isCurrentlyChunked = currentMetadata?.isChunk === true;\n const hasRelatedChunks = currentMetadata?.parentDocumentId || isCurrentlyChunked;\n\n // Determine if we need chunked update\n const shouldChunk = autoChunk ?? config.autoChunk;\n const chunkSize = config.chunkSize || 4000;\n const newContent = content ?? currentEntry.content;\n const contentNeedsChunking = shouldChunk && needsChunking(newContent, chunkSize);\n const contentChanged = content !== undefined && content !== currentEntry.content;\n\n // Delegate to chunked update if:\n // 1. The entry is currently part of a chunk group, OR\n // 2. The new content needs chunking\n if (hasRelatedChunks || contentNeedsChunking) {\n // Pass preprocessed content to avoid double-preprocessing\n const result = await this.updateChunkedEmbedding(id, {\n data: { ...data.data, content },\n });\n return result.entity;\n }\n\n // Simple update for non-chunked content\n const updateData: Record<string, any> = {};\n if (title !== undefined) updateData.title = title;\n if (content !== undefined) updateData.content = content;\n if (metadata !== undefined) updateData.metadata = metadata;\n\n // Update entity in Strapi DB\n let updatedEntity = await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: id,\n data: updateData,\n });\n\n // If content changed and plugin is initialized, update the vector\n if (contentChanged && pluginManager.isInitialized()) {\n try {\n // Delete old embedding from vector store\n await pluginManager.deleteEmbedding(id);\n\n // Create new embedding with updated content (already preprocessed)\n const result = await pluginManager.createEmbedding({\n id,\n title: title || currentEntry.title,\n content: content,\n collectionType: currentEntry.collectionType || \"standalone\",\n fieldName: currentEntry.fieldName || \"content\",\n });\n\n // Update entity with new embedding data\n updatedEntity = await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: id,\n data: {\n embeddingId: result.embeddingId,\n embedding: result.embedding,\n } as any,\n });\n } catch (error) {\n console.error(\"Failed to update embedding in vector store:\", error);\n }\n }\n\n return updatedEntity;\n },\n\n async queryEmbeddings(query: string) {\n if (!query || query.trim() === \"\") {\n return { error: \"Please provide a query\" };\n }\n\n if (!pluginManager.isInitialized()) {\n return { error: \"Plugin not initialized. Check your configuration.\" };\n }\n\n try {\n const response = await pluginManager.queryEmbedding(query);\n return response;\n } catch (error) {\n console.error(\"Query failed:\", error);\n return { error: \"Failed to query embeddings\" };\n }\n },\n\n async getEmbedding(id: number | string) {\n return await strapi.documents(CONTENT_TYPE_UID).findOne({\n documentId: String(id),\n });\n },\n\n async getEmbeddings(params?: {\n page?: number;\n pageSize?: number;\n filters?: any;\n }) {\n const page = params?.page || 1;\n const pageSize = params?.pageSize || 10;\n const start = (page - 1) * pageSize;\n\n const [data, totalCount] = await Promise.all([\n strapi.documents(CONTENT_TYPE_UID).findMany({\n limit: pageSize,\n start,\n filters: params?.filters,\n }),\n strapi.documents(CONTENT_TYPE_UID).count({\n filters: params?.filters,\n }),\n ]);\n\n return {\n data,\n count: data.length,\n totalCount,\n };\n },\n});\n\nexport default embeddings;\n","import type { Core } from \"@strapi/strapi\";\nimport { pluginManager } from \"../plugin-manager\";\n\nconst PLUGIN_ID = \"strapi-content-embeddings\";\nconst CONTENT_TYPE_UID = `plugin::${PLUGIN_ID}.embedding` as const;\n\nexport interface SyncResult {\n success: boolean;\n timestamp: string;\n dryRun: boolean;\n neonCount: number;\n strapiCount: number;\n actions: {\n created: number;\n updated: number;\n orphansRemoved: number;\n };\n details: {\n created: string[];\n updated: string[];\n orphansRemoved: string[];\n };\n errors: string[];\n}\n\ninterface NeonEmbedding {\n id: string;\n strapiId: string;\n title: string;\n content: string;\n collectionType: string;\n fieldName: string;\n}\n\ninterface StrapiEmbedding {\n documentId: string;\n title: string;\n content: string;\n embeddingId: string | null;\n collectionType: string;\n fieldName: string;\n}\n\nexport interface RecreateResult {\n success: boolean;\n timestamp: string;\n deletedFromNeon: number;\n processedFromStrapi: number;\n recreatedInNeon: number;\n errors: string[];\n details: {\n recreated: string[];\n failed: string[];\n };\n}\n\nconst sync = ({ strapi }: { strapi: Core.Strapi }) => ({\n /**\n * Sync embeddings from Neon DB to Strapi DB\n *\n * This performs the following operations:\n * 1. Fetches all embeddings from Neon DB (source of truth)\n * 2. Fetches all embeddings from Strapi DB\n * 3. Creates missing entries in Strapi that exist in Neon\n * 4. Updates Strapi entries where content differs from Neon\n * 5. Optionally removes orphaned Strapi entries (no matching Neon record)\n */\n async syncFromNeon(options?: {\n removeOrphans?: boolean;\n dryRun?: boolean;\n }): Promise<SyncResult> {\n const { removeOrphans = false, dryRun = false } = options || {};\n\n const result: SyncResult = {\n success: false,\n timestamp: new Date().toISOString(),\n dryRun,\n neonCount: 0,\n strapiCount: 0,\n actions: {\n created: 0,\n updated: 0,\n orphansRemoved: 0,\n },\n details: {\n created: [],\n updated: [],\n orphansRemoved: [],\n },\n errors: [],\n };\n\n // Check if plugin is initialized\n if (!pluginManager.isInitialized()) {\n result.errors.push(\n \"Plugin manager not initialized. Check your Neon and OpenAI configuration.\"\n );\n return result;\n }\n\n try {\n // Step 1: Get all embeddings from Neon DB\n const neonEmbeddings = await pluginManager.getAllNeonEmbeddings();\n result.neonCount = neonEmbeddings.length;\n\n // Step 2: Get all embeddings from Strapi DB\n const strapiEmbeddings = (await strapi\n .documents(CONTENT_TYPE_UID)\n .findMany({\n limit: 10000, // High limit to get all\n })) as unknown as StrapiEmbedding[];\n result.strapiCount = strapiEmbeddings.length;\n\n // Create lookup maps\n const neonBystrapiId = new Map<string, NeonEmbedding>();\n for (const neon of neonEmbeddings) {\n if (neon.strapiId) {\n neonBystrapiId.set(neon.strapiId, neon);\n }\n }\n\n const strapiByDocumentId = new Map<string, StrapiEmbedding>();\n for (const strapi of strapiEmbeddings) {\n strapiByDocumentId.set(strapi.documentId, strapi);\n }\n\n // Step 3: Find Neon embeddings that don't exist in Strapi\n for (const neon of neonEmbeddings) {\n if (!neon.strapiId) {\n // Neon record has no Strapi reference - skip or log\n result.errors.push(\n `Neon embedding ${neon.id} has no strapiId in metadata`\n );\n continue;\n }\n\n const existingStrapi = strapiByDocumentId.get(neon.strapiId);\n\n if (!existingStrapi) {\n // Create new Strapi entry\n if (!dryRun) {\n try {\n await strapi.documents(CONTENT_TYPE_UID).create({\n data: {\n documentId: neon.strapiId,\n title: neon.title,\n content: neon.content,\n embeddingId: neon.id,\n collectionType: neon.collectionType,\n fieldName: neon.fieldName,\n } as any,\n });\n result.actions.created++;\n result.details.created.push(\n `${neon.strapiId} (${neon.title || \"untitled\"})`\n );\n } catch (error) {\n result.errors.push(\n `Failed to create Strapi entry for ${neon.strapiId}: ${error}`\n );\n }\n } else {\n result.actions.created++;\n result.details.created.push(\n `[DRY RUN] ${neon.strapiId} (${neon.title || \"untitled\"})`\n );\n }\n } else {\n // Check if content needs updating\n const contentChanged = existingStrapi.content !== neon.content;\n const titleChanged = existingStrapi.title !== neon.title;\n const embeddingIdMissing = !existingStrapi.embeddingId;\n\n if (contentChanged || titleChanged || embeddingIdMissing) {\n if (!dryRun) {\n try {\n await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: neon.strapiId,\n data: {\n title: neon.title,\n content: neon.content,\n embeddingId: neon.id,\n } as any,\n });\n result.actions.updated++;\n result.details.updated.push(\n `${neon.strapiId} (${neon.title || \"untitled\"})`\n );\n } catch (error) {\n result.errors.push(\n `Failed to update Strapi entry ${neon.strapiId}: ${error}`\n );\n }\n } else {\n result.actions.updated++;\n result.details.updated.push(\n `[DRY RUN] ${neon.strapiId} (${neon.title || \"untitled\"})`\n );\n }\n }\n }\n }\n\n // Step 4: Handle orphaned Strapi entries (exist in Strapi but not in Neon)\n if (removeOrphans) {\n for (const strapiEmbed of strapiEmbeddings) {\n const hasNeonRecord = neonBystrapiId.has(strapiEmbed.documentId);\n\n if (!hasNeonRecord) {\n if (!dryRun) {\n try {\n await strapi.documents(CONTENT_TYPE_UID).delete({\n documentId: strapiEmbed.documentId,\n });\n result.actions.orphansRemoved++;\n result.details.orphansRemoved.push(\n `${strapiEmbed.documentId} (${strapiEmbed.title || \"untitled\"})`\n );\n } catch (error) {\n result.errors.push(\n `Failed to remove orphan ${strapiEmbed.documentId}: ${error}`\n );\n }\n } else {\n result.actions.orphansRemoved++;\n result.details.orphansRemoved.push(\n `[DRY RUN] ${strapiEmbed.documentId} (${strapiEmbed.title || \"untitled\"})`\n );\n }\n }\n }\n }\n\n result.success = result.errors.length === 0;\n return result;\n } catch (error) {\n result.errors.push(`Sync failed: ${error}`);\n return result;\n }\n },\n\n /**\n * Get sync status - compare Neon and Strapi without making changes\n */\n async getSyncStatus(): Promise<{\n neonCount: number;\n strapiCount: number;\n inSync: boolean;\n missingInStrapi: number;\n missingInNeon: number;\n contentDifferences: number;\n }> {\n if (!pluginManager.isInitialized()) {\n throw new Error(\"Plugin manager not initialized\");\n }\n\n const neonEmbeddings = await pluginManager.getAllNeonEmbeddings();\n const strapiEmbeddings = (await strapi\n .documents(CONTENT_TYPE_UID)\n .findMany({\n limit: 10000,\n })) as unknown as StrapiEmbedding[];\n\n const neonBystrapiId = new Map<string, NeonEmbedding>();\n for (const neon of neonEmbeddings) {\n if (neon.strapiId) {\n neonBystrapiId.set(neon.strapiId, neon);\n }\n }\n\n const strapiByDocumentId = new Map<string, StrapiEmbedding>();\n for (const s of strapiEmbeddings) {\n strapiByDocumentId.set(s.documentId, s);\n }\n\n let missingInStrapi = 0;\n let contentDifferences = 0;\n\n for (const neon of neonEmbeddings) {\n if (!neon.strapiId) continue;\n const strapiRecord = strapiByDocumentId.get(neon.strapiId);\n if (!strapiRecord) {\n missingInStrapi++;\n } else if (strapiRecord.content !== neon.content) {\n contentDifferences++;\n }\n }\n\n let missingInNeon = 0;\n for (const s of strapiEmbeddings) {\n if (!neonBystrapiId.has(s.documentId)) {\n missingInNeon++;\n }\n }\n\n return {\n neonCount: neonEmbeddings.length,\n strapiCount: strapiEmbeddings.length,\n inSync:\n missingInStrapi === 0 &&\n missingInNeon === 0 &&\n contentDifferences === 0,\n missingInStrapi,\n missingInNeon,\n contentDifferences,\n };\n },\n\n /**\n * Recreate all embeddings in Neon DB from Strapi data\n *\n * This will:\n * 1. Delete ALL embeddings from Neon DB\n * 2. Re-create embeddings for each Strapi embedding entry\n * 3. Update Strapi entries with new embedding IDs\n *\n * Use this when embeddings were created with incorrect metadata format\n */\n async recreateAllEmbeddings(): Promise<RecreateResult> {\n const result: RecreateResult = {\n success: false,\n timestamp: new Date().toISOString(),\n deletedFromNeon: 0,\n processedFromStrapi: 0,\n recreatedInNeon: 0,\n errors: [],\n details: {\n recreated: [],\n failed: [],\n },\n };\n\n if (!pluginManager.isInitialized()) {\n result.errors.push(\n \"Plugin manager not initialized. Check your Neon and OpenAI configuration.\"\n );\n return result;\n }\n\n try {\n // Step 1: Clear all embeddings from Neon\n console.log(\"[recreateAllEmbeddings] Step 1: Clearing Neon DB...\");\n result.deletedFromNeon = await pluginManager.clearAllNeonEmbeddings();\n console.log(`[recreateAllEmbeddings] Deleted ${result.deletedFromNeon} embeddings from Neon`);\n\n // Step 2: Get all embeddings from Strapi\n console.log(\"[recreateAllEmbeddings] Step 2: Fetching Strapi embeddings...\");\n const strapiEmbeddings = await strapi\n .documents(CONTENT_TYPE_UID)\n .findMany({\n limit: -1, // Get all\n });\n\n result.processedFromStrapi = strapiEmbeddings.length;\n console.log(`[recreateAllEmbeddings] Found ${strapiEmbeddings.length} embeddings in Strapi`);\n\n if (strapiEmbeddings.length === 0) {\n result.success = true;\n return result;\n }\n\n // Step 3: Recreate each embedding in Neon\n console.log(\"[recreateAllEmbeddings] Step 3: Recreating embeddings in Neon...\");\n\n for (let i = 0; i < strapiEmbeddings.length; i++) {\n const entry = strapiEmbeddings[i] as any;\n const progress = `[${i + 1}/${strapiEmbeddings.length}]`;\n\n if (!entry.content) {\n console.log(`${progress} Skipping ${entry.documentId} - no content`);\n result.details.failed.push(`${entry.documentId}: no content`);\n continue;\n }\n\n try {\n console.log(`${progress} Creating embedding for: ${entry.title || entry.documentId}`);\n\n // Create embedding in Neon with proper JSONB metadata\n const embeddingResult = await pluginManager.createEmbedding({\n id: entry.documentId,\n title: entry.title || \"\",\n content: entry.content,\n collectionType: entry.collectionType || \"standalone\",\n fieldName: entry.fieldName || \"content\",\n });\n\n // Update Strapi entry with new embedding ID\n await strapi.documents(CONTENT_TYPE_UID).update({\n documentId: entry.documentId,\n data: {\n embeddingId: embeddingResult.embeddingId,\n embedding: embeddingResult.embedding,\n } as any,\n });\n\n result.recreatedInNeon++;\n result.details.recreated.push(`${entry.documentId} (${entry.title || \"untitled\"})`);\n\n // Add small delay to avoid rate limiting\n if (i < strapiEmbeddings.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n } catch (error: any) {\n console.error(`${progress} Failed:`, error.message || error);\n result.errors.push(`${entry.documentId}: ${error.message || error}`);\n result.details.failed.push(`${entry.documentId}: ${error.message || error}`);\n }\n }\n\n result.success = result.errors.length === 0;\n console.log(`[recreateAllEmbeddings] Complete. Recreated: ${result.recreatedInNeon}, Failed: ${result.details.failed.length}`);\n\n return result;\n } catch (error: any) {\n result.errors.push(`Recreate failed: ${error.message || error}`);\n return result;\n }\n },\n});\n\nexport default sync;\n","import embeddings from \"./embeddings\";\nimport sync from \"./sync\";\n\nexport default {\n embeddings,\n sync,\n};\n","/**\n * Application methods\n */\nimport bootstrap from './bootstrap';\nimport destroy from './destroy';\nimport register from './register';\n\n/**\n * Plugin server methods\n */\nimport config from './config';\nimport contentTypes from './content-types';\nimport controllers from './controllers';\nimport middlewares from './middlewares';\nimport policies from './policies';\nimport routes from './routes';\nimport services from './services';\n\nexport default {\n register,\n bootstrap,\n destroy,\n config,\n controllers,\n routes,\n services,\n contentTypes,\n policies,\n middlewares,\n};\n"],"names":["config","Pool","OpenAIEmbeddings","ChatOpenAI","PGVectorStore","ChatPromptTemplate","RunnableSequence","RunnablePassthrough","StringOutputParser","z","schema","pluginManager","index","embeddings","embedding","Server","ListToolsRequestSchema","CallToolRequestSchema","PLUGIN_ID","randomUUID","StreamableHTTPServerTransport","mcp","options","convert","removeMarkdown","CONTENT_TYPE_UID","strapi"],"mappings":"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"}
|
package/dist/server/index.mjs
CHANGED