UNPKG

@escher-dbai/rag-module

Version:

Enterprise RAG module with chat context storage, vector search, and session management. Complete chat history retrieval and streaming content extraction for Electron apps.

142 lines (119 loc) 3.92 kB
const fs = require('fs-extra'); const path = require('path'); /** * Mapping Service - Handles ARN to anonymous ID mapping */ class MappingService { constructor(basePath, encryptionService) { this.basePath = basePath; this.encryptionService = encryptionService; this.mappingsPath = path.join(basePath, 'data', 'mappings.encrypted'); // In-memory cache this.mappings = new Map(); // realId -> anonymousId this.reverseMappings = new Map(); // anonymousId -> realId this.loaded = false; } /** * Load mappings from encrypted storage */ async loadMappings() { try { if (await fs.pathExists(this.mappingsPath)) { const encryptedData = await fs.readFile(this.mappingsPath, 'utf8'); const decryptedData = await this.encryptionService.decryptForSync(encryptedData); const mappingsData = JSON.parse(decryptedData); this.mappings.clear(); this.reverseMappings.clear(); for (const [realId, anonymousId] of Object.entries(mappingsData)) { this.mappings.set(realId, anonymousId); this.reverseMappings.set(anonymousId, realId); } } this.loaded = true; } catch (error) { // If loading fails, start with empty mappings this.mappings.clear(); this.reverseMappings.clear(); this.loaded = true; } } /** * Save mappings to encrypted storage */ async saveMappings() { const mappingsData = Object.fromEntries(this.mappings); const encryptedData = await this.encryptionService.encryptForSync(JSON.stringify(mappingsData)); await fs.ensureDir(path.dirname(this.mappingsPath)); await fs.writeFile(this.mappingsPath, encryptedData); } /** * Create mapping for a resource */ async createMapping(realId, metadata = {}) { if (!this.loaded) await this.loadMappings(); if (!this.mappings.has(realId)) { const anonymousId = this._generateAnonymousId(realId, metadata); this.mappings.set(realId, anonymousId); this.reverseMappings.set(anonymousId, realId); await this.saveMappings(); } return this.mappings.get(realId); } /** * Get anonymous ID for real ID */ async getAnonymousId(realId) { if (!this.loaded) await this.loadMappings(); return this.mappings.get(realId) || null; } /** * Get real ID from anonymous ID (internal use only) */ async getRealId(anonymousId) { if (!this.loaded) await this.loadMappings(); return this.reverseMappings.get(anonymousId) || null; } /** * Remove mapping */ async removeMapping(realId) { if (!this.loaded) await this.loadMappings(); const anonymousId = this.mappings.get(realId); if (anonymousId) { this.mappings.delete(realId); this.reverseMappings.delete(anonymousId); await this.saveMappings(); } } /** * Get encrypted mapping data for backend service */ async getEncryptedMapping(resourceIds) { if (!this.loaded) await this.loadMappings(); const mappingSubset = {}; for (const resourceId of resourceIds) { const realId = await this.getRealId(resourceId) || resourceId; if (this.mappings.has(realId)) { mappingSubset[resourceId] = realId; } } return await this.encryptionService.encryptForSync(JSON.stringify(mappingSubset)); } /** * Sync mappings to backend service */ async syncToBackend(config) { // This would implement the actual backend sync // For now, just return success return true; } /** * Generate anonymous ID */ _generateAnonymousId(realId, metadata = {}) { const crypto = require('crypto'); const hash = crypto.createHash('sha256').update(realId + JSON.stringify(metadata)).digest('hex'); return 'res-' + hash.substring(0, 16); } } module.exports = MappingService;