@syntropysoft/syntropyfront 0.4.0 → 0.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.min.js","sources":["../src/core/breadcrumbs/BreadcrumbStore.js","../src/core/agent/ConfigurationManager.js","../src/core/agent/QueueManager.js","../src/core/retry/RetryManager.js","../src/utils/RobustSerializer.js","../src/core/agent/HttpTransport.js","../src/core/database/DatabaseConfigManager.js","../src/core/database/DatabaseConnectionManager.js","../src/core/database/DatabaseTransactionManager.js","../src/core/database/DatabaseManager.js","../src/core/database/StorageManager.js","../src/core/retry/RetryLogicManager.js","../src/core/database/SerializationManager.js","../src/core/persistent/PersistentBufferManager.js","../src/core/agent/Agent.js","../src/core/context/ContextCollector.js","../src/interceptors/Interceptors.js","../src/index.js"],"sourcesContent":["/**\n * BreadcrumbStore - Almacén de huellas del usuario\n * Mantiene un historial de las últimas acciones del usuario\n */\nexport class BreadcrumbStore {\n constructor(maxBreadcrumbs = 25) {\n this.maxBreadcrumbs = maxBreadcrumbs;\n this.breadcrumbs = [];\n this.agent = null;\n }\n\n /**\n * Configura el agent para envío automático\n * @param {Object} agent - Instancia del agent\n */\n setAgent(agent) {\n this.agent = agent;\n }\n\n /**\n * Configura el tamaño máximo de breadcrumbs\n * @param {number} maxBreadcrumbs - Nuevo tamaño máximo\n */\n setMaxBreadcrumbs(maxBreadcrumbs) {\n this.maxBreadcrumbs = maxBreadcrumbs;\n \n // Si el nuevo tamaño es menor, eliminar breadcrumbs excedentes\n if (this.breadcrumbs.length > this.maxBreadcrumbs) {\n this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);\n }\n }\n\n /**\n * Obtiene el tamaño máximo actual\n * @returns {number} Tamaño máximo de breadcrumbs\n */\n getMaxBreadcrumbs() {\n return this.maxBreadcrumbs;\n }\n\n /**\n * Añade un breadcrumb a la lista\n * @param {Object} crumb - El breadcrumb a añadir\n * @param {string} crumb.category - Categoría del evento (ui, network, error, etc.)\n * @param {string} crumb.message - Mensaje descriptivo\n * @param {Object} [crumb.data] - Datos adicionales opcionales\n */\n add(crumb) {\n const breadcrumb = {\n ...crumb,\n timestamp: new Date().toISOString(),\n };\n\n if (this.breadcrumbs.length >= this.maxBreadcrumbs) {\n this.breadcrumbs.shift(); // Elimina el más antiguo\n }\n \n this.breadcrumbs.push(breadcrumb);\n \n // Callback opcional para logging\n if (this.onBreadcrumbAdded) {\n this.onBreadcrumbAdded(breadcrumb);\n }\n \n // Enviar al agent si está configurado y habilitado\n if (this.agent && this.agent.isEnabled) {\n try {\n this.agent.sendBreadcrumbs([breadcrumb]);\n } catch (error) {\n console.warn('SyntropyFront: Error enviando breadcrumb al agent:', error);\n }\n }\n }\n\n /**\n * Devuelve todos los breadcrumbs\n * @returns {Array} Copia de todos los breadcrumbs\n */\n getAll() {\n return [...this.breadcrumbs];\n }\n\n /**\n * Limpia todos los breadcrumbs\n */\n clear() {\n this.breadcrumbs = [];\n }\n\n /**\n * Obtiene breadcrumbs por categoría\n * @param {string} category - Categoría a filtrar\n * @returns {Array} Breadcrumbs de la categoría especificada\n */\n getByCategory(category) {\n return this.breadcrumbs.filter(b => b.category === category);\n }\n}\n\n// Instancia singleton\nexport const breadcrumbStore = new BreadcrumbStore(); ","/**\n * ConfigurationManager - Maneja la configuración del Agent\n * Responsabilidad única: Gestionar configuración y validación\n */\nexport class ConfigurationManager {\n constructor() {\n this.endpoint = null;\n this.headers = {\n 'Content-Type': 'application/json'\n };\n this.batchSize = 10;\n this.batchTimeout = null;\n this.isEnabled = false;\n this.sendBreadcrumbs = false;\n this.encrypt = null;\n this.usePersistentBuffer = false;\n this.maxRetries = 5;\n this.baseDelay = 1000;\n this.maxDelay = 30000;\n }\n\n /**\n * Configura el manager\n * @param {Object} config - Configuración\n */\n configure(config) {\n this.endpoint = config.endpoint;\n this.headers = { ...this.headers, ...config.headers };\n this.batchSize = config.batchSize || this.batchSize;\n this.batchTimeout = config.batchTimeout;\n this.isEnabled = !!config.endpoint;\n this.encrypt = config.encrypt || null;\n this.usePersistentBuffer = config.usePersistentBuffer === true;\n this.maxRetries = config.maxRetries || this.maxRetries;\n \n // Lógica simple: si hay batchTimeout = enviar breadcrumbs, sino = solo errores\n this.sendBreadcrumbs = !!config.batchTimeout;\n }\n\n /**\n * Verifica si el agent está habilitado\n */\n isAgentEnabled() {\n return this.isEnabled;\n }\n\n /**\n * Verifica si debe enviar breadcrumbs\n */\n shouldSendBreadcrumbs() {\n return this.sendBreadcrumbs;\n }\n\n /**\n * Obtiene la configuración actual\n */\n getConfig() {\n return {\n endpoint: this.endpoint,\n headers: this.headers,\n batchSize: this.batchSize,\n batchTimeout: this.batchTimeout,\n isEnabled: this.isEnabled,\n sendBreadcrumbs: this.sendBreadcrumbs,\n encrypt: this.encrypt,\n usePersistentBuffer: this.usePersistentBuffer,\n maxRetries: this.maxRetries,\n baseDelay: this.baseDelay,\n maxDelay: this.maxDelay\n };\n }\n} ","/**\n * QueueManager - Maneja la cola de envío y batching\n * Responsabilidad única: Gestionar cola de items y batching\n */\nexport class QueueManager {\n constructor(configManager) {\n this.config = configManager;\n this.queue = [];\n this.batchTimer = null;\n this.flushCallback = null; // Callback interno para flush automático\n }\n\n /**\n * Añade un item a la cola\n * @param {Object} item - Item a añadir\n */\n add(item) {\n this.queue.push(item);\n\n // Enviar inmediatamente si alcanza el tamaño del batch\n if (this.queue.length >= this.config.batchSize) {\n this.flush(this.flushCallback);\n } else if (this.config.batchSize && this.config.batchTimeout && !this.batchTimer) {\n // Solo programar timeout si batchTimeout está configurado\n this.batchTimer = setTimeout(() => {\n this.flush(this.flushCallback);\n }, this.config.batchTimeout);\n }\n }\n\n /**\n * Obtiene todos los items de la cola\n */\n getAll() {\n return [...this.queue];\n }\n\n /**\n * Limpia la cola\n */\n clear() {\n this.queue = [];\n this.clearTimer();\n }\n\n /**\n * Limpia el timer\n */\n clearTimer() {\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n }\n\n /**\n * Obtiene el tamaño de la cola\n */\n getSize() {\n return this.queue.length;\n }\n\n /**\n * Verifica si la cola está vacía\n */\n isEmpty() {\n return this.queue.length === 0;\n }\n\n /**\n * Flush de la cola (método que será llamado por el Agent)\n * @param {Function} flushCallback - Callback para procesar los items\n */\n async flush(flushCallback) {\n if (this.queue.length === 0) return;\n\n const itemsToSend = [...this.queue];\n this.queue = [];\n this.clearTimer();\n\n if (flushCallback) {\n await flushCallback(itemsToSend);\n }\n }\n} ","/**\n * RetryManager - Maneja el sistema de reintentos\n * Responsabilidad única: Gestionar reintentos con backoff exponencial\n */\nexport class RetryManager {\n constructor(configManager) {\n this.config = configManager;\n this.retryQueue = [];\n this.retryTimer = null;\n }\n\n /**\n * Añade items a la cola de reintentos\n * @param {Array} items - Items a reintentar\n * @param {number} retryCount - Número de reintento\n * @param {number} persistentId - ID en buffer persistente (opcional)\n */\n addToRetryQueue(items, retryCount = 1, persistentId = null) {\n const delay = Math.min(this.config.baseDelay * Math.pow(2, retryCount - 1), this.config.maxDelay);\n \n this.retryQueue.push({\n items,\n retryCount,\n persistentId,\n nextRetry: Date.now() + delay\n });\n\n this.scheduleRetry();\n }\n\n /**\n * Programa el próximo reintento\n */\n scheduleRetry() {\n if (this.retryTimer) return;\n\n const nextItem = this.retryQueue.find(item => item.nextRetry <= Date.now());\n if (!nextItem) return;\n\n this.retryTimer = setTimeout(() => {\n this.processRetryQueue();\n }, Math.max(0, nextItem.nextRetry - Date.now()));\n }\n\n /**\n * Procesa la cola de reintentos\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removePersistentCallback - Callback para remover del buffer persistente\n */\n async processRetryQueue(sendCallback, removePersistentCallback) {\n this.retryTimer = null;\n\n const now = Date.now();\n const itemsToRetry = this.retryQueue.filter(item => item.nextRetry <= now);\n \n for (const item of itemsToRetry) {\n try {\n if (sendCallback) {\n await sendCallback(item.items);\n }\n \n // ✅ Éxito: remover de cola de reintentos\n this.retryQueue = this.retryQueue.filter(q => q !== item);\n \n // Remover del buffer persistente si existe\n if (item.persistentId && removePersistentCallback) {\n await removePersistentCallback(item.persistentId);\n }\n \n console.log(`SyntropyFront: Reintento exitoso después de ${item.retryCount} intentos`);\n } catch (error) {\n console.warn(`SyntropyFront: Reintento ${item.retryCount} falló:`, error);\n \n if (item.retryCount >= this.config.maxRetries) {\n // ❌ Máximo de reintentos alcanzado\n this.retryQueue = this.retryQueue.filter(q => q !== item);\n console.error('SyntropyFront: Item excedió máximo de reintentos, datos perdidos');\n } else {\n // Programar próximo reintento\n item.retryCount++;\n item.nextRetry = Date.now() + Math.min(\n this.config.baseDelay * Math.pow(2, item.retryCount - 1), \n this.config.maxDelay\n );\n }\n }\n }\n\n // Programar próximo reintento si quedan items\n if (this.retryQueue.length > 0) {\n this.scheduleRetry();\n }\n }\n\n /**\n * Limpia la cola de reintentos\n */\n clear() {\n this.retryQueue = [];\n this.clearTimer();\n }\n\n /**\n * Limpia el timer\n */\n clearTimer() {\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n }\n\n /**\n * Obtiene el tamaño de la cola de reintentos\n */\n getSize() {\n return this.retryQueue.length;\n }\n\n /**\n * Verifica si la cola de reintentos está vacía\n */\n isEmpty() {\n return this.retryQueue.length === 0;\n }\n} ","/**\n * RobustSerializer - Serializador robusto que maneja referencias circulares\n * Implementa una solución similar a flatted pero sin dependencias externas\n */\nexport class RobustSerializer {\n constructor() {\n this.seen = new WeakSet();\n this.circularRefs = new Map();\n this.refCounter = 0;\n }\n\n /**\n * Serializa un objeto de forma segura, manejando referencias circulares\n * @param {any} obj - Objeto a serializar\n * @returns {string} JSON string seguro\n */\n serialize(obj) {\n try {\n // Reset state\n this.seen = new WeakSet();\n this.circularRefs = new Map();\n this.refCounter = 0;\n\n // Serializar con manejo de referencias circulares\n const safeObj = this.makeSerializable(obj);\n \n // Convertir a JSON\n return JSON.stringify(safeObj);\n } catch (error) {\n console.error('SyntropyFront: Error en serialización robusta:', error);\n \n // Fallback: intentar serialización básica con información de error\n return JSON.stringify({\n __serializationError: true,\n error: error.message,\n originalType: typeof obj,\n isObject: obj !== null && typeof obj === 'object',\n timestamp: new Date().toISOString()\n });\n }\n }\n\n /**\n * Hace un objeto serializable, manejando referencias circulares\n * @param {any} obj - Objeto a procesar\n * @param {string} path - Ruta actual en el objeto\n * @returns {any} Objeto serializable\n */\n makeSerializable(obj, path = '') {\n // Casos primitivos\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {\n return obj;\n }\n\n // Casos especiales\n if (obj instanceof Date) {\n return {\n __type: 'Date',\n value: obj.toISOString()\n };\n }\n\n if (obj instanceof Error) {\n return {\n __type: 'Error',\n name: obj.name,\n message: obj.message,\n stack: obj.stack,\n cause: obj.cause ? this.makeSerializable(obj.cause, `${path}.cause`) : undefined\n };\n }\n\n if (obj instanceof RegExp) {\n return {\n __type: 'RegExp',\n source: obj.source,\n flags: obj.flags\n };\n }\n\n // Arrays\n if (Array.isArray(obj)) {\n // Verificar referencia circular\n if (this.seen.has(obj)) {\n const refId = this.circularRefs.get(obj);\n return {\n __circular: true,\n refId\n };\n }\n\n this.seen.add(obj);\n const refId = `ref_${++this.refCounter}`;\n this.circularRefs.set(obj, refId);\n\n return obj.map((item, index) => \n this.makeSerializable(item, `${path}[${index}]`)\n );\n }\n\n // Objetos\n if (typeof obj === 'object') {\n // Verificar referencia circular\n if (this.seen.has(obj)) {\n const refId = this.circularRefs.get(obj);\n return {\n __circular: true,\n refId\n };\n }\n\n this.seen.add(obj);\n const refId = `ref_${++this.refCounter}`;\n this.circularRefs.set(obj, refId);\n\n const result = {};\n\n // Procesar propiedades del objeto\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n try {\n const value = obj[key];\n const safeValue = this.makeSerializable(value, `${path}.${key}`);\n result[key] = safeValue;\n } catch (error) {\n // Si falla la serialización de una propiedad, la omitimos\n result[key] = {\n __serializationError: true,\n error: error.message,\n propertyName: key\n };\n }\n }\n }\n\n // Procesar símbolos si están disponibles\n if (Object.getOwnPropertySymbols) {\n const symbols = Object.getOwnPropertySymbols(obj);\n for (const symbol of symbols) {\n try {\n const value = obj[symbol];\n const safeValue = this.makeSerializable(value, `${path}[Symbol(${symbol.description})]`);\n result[`__symbol_${symbol.description || 'anonymous'}`] = safeValue;\n } catch (error) {\n result[`__symbol_${symbol.description || 'anonymous'}`] = {\n __serializationError: true,\n error: error.message,\n symbolName: symbol.description || 'anonymous'\n };\n }\n }\n }\n\n return result;\n }\n\n // Funciones y otros tipos\n if (typeof obj === 'function') {\n return {\n __type: 'Function',\n name: obj.name || 'anonymous',\n length: obj.length,\n toString: `${obj.toString().substring(0, 200) }...`\n };\n }\n\n // Fallback para otros tipos\n return {\n __type: 'Unknown',\n constructor: obj.constructor ? obj.constructor.name : 'Unknown',\n toString: `${String(obj).substring(0, 200) }...`\n };\n }\n\n /**\n * Deserializa un objeto serializado con referencias circulares\n * @param {string} jsonString - JSON string a deserializar\n * @returns {any} Objeto deserializado\n */\n deserialize(jsonString) {\n try {\n const parsed = JSON.parse(jsonString);\n return this.restoreCircularRefs(parsed);\n } catch (error) {\n console.error('SyntropyFront: Error en deserialización:', error);\n return null;\n }\n }\n\n /**\n * Restaura referencias circulares en un objeto deserializado\n * @param {any} obj - Objeto a restaurar\n * @param {Map} refs - Mapa de referencias\n * @returns {any} Objeto con referencias restauradas\n */\n restoreCircularRefs(obj, refs = new Map()) {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {\n return obj;\n }\n\n // Restaurar tipos especiales\n if (obj.__type === 'Date') {\n return new Date(obj.value);\n }\n\n if (obj.__type === 'Error') {\n const error = new Error(obj.message);\n error.name = obj.name;\n error.stack = obj.stack;\n if (obj.cause) {\n error.cause = this.restoreCircularRefs(obj.cause, refs);\n }\n return error;\n }\n\n if (obj.__type === 'RegExp') {\n return new RegExp(obj.source, obj.flags);\n }\n\n if (obj.__type === 'Function') {\n // No podemos restaurar funciones completamente, devolvemos info\n return `[Function: ${obj.name}]`;\n }\n\n // Arrays\n if (Array.isArray(obj)) {\n const result = [];\n refs.set(obj, result);\n\n for (let i = 0; i < obj.length; i++) {\n if (obj[i] && obj[i].__circular) {\n const refId = obj[i].refId;\n if (refs.has(refId)) {\n result[i] = refs.get(refId);\n } else {\n result[i] = null; // Referencia no encontrada\n }\n } else {\n result[i] = this.restoreCircularRefs(obj[i], refs);\n }\n }\n\n return result;\n }\n\n // Objetos\n if (typeof obj === 'object') {\n const result = {};\n refs.set(obj, result);\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n if (key.startsWith('__')) {\n // Propiedades especiales\n continue;\n }\n\n const value = obj[key];\n if (value && value.__circular) {\n const refId = value.refId;\n if (refs.has(refId)) {\n result[key] = refs.get(refId);\n } else {\n result[key] = null; // Referencia no encontrada\n }\n } else {\n result[key] = this.restoreCircularRefs(value, refs);\n }\n }\n }\n\n return result;\n }\n\n return obj;\n }\n\n /**\n * Serializa de forma segura para logging (versión simplificada)\n * @param {any} obj - Objeto a serializar\n * @returns {string} JSON string seguro para logs\n */\n serializeForLogging(obj) {\n try {\n return this.serialize(obj);\n } catch (error) {\n return JSON.stringify({\n __logError: true,\n message: 'Error serializando para logging',\n originalError: error.message,\n timestamp: new Date().toISOString()\n });\n }\n }\n}\n\n// Instancia singleton\nexport const robustSerializer = new RobustSerializer(); ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * HttpTransport - Maneja el envío HTTP\n * Responsabilidad única: Gestionar envío HTTP y serialización\n */\nexport class HttpTransport {\n constructor(configManager) {\n this.config = configManager;\n }\n\n /**\n * Envía datos al backend\n * @param {Array} items - Items a enviar\n */\n async send(items) {\n const payload = {\n timestamp: new Date().toISOString(),\n items\n };\n\n // ✅ SERIALIZACIÓN ROBUSTA: Usar serializador que maneja referencias circulares\n let serializedPayload;\n try {\n serializedPayload = robustSerializer.serialize(payload);\n } catch (error) {\n console.error('SyntropyFront: Error en serialización del payload:', error);\n \n // Fallback: intentar serialización básica con información de error\n serializedPayload = JSON.stringify({\n __serializationError: true,\n error: error.message,\n timestamp: new Date().toISOString(),\n itemsCount: items.length,\n fallbackData: 'Serialización falló, datos no enviados'\n });\n }\n\n const response = await fetch(this.config.endpoint, {\n method: 'POST',\n headers: this.config.headers,\n body: serializedPayload\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return response.json();\n }\n\n /**\n * Aplica encriptación si está configurada\n * @param {*} data - Datos a encriptar\n */\n applyEncryption(data) {\n if (this.config.encrypt) {\n return this.config.encrypt(data);\n }\n return data;\n }\n\n /**\n * Verifica si el transport está configurado\n */\n isConfigured() {\n return !!this.config.endpoint;\n }\n} ","/**\n * DatabaseConfigManager - Maneja la configuración de IndexedDB\n * Responsabilidad única: Validar y gestionar la configuración de la base de datos\n */\nexport class DatabaseConfigManager {\n constructor(dbName, dbVersion, storeName) {\n this.dbName = dbName;\n this.dbVersion = dbVersion;\n this.storeName = storeName;\n }\n\n /**\n * Valida que la configuración sea correcta\n * @returns {Object} Resultado de validación\n */\n validateConfig() {\n const validationResult = {\n isValid: true,\n errors: [],\n timestamp: new Date().toISOString()\n };\n\n if (!this.dbName || typeof this.dbName !== 'string') {\n validationResult.isValid = false;\n validationResult.errors.push('dbName debe ser un string no vacío');\n }\n\n if (!this.dbVersion || typeof this.dbVersion !== 'number' || this.dbVersion < 1) {\n validationResult.isValid = false;\n validationResult.errors.push('dbVersion debe ser un número mayor a 0');\n }\n\n if (!this.storeName || typeof this.storeName !== 'string') {\n validationResult.isValid = false;\n validationResult.errors.push('storeName debe ser un string no vacío');\n }\n\n return validationResult;\n }\n\n /**\n * Verifica si IndexedDB está disponible en el entorno\n * @returns {Object} Resultado de disponibilidad\n */\n checkIndexedDBAvailability() {\n const availabilityResult = {\n isAvailable: false,\n reason: null,\n timestamp: new Date().toISOString()\n };\n\n if (typeof window === 'undefined') {\n availabilityResult.reason = 'No estamos en un entorno de browser';\n return availabilityResult;\n }\n\n if (!window.indexedDB) {\n availabilityResult.reason = 'IndexedDB no está disponible en este browser';\n return availabilityResult;\n }\n\n availabilityResult.isAvailable = true;\n return availabilityResult;\n }\n\n /**\n * Obtiene la configuración actual\n * @returns {Object} Configuración\n */\n getConfig() {\n return {\n dbName: this.dbName,\n dbVersion: this.dbVersion,\n storeName: this.storeName\n };\n }\n\n /**\n * Crea la configuración del object store\n * @returns {Object} Configuración del store\n */\n getStoreConfig() {\n return {\n keyPath: 'id',\n autoIncrement: true\n };\n }\n} ","/**\n * DatabaseConnectionManager - Maneja la conexión con IndexedDB\n * Responsabilidad única: Gestionar la apertura y cierre de conexiones\n */\nexport class DatabaseConnectionManager {\n constructor(configManager) {\n this.configManager = configManager;\n this.db = null;\n this.isAvailable = false;\n }\n\n /**\n * Inicializa la conexión con IndexedDB\n * @returns {Promise<Object>} Resultado de la inicialización\n */\n async init() {\n const initResult = {\n success: false,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n // Validar configuración\n const configValidation = this.configManager.validateConfig();\n if (!configValidation.isValid) {\n initResult.error = `Configuración inválida: ${configValidation.errors.join(', ')}`;\n return initResult;\n }\n\n // Verificar disponibilidad de IndexedDB\n const availabilityCheck = this.configManager.checkIndexedDBAvailability();\n if (!availabilityCheck.isAvailable) {\n initResult.error = availabilityCheck.reason;\n return initResult;\n }\n\n // Abrir conexión\n const connectionResult = await this.openConnection();\n if (!connectionResult.success) {\n initResult.error = connectionResult.error;\n return initResult;\n }\n\n this.db = connectionResult.db;\n this.isAvailable = true;\n initResult.success = true;\n\n return initResult;\n } catch (error) {\n initResult.error = `Error inesperado: ${error.message}`;\n return initResult;\n }\n }\n\n /**\n * Abre la conexión con IndexedDB\n * @returns {Promise<Object>} Resultado de la conexión\n */\n openConnection() {\n return new Promise((resolve) => {\n const config = this.configManager.getConfig();\n const request = indexedDB.open(config.dbName, config.dbVersion);\n\n request.onerror = () => {\n resolve({\n success: false,\n error: 'Error abriendo IndexedDB',\n db: null\n });\n };\n\n request.onupgradeneeded = (event) => {\n const db = event.target.result;\n const storeConfig = this.configManager.getStoreConfig();\n \n if (!db.objectStoreNames.contains(config.storeName)) {\n db.createObjectStore(config.storeName, storeConfig);\n }\n };\n\n request.onsuccess = () => {\n resolve({\n success: true,\n error: null,\n db: request.result\n });\n };\n });\n }\n\n /**\n * Cierra la conexión con la base de datos\n * @returns {Object} Resultado del cierre\n */\n close() {\n const closeResult = {\n success: false,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n if (this.db) {\n this.db.close();\n this.db = null;\n this.isAvailable = false;\n closeResult.success = true;\n } else {\n closeResult.error = 'No hay conexión activa para cerrar';\n }\n } catch (error) {\n closeResult.error = `Error cerrando conexión: ${error.message}`;\n }\n\n return closeResult;\n }\n\n /**\n * Verifica si la base de datos está disponible\n * @returns {boolean} True si está disponible\n */\n isDatabaseAvailable() {\n return this.isAvailable && this.db !== null;\n }\n\n /**\n * Obtiene la instancia de la base de datos\n * @returns {IDBDatabase|null} Instancia de la base de datos\n */\n getDatabase() {\n return this.isDatabaseAvailable() ? this.db : null;\n }\n} ","/**\n * DatabaseTransactionManager - Maneja las transacciones de IndexedDB\n * Responsabilidad única: Gestionar transacciones de lectura y escritura\n */\nexport class DatabaseTransactionManager {\n constructor(connectionManager, configManager) {\n this.connectionManager = connectionManager;\n this.configManager = configManager;\n }\n\n /**\n * Obtiene una transacción de lectura\n * @returns {IDBTransaction} Transacción de lectura\n * @throws {Error} Si la base de datos no está disponible\n */\n getReadTransaction() {\n this.ensureDatabaseAvailable();\n \n const config = this.configManager.getConfig();\n const db = this.connectionManager.getDatabase();\n \n return db.transaction([config.storeName], 'readonly');\n }\n\n /**\n * Obtiene una transacción de escritura\n * @returns {IDBTransaction} Transacción de escritura\n * @throws {Error} Si la base de datos no está disponible\n */\n getWriteTransaction() {\n this.ensureDatabaseAvailable();\n \n const config = this.configManager.getConfig();\n const db = this.connectionManager.getDatabase();\n \n return db.transaction([config.storeName], 'readwrite');\n }\n\n /**\n * Obtiene el object store para una transacción\n * @param {IDBTransaction} transaction - Transacción activa\n * @returns {IDBObjectStore} Object store\n */\n getObjectStore(transaction) {\n const config = this.configManager.getConfig();\n return transaction.objectStore(config.storeName);\n }\n\n /**\n * Ejecuta una operación de lectura de manera segura\n * @param {Function} operation - Operación a ejecutar\n * @returns {Promise<Object>} Resultado de la operación\n */\n async executeReadOperation(operation) {\n const operationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const transaction = this.getReadTransaction();\n const store = this.getObjectStore(transaction);\n \n const result = await operation(store);\n \n operationResult.success = true;\n operationResult.data = result;\n \n return operationResult;\n } catch (error) {\n operationResult.error = `Error en operación de lectura: ${error.message}`;\n return operationResult;\n }\n }\n\n /**\n * Ejecuta una operación de escritura de manera segura\n * @param {Function} operation - Operación a ejecutar\n * @returns {Promise<Object>} Resultado de la operación\n */\n async executeWriteOperation(operation) {\n const operationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const transaction = this.getWriteTransaction();\n const store = this.getObjectStore(transaction);\n \n const result = await operation(store);\n \n operationResult.success = true;\n operationResult.data = result;\n \n return operationResult;\n } catch (error) {\n operationResult.error = `Error en operación de escritura: ${error.message}`;\n return operationResult;\n }\n }\n\n /**\n * Verifica que la base de datos esté disponible\n * @throws {Error} Si la base de datos no está disponible\n */\n ensureDatabaseAvailable() {\n if (!this.connectionManager.isDatabaseAvailable()) {\n throw new Error('Database not available');\n }\n }\n\n /**\n * Obtiene información sobre el estado de las transacciones\n * @returns {Object} Estado de las transacciones\n */\n getTransactionStatus() {\n return {\n isDatabaseAvailable: this.connectionManager.isDatabaseAvailable(),\n storeName: this.configManager.getConfig().storeName,\n timestamp: new Date().toISOString()\n };\n }\n} ","import { DatabaseConfigManager } from './DatabaseConfigManager.js';\nimport { DatabaseConnectionManager } from './DatabaseConnectionManager.js';\nimport { DatabaseTransactionManager } from './DatabaseTransactionManager.js';\n\n/**\n * DatabaseManager - Coordinador de la gestión de IndexedDB\n * Responsabilidad única: Coordinar los managers especializados\n */\nexport class DatabaseManager {\n constructor(dbName, dbVersion, storeName) {\n this.configManager = new DatabaseConfigManager(dbName, dbVersion, storeName);\n this.connectionManager = new DatabaseConnectionManager(this.configManager);\n this.transactionManager = new DatabaseTransactionManager(this.connectionManager, this.configManager);\n }\n\n /**\n * Inicializa la conexión con IndexedDB\n */\n async init() {\n const initResult = await this.connectionManager.init();\n \n if (initResult.success) {\n console.log('SyntropyFront: Base de datos inicializada');\n } else {\n console.warn('SyntropyFront: Error inicializando base de datos:', initResult.error);\n }\n \n return initResult.success;\n }\n\n /**\n * Obtiene una transacción de lectura\n */\n getReadTransaction() {\n return this.transactionManager.getReadTransaction();\n }\n\n /**\n * Obtiene una transacción de escritura\n */\n getWriteTransaction() {\n return this.transactionManager.getWriteTransaction();\n }\n\n /**\n * Cierra la conexión con la base de datos\n */\n close() {\n const closeResult = this.connectionManager.close();\n \n if (!closeResult.success) {\n console.warn('SyntropyFront: Error cerrando base de datos:', closeResult.error);\n }\n \n return closeResult.success;\n }\n\n /**\n * Verifica si la base de datos está disponible\n */\n isDatabaseAvailable() {\n return this.connectionManager.isDatabaseAvailable();\n }\n\n // ===== Propiedades de compatibilidad =====\n \n /**\n * @deprecated Usar configManager.getConfig().dbName\n */\n get dbName() {\n return this.configManager.dbName;\n }\n\n /**\n * @deprecated Usar configManager.getConfig().dbVersion\n */\n get dbVersion() {\n return this.configManager.dbVersion;\n }\n\n /**\n * @deprecated Usar configManager.getConfig().storeName\n */\n get storeName() {\n return this.configManager.storeName;\n }\n\n /**\n * @deprecated Usar connectionManager.getDatabase()\n */\n get db() {\n return this.connectionManager.getDatabase();\n }\n\n /**\n * @deprecated Usar connectionManager.isDatabaseAvailable()\n */\n get isAvailable() {\n return this.connectionManager.isDatabaseAvailable();\n }\n}\n","/**\n * StorageManager - Maneja las operaciones CRUD de IndexedDB\n * Responsabilidad única: Gestionar operaciones de almacenamiento y recuperación\n */\nexport class StorageManager {\n constructor(databaseManager, serializationManager) {\n this.databaseManager = databaseManager;\n this.serializationManager = serializationManager;\n }\n\n /**\n * Guarda items en el almacenamiento\n * @param {Array} items - Items a guardar\n * @returns {Promise<number>} ID del item guardado\n */\n async save(items) {\n this.ensureDatabaseAvailable();\n\n const serializationResult = this.serializationManager.serialize(items);\n const serializedData = this.serializationManager.getData(serializationResult, '[]');\n\n const item = {\n items: serializedData,\n timestamp: new Date().toISOString(),\n retryCount: 0,\n serializationError: serializationResult.error\n };\n\n return this.executeWriteOperation(store => store.add(item));\n }\n\n /**\n * Obtiene todos los items del almacenamiento\n * @returns {Promise<Array>} Items deserializados\n */\n async retrieve() {\n if (!this.databaseManager.isDatabaseAvailable()) {\n return [];\n }\n\n const rawItems = await this.executeReadOperation(store => store.getAll());\n return this.deserializeItems(rawItems);\n }\n\n /**\n * Obtiene un item específico por ID\n * @param {number} id - ID del item\n * @returns {Promise<Object|null>} Item deserializado o null\n */\n async retrieveById(id) {\n if (!this.databaseManager.isDatabaseAvailable()) {\n return null;\n }\n\n const rawItem = await this.executeReadOperation(store => store.get(id));\n return rawItem ? this.deserializeItem(rawItem) : null;\n }\n\n /**\n * Remueve un item del almacenamiento\n * @param {number} id - ID del item a remover\n * @returns {Promise<void>}\n */\n async remove(id) {\n this.ensureDatabaseAvailable();\n return this.executeWriteOperation(store => store.delete(id));\n }\n\n /**\n * Actualiza un item en el almacenamiento\n * @param {number} id - ID del item\n * @param {Object} updates - Campos a actualizar\n * @returns {Promise<number>} ID del item actualizado\n */\n async update(id, updates) {\n this.ensureDatabaseAvailable();\n\n const currentItem = await this.retrieveById(id);\n if (!currentItem) {\n throw new Error('Item not found');\n }\n\n const updatedItem = { ...currentItem, ...updates };\n return this.executeWriteOperation(store => store.put(updatedItem));\n }\n\n /**\n * Limpia todo el almacenamiento\n * @returns {Promise<void>}\n */\n async clear() {\n this.ensureDatabaseAvailable();\n return this.executeWriteOperation(store => store.clear());\n }\n\n // ===== Métodos privados declarativos =====\n\n /**\n * Verifica que la base de datos esté disponible\n * @throws {Error} Si la base de datos no está disponible\n */\n ensureDatabaseAvailable() {\n if (!this.databaseManager.isDatabaseAvailable()) {\n throw new Error('Database not available');\n }\n }\n\n /**\n * Ejecuta una operación de lectura de manera declarativa\n * @param {Function} operation - Operación a ejecutar en el store\n * @returns {Promise<*>} Resultado de la operación\n */\n executeReadOperation(operation) {\n return new Promise((resolve, reject) => {\n try {\n const transaction = this.databaseManager.getReadTransaction();\n const store = transaction.objectStore(this.databaseManager.storeName);\n const request = operation(store);\n \n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Ejecuta una operación de escritura de manera declarativa\n * @param {Function} operation - Operación a ejecutar en el store\n * @returns {Promise<*>} Resultado de la operación\n */\n executeWriteOperation(operation) {\n return new Promise((resolve, reject) => {\n try {\n const transaction = this.databaseManager.getWriteTransaction();\n const store = transaction.objectStore(this.databaseManager.storeName);\n const request = operation(store);\n \n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Deserializa un array de items\n * @param {Array} rawItems - Items crudos de la base de datos\n * @returns {Array} Items deserializados\n */\n deserializeItems(rawItems) {\n return rawItems.map(item => this.deserializeItem(item));\n }\n\n /**\n * Deserializa un item individual\n * @param {Object} rawItem - Item crudo de la base de datos\n * @returns {Object} Item deserializado\n */\n deserializeItem(rawItem) {\n const deserializationResult = this.serializationManager.deserialize(rawItem.items);\n const deserializedItems = this.serializationManager.getData(deserializationResult, []);\n\n return {\n ...rawItem,\n items: deserializedItems,\n deserializationError: deserializationResult.error\n };\n }\n} ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * RetryLogicManager - Maneja la lógica de reintentos y limpieza\n * Responsabilidad única: Gestionar reintentos y limpieza de items fallidos\n */\nexport class RetryLogicManager {\n constructor(storageManager, configManager) {\n this.storageManager = storageManager;\n this.config = configManager;\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removeCallback - Callback para remover items exitosos\n */\n async retryFailedItems(sendCallback, removeCallback) {\n if (!this.storageManager) {\n console.warn('SyntropyFront: Storage manager no disponible');\n return;\n }\n\n try {\n const failedItems = await this.storageManager.retrieve();\n \n for (const item of failedItems) {\n if (item.retryCount < this.config.maxRetries) {\n // Deserializar items del buffer\n let deserializedItems;\n try {\n if (typeof item.items === 'string') {\n deserializedItems = robustSerializer.deserialize(item.items);\n } else {\n deserializedItems = item.items;\n }\n } catch (error) {\n console.error('SyntropyFront: Error deserializando items del buffer:', error);\n await this.removeFailedItem(item.id);\n continue;\n }\n \n if (sendCallback) {\n try {\n await sendCallback(deserializedItems, item.retryCount + 1, item.id);\n \n // Si el envío fue exitoso, remover del buffer\n if (removeCallback) {\n await removeCallback(item.id);\n } else {\n await this.removeFailedItem(item.id);\n }\n \n console.log(`SyntropyFront: Reintento exitoso para item ${item.id}`);\n } catch (error) {\n console.warn(`SyntropyFront: Reintento falló para item ${item.id}:`, error);\n \n // Incrementar contador de reintentos\n await this.incrementRetryCount(item.id);\n }\n }\n } else {\n console.warn(`SyntropyFront: Item ${item.id} excedió máximo de reintentos, removiendo del buffer`);\n await this.removeFailedItem(item.id);\n }\n }\n } catch (error) {\n console.error('SyntropyFront: Error procesando reintentos:', error);\n }\n }\n\n /**\n * Incrementa el contador de reintentos de un item\n * @param {number} id - ID del item\n */\n async incrementRetryCount(id) {\n try {\n const currentItem = await this.storageManager.retrieveById(id);\n if (currentItem) {\n await this.storageManager.update(id, {\n retryCount: currentItem.retryCount + 1\n });\n }\n } catch (error) {\n console.error('SyntropyFront: Error incrementando contador de reintentos:', error);\n }\n }\n\n /**\n * Remueve un item fallido del buffer\n * @param {number} id - ID del item\n */\n async removeFailedItem(id) {\n try {\n await this.storageManager.remove(id);\n } catch (error) {\n console.error('SyntropyFront: Error removiendo item fallido:', error);\n }\n }\n\n /**\n * Limpia items que han excedido el máximo de reintentos\n */\n async cleanupExpiredItems() {\n try {\n const allItems = await this.storageManager.retrieve();\n const expiredItems = allItems.filter(item => item.retryCount >= this.config.maxRetries);\n \n for (const item of expiredItems) {\n await this.removeFailedItem(item.id);\n console.warn(`SyntropyFront: Item ${item.id} removido por exceder máximo de reintentos`);\n }\n \n if (expiredItems.length > 0) {\n console.log(`SyntropyFront: Limpieza completada, ${expiredItems.length} items removidos`);\n }\n } catch (error) {\n console.error('SyntropyFront: Error en limpieza de items expirados:', error);\n }\n }\n\n /**\n * Obtiene estadísticas de reintentos\n */\n async getRetryStats() {\n try {\n const allItems = await this.storageManager.retrieve();\n \n const stats = {\n totalItems: allItems.length,\n itemsByRetryCount: {},\n averageRetryCount: 0\n };\n\n if (allItems.length > 0) {\n const totalRetries = allItems.reduce((sum, item) => sum + item.retryCount, 0);\n stats.averageRetryCount = totalRetries / allItems.length;\n \n allItems.forEach(item => {\n const retryCount = item.retryCount;\n stats.itemsByRetryCount[retryCount] = (stats.itemsByRetryCount[retryCount] || 0) + 1;\n });\n }\n\n return stats;\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo estadísticas de reintentos:', error);\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0\n };\n }\n }\n} ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * SerializationManager - Maneja la serialización y deserialización de datos\n * Responsabilidad única: Gestionar la transformación de datos para almacenamiento\n */\nexport class SerializationManager {\n constructor() {\n this.serializer = robustSerializer;\n }\n\n /**\n * Serializa items con manejo declarativo de errores\n * @param {Array} items - Items a serializar\n * @returns {Object} Resultado de serialización\n */\n serialize(items) {\n const serializationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const serializedData = this.serializer.serialize(items);\n return {\n ...serializationResult,\n success: true,\n data: serializedData\n };\n } catch (error) {\n return {\n ...serializationResult,\n error: this.createSerializationError(error),\n data: this.createFallbackData(error)\n };\n }\n }\n\n /**\n * Deserializa datos con manejo declarativo de errores\n * @param {string} serializedData - Datos serializados\n * @returns {Object} Resultado de deserialización\n */\n deserialize(serializedData) {\n const deserializationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const deserializedData = this.serializer.deserialize(serializedData);\n return {\n ...deserializationResult,\n success: true,\n data: deserializedData\n };\n } catch (error) {\n return {\n ...deserializationResult,\n error: this.createDeserializationError(error),\n data: []\n };\n }\n }\n\n /**\n * Crea un error de serialización estructurado\n * @param {Error} error - Error original\n * @returns {Object} Error estructurado\n */\n createSerializationError(error) {\n return {\n type: 'serialization_error',\n message: error.message,\n originalError: error,\n timestamp: new Date().toISOString()\n };\n }\n\n /**\n * Crea un error de deserialización estructurado\n * @param {Error} error - Error original\n * @returns {Object} Error estructurado\n */\n createDeserializationError(error) {\n return {\n type: 'deserialization_error',\n message: error.message,\n originalError: error,\n timestamp: new Date().toISOString()\n };\n }\n\n /**\n * Crea datos de fallback cuando falla la serialización\n * @param {Error} error - Error que causó el fallback\n * @returns {string} Datos de fallback serializados\n */\n createFallbackData(error) {\n const fallbackPayload = {\n __serializationError: true,\n error: error.message,\n timestamp: new Date().toISOString(),\n fallbackData: 'Items no serializables - usando fallback'\n };\n\n return JSON.stringify(fallbackPayload);\n }\n\n /**\n * Verifica si un resultado de serialización fue exitoso\n * @param {Object} result - Resultado de serialización/deserialización\n * @returns {boolean} True si fue exitoso\n */\n isSuccessful(result) {\n return Boolean(result && result.success === true);\n }\n\n /**\n * Obtiene los datos de un resultado, con fallback\n * @param {Object} result - Resultado de serialización/deserialización\n * @param {*} fallback - Valor por defecto si falla\n * @returns {*} Datos o fallback\n */\n getData(result, fallback = null) {\n return this.isSuccessful(result) ? result.data : fallback;\n }\n} ","import { DatabaseManager } from '../database/DatabaseManager.js';\nimport { StorageManager } from '../database/StorageManager.js';\nimport { RetryLogicManager } from '../retry/RetryLogicManager.js';\nimport { SerializationManager } from '../database/SerializationManager.js';\n\n/**\n * PersistentBufferManager - Coordinador del buffer persistente\n * Responsabilidad única: Coordinar los componentes de almacenamiento persistente\n */\nexport class PersistentBufferManager {\n constructor(configManager) {\n this.config = configManager;\n this.usePersistentBuffer = false;\n \n // Inicializar componentes especializados\n this.databaseManager = new DatabaseManager(\n 'SyntropyFrontBuffer',\n 1,\n 'failedItems'\n );\n \n this.serializationManager = new SerializationManager();\n this.storageManager = new StorageManager(this.databaseManager, this.serializationManager);\n this.retryLogicManager = new RetryLogicManager(this.storageManager, this.config);\n \n // Inicializar buffer persistente si está disponible\n this.initPersistentBuffer();\n }\n\n /**\n * Inicializa el buffer persistente\n */\n async initPersistentBuffer() {\n try {\n const success = await this.databaseManager.init();\n if (success) {\n this.usePersistentBuffer = this.config.usePersistentBuffer;\n console.log('SyntropyFront: Buffer persistente inicializado');\n }\n } catch (error) {\n console.warn('SyntropyFront: Error inicializando buffer persistente:', error);\n }\n }\n\n /**\n * Guarda items fallidos en el buffer persistente\n * @param {Array} items - Items a guardar\n */\n async save(items) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.save(items);\n console.log('SyntropyFront: Items guardados en buffer persistente');\n } catch (error) {\n console.error('SyntropyFront: Error guardando en buffer persistente:', error);\n }\n }\n\n /**\n * Obtiene items fallidos del buffer persistente\n */\n async retrieve() {\n if (!this.usePersistentBuffer) {\n return [];\n }\n\n try {\n return await this.storageManager.retrieve();\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo del buffer persistente:', error);\n return [];\n }\n }\n\n /**\n * Remueve items del buffer persistente\n * @param {number} id - ID del item a remover\n */\n async remove(id) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.remove(id);\n } catch (error) {\n console.error('SyntropyFront: Error removiendo del buffer persistente:', error);\n }\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removeCallback - Callback para remover items exitosos\n */\n async retryFailedItems(sendCallback, removeCallback) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n await this.retryLogicManager.retryFailedItems(sendCallback, removeCallback);\n }\n\n /**\n * Limpia items que han excedido el máximo de reintentos\n */\n async cleanupExpiredItems() {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n await this.retryLogicManager.cleanupExpiredItems();\n }\n\n /**\n * Obtiene estadísticas del buffer persistente\n */\n async getStats() {\n if (!this.usePersistentBuffer) {\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0,\n isAvailable: false\n };\n }\n\n try {\n const retryStats = await this.retryLogicManager.getRetryStats();\n return {\n ...retryStats,\n isAvailable: this.isAvailable()\n };\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo estadísticas:', error);\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0,\n isAvailable: this.isAvailable()\n };\n }\n }\n\n /**\n * Verifica si el buffer persistente está disponible\n */\n isAvailable() {\n return this.usePersistentBuffer && this.databaseManager.isDatabaseAvailable();\n }\n\n /**\n * Limpia todo el buffer persistente\n */\n async clear() {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.clear();\n console.log('SyntropyFront: Buffer persistente limpiado');\n } catch (error) {\n console.error('SyntropyFront: Error limpiando buffer persistente:', error);\n }\n }\n\n /**\n * Cierra la conexión con la base de datos\n */\n close() {\n this.databaseManager.close();\n this.usePersistentBuffer = false;\n }\n} ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConfigurationManager } from './ConfigurationManager.js';\nimport { QueueManager } from './QueueManager.js';\nimport { RetryManager } from '../retry/RetryManager.js';\nimport { HttpTransport } from './HttpTransport.js';\nimport { PersistentBufferManager } from '../persistent/PersistentBufferManager.js';\n\n/**\n * Agent - Envía datos de trazabilidad al backend\n * Coordinador que usa componentes especializados para cada responsabilidad\n */\nexport class Agent {\n constructor() {\n // Componentes especializados\n this.config = new ConfigurationManager();\n this.queue = new QueueManager(this.config);\n this.retry = new RetryManager(this.config);\n this.transport = new HttpTransport(this.config);\n this.buffer = new PersistentBufferManager(this.config);\n \n // Configurar callbacks para coordinación\n this.setupCallbacks();\n }\n\n /**\n * Configura callbacks para coordinación entre componentes\n */\n setupCallbacks() {\n // Callback para el QueueManager cuando hace flush\n this.queue.flushCallback = async (items) => {\n try {\n await this.transport.send(items);\n console.log('SyntropyFront: Datos enviados exitosamente');\n } catch (error) {\n console.error('SyntropyFront Agent: Error enviando datos:', error);\n \n // Agregar a cola de reintentos\n this.retry.addToRetryQueue(items);\n \n // Guardar en buffer persistente\n await this.buffer.save(items);\n }\n };\n\n // Callback para el RetryManager cuando procesa reintentos\n this.retry.sendCallback = async (items) => {\n return await this.transport.send(items);\n };\n\n this.retry.removePersistentCallback = async (id) => {\n await this.buffer.remove(id);\n };\n\n // Callback para el PersistentBufferManager cuando retry items\n this.buffer.sendCallback = (items, retryCount, persistentId) => {\n this.retry.addToRetryQueue(items, retryCount, persistentId);\n };\n }\n\n\n\n /**\n * Configura el agent\n * @param {Object} config - Configuración del agent\n */\n configure(config) {\n this.config.configure(config);\n }\n\n /**\n * Envía un error al backend\n * @param {Object} errorPayload - Payload del error\n * @param {Object} context - Contexto adicional (opcional)\n */\n sendError(errorPayload, context = null) {\n if (!this.config.isAgentEnabled()) {\n console.warn('SyntropyFront Agent: No configurado, error no enviado');\n return;\n }\n\n // Agregar contexto si está disponible\n const payloadWithContext = context ? {\n ...errorPayload,\n context\n } : errorPayload;\n\n // Aplicar encriptación si está configurada\n const dataToSend = this.transport.applyEncryption(payloadWithContext);\n\n this.queue.add({\n type: 'error',\n data: dataToSend,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Envía breadcrumbs al backend\n * @param {Array} breadcrumbs - Lista de breadcrumbs\n */\n sendBreadcrumbs(breadcrumbs) {\n // Solo enviar breadcrumbs si está habilitado (batchTimeout configurado)\n if (!this.config.isAgentEnabled() || !this.config.shouldSendBreadcrumbs() || !breadcrumbs.length) {\n return;\n }\n\n // Aplicar encriptación si está configurada\n const dataToSend = this.transport.applyEncryption(breadcrumbs);\n\n this.queue.add({\n type: 'breadcrumbs',\n data: dataToSend,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Añade un item a la cola de envío (método público para compatibilidad)\n * @param {Object} item - Item a añadir\n */\n addToQueue(item) {\n this.queue.add(item);\n }\n\n /**\n * Añade items a la cola de reintentos (método público para compatibilidad)\n * @param {Array} items - Items a reintentar\n * @param {number} retryCount - Número de reintento\n * @param {number} persistentId - ID en buffer persistente (opcional)\n */\n addToRetryQueue(items, retryCount = 1, persistentId = null) {\n this.retry.addToRetryQueue(items, retryCount, persistentId);\n }\n\n /**\n * Procesa la cola de reintentos (método público para compatibilidad)\n */\n async processRetryQueue() {\n await this.retry.processRetryQueue(\n this.retry.sendCallback,\n this.retry.removePersistentCallback\n );\n }\n\n /**\n * Envía todos los items en cola\n */\n async flush() {\n await this.queue.flush(this.queue.flushCallback);\n }\n\n /**\n * Fuerza el envío inmediato de todos los datos pendientes\n */\n async forceFlush() {\n await this.flush();\n \n // También intentar enviar items en cola de reintentos\n if (!this.retry.isEmpty()) {\n console.log('SyntropyFront: Intentando enviar items en cola de reintentos...');\n await this.processRetryQueue();\n }\n }\n\n /**\n * Obtiene estadísticas del agent\n * @returns {Object} Estadísticas\n */\n getStats() {\n const config = this.config.getConfig();\n return {\n queueLength: this.queue.getSize(),\n retryQueueLength: this.retry.getSize(),\n isEnabled: this.config.isAgentEnabled(),\n usePersistentBuffer: config.usePersistentBuffer,\n maxRetries: config.maxRetries\n };\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n */\n async retryFailedItems() {\n await this.buffer.retryFailedItems(this.buffer.sendCallback);\n }\n\n /**\n * Desactiva el agent\n */\n disable() {\n this.config.configure({ endpoint: null }); // Deshabilitar\n this.queue.clear();\n this.retry.clear();\n }\n}\n\n// Instancia singleton\nexport const agent = new Agent(); ","/**\n * ContextCollector - Recolector dinámico de contexto\n * Sistema elegante para recolectar datos según lo que pida el usuario\n * Por defecto: Sets curados y seguros\n * Configuración específica: El usuario elige exactamente qué quiere\n */\nexport class ContextCollector {\n constructor() {\n // Sets curados por defecto (seguros y útiles)\n this.defaultContexts = {\n device: {\n userAgent: () => navigator.userAgent,\n language: () => navigator.language,\n screen: () => ({\n width: window.screen.width,\n height: window.screen.height\n }),\n timezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone\n },\n window: {\n url: () => window.location.href,\n viewport: () => ({\n width: window.innerWidth,\n height: window.innerHeight\n }),\n title: () => document.title\n },\n session: {\n sessionId: () => this.generateSessionId(),\n pageLoadTime: () => performance.now()\n },\n ui: {\n visibility: () => document.visibilityState,\n activeElement: () => document.activeElement ? {\n tagName: document.activeElement.tagName\n } : null\n },\n network: {\n online: () => navigator.onLine,\n connection: () => navigator.connection ? {\n effectiveType: navigator.connection.effectiveType\n } : null\n }\n };\n\n // Mapeo completo de todos los campos disponibles\n this.allFields = {\n device: {\n userAgent: () => navigator.userAgent,\n language: () => navigator.language,\n languages: () => navigator.languages,\n screen: () => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n colorDepth: window.screen.colorDepth,\n pixelDepth: window.screen.pixelDepth\n }),\n timezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone,\n cookieEnabled: () => navigator.cookieEnabled,\n doNotTrack: () => navigator.doNotTrack\n },\n window: {\n url: () => window.location.href,\n pathname: () => window.location.pathname,\n search: () => window.location.search,\n hash: () => window.location.hash,\n referrer: () => document.referrer,\n title: () => document.title,\n viewport: () => ({\n width: window.innerWidth,\n height: window.innerHeight\n })\n },\n storage: {\n localStorage: () => {\n const keys = Object.keys(localStorage);\n return {\n keys: keys.length,\n size: JSON.stringify(localStorage).length,\n keyNames: keys // Solo nombres, no valores\n };\n },\n sessionStorage: () => {\n const keys = Object.keys(sessionStorage);\n return {\n keys: keys.length,\n size: JSON.stringify(sessionStorage).length,\n keyNames: keys // Solo nombres, no valores\n };\n }\n },\n network: {\n online: () => navigator.onLine,\n connection: () => navigator.connection ? {\n effectiveType: navigator.connection.effectiveType,\n downlink: navigator.connection.downlink,\n rtt: navigator.connection.rtt\n } : null\n },\n ui: {\n focused: () => document.hasFocus(),\n visibility: () => document.visibilityState,\n activeElement: () => document.activeElement ? {\n tagName: document.activeElement.tagName,\n id: document.activeElement.id,\n className: document.activeElement.className\n } : null\n },\n performance: {\n memory: () => window.performance && window.performance.memory ? {\n used: Math.round(window.performance.memory.usedJSHeapSize / 1048576),\n total: Math.round(window.performance.memory.totalJSHeapSize / 1048576),\n limit: Math.round(window.performance.memory.jsHeapSizeLimit / 1048576)\n } : null,\n timing: () => window.performance ? {\n navigationStart: window.performance.timing.navigationStart,\n loadEventEnd: window.performance.timing.loadEventEnd\n } : null\n },\n session: {\n sessionId: () => this.generateSessionId(),\n startTime: () => new Date().toISOString(),\n pageLoadTime: () => performance.now()\n }\n };\n }\n\n /**\n * Recolecta contexto según la configuración\n * @param {Object} contextConfig - Configuración de contexto\n * @returns {Object} Contexto recolectado\n */\n collect(contextConfig = {}) {\n const context = {};\n\n Object.entries(contextConfig).forEach(([contextType, config]) => {\n try {\n if (config === true) {\n // Usar set curado por defecto\n context[contextType] = this.collectDefaultContext(contextType);\n } else if (Array.isArray(config)) {\n // Configuración específica: array de campos\n context[contextType] = this.collectSpecificFields(contextType, config);\n } else if (config === false) {\n // Explícitamente deshabilitado\n // No hacer nada\n } else {\n console.warn(`SyntropyFront: Configuración de contexto inválida para ${contextType}:`, config);\n }\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando contexto ${contextType}:`, error);\n context[contextType] = { error: 'Failed to collect' };\n }\n });\n\n return context;\n }\n\n /**\n * Recolecta el set curado por defecto\n * @param {string} contextType - Tipo de contexto\n * @returns {Object} Contexto por defecto\n */\n collectDefaultContext(contextType) {\n const defaultContext = this.defaultContexts[contextType];\n if (!defaultContext) {\n console.warn(`SyntropyFront: No hay set por defecto para ${contextType}`);\n return {};\n }\n\n const result = {};\n Object.entries(defaultContext).forEach(([field, getter]) => {\n try {\n result[field] = getter();\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando campo ${field} de ${contextType}:`, error);\n result[field] = null;\n }\n });\n\n return result;\n }\n\n /**\n * Recolecta campos específicos\n * @param {string} contextType - Tipo de contexto\n * @param {Array} fields - Campos específicos a recolectar\n * @returns {Object} Contexto específico\n */\n collectSpecificFields(contextType, fields) {\n const allFields = this.allFields[contextType];\n if (!allFields) {\n console.warn(`SyntropyFront: Tipo de contexto desconocido: ${contextType}`);\n return {};\n }\n\n const result = {};\n fields.forEach(field => {\n try {\n if (allFields[field]) {\n result[field] = allFields[field]();\n } else {\n console.warn(`SyntropyFront: Campo ${field} no disponible en ${contextType}`);\n }\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando campo ${field} de ${contextType}:`, error);\n result[field] = null;\n }\n });\n\n return result;\n }\n\n /**\n * Genera un ID de sesión seguro usando crypto.randomUUID() cuando esté disponible\n * @returns {string} ID de sesión seguro\n */\n generateSecureId() {\n try {\n // Intentar usar crypto.randomUUID() si está disponible (Node.js 14.17+, browsers modernos)\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n \n // Fallback para navegadores más antiguos: usar crypto.getRandomValues()\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n \n // Convertir a formato UUID v4\n const hex = Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32)\n ].join('-');\n }\n \n // Fallback final: timestamp + random (menos seguro pero funcional)\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 15);\n return `${timestamp}-${random}`;\n } catch (error) {\n console.warn('SyntropyFront: Error generando ID seguro, usando fallback:', error);\n // Fallback de emergencia\n return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n }\n\n /**\n * Genera un ID de sesión simple\n */\n generateSessionId() {\n if (!this._sessionId) {\n this._sessionId = `session_${this.generateSecureId()}`;\n }\n return this._sessionId;\n }\n\n /**\n * Obtiene la lista de tipos de contexto disponibles\n * @returns {Array} Tipos disponibles\n */\n getAvailableTypes() {\n return Object.keys(this.allFields);\n }\n\n /**\n * Obtiene la lista de campos disponibles para un tipo de contexto\n * @param {string} contextType - Tipo de contexto\n * @returns {Array} Campos disponibles\n */\n getAvailableFields(contextType) {\n const fields = this.allFields[contextType];\n return fields ? Object.keys(fields) : [];\n }\n\n /**\n * Obtiene información sobre los sets por defecto\n * @returns {Object} Información de sets por defecto\n */\n getDefaultContextsInfo() {\n const info = {};\n Object.entries(this.defaultContexts).forEach(([type, fields]) => {\n info[type] = Object.keys(fields);\n });\n return info;\n }\n}\n\n// Instancia singleton\nexport const contextCollector = new ContextCollector(); ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { breadcrumbStore } from '../core/breadcrumbs/BreadcrumbStore.js';\nimport { agent } from '../core/agent/Agent.js';\nimport { contextCollector } from '../core/context/ContextCollector.js';\n\n/**\n * Interceptors - Observadores que capturan eventos automáticamente\n * Implementa Chaining Pattern para coexistir con otros APMs\n */\nexport class Interceptors {\n constructor() {\n this.isInitialized = false;\n this.config = {\n captureClicks: true,\n captureFetch: true,\n captureErrors: true,\n captureUnhandledRejections: true\n };\n this.contextTypes = [];\n\n // Referencias originales para restaurar en destroy()\n this.originalHandlers = {\n fetch: null,\n onerror: null,\n onunhandledrejection: null\n };\n\n // Event listeners para limpiar\n this.eventListeners = new Map();\n }\n\n /**\n * Configura los interceptores\n * @param {Object} config - Configuración de interceptores\n */\n configure(config) {\n this.config = { ...this.config, ...config };\n this.contextTypes = config.context || [];\n }\n\n /**\n * Inicializa todos los interceptores\n */\n init() {\n if (this.isInitialized) {\n console.warn('SyntropyFront: Interceptors ya están inicializados');\n return;\n }\n\n if (this.config.captureClicks) {\n this.setupClickInterceptor();\n }\n\n if (this.config.captureFetch) {\n this.setupFetchInterceptor();\n }\n\n if (this.config.captureErrors || this.config.captureUnhandledRejections) {\n this.setupErrorInterceptors();\n }\n\n this.isInitialized = true;\n console.log('SyntropyFront: Interceptors inicializados con Chaining Pattern');\n }\n\n /**\n * Intercepta clics de usuario\n */\n setupClickInterceptor() {\n // Solo configurar en el browser\n if (typeof document === 'undefined') {\n console.log('SyntropyFront: Click interceptor no disponible (no browser)');\n return;\n }\n\n let lastClickTime = 0;\n const THROTTLE_MS = 500;\n\n const clickHandler = (event) => {\n const el = event.target;\n if (!el) return;\n\n // ✅ THROTTLE: Evitar ráfagas de clicks (ej: double clicks accidentales)\n const now = Date.now();\n if (now - lastClickTime < THROTTLE_MS) return;\n lastClickTime = now;\n\n // ✅ FILTER: Solo capturar elementos potencialmente interactivos\n const isInteractive = (element) => {\n if (!element || element.nodeType !== 1) return false;\n const interactiveTags = ['a', 'button', 'input', 'select', 'textarea', 'label', 'summary'];\n const isClickableRole = ['button', 'link', 'checkbox', 'radio', 'menuitem'].includes(element.getAttribute?.('role'));\n\n let hasPointerCursor = false;\n try {\n hasPointerCursor = window.getComputedStyle?.(element)?.cursor === 'pointer';\n } catch (e) {\n // Ignorar errores en entornos donde getComputedStyle falla (ej: JSDOM con mocks incompletos)\n }\n\n return interactiveTags.includes(element.tagName.toLowerCase()) || isClickableRole || hasPointerCursor;\n };\n\n // Si el elemento no es interactivo, buscar hacia arriba en el DOM (bubbling)\n let target = el;\n while (target && target !== document.body) {\n if (isInteractive(target)) break;\n target = target.parentElement;\n }\n\n // Si no encontramos un elemento interactivo, ignoramos el click (reduce ruido)\n if (!target || target === document.body) return;\n\n // Genera un selector CSS simple para identificar el elemento\n let selector = target.tagName.toLowerCase();\n if (target.id) {\n selector += `#${target.id}`;\n } else if (target.className && typeof target.className === 'string') {\n selector += `.${target.className.split(' ').filter(Boolean).join('.')}`;\n }\n\n breadcrumbStore.add({\n category: 'ui',\n message: `Usuario hizo click en '${selector}'`,\n data: {\n selector,\n tagName: target.tagName,\n id: target.id,\n className: target.className,\n text: target.innerText?.substring(0, 30).trim() || target.value?.substring(0, 30)\n }\n });\n };\n\n // Guardar referencia para limpiar después\n this.eventListeners.set('click', clickHandler);\n document.addEventListener('click', clickHandler, true);\n }\n\n /**\n * Intercepta llamadas de red (fetch) con Chaining\n */\n setupFetchInterceptor() {\n // Solo configurar en el browser\n if (typeof window === 'undefined' || !window.fetch) {\n console.log('SyntropyFront: Fetch interceptor no disponible (no browser/fetch)');\n return;\n }\n\n // Guardar referencia original\n this.originalHandlers.fetch = window.fetch;\n\n // Crear nuevo handler que encadena con el original\n const syntropyFetchHandler = (...args) => {\n const url = args[0] instanceof Request ? args[0].url : args[0];\n const method = args[0] instanceof Request ? args[0].method : (args[1]?.method || 'GET');\n\n breadcrumbStore.add({\n category: 'network',\n message: `Request: ${method} ${url}`,\n data: {\n url,\n method,\n timestamp: Date.now()\n }\n });\n\n // ✅ CHAINING: Llamar al handler original\n return this.originalHandlers.fetch.apply(window, args);\n };\n\n // Sobrescribir con el nuevo handler\n window.fetch = syntropyFetchHandler;\n }\n\n /**\n * Intercepta errores globales con Chaining\n */\n setupErrorInterceptors() {\n // Solo configurar en el browser\n if (typeof window === 'undefined') {\n console.log('SyntropyFront: Error interceptors no disponibles (no browser)');\n return;\n }\n\n if (this.config.captureErrors) {\n // Guardar referencia original\n this.originalHandlers.onerror = window.onerror;\n\n // Crear nuevo handler que encadena con el original\n const syntropyErrorHandler = (message, source, lineno, colno, error) => {\n const errorPayload = {\n type: 'uncaught_exception',\n error: {\n message,\n source,\n lineno,\n colno,\n stack: error?.stack\n },\n breadcrumbs: breadcrumbStore.getAll(),\n timestamp: new Date().toISOString()\n };\n\n this.handleError(errorPayload);\n\n // ✅ CHAINING: Llamar al handler original si existe\n if (this.originalHandlers.onerror) {\n try {\n return this.originalHandlers.onerror(message, source, lineno, colno, error);\n } catch (originalError) {\n console.warn('SyntropyFront: Error en handler original:', originalError);\n return false;\n }\n }\n\n return false; // No prevenir el error por defecto\n };\n\n // Sobrescribir con el nuevo handler\n window.onerror = syntropyErrorHandler;\n }\n\n if (this.config.captureUnhandledRejections) {\n // Guardar referencia original\n this.originalHandlers.onunhandledrejection = window.onunhandledrejection;\n\n // Crear nuevo handler que encadena con el original\n const syntropyRejectionHandler = (event) => {\n const errorPayload = {\n type: 'unhandled_rejection',\n error: {\n message: event.reason?.message || 'Rechazo de promesa sin mensaje',\n stack: event.reason?.stack,\n },\n breadcrumbs: breadcrumbStore.getAll(),\n timestamp: new Date().toISOString()\n };\n\n this.handleError(errorPayload);\n\n // ✅ CHAINING: Llamar al handler original si existe\n if (this.originalHandlers.onunhandledrejection) {\n try {\n this.originalHandlers.onunhandledrejection(event);\n } catch (originalError) {\n console.warn('SyntropyFront: Error en handler original de rejection:', originalError);\n }\n }\n };\n\n // Sobrescribir con el nuevo handler\n window.onunhandledrejection = syntropyRejectionHandler;\n }\n }\n\n /**\n * Maneja los errores capturados\n * @param {Object} errorPayload - Payload del error\n */\n handleError(errorPayload) {\n // Recolectar contexto si está configurado\n const context = this.contextTypes.length > 0 ? contextCollector.collect(this.contextTypes) : null;\n\n // Enviar al agent si está configurado\n agent.sendError(errorPayload, context);\n\n // Callback para manejo personalizado de errores\n if (this.onError) {\n this.onError(errorPayload);\n } else {\n // Comportamiento por defecto: log a consola\n console.error('SyntropyFront - Error detectado:', errorPayload);\n }\n }\n\n /**\n * Desactiva todos los interceptores y restaura handlers originales\n */\n destroy() {\n if (!this.isInitialized) return;\n\n console.log('SyntropyFront: Limpiando interceptores...');\n\n // ✅ RESTAURAR: Handlers originales\n if (this.originalHandlers.fetch) {\n window.fetch = this.originalHandlers.fetch;\n console.log('SyntropyFront: fetch original restaurado');\n }\n\n if (this.originalHandlers.onerror) {\n window.onerror = this.originalHandlers.onerror;\n console.log('SyntropyFront: onerror original restaurado');\n }\n\n if (this.originalHandlers.onunhandledrejection) {\n window.onunhandledrejection = this.originalHandlers.onunhandledrejection;\n console.log('SyntropyFront: onunhandledrejection original restaurado');\n }\n\n // ✅ LIMPIAR: Event listeners\n if (typeof document !== 'undefined') {\n this.eventListeners.forEach((handler, eventType) => {\n document.removeEventListener(eventType, handler, true);\n console.log(`SyntropyFront: Event listener ${eventType} removido`);\n });\n }\n\n // Limpiar referencias\n this.originalHandlers = {\n fetch: null,\n onerror: null,\n onunhandledrejection: null\n };\n this.eventListeners.clear();\n this.isInitialized = false;\n\n console.log('SyntropyFront: Interceptors destruidos y handlers restaurados');\n }\n\n /**\n * Obtiene información sobre los handlers originales\n * @returns {Object} Información de handlers\n */\n getHandlerInfo() {\n return {\n isInitialized: this.isInitialized,\n hasOriginalFetch: !!this.originalHandlers.fetch,\n hasOriginalOnError: !!this.originalHandlers.onerror,\n hasOriginalOnUnhandledRejection: !!this.originalHandlers.onunhandledrejection,\n eventListenersCount: this.eventListeners.size\n };\n }\n}\n\n// Instancia singleton\nexport const interceptors = new Interceptors(); ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SyntropyFront - Biblioteca de observabilidad con captura automática\n * Actúa como Facade conectando el Agent y los Interceptors modulares\n */\nimport { breadcrumbStore } from './core/breadcrumbs/BreadcrumbStore.js';\nimport { agent } from './core/agent/Agent.js';\nimport { interceptors } from './interceptors/Interceptors.js';\n\nclass SyntropyFront {\n constructor() {\n this.isActive = false;\n this.config = {\n maxEvents: 50,\n endpoint: null,\n headers: {},\n usePersistentBuffer: true,\n captureClicks: true,\n captureFetch: true,\n captureErrors: true,\n captureUnhandledRejections: true,\n onError: null\n };\n\n // Auto-inicializar\n this.init();\n }\n\n /**\n * Inicializa la biblioteca y activa los interceptores\n */\n init() {\n if (this.isActive) return;\n\n // Configurar el agent por defecto\n agent.configure({\n endpoint: this.config.endpoint,\n headers: this.config.headers,\n usePersistentBuffer: this.config.usePersistentBuffer\n });\n\n // Inicializar interceptores\n interceptors.configure({\n captureClicks: this.config.captureClicks,\n captureFetch: this.config.captureFetch,\n captureErrors: this.config.captureErrors,\n captureUnhandledRejections: this.config.captureUnhandledRejections\n });\n\n // Inyectar callback de error si existe\n if (this.config.onError) {\n interceptors.onError = this.config.onError;\n }\n\n interceptors.init();\n\n // Intentar reintentar items fallidos de sesiones previas\n agent.retryFailedItems().catch(err => {\n console.warn('SyntropyFront: Error al intentar recuperar items persistentes:', err);\n });\n\n this.isActive = true;\n console.log('🚀 SyntropyFront: Inicializado con arquitectura modular resiliente');\n }\n\n /**\n * Configura SyntropyFront\n * @param {Object} config - Configuración\n */\n configure(config = {}) {\n // Actualizar configuración local\n this.config = { ...this.config, ...config };\n\n // Si se pasa 'fetch', extraer endpoint y headers por compatibilidad\n if (config.fetch) {\n this.config.endpoint = config.fetch.url;\n this.config.headers = config.fetch.options?.headers || {};\n }\n\n // Re-configurar componentes internos\n agent.configure({\n endpoint: this.config.endpoint,\n headers: this.config.headers,\n usePersistentBuffer: this.config.usePersistentBuffer\n });\n\n interceptors.configure({\n captureClicks: this.config.captureClicks,\n captureFetch: this.config.captureFetch,\n captureErrors: this.config.captureErrors,\n captureUnhandledRejections: this.config.captureUnhandledRejections\n });\n\n if (this.config.onError) {\n interceptors.onError = this.config.onError;\n }\n\n const mode = this.config.endpoint ? `endpoint: ${this.config.endpoint}` : 'console only';\n console.log(`✅ SyntropyFront: Configurado - ${mode}`);\n }\n\n /**\n * Añade un breadcrumb manualmente\n */\n addBreadcrumb(category, message, data = {}) {\n return breadcrumbStore.add({ category, message, data });\n }\n\n /**\n * Obtiene todos los breadcrumbs\n */\n getBreadcrumbs() {\n return breadcrumbStore.getAll();\n }\n\n /**\n * Limpia los breadcrumbs\n */\n clearBreadcrumbs() {\n breadcrumbStore.clear();\n }\n\n /**\n * Envía un error manualmente con contexto\n */\n sendError(error, context = {}) {\n const errorPayload = {\n type: 'manual_error',\n error: {\n message: error.message || String(error),\n name: error.name || 'Error',\n stack: error.stack\n },\n breadcrumbs: this.getBreadcrumbs(),\n timestamp: new Date().toISOString()\n };\n\n agent.sendError(errorPayload, context);\n return errorPayload;\n }\n\n /**\n * Fuerza el envío de datos pendientes\n */\n async flush() {\n await agent.forceFlush();\n }\n\n /**\n * Obtiene estadísticas de uso\n */\n getStats() {\n return {\n isActive: this.isActive,\n breadcrumbs: breadcrumbStore.count(),\n agent: agent.getStats(),\n config: { ...this.config }\n };\n }\n\n /**\n * Desactiva la biblioteca y restaura hooks originales\n */\n destroy() {\n interceptors.destroy();\n agent.disable();\n this.isActive = false;\n console.log('SyntropyFront: Desactivado');\n }\n}\n\n// Instancia única (Singleton)\nconst syntropyFront = new SyntropyFront();\n\n// Exportar la instancia por defecto\nexport default syntropyFront;"],"names":["breadcrumbStore","constructor","maxBreadcrumbs","this","breadcrumbs","agent","setAgent","setMaxBreadcrumbs","length","slice","getMaxBreadcrumbs","add","crumb","breadcrumb","timestamp","Date","toISOString","shift","push","onBreadcrumbAdded","isEnabled","sendBreadcrumbs","error","console","warn","getAll","clear","getByCategory","category","filter","b","ConfigurationManager","endpoint","headers","batchSize","batchTimeout","encrypt","usePersistentBuffer","maxRetries","baseDelay","maxDelay","configure","config","isAgentEnabled","shouldSendBreadcrumbs","getConfig","QueueManager","configManager","queue","batchTimer","flushCallback","item","flush","setTimeout","clearTimer","clearTimeout","getSize","isEmpty","itemsToSend","RetryManager","retryQueue","retryTimer","addToRetryQueue","items","retryCount","persistentId","delay","Math","min","pow","nextRetry","now","scheduleRetry","nextItem","find","processRetryQueue","max","sendCallback","removePersistentCallback","itemsToRetry","q","log","robustSerializer","seen","WeakSet","circularRefs","Map","refCounter","serialize","obj","safeObj","makeSerializable","JSON","stringify","__serializationError","message","originalType","isObject","path","__type","value","Error","name","stack","cause","undefined","RegExp","source","flags","Array","isArray","has","__circular","refId","get","set","map","index","result","key","Object","prototype","hasOwnProperty","call","safeValue","propertyName","getOwnPropertySymbols","symbols","symbol","description","symbolName","toString","substring","String","deserialize","jsonString","parsed","parse","restoreCircularRefs","refs","i","startsWith","serializeForLogging","__logError","originalError","HttpTransport","send","payload","serializedPayload","itemsCount","fallbackData","response","fetch","method","body","ok","status","statusText","json","applyEncryption","data","isConfigured","DatabaseConfigManager","dbName","dbVersion","storeName","validateConfig","validationResult","isValid","errors","checkIndexedDBAvailability","availabilityResult","isAvailable","reason","window","indexedDB","getStoreConfig","keyPath","autoIncrement","DatabaseConnectionManager","db","init","initResult","success","configValidation","join","availabilityCheck","connectionResult","openConnection","Promise","resolve","request","open","onerror","onupgradeneeded","event","target","storeConfig","objectStoreNames","contains","createObjectStore","onsuccess","close","closeResult","isDatabaseAvailable","getDatabase","DatabaseTransactionManager","connectionManager","getReadTransaction","ensureDatabaseAvailable","transaction","getWriteTransaction","getObjectStore","objectStore","executeReadOperation","operation","operationResult","store","executeWriteOperation","getTransactionStatus","DatabaseManager","transactionManager","StorageManager","databaseManager","serializationManager","save","serializationResult","getData","serializationError","retrieve","rawItems","deserializeItems","retrieveById","id","rawItem","deserializeItem","remove","delete","update","updates","currentItem","updatedItem","put","reject","deserializationResult","deserializedItems","deserializationError","RetryLogicManager","storageManager","retryFailedItems","removeCallback","failedItems","removeFailedItem","incrementRetryCount","cleanupExpiredItems","expiredItems","getRetryStats","allItems","stats","totalItems","itemsByRetryCount","averageRetryCount","totalRetries","reduce","sum","forEach","SerializationManager","serializer","serializedData","createSerializationError","createFallbackData","deserializedData","createDeserializationError","type","fallbackPayload","isSuccessful","Boolean","fallback","PersistentBufferManager","retryLogicManager","initPersistentBuffer","getStats","retry","transport","buffer","setupCallbacks","async","sendError","errorPayload","context","payloadWithContext","dataToSend","addToQueue","forceFlush","queueLength","retryQueueLength","disable","contextCollector","defaultContexts","device","userAgent","navigator","language","screen","width","height","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","url","location","href","viewport","innerWidth","innerHeight","title","document","session","sessionId","generateSessionId","pageLoadTime","performance","ui","visibility","visibilityState","activeElement","tagName","network","online","onLine","connection","effectiveType","allFields","languages","availWidth","availHeight","colorDepth","pixelDepth","cookieEnabled","doNotTrack","pathname","search","hash","referrer","storage","localStorage","keys","size","keyNames","sessionStorage","downlink","rtt","focused","hasFocus","className","memory","used","round","usedJSHeapSize","total","totalJSHeapSize","limit","jsHeapSizeLimit","timing","navigationStart","loadEventEnd","startTime","collect","contextConfig","entries","contextType","collectDefaultContext","collectSpecificFields","defaultContext","field","getter","fields","generateSecureId","crypto","randomUUID","getRandomValues","array","Uint8Array","hex","from","byte","padStart","random","_sessionId","getAvailableTypes","getAvailableFields","getDefaultContextsInfo","info","interceptors","isInitialized","captureClicks","captureFetch","captureErrors","captureUnhandledRejections","contextTypes","originalHandlers","onunhandledrejection","eventListeners","setupClickInterceptor","setupFetchInterceptor","setupErrorInterceptors","lastClickTime","clickHandler","el","isInteractive","element","nodeType","isClickableRole","includes","getAttribute","hasPointerCursor","getComputedStyle","cursor","e","toLowerCase","parentElement","selector","split","text","innerText","trim","addEventListener","args","Request","apply","syntropyErrorHandler","lineno","colno","handleError","syntropyRejectionHandler","onError","destroy","handler","eventType","removeEventListener","getHandlerInfo","hasOriginalFetch","hasOriginalOnError","hasOriginalOnUnhandledRejection","eventListenersCount","isActive","maxEvents","catch","err","options","mode","addBreadcrumb","getBreadcrumbs","clearBreadcrumbs","count"],"mappings":"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"}
1
+ {"version":3,"file":"index.min.js","sources":["../src/core/breadcrumbs/BreadcrumbStore.js","../src/core/agent/ConfigurationManager.js","../src/core/agent/QueueManager.js","../src/core/retry/RetryManager.js","../src/utils/RobustSerializer.js","../src/core/agent/HttpTransport.js","../src/core/database/DatabaseConfigManager.js","../src/core/database/DatabaseConnectionManager.js","../src/core/database/DatabaseTransactionManager.js","../src/core/database/DatabaseManager.js","../src/core/database/StorageManager.js","../src/core/retry/RetryLogicManager.js","../src/core/database/SerializationManager.js","../src/core/persistent/PersistentBufferManager.js","../src/core/agent/Agent.js","../src/core/context/ContextCollector.js","../src/interceptors/Interceptors.js","../src/index.js"],"sourcesContent":["/**\n * BreadcrumbStore - Almacén de huellas del usuario\n * Mantiene un historial de las últimas acciones del usuario\n */\nexport class BreadcrumbStore {\n constructor(maxBreadcrumbs = 25) {\n this.maxBreadcrumbs = maxBreadcrumbs;\n this.breadcrumbs = [];\n this.agent = null;\n }\n\n /**\n * Configura el agent para envío automático\n * @param {Object} agent - Instancia del agent\n */\n setAgent(agent) {\n this.agent = agent;\n }\n\n /**\n * Configura el tamaño máximo de breadcrumbs\n * @param {number} maxBreadcrumbs - Nuevo tamaño máximo\n */\n setMaxBreadcrumbs(maxBreadcrumbs) {\n this.maxBreadcrumbs = maxBreadcrumbs;\n \n // Si el nuevo tamaño es menor, eliminar breadcrumbs excedentes\n if (this.breadcrumbs.length > this.maxBreadcrumbs) {\n this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);\n }\n }\n\n /**\n * Obtiene el tamaño máximo actual\n * @returns {number} Tamaño máximo de breadcrumbs\n */\n getMaxBreadcrumbs() {\n return this.maxBreadcrumbs;\n }\n\n /**\n * Añade un breadcrumb a la lista\n * @param {Object} crumb - El breadcrumb a añadir\n * @param {string} crumb.category - Categoría del evento (ui, network, error, etc.)\n * @param {string} crumb.message - Mensaje descriptivo\n * @param {Object} [crumb.data] - Datos adicionales opcionales\n */\n add(crumb) {\n const breadcrumb = {\n ...crumb,\n timestamp: new Date().toISOString(),\n };\n\n if (this.breadcrumbs.length >= this.maxBreadcrumbs) {\n this.breadcrumbs.shift(); // Elimina el más antiguo\n }\n \n this.breadcrumbs.push(breadcrumb);\n \n // Callback opcional para logging\n if (this.onBreadcrumbAdded) {\n this.onBreadcrumbAdded(breadcrumb);\n }\n \n // Enviar al agent si está configurado y habilitado\n if (this.agent && this.agent.isEnabled) {\n try {\n this.agent.sendBreadcrumbs([breadcrumb]);\n } catch (error) {\n console.warn('SyntropyFront: Error enviando breadcrumb al agent:', error);\n }\n }\n }\n\n /**\n * Devuelve todos los breadcrumbs\n * @returns {Array} Copia de todos los breadcrumbs\n */\n getAll() {\n return [...this.breadcrumbs];\n }\n\n /**\n * Limpia todos los breadcrumbs\n */\n clear() {\n this.breadcrumbs = [];\n }\n\n /**\n * Obtiene breadcrumbs por categoría\n * @param {string} category - Categoría a filtrar\n * @returns {Array} Breadcrumbs de la categoría especificada\n */\n getByCategory(category) {\n return this.breadcrumbs.filter(b => b.category === category);\n }\n}\n\n// Instancia singleton\nexport const breadcrumbStore = new BreadcrumbStore(); ","/**\n * ConfigurationManager - Maneja la configuración del Agent\n * Responsabilidad única: Gestionar configuración y validación\n */\nexport class ConfigurationManager {\n constructor() {\n this.endpoint = null;\n this.headers = {\n 'Content-Type': 'application/json'\n };\n this.batchSize = 10;\n this.batchTimeout = null;\n this.isEnabled = false;\n this.sendBreadcrumbs = false;\n this.encrypt = null;\n this.usePersistentBuffer = false;\n this.maxRetries = 5;\n this.baseDelay = 1000;\n this.maxDelay = 30000;\n }\n\n /**\n * Configura el manager\n * @param {Object} config - Configuración\n */\n configure(config) {\n this.endpoint = config.endpoint;\n this.headers = { ...this.headers, ...config.headers };\n this.batchSize = config.batchSize || this.batchSize;\n this.batchTimeout = config.batchTimeout;\n this.isEnabled = !!config.endpoint;\n this.encrypt = config.encrypt || null;\n this.usePersistentBuffer = config.usePersistentBuffer === true;\n this.maxRetries = config.maxRetries || this.maxRetries;\n \n // Lógica simple: si hay batchTimeout = enviar breadcrumbs, sino = solo errores\n this.sendBreadcrumbs = !!config.batchTimeout;\n }\n\n /**\n * Verifica si el agent está habilitado\n */\n isAgentEnabled() {\n return this.isEnabled;\n }\n\n /**\n * Verifica si debe enviar breadcrumbs\n */\n shouldSendBreadcrumbs() {\n return this.sendBreadcrumbs;\n }\n\n /**\n * Obtiene la configuración actual\n */\n getConfig() {\n return {\n endpoint: this.endpoint,\n headers: this.headers,\n batchSize: this.batchSize,\n batchTimeout: this.batchTimeout,\n isEnabled: this.isEnabled,\n sendBreadcrumbs: this.sendBreadcrumbs,\n encrypt: this.encrypt,\n usePersistentBuffer: this.usePersistentBuffer,\n maxRetries: this.maxRetries,\n baseDelay: this.baseDelay,\n maxDelay: this.maxDelay\n };\n }\n} ","/**\n * QueueManager - Maneja la cola de envío y batching\n * Responsabilidad única: Gestionar cola de items y batching\n */\nexport class QueueManager {\n constructor(configManager) {\n this.config = configManager;\n this.queue = [];\n this.batchTimer = null;\n this.flushCallback = null; // Callback interno para flush automático\n }\n\n /**\n * Añade un item a la cola\n * @param {Object} item - Item a añadir\n */\n add(item) {\n this.queue.push(item);\n\n // Enviar inmediatamente si alcanza el tamaño del batch\n if (this.queue.length >= this.config.batchSize) {\n this.flush(this.flushCallback);\n } else if (this.config.batchSize && this.config.batchTimeout && !this.batchTimer) {\n // Solo programar timeout si batchTimeout está configurado\n this.batchTimer = setTimeout(() => {\n this.flush(this.flushCallback);\n }, this.config.batchTimeout);\n }\n }\n\n /**\n * Obtiene todos los items de la cola\n */\n getAll() {\n return [...this.queue];\n }\n\n /**\n * Limpia la cola\n */\n clear() {\n this.queue = [];\n this.clearTimer();\n }\n\n /**\n * Limpia el timer\n */\n clearTimer() {\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n }\n\n /**\n * Obtiene el tamaño de la cola\n */\n getSize() {\n return this.queue.length;\n }\n\n /**\n * Verifica si la cola está vacía\n */\n isEmpty() {\n return this.queue.length === 0;\n }\n\n /**\n * Flush de la cola (método que será llamado por el Agent)\n * @param {Function} flushCallback - Callback para procesar los items\n */\n async flush(flushCallback) {\n if (this.queue.length === 0) return;\n\n const itemsToSend = [...this.queue];\n this.queue = [];\n this.clearTimer();\n\n if (flushCallback) {\n await flushCallback(itemsToSend);\n }\n }\n} ","/**\n * RetryManager - Maneja el sistema de reintentos\n * Responsabilidad única: Gestionar reintentos con backoff exponencial\n */\nexport class RetryManager {\n constructor(configManager) {\n this.config = configManager;\n this.retryQueue = [];\n this.retryTimer = null;\n }\n\n /**\n * Añade items a la cola de reintentos\n * @param {Array} items - Items a reintentar\n * @param {number} retryCount - Número de reintento\n * @param {number} persistentId - ID en buffer persistente (opcional)\n */\n addToRetryQueue(items, retryCount = 1, persistentId = null) {\n const delay = Math.min(this.config.baseDelay * Math.pow(2, retryCount - 1), this.config.maxDelay);\n \n this.retryQueue.push({\n items,\n retryCount,\n persistentId,\n nextRetry: Date.now() + delay\n });\n\n this.scheduleRetry();\n }\n\n /**\n * Programa el próximo reintento\n */\n scheduleRetry() {\n if (this.retryTimer) return;\n\n const nextItem = this.retryQueue.find(item => item.nextRetry <= Date.now());\n if (!nextItem) return;\n\n this.retryTimer = setTimeout(() => {\n this.processRetryQueue();\n }, Math.max(0, nextItem.nextRetry - Date.now()));\n }\n\n /**\n * Procesa la cola de reintentos\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removePersistentCallback - Callback para remover del buffer persistente\n */\n async processRetryQueue(sendCallback, removePersistentCallback) {\n this.retryTimer = null;\n\n const now = Date.now();\n const itemsToRetry = this.retryQueue.filter(item => item.nextRetry <= now);\n \n for (const item of itemsToRetry) {\n try {\n if (sendCallback) {\n await sendCallback(item.items);\n }\n \n // ✅ Éxito: remover de cola de reintentos\n this.retryQueue = this.retryQueue.filter(q => q !== item);\n \n // Remover del buffer persistente si existe\n if (item.persistentId && removePersistentCallback) {\n await removePersistentCallback(item.persistentId);\n }\n \n console.log(`SyntropyFront: Reintento exitoso después de ${item.retryCount} intentos`);\n } catch (error) {\n console.warn(`SyntropyFront: Reintento ${item.retryCount} falló:`, error);\n \n if (item.retryCount >= this.config.maxRetries) {\n // ❌ Máximo de reintentos alcanzado\n this.retryQueue = this.retryQueue.filter(q => q !== item);\n console.error('SyntropyFront: Item excedió máximo de reintentos, datos perdidos');\n } else {\n // Programar próximo reintento\n item.retryCount++;\n item.nextRetry = Date.now() + Math.min(\n this.config.baseDelay * Math.pow(2, item.retryCount - 1), \n this.config.maxDelay\n );\n }\n }\n }\n\n // Programar próximo reintento si quedan items\n if (this.retryQueue.length > 0) {\n this.scheduleRetry();\n }\n }\n\n /**\n * Limpia la cola de reintentos\n */\n clear() {\n this.retryQueue = [];\n this.clearTimer();\n }\n\n /**\n * Limpia el timer\n */\n clearTimer() {\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n }\n\n /**\n * Obtiene el tamaño de la cola de reintentos\n */\n getSize() {\n return this.retryQueue.length;\n }\n\n /**\n * Verifica si la cola de reintentos está vacía\n */\n isEmpty() {\n return this.retryQueue.length === 0;\n }\n} ","/**\n * RobustSerializer - Serializador robusto que maneja referencias circulares\n * Implementa una solución similar a flatted pero sin dependencias externas\n */\nexport class RobustSerializer {\n constructor() {\n this.seen = new WeakSet();\n this.circularRefs = new Map();\n this.refCounter = 0;\n }\n\n /**\n * Serializa un objeto de forma segura, manejando referencias circulares\n * @param {any} obj - Objeto a serializar\n * @returns {string} JSON string seguro\n */\n serialize(obj) {\n try {\n // Reset state\n this.seen = new WeakSet();\n this.circularRefs = new Map();\n this.refCounter = 0;\n\n // Serializar con manejo de referencias circulares\n const safeObj = this.makeSerializable(obj);\n \n // Convertir a JSON\n return JSON.stringify(safeObj);\n } catch (error) {\n console.error('SyntropyFront: Error en serialización robusta:', error);\n \n // Fallback: intentar serialización básica con información de error\n return JSON.stringify({\n __serializationError: true,\n error: error.message,\n originalType: typeof obj,\n isObject: obj !== null && typeof obj === 'object',\n timestamp: new Date().toISOString()\n });\n }\n }\n\n /**\n * Hace un objeto serializable, manejando referencias circulares\n * @param {any} obj - Objeto a procesar\n * @param {string} path - Ruta actual en el objeto\n * @returns {any} Objeto serializable\n */\n makeSerializable(obj, path = '') {\n // Casos primitivos\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {\n return obj;\n }\n\n // Casos especiales\n if (obj instanceof Date) {\n return {\n __type: 'Date',\n value: obj.toISOString()\n };\n }\n\n if (obj instanceof Error) {\n return {\n __type: 'Error',\n name: obj.name,\n message: obj.message,\n stack: obj.stack,\n cause: obj.cause ? this.makeSerializable(obj.cause, `${path}.cause`) : undefined\n };\n }\n\n if (obj instanceof RegExp) {\n return {\n __type: 'RegExp',\n source: obj.source,\n flags: obj.flags\n };\n }\n\n // Arrays\n if (Array.isArray(obj)) {\n // Verificar referencia circular\n if (this.seen.has(obj)) {\n const refId = this.circularRefs.get(obj);\n return {\n __circular: true,\n refId\n };\n }\n\n this.seen.add(obj);\n const refId = `ref_${++this.refCounter}`;\n this.circularRefs.set(obj, refId);\n\n return obj.map((item, index) => \n this.makeSerializable(item, `${path}[${index}]`)\n );\n }\n\n // Objetos\n if (typeof obj === 'object') {\n // Verificar referencia circular\n if (this.seen.has(obj)) {\n const refId = this.circularRefs.get(obj);\n return {\n __circular: true,\n refId\n };\n }\n\n this.seen.add(obj);\n const refId = `ref_${++this.refCounter}`;\n this.circularRefs.set(obj, refId);\n\n const result = {};\n\n // Procesar propiedades del objeto\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n try {\n const value = obj[key];\n const safeValue = this.makeSerializable(value, `${path}.${key}`);\n result[key] = safeValue;\n } catch (error) {\n // Si falla la serialización de una propiedad, la omitimos\n result[key] = {\n __serializationError: true,\n error: error.message,\n propertyName: key\n };\n }\n }\n }\n\n // Procesar símbolos si están disponibles\n if (Object.getOwnPropertySymbols) {\n const symbols = Object.getOwnPropertySymbols(obj);\n for (const symbol of symbols) {\n try {\n const value = obj[symbol];\n const safeValue = this.makeSerializable(value, `${path}[Symbol(${symbol.description})]`);\n result[`__symbol_${symbol.description || 'anonymous'}`] = safeValue;\n } catch (error) {\n result[`__symbol_${symbol.description || 'anonymous'}`] = {\n __serializationError: true,\n error: error.message,\n symbolName: symbol.description || 'anonymous'\n };\n }\n }\n }\n\n return result;\n }\n\n // Funciones y otros tipos\n if (typeof obj === 'function') {\n return {\n __type: 'Function',\n name: obj.name || 'anonymous',\n length: obj.length,\n toString: `${obj.toString().substring(0, 200) }...`\n };\n }\n\n // Fallback para otros tipos\n return {\n __type: 'Unknown',\n constructor: obj.constructor ? obj.constructor.name : 'Unknown',\n toString: `${String(obj).substring(0, 200) }...`\n };\n }\n\n /**\n * Deserializa un objeto serializado con referencias circulares\n * @param {string} jsonString - JSON string a deserializar\n * @returns {any} Objeto deserializado\n */\n deserialize(jsonString) {\n try {\n const parsed = JSON.parse(jsonString);\n return this.restoreCircularRefs(parsed);\n } catch (error) {\n console.error('SyntropyFront: Error en deserialización:', error);\n return null;\n }\n }\n\n /**\n * Restaura referencias circulares en un objeto deserializado\n * @param {any} obj - Objeto a restaurar\n * @param {Map} refs - Mapa de referencias\n * @returns {any} Objeto con referencias restauradas\n */\n restoreCircularRefs(obj, refs = new Map()) {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {\n return obj;\n }\n\n // Restaurar tipos especiales\n if (obj.__type === 'Date') {\n return new Date(obj.value);\n }\n\n if (obj.__type === 'Error') {\n const error = new Error(obj.message);\n error.name = obj.name;\n error.stack = obj.stack;\n if (obj.cause) {\n error.cause = this.restoreCircularRefs(obj.cause, refs);\n }\n return error;\n }\n\n if (obj.__type === 'RegExp') {\n return new RegExp(obj.source, obj.flags);\n }\n\n if (obj.__type === 'Function') {\n // No podemos restaurar funciones completamente, devolvemos info\n return `[Function: ${obj.name}]`;\n }\n\n // Arrays\n if (Array.isArray(obj)) {\n const result = [];\n refs.set(obj, result);\n\n for (let i = 0; i < obj.length; i++) {\n if (obj[i] && obj[i].__circular) {\n const refId = obj[i].refId;\n if (refs.has(refId)) {\n result[i] = refs.get(refId);\n } else {\n result[i] = null; // Referencia no encontrada\n }\n } else {\n result[i] = this.restoreCircularRefs(obj[i], refs);\n }\n }\n\n return result;\n }\n\n // Objetos\n if (typeof obj === 'object') {\n const result = {};\n refs.set(obj, result);\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n if (key.startsWith('__')) {\n // Propiedades especiales\n continue;\n }\n\n const value = obj[key];\n if (value && value.__circular) {\n const refId = value.refId;\n if (refs.has(refId)) {\n result[key] = refs.get(refId);\n } else {\n result[key] = null; // Referencia no encontrada\n }\n } else {\n result[key] = this.restoreCircularRefs(value, refs);\n }\n }\n }\n\n return result;\n }\n\n return obj;\n }\n\n /**\n * Serializa de forma segura para logging (versión simplificada)\n * @param {any} obj - Objeto a serializar\n * @returns {string} JSON string seguro para logs\n */\n serializeForLogging(obj) {\n try {\n return this.serialize(obj);\n } catch (error) {\n return JSON.stringify({\n __logError: true,\n message: 'Error serializando para logging',\n originalError: error.message,\n timestamp: new Date().toISOString()\n });\n }\n }\n}\n\n// Instancia singleton\nexport const robustSerializer = new RobustSerializer(); ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * HttpTransport - Maneja el envío HTTP\n * Responsabilidad única: Gestionar envío HTTP y serialización\n */\nexport class HttpTransport {\n constructor(configManager) {\n this.config = configManager;\n }\n\n /**\n * Envía datos al backend\n * @param {Array} items - Items a enviar\n */\n async send(items) {\n const payload = {\n timestamp: new Date().toISOString(),\n items\n };\n\n // ✅ SERIALIZACIÓN ROBUSTA: Usar serializador que maneja referencias circulares\n let serializedPayload;\n try {\n serializedPayload = robustSerializer.serialize(payload);\n } catch (error) {\n console.error('SyntropyFront: Error en serialización del payload:', error);\n \n // Fallback: intentar serialización básica con información de error\n serializedPayload = JSON.stringify({\n __serializationError: true,\n error: error.message,\n timestamp: new Date().toISOString(),\n itemsCount: items.length,\n fallbackData: 'Serialización falló, datos no enviados'\n });\n }\n\n const response = await fetch(this.config.endpoint, {\n method: 'POST',\n headers: this.config.headers,\n body: serializedPayload\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return response.json();\n }\n\n /**\n * Aplica encriptación si está configurada\n * @param {*} data - Datos a encriptar\n */\n applyEncryption(data) {\n if (this.config.encrypt) {\n return this.config.encrypt(data);\n }\n return data;\n }\n\n /**\n * Verifica si el transport está configurado\n */\n isConfigured() {\n return !!this.config.endpoint;\n }\n} ","/**\n * DatabaseConfigManager - Maneja la configuración de IndexedDB\n * Responsabilidad única: Validar y gestionar la configuración de la base de datos\n */\nexport class DatabaseConfigManager {\n constructor(dbName, dbVersion, storeName) {\n this.dbName = dbName;\n this.dbVersion = dbVersion;\n this.storeName = storeName;\n }\n\n /**\n * Valida que la configuración sea correcta\n * @returns {Object} Resultado de validación\n */\n validateConfig() {\n const validationResult = {\n isValid: true,\n errors: [],\n timestamp: new Date().toISOString()\n };\n\n if (!this.dbName || typeof this.dbName !== 'string') {\n validationResult.isValid = false;\n validationResult.errors.push('dbName debe ser un string no vacío');\n }\n\n if (!this.dbVersion || typeof this.dbVersion !== 'number' || this.dbVersion < 1) {\n validationResult.isValid = false;\n validationResult.errors.push('dbVersion debe ser un número mayor a 0');\n }\n\n if (!this.storeName || typeof this.storeName !== 'string') {\n validationResult.isValid = false;\n validationResult.errors.push('storeName debe ser un string no vacío');\n }\n\n return validationResult;\n }\n\n /**\n * Verifica si IndexedDB está disponible en el entorno\n * @returns {Object} Resultado de disponibilidad\n */\n checkIndexedDBAvailability() {\n const availabilityResult = {\n isAvailable: false,\n reason: null,\n timestamp: new Date().toISOString()\n };\n\n if (typeof window === 'undefined') {\n availabilityResult.reason = 'No estamos en un entorno de browser';\n return availabilityResult;\n }\n\n if (!window.indexedDB) {\n availabilityResult.reason = 'IndexedDB no está disponible en este browser';\n return availabilityResult;\n }\n\n availabilityResult.isAvailable = true;\n return availabilityResult;\n }\n\n /**\n * Obtiene la configuración actual\n * @returns {Object} Configuración\n */\n getConfig() {\n return {\n dbName: this.dbName,\n dbVersion: this.dbVersion,\n storeName: this.storeName\n };\n }\n\n /**\n * Crea la configuración del object store\n * @returns {Object} Configuración del store\n */\n getStoreConfig() {\n return {\n keyPath: 'id',\n autoIncrement: true\n };\n }\n} ","/**\n * DatabaseConnectionManager - Maneja la conexión con IndexedDB\n * Responsabilidad única: Gestionar la apertura y cierre de conexiones\n */\nexport class DatabaseConnectionManager {\n constructor(configManager) {\n this.configManager = configManager;\n this.db = null;\n this.isAvailable = false;\n }\n\n /**\n * Inicializa la conexión con IndexedDB\n * @returns {Promise<Object>} Resultado de la inicialización\n */\n async init() {\n const initResult = {\n success: false,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n // Validar configuración\n const configValidation = this.configManager.validateConfig();\n if (!configValidation.isValid) {\n initResult.error = `Configuración inválida: ${configValidation.errors.join(', ')}`;\n return initResult;\n }\n\n // Verificar disponibilidad de IndexedDB\n const availabilityCheck = this.configManager.checkIndexedDBAvailability();\n if (!availabilityCheck.isAvailable) {\n initResult.error = availabilityCheck.reason;\n return initResult;\n }\n\n // Abrir conexión\n const connectionResult = await this.openConnection();\n if (!connectionResult.success) {\n initResult.error = connectionResult.error;\n return initResult;\n }\n\n this.db = connectionResult.db;\n this.isAvailable = true;\n initResult.success = true;\n\n return initResult;\n } catch (error) {\n initResult.error = `Error inesperado: ${error.message}`;\n return initResult;\n }\n }\n\n /**\n * Abre la conexión con IndexedDB\n * @returns {Promise<Object>} Resultado de la conexión\n */\n openConnection() {\n return new Promise((resolve) => {\n const config = this.configManager.getConfig();\n const request = indexedDB.open(config.dbName, config.dbVersion);\n\n request.onerror = () => {\n resolve({\n success: false,\n error: 'Error abriendo IndexedDB',\n db: null\n });\n };\n\n request.onupgradeneeded = (event) => {\n const db = event.target.result;\n const storeConfig = this.configManager.getStoreConfig();\n \n if (!db.objectStoreNames.contains(config.storeName)) {\n db.createObjectStore(config.storeName, storeConfig);\n }\n };\n\n request.onsuccess = () => {\n resolve({\n success: true,\n error: null,\n db: request.result\n });\n };\n });\n }\n\n /**\n * Cierra la conexión con la base de datos\n * @returns {Object} Resultado del cierre\n */\n close() {\n const closeResult = {\n success: false,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n if (this.db) {\n this.db.close();\n this.db = null;\n this.isAvailable = false;\n closeResult.success = true;\n } else {\n closeResult.error = 'No hay conexión activa para cerrar';\n }\n } catch (error) {\n closeResult.error = `Error cerrando conexión: ${error.message}`;\n }\n\n return closeResult;\n }\n\n /**\n * Verifica si la base de datos está disponible\n * @returns {boolean} True si está disponible\n */\n isDatabaseAvailable() {\n return this.isAvailable && this.db !== null;\n }\n\n /**\n * Obtiene la instancia de la base de datos\n * @returns {IDBDatabase|null} Instancia de la base de datos\n */\n getDatabase() {\n return this.isDatabaseAvailable() ? this.db : null;\n }\n} ","/**\n * DatabaseTransactionManager - Maneja las transacciones de IndexedDB\n * Responsabilidad única: Gestionar transacciones de lectura y escritura\n */\nexport class DatabaseTransactionManager {\n constructor(connectionManager, configManager) {\n this.connectionManager = connectionManager;\n this.configManager = configManager;\n }\n\n /**\n * Obtiene una transacción de lectura\n * @returns {IDBTransaction} Transacción de lectura\n * @throws {Error} Si la base de datos no está disponible\n */\n getReadTransaction() {\n this.ensureDatabaseAvailable();\n \n const config = this.configManager.getConfig();\n const db = this.connectionManager.getDatabase();\n \n return db.transaction([config.storeName], 'readonly');\n }\n\n /**\n * Obtiene una transacción de escritura\n * @returns {IDBTransaction} Transacción de escritura\n * @throws {Error} Si la base de datos no está disponible\n */\n getWriteTransaction() {\n this.ensureDatabaseAvailable();\n \n const config = this.configManager.getConfig();\n const db = this.connectionManager.getDatabase();\n \n return db.transaction([config.storeName], 'readwrite');\n }\n\n /**\n * Obtiene el object store para una transacción\n * @param {IDBTransaction} transaction - Transacción activa\n * @returns {IDBObjectStore} Object store\n */\n getObjectStore(transaction) {\n const config = this.configManager.getConfig();\n return transaction.objectStore(config.storeName);\n }\n\n /**\n * Ejecuta una operación de lectura de manera segura\n * @param {Function} operation - Operación a ejecutar\n * @returns {Promise<Object>} Resultado de la operación\n */\n async executeReadOperation(operation) {\n const operationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const transaction = this.getReadTransaction();\n const store = this.getObjectStore(transaction);\n \n const result = await operation(store);\n \n operationResult.success = true;\n operationResult.data = result;\n \n return operationResult;\n } catch (error) {\n operationResult.error = `Error en operación de lectura: ${error.message}`;\n return operationResult;\n }\n }\n\n /**\n * Ejecuta una operación de escritura de manera segura\n * @param {Function} operation - Operación a ejecutar\n * @returns {Promise<Object>} Resultado de la operación\n */\n async executeWriteOperation(operation) {\n const operationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const transaction = this.getWriteTransaction();\n const store = this.getObjectStore(transaction);\n \n const result = await operation(store);\n \n operationResult.success = true;\n operationResult.data = result;\n \n return operationResult;\n } catch (error) {\n operationResult.error = `Error en operación de escritura: ${error.message}`;\n return operationResult;\n }\n }\n\n /**\n * Verifica que la base de datos esté disponible\n * @throws {Error} Si la base de datos no está disponible\n */\n ensureDatabaseAvailable() {\n if (!this.connectionManager.isDatabaseAvailable()) {\n throw new Error('Database not available');\n }\n }\n\n /**\n * Obtiene información sobre el estado de las transacciones\n * @returns {Object} Estado de las transacciones\n */\n getTransactionStatus() {\n return {\n isDatabaseAvailable: this.connectionManager.isDatabaseAvailable(),\n storeName: this.configManager.getConfig().storeName,\n timestamp: new Date().toISOString()\n };\n }\n} ","import { DatabaseConfigManager } from './DatabaseConfigManager.js';\nimport { DatabaseConnectionManager } from './DatabaseConnectionManager.js';\nimport { DatabaseTransactionManager } from './DatabaseTransactionManager.js';\n\n/**\n * DatabaseManager - Coordinador de la gestión de IndexedDB\n * Responsabilidad única: Coordinar los managers especializados\n */\nexport class DatabaseManager {\n constructor(dbName, dbVersion, storeName) {\n this.configManager = new DatabaseConfigManager(dbName, dbVersion, storeName);\n this.connectionManager = new DatabaseConnectionManager(this.configManager);\n this.transactionManager = new DatabaseTransactionManager(this.connectionManager, this.configManager);\n }\n\n /**\n * Inicializa la conexión con IndexedDB\n */\n async init() {\n const initResult = await this.connectionManager.init();\n \n if (initResult.success) {\n console.log('SyntropyFront: Base de datos inicializada');\n } else {\n console.warn('SyntropyFront: Error inicializando base de datos:', initResult.error);\n }\n \n return initResult.success;\n }\n\n /**\n * Obtiene una transacción de lectura\n */\n getReadTransaction() {\n return this.transactionManager.getReadTransaction();\n }\n\n /**\n * Obtiene una transacción de escritura\n */\n getWriteTransaction() {\n return this.transactionManager.getWriteTransaction();\n }\n\n /**\n * Cierra la conexión con la base de datos\n */\n close() {\n const closeResult = this.connectionManager.close();\n \n if (!closeResult.success) {\n console.warn('SyntropyFront: Error cerrando base de datos:', closeResult.error);\n }\n \n return closeResult.success;\n }\n\n /**\n * Verifica si la base de datos está disponible\n */\n isDatabaseAvailable() {\n return this.connectionManager.isDatabaseAvailable();\n }\n\n // ===== Propiedades de compatibilidad =====\n \n /**\n * @deprecated Usar configManager.getConfig().dbName\n */\n get dbName() {\n return this.configManager.dbName;\n }\n\n /**\n * @deprecated Usar configManager.getConfig().dbVersion\n */\n get dbVersion() {\n return this.configManager.dbVersion;\n }\n\n /**\n * @deprecated Usar configManager.getConfig().storeName\n */\n get storeName() {\n return this.configManager.storeName;\n }\n\n /**\n * @deprecated Usar connectionManager.getDatabase()\n */\n get db() {\n return this.connectionManager.getDatabase();\n }\n\n /**\n * @deprecated Usar connectionManager.isDatabaseAvailable()\n */\n get isAvailable() {\n return this.connectionManager.isDatabaseAvailable();\n }\n}\n","/**\n * StorageManager - Maneja las operaciones CRUD de IndexedDB\n * Responsabilidad única: Gestionar operaciones de almacenamiento y recuperación\n */\nexport class StorageManager {\n constructor(databaseManager, serializationManager) {\n this.databaseManager = databaseManager;\n this.serializationManager = serializationManager;\n }\n\n /**\n * Guarda items en el almacenamiento\n * @param {Array} items - Items a guardar\n * @returns {Promise<number>} ID del item guardado\n */\n async save(items) {\n this.ensureDatabaseAvailable();\n\n const serializationResult = this.serializationManager.serialize(items);\n const serializedData = this.serializationManager.getData(serializationResult, '[]');\n\n const item = {\n items: serializedData,\n timestamp: new Date().toISOString(),\n retryCount: 0,\n serializationError: serializationResult.error\n };\n\n return this.executeWriteOperation(store => store.add(item));\n }\n\n /**\n * Obtiene todos los items del almacenamiento\n * @returns {Promise<Array>} Items deserializados\n */\n async retrieve() {\n if (!this.databaseManager.isDatabaseAvailable()) {\n return [];\n }\n\n const rawItems = await this.executeReadOperation(store => store.getAll());\n return this.deserializeItems(rawItems);\n }\n\n /**\n * Obtiene un item específico por ID\n * @param {number} id - ID del item\n * @returns {Promise<Object|null>} Item deserializado o null\n */\n async retrieveById(id) {\n if (!this.databaseManager.isDatabaseAvailable()) {\n return null;\n }\n\n const rawItem = await this.executeReadOperation(store => store.get(id));\n return rawItem ? this.deserializeItem(rawItem) : null;\n }\n\n /**\n * Remueve un item del almacenamiento\n * @param {number} id - ID del item a remover\n * @returns {Promise<void>}\n */\n async remove(id) {\n this.ensureDatabaseAvailable();\n return this.executeWriteOperation(store => store.delete(id));\n }\n\n /**\n * Actualiza un item en el almacenamiento\n * @param {number} id - ID del item\n * @param {Object} updates - Campos a actualizar\n * @returns {Promise<number>} ID del item actualizado\n */\n async update(id, updates) {\n this.ensureDatabaseAvailable();\n\n const currentItem = await this.retrieveById(id);\n if (!currentItem) {\n throw new Error('Item not found');\n }\n\n const updatedItem = { ...currentItem, ...updates };\n return this.executeWriteOperation(store => store.put(updatedItem));\n }\n\n /**\n * Limpia todo el almacenamiento\n * @returns {Promise<void>}\n */\n async clear() {\n this.ensureDatabaseAvailable();\n return this.executeWriteOperation(store => store.clear());\n }\n\n // ===== Métodos privados declarativos =====\n\n /**\n * Verifica que la base de datos esté disponible\n * @throws {Error} Si la base de datos no está disponible\n */\n ensureDatabaseAvailable() {\n if (!this.databaseManager.isDatabaseAvailable()) {\n throw new Error('Database not available');\n }\n }\n\n /**\n * Ejecuta una operación de lectura de manera declarativa\n * @param {Function} operation - Operación a ejecutar en el store\n * @returns {Promise<*>} Resultado de la operación\n */\n executeReadOperation(operation) {\n return new Promise((resolve, reject) => {\n try {\n const transaction = this.databaseManager.getReadTransaction();\n const store = transaction.objectStore(this.databaseManager.storeName);\n const request = operation(store);\n \n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Ejecuta una operación de escritura de manera declarativa\n * @param {Function} operation - Operación a ejecutar en el store\n * @returns {Promise<*>} Resultado de la operación\n */\n executeWriteOperation(operation) {\n return new Promise((resolve, reject) => {\n try {\n const transaction = this.databaseManager.getWriteTransaction();\n const store = transaction.objectStore(this.databaseManager.storeName);\n const request = operation(store);\n \n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Deserializa un array de items\n * @param {Array} rawItems - Items crudos de la base de datos\n * @returns {Array} Items deserializados\n */\n deserializeItems(rawItems) {\n return rawItems.map(item => this.deserializeItem(item));\n }\n\n /**\n * Deserializa un item individual\n * @param {Object} rawItem - Item crudo de la base de datos\n * @returns {Object} Item deserializado\n */\n deserializeItem(rawItem) {\n const deserializationResult = this.serializationManager.deserialize(rawItem.items);\n const deserializedItems = this.serializationManager.getData(deserializationResult, []);\n\n return {\n ...rawItem,\n items: deserializedItems,\n deserializationError: deserializationResult.error\n };\n }\n} ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * RetryLogicManager - Maneja la lógica de reintentos y limpieza\n * Responsabilidad única: Gestionar reintentos y limpieza de items fallidos\n */\nexport class RetryLogicManager {\n constructor(storageManager, configManager) {\n this.storageManager = storageManager;\n this.config = configManager;\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removeCallback - Callback para remover items exitosos\n */\n async retryFailedItems(sendCallback, removeCallback) {\n if (!this.storageManager) {\n console.warn('SyntropyFront: Storage manager no disponible');\n return;\n }\n\n try {\n const failedItems = await this.storageManager.retrieve();\n \n for (const item of failedItems) {\n if (item.retryCount < this.config.maxRetries) {\n // Deserializar items del buffer\n let deserializedItems;\n try {\n if (typeof item.items === 'string') {\n deserializedItems = robustSerializer.deserialize(item.items);\n } else {\n deserializedItems = item.items;\n }\n } catch (error) {\n console.error('SyntropyFront: Error deserializando items del buffer:', error);\n await this.removeFailedItem(item.id);\n continue;\n }\n \n if (sendCallback) {\n try {\n await sendCallback(deserializedItems, item.retryCount + 1, item.id);\n \n // Si el envío fue exitoso, remover del buffer\n if (removeCallback) {\n await removeCallback(item.id);\n } else {\n await this.removeFailedItem(item.id);\n }\n \n console.log(`SyntropyFront: Reintento exitoso para item ${item.id}`);\n } catch (error) {\n console.warn(`SyntropyFront: Reintento falló para item ${item.id}:`, error);\n \n // Incrementar contador de reintentos\n await this.incrementRetryCount(item.id);\n }\n }\n } else {\n console.warn(`SyntropyFront: Item ${item.id} excedió máximo de reintentos, removiendo del buffer`);\n await this.removeFailedItem(item.id);\n }\n }\n } catch (error) {\n console.error('SyntropyFront: Error procesando reintentos:', error);\n }\n }\n\n /**\n * Incrementa el contador de reintentos de un item\n * @param {number} id - ID del item\n */\n async incrementRetryCount(id) {\n try {\n const currentItem = await this.storageManager.retrieveById(id);\n if (currentItem) {\n await this.storageManager.update(id, {\n retryCount: currentItem.retryCount + 1\n });\n }\n } catch (error) {\n console.error('SyntropyFront: Error incrementando contador de reintentos:', error);\n }\n }\n\n /**\n * Remueve un item fallido del buffer\n * @param {number} id - ID del item\n */\n async removeFailedItem(id) {\n try {\n await this.storageManager.remove(id);\n } catch (error) {\n console.error('SyntropyFront: Error removiendo item fallido:', error);\n }\n }\n\n /**\n * Limpia items que han excedido el máximo de reintentos\n */\n async cleanupExpiredItems() {\n try {\n const allItems = await this.storageManager.retrieve();\n const expiredItems = allItems.filter(item => item.retryCount >= this.config.maxRetries);\n \n for (const item of expiredItems) {\n await this.removeFailedItem(item.id);\n console.warn(`SyntropyFront: Item ${item.id} removido por exceder máximo de reintentos`);\n }\n \n if (expiredItems.length > 0) {\n console.log(`SyntropyFront: Limpieza completada, ${expiredItems.length} items removidos`);\n }\n } catch (error) {\n console.error('SyntropyFront: Error en limpieza de items expirados:', error);\n }\n }\n\n /**\n * Obtiene estadísticas de reintentos\n */\n async getRetryStats() {\n try {\n const allItems = await this.storageManager.retrieve();\n \n const stats = {\n totalItems: allItems.length,\n itemsByRetryCount: {},\n averageRetryCount: 0\n };\n\n if (allItems.length > 0) {\n const totalRetries = allItems.reduce((sum, item) => sum + item.retryCount, 0);\n stats.averageRetryCount = totalRetries / allItems.length;\n \n allItems.forEach(item => {\n const retryCount = item.retryCount;\n stats.itemsByRetryCount[retryCount] = (stats.itemsByRetryCount[retryCount] || 0) + 1;\n });\n }\n\n return stats;\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo estadísticas de reintentos:', error);\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0\n };\n }\n }\n} ","import { robustSerializer } from '../../utils/RobustSerializer.js';\n\n/**\n * SerializationManager - Maneja la serialización y deserialización de datos\n * Responsabilidad única: Gestionar la transformación de datos para almacenamiento\n */\nexport class SerializationManager {\n constructor() {\n this.serializer = robustSerializer;\n }\n\n /**\n * Serializa items con manejo declarativo de errores\n * @param {Array} items - Items a serializar\n * @returns {Object} Resultado de serialización\n */\n serialize(items) {\n const serializationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const serializedData = this.serializer.serialize(items);\n return {\n ...serializationResult,\n success: true,\n data: serializedData\n };\n } catch (error) {\n return {\n ...serializationResult,\n error: this.createSerializationError(error),\n data: this.createFallbackData(error)\n };\n }\n }\n\n /**\n * Deserializa datos con manejo declarativo de errores\n * @param {string} serializedData - Datos serializados\n * @returns {Object} Resultado de deserialización\n */\n deserialize(serializedData) {\n const deserializationResult = {\n success: false,\n data: null,\n error: null,\n timestamp: new Date().toISOString()\n };\n\n try {\n const deserializedData = this.serializer.deserialize(serializedData);\n return {\n ...deserializationResult,\n success: true,\n data: deserializedData\n };\n } catch (error) {\n return {\n ...deserializationResult,\n error: this.createDeserializationError(error),\n data: []\n };\n }\n }\n\n /**\n * Crea un error de serialización estructurado\n * @param {Error} error - Error original\n * @returns {Object} Error estructurado\n */\n createSerializationError(error) {\n return {\n type: 'serialization_error',\n message: error.message,\n originalError: error,\n timestamp: new Date().toISOString()\n };\n }\n\n /**\n * Crea un error de deserialización estructurado\n * @param {Error} error - Error original\n * @returns {Object} Error estructurado\n */\n createDeserializationError(error) {\n return {\n type: 'deserialization_error',\n message: error.message,\n originalError: error,\n timestamp: new Date().toISOString()\n };\n }\n\n /**\n * Crea datos de fallback cuando falla la serialización\n * @param {Error} error - Error que causó el fallback\n * @returns {string} Datos de fallback serializados\n */\n createFallbackData(error) {\n const fallbackPayload = {\n __serializationError: true,\n error: error.message,\n timestamp: new Date().toISOString(),\n fallbackData: 'Items no serializables - usando fallback'\n };\n\n return JSON.stringify(fallbackPayload);\n }\n\n /**\n * Verifica si un resultado de serialización fue exitoso\n * @param {Object} result - Resultado de serialización/deserialización\n * @returns {boolean} True si fue exitoso\n */\n isSuccessful(result) {\n return Boolean(result && result.success === true);\n }\n\n /**\n * Obtiene los datos de un resultado, con fallback\n * @param {Object} result - Resultado de serialización/deserialización\n * @param {*} fallback - Valor por defecto si falla\n * @returns {*} Datos o fallback\n */\n getData(result, fallback = null) {\n return this.isSuccessful(result) ? result.data : fallback;\n }\n} ","import { DatabaseManager } from '../database/DatabaseManager.js';\nimport { StorageManager } from '../database/StorageManager.js';\nimport { RetryLogicManager } from '../retry/RetryLogicManager.js';\nimport { SerializationManager } from '../database/SerializationManager.js';\n\n/**\n * PersistentBufferManager - Coordinador del buffer persistente\n * Responsabilidad única: Coordinar los componentes de almacenamiento persistente\n */\nexport class PersistentBufferManager {\n constructor(configManager) {\n this.config = configManager;\n this.usePersistentBuffer = false;\n \n // Inicializar componentes especializados\n this.databaseManager = new DatabaseManager(\n 'SyntropyFrontBuffer',\n 1,\n 'failedItems'\n );\n \n this.serializationManager = new SerializationManager();\n this.storageManager = new StorageManager(this.databaseManager, this.serializationManager);\n this.retryLogicManager = new RetryLogicManager(this.storageManager, this.config);\n \n // Inicializar buffer persistente si está disponible\n this.initPersistentBuffer();\n }\n\n /**\n * Inicializa el buffer persistente\n */\n async initPersistentBuffer() {\n try {\n const success = await this.databaseManager.init();\n if (success) {\n this.usePersistentBuffer = this.config.usePersistentBuffer;\n console.log('SyntropyFront: Buffer persistente inicializado');\n }\n } catch (error) {\n console.warn('SyntropyFront: Error inicializando buffer persistente:', error);\n }\n }\n\n /**\n * Guarda items fallidos en el buffer persistente\n * @param {Array} items - Items a guardar\n */\n async save(items) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.save(items);\n console.log('SyntropyFront: Items guardados en buffer persistente');\n } catch (error) {\n console.error('SyntropyFront: Error guardando en buffer persistente:', error);\n }\n }\n\n /**\n * Obtiene items fallidos del buffer persistente\n */\n async retrieve() {\n if (!this.usePersistentBuffer) {\n return [];\n }\n\n try {\n return await this.storageManager.retrieve();\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo del buffer persistente:', error);\n return [];\n }\n }\n\n /**\n * Remueve items del buffer persistente\n * @param {number} id - ID del item a remover\n */\n async remove(id) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.remove(id);\n } catch (error) {\n console.error('SyntropyFront: Error removiendo del buffer persistente:', error);\n }\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n * @param {Function} sendCallback - Callback para enviar items\n * @param {Function} removeCallback - Callback para remover items exitosos\n */\n async retryFailedItems(sendCallback, removeCallback) {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n await this.retryLogicManager.retryFailedItems(sendCallback, removeCallback);\n }\n\n /**\n * Limpia items que han excedido el máximo de reintentos\n */\n async cleanupExpiredItems() {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n await this.retryLogicManager.cleanupExpiredItems();\n }\n\n /**\n * Obtiene estadísticas del buffer persistente\n */\n async getStats() {\n if (!this.usePersistentBuffer) {\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0,\n isAvailable: false\n };\n }\n\n try {\n const retryStats = await this.retryLogicManager.getRetryStats();\n return {\n ...retryStats,\n isAvailable: this.isAvailable()\n };\n } catch (error) {\n console.error('SyntropyFront: Error obteniendo estadísticas:', error);\n return {\n totalItems: 0,\n itemsByRetryCount: {},\n averageRetryCount: 0,\n isAvailable: this.isAvailable()\n };\n }\n }\n\n /**\n * Verifica si el buffer persistente está disponible\n */\n isAvailable() {\n return this.usePersistentBuffer && this.databaseManager.isDatabaseAvailable();\n }\n\n /**\n * Limpia todo el buffer persistente\n */\n async clear() {\n if (!this.usePersistentBuffer) {\n return;\n }\n\n try {\n await this.storageManager.clear();\n console.log('SyntropyFront: Buffer persistente limpiado');\n } catch (error) {\n console.error('SyntropyFront: Error limpiando buffer persistente:', error);\n }\n }\n\n /**\n * Cierra la conexión con la base de datos\n */\n close() {\n this.databaseManager.close();\n this.usePersistentBuffer = false;\n }\n} ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ConfigurationManager } from './ConfigurationManager.js';\nimport { QueueManager } from './QueueManager.js';\nimport { RetryManager } from '../retry/RetryManager.js';\nimport { HttpTransport } from './HttpTransport.js';\nimport { PersistentBufferManager } from '../persistent/PersistentBufferManager.js';\n\n/**\n * Agent - Envía datos de trazabilidad al backend\n * Coordinador que usa componentes especializados para cada responsabilidad\n */\nexport class Agent {\n constructor() {\n // Componentes especializados\n this.config = new ConfigurationManager();\n this.queue = new QueueManager(this.config);\n this.retry = new RetryManager(this.config);\n this.transport = new HttpTransport(this.config);\n this.buffer = new PersistentBufferManager(this.config);\n \n // Configurar callbacks para coordinación\n this.setupCallbacks();\n }\n\n /**\n * Configura callbacks para coordinación entre componentes\n */\n setupCallbacks() {\n // Callback para el QueueManager cuando hace flush\n this.queue.flushCallback = async (items) => {\n try {\n await this.transport.send(items);\n console.log('SyntropyFront: Datos enviados exitosamente');\n } catch (error) {\n console.error('SyntropyFront Agent: Error enviando datos:', error);\n \n // Agregar a cola de reintentos\n this.retry.addToRetryQueue(items);\n \n // Guardar en buffer persistente\n await this.buffer.save(items);\n }\n };\n\n // Callback para el RetryManager cuando procesa reintentos\n this.retry.sendCallback = async (items) => {\n return await this.transport.send(items);\n };\n\n this.retry.removePersistentCallback = async (id) => {\n await this.buffer.remove(id);\n };\n\n // Callback para el PersistentBufferManager cuando retry items\n this.buffer.sendCallback = (items, retryCount, persistentId) => {\n this.retry.addToRetryQueue(items, retryCount, persistentId);\n };\n }\n\n\n\n /**\n * Configura el agent\n * @param {Object} config - Configuración del agent\n */\n configure(config) {\n this.config.configure(config);\n }\n\n /**\n * Envía un error al backend\n * @param {Object} errorPayload - Payload del error\n * @param {Object} context - Contexto adicional (opcional)\n */\n sendError(errorPayload, context = null) {\n if (!this.config.isAgentEnabled()) {\n console.warn('SyntropyFront Agent: No configurado, error no enviado');\n return;\n }\n\n // Agregar contexto si está disponible\n const payloadWithContext = context ? {\n ...errorPayload,\n context\n } : errorPayload;\n\n // Aplicar encriptación si está configurada\n const dataToSend = this.transport.applyEncryption(payloadWithContext);\n\n this.queue.add({\n type: 'error',\n data: dataToSend,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Envía breadcrumbs al backend\n * @param {Array} breadcrumbs - Lista de breadcrumbs\n */\n sendBreadcrumbs(breadcrumbs) {\n // Solo enviar breadcrumbs si está habilitado (batchTimeout configurado)\n if (!this.config.isAgentEnabled() || !this.config.shouldSendBreadcrumbs() || !breadcrumbs.length) {\n return;\n }\n\n // Aplicar encriptación si está configurada\n const dataToSend = this.transport.applyEncryption(breadcrumbs);\n\n this.queue.add({\n type: 'breadcrumbs',\n data: dataToSend,\n timestamp: new Date().toISOString()\n });\n }\n\n /**\n * Añade un item a la cola de envío (método público para compatibilidad)\n * @param {Object} item - Item a añadir\n */\n addToQueue(item) {\n this.queue.add(item);\n }\n\n /**\n * Añade items a la cola de reintentos (método público para compatibilidad)\n * @param {Array} items - Items a reintentar\n * @param {number} retryCount - Número de reintento\n * @param {number} persistentId - ID en buffer persistente (opcional)\n */\n addToRetryQueue(items, retryCount = 1, persistentId = null) {\n this.retry.addToRetryQueue(items, retryCount, persistentId);\n }\n\n /**\n * Procesa la cola de reintentos (método público para compatibilidad)\n */\n async processRetryQueue() {\n await this.retry.processRetryQueue(\n this.retry.sendCallback,\n this.retry.removePersistentCallback\n );\n }\n\n /**\n * Envía todos los items en cola\n */\n async flush() {\n await this.queue.flush(this.queue.flushCallback);\n }\n\n /**\n * Fuerza el envío inmediato de todos los datos pendientes\n */\n async forceFlush() {\n await this.flush();\n \n // También intentar enviar items en cola de reintentos\n if (!this.retry.isEmpty()) {\n console.log('SyntropyFront: Intentando enviar items en cola de reintentos...');\n await this.processRetryQueue();\n }\n }\n\n /**\n * Obtiene estadísticas del agent\n * @returns {Object} Estadísticas\n */\n getStats() {\n const config = this.config.getConfig();\n return {\n queueLength: this.queue.getSize(),\n retryQueueLength: this.retry.getSize(),\n isEnabled: this.config.isAgentEnabled(),\n usePersistentBuffer: config.usePersistentBuffer,\n maxRetries: config.maxRetries\n };\n }\n\n /**\n * Intenta enviar items fallidos del buffer persistente\n */\n async retryFailedItems() {\n await this.buffer.retryFailedItems(this.buffer.sendCallback);\n }\n\n /**\n * Desactiva el agent\n */\n disable() {\n this.config.configure({ endpoint: null }); // Deshabilitar\n this.queue.clear();\n this.retry.clear();\n }\n}\n\n// Instancia singleton\nexport const agent = new Agent(); ","/**\n * ContextCollector - Recolector dinámico de contexto\n * Sistema elegante para recolectar datos según lo que pida el usuario\n * Por defecto: Sets curados y seguros\n * Configuración específica: El usuario elige exactamente qué quiere\n */\nexport class ContextCollector {\n constructor() {\n // Sets curados por defecto (seguros y útiles)\n this.defaultContexts = {\n device: {\n userAgent: () => navigator.userAgent,\n language: () => navigator.language,\n screen: () => ({\n width: window.screen.width,\n height: window.screen.height\n }),\n timezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone\n },\n window: {\n url: () => window.location.href,\n viewport: () => ({\n width: window.innerWidth,\n height: window.innerHeight\n }),\n title: () => document.title\n },\n session: {\n sessionId: () => this.generateSessionId(),\n pageLoadTime: () => performance.now()\n },\n ui: {\n visibility: () => document.visibilityState,\n activeElement: () => document.activeElement ? {\n tagName: document.activeElement.tagName\n } : null\n },\n network: {\n online: () => navigator.onLine,\n connection: () => navigator.connection ? {\n effectiveType: navigator.connection.effectiveType\n } : null\n }\n };\n\n // Mapeo completo de todos los campos disponibles\n this.allFields = {\n device: {\n userAgent: () => navigator.userAgent,\n language: () => navigator.language,\n languages: () => navigator.languages,\n screen: () => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n colorDepth: window.screen.colorDepth,\n pixelDepth: window.screen.pixelDepth\n }),\n timezone: () => Intl.DateTimeFormat().resolvedOptions().timeZone,\n cookieEnabled: () => navigator.cookieEnabled,\n doNotTrack: () => navigator.doNotTrack\n },\n window: {\n url: () => window.location.href,\n pathname: () => window.location.pathname,\n search: () => window.location.search,\n hash: () => window.location.hash,\n referrer: () => document.referrer,\n title: () => document.title,\n viewport: () => ({\n width: window.innerWidth,\n height: window.innerHeight\n })\n },\n storage: {\n localStorage: () => {\n const keys = Object.keys(localStorage);\n return {\n keys: keys.length,\n size: JSON.stringify(localStorage).length,\n keyNames: keys // Solo nombres, no valores\n };\n },\n sessionStorage: () => {\n const keys = Object.keys(sessionStorage);\n return {\n keys: keys.length,\n size: JSON.stringify(sessionStorage).length,\n keyNames: keys // Solo nombres, no valores\n };\n }\n },\n network: {\n online: () => navigator.onLine,\n connection: () => navigator.connection ? {\n effectiveType: navigator.connection.effectiveType,\n downlink: navigator.connection.downlink,\n rtt: navigator.connection.rtt\n } : null\n },\n ui: {\n focused: () => document.hasFocus(),\n visibility: () => document.visibilityState,\n activeElement: () => document.activeElement ? {\n tagName: document.activeElement.tagName,\n id: document.activeElement.id,\n className: document.activeElement.className\n } : null\n },\n performance: {\n memory: () => window.performance && window.performance.memory ? {\n used: Math.round(window.performance.memory.usedJSHeapSize / 1048576),\n total: Math.round(window.performance.memory.totalJSHeapSize / 1048576),\n limit: Math.round(window.performance.memory.jsHeapSizeLimit / 1048576)\n } : null,\n timing: () => window.performance ? {\n navigationStart: window.performance.timing.navigationStart,\n loadEventEnd: window.performance.timing.loadEventEnd\n } : null\n },\n session: {\n sessionId: () => this.generateSessionId(),\n startTime: () => new Date().toISOString(),\n pageLoadTime: () => performance.now()\n }\n };\n }\n\n /**\n * Recolecta contexto según la configuración\n * @param {Object} contextConfig - Configuración de contexto\n * @returns {Object} Contexto recolectado\n */\n collect(contextConfig = {}) {\n const context = {};\n\n Object.entries(contextConfig).forEach(([contextType, config]) => {\n try {\n if (config === true) {\n // Usar set curado por defecto\n context[contextType] = this.collectDefaultContext(contextType);\n } else if (Array.isArray(config)) {\n // Configuración específica: array de campos\n context[contextType] = this.collectSpecificFields(contextType, config);\n } else if (config === false) {\n // Explícitamente deshabilitado\n // No hacer nada\n } else {\n console.warn(`SyntropyFront: Configuración de contexto inválida para ${contextType}:`, config);\n }\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando contexto ${contextType}:`, error);\n context[contextType] = { error: 'Failed to collect' };\n }\n });\n\n return context;\n }\n\n /**\n * Recolecta el set curado por defecto\n * @param {string} contextType - Tipo de contexto\n * @returns {Object} Contexto por defecto\n */\n collectDefaultContext(contextType) {\n const defaultContext = this.defaultContexts[contextType];\n if (!defaultContext) {\n console.warn(`SyntropyFront: No hay set por defecto para ${contextType}`);\n return {};\n }\n\n const result = {};\n Object.entries(defaultContext).forEach(([field, getter]) => {\n try {\n result[field] = getter();\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando campo ${field} de ${contextType}:`, error);\n result[field] = null;\n }\n });\n\n return result;\n }\n\n /**\n * Recolecta campos específicos\n * @param {string} contextType - Tipo de contexto\n * @param {Array} fields - Campos específicos a recolectar\n * @returns {Object} Contexto específico\n */\n collectSpecificFields(contextType, fields) {\n const allFields = this.allFields[contextType];\n if (!allFields) {\n console.warn(`SyntropyFront: Tipo de contexto desconocido: ${contextType}`);\n return {};\n }\n\n const result = {};\n fields.forEach(field => {\n try {\n if (allFields[field]) {\n result[field] = allFields[field]();\n } else {\n console.warn(`SyntropyFront: Campo ${field} no disponible en ${contextType}`);\n }\n } catch (error) {\n console.warn(`SyntropyFront: Error recolectando campo ${field} de ${contextType}:`, error);\n result[field] = null;\n }\n });\n\n return result;\n }\n\n /**\n * Genera un ID de sesión seguro usando crypto.randomUUID() cuando esté disponible\n * @returns {string} ID de sesión seguro\n */\n generateSecureId() {\n try {\n // Intentar usar crypto.randomUUID() si está disponible (Node.js 14.17+, browsers modernos)\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n \n // Fallback para navegadores más antiguos: usar crypto.getRandomValues()\n if (typeof crypto !== 'undefined' && crypto.getRandomValues) {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n \n // Convertir a formato UUID v4\n const hex = Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32)\n ].join('-');\n }\n \n // Fallback final: timestamp + random (menos seguro pero funcional)\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 15);\n return `${timestamp}-${random}`;\n } catch (error) {\n console.warn('SyntropyFront: Error generando ID seguro, usando fallback:', error);\n // Fallback de emergencia\n return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;\n }\n }\n\n /**\n * Genera un ID de sesión simple\n */\n generateSessionId() {\n if (!this._sessionId) {\n this._sessionId = `session_${this.generateSecureId()}`;\n }\n return this._sessionId;\n }\n\n /**\n * Obtiene la lista de tipos de contexto disponibles\n * @returns {Array} Tipos disponibles\n */\n getAvailableTypes() {\n return Object.keys(this.allFields);\n }\n\n /**\n * Obtiene la lista de campos disponibles para un tipo de contexto\n * @param {string} contextType - Tipo de contexto\n * @returns {Array} Campos disponibles\n */\n getAvailableFields(contextType) {\n const fields = this.allFields[contextType];\n return fields ? Object.keys(fields) : [];\n }\n\n /**\n * Obtiene información sobre los sets por defecto\n * @returns {Object} Información de sets por defecto\n */\n getDefaultContextsInfo() {\n const info = {};\n Object.entries(this.defaultContexts).forEach(([type, fields]) => {\n info[type] = Object.keys(fields);\n });\n return info;\n }\n}\n\n// Instancia singleton\nexport const contextCollector = new ContextCollector(); ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { breadcrumbStore } from '../core/breadcrumbs/BreadcrumbStore.js';\nimport { agent } from '../core/agent/Agent.js';\nimport { contextCollector } from '../core/context/ContextCollector.js';\n\n/**\n * Interceptors - Observadores que capturan eventos automáticamente\n * Implementa Chaining Pattern para coexistir con otros APMs\n */\nexport class Interceptors {\n constructor() {\n this.isInitialized = false;\n this.config = {\n captureClicks: true,\n captureFetch: true,\n captureErrors: true,\n captureUnhandledRejections: true\n };\n this.contextTypes = [];\n\n // Referencias originales para restaurar en destroy()\n this.originalHandlers = {\n fetch: null,\n onerror: null,\n onunhandledrejection: null\n };\n\n // Event listeners para limpiar\n this.eventListeners = new Map();\n }\n\n /**\n * Configura los interceptores\n * @param {Object} config - Configuración de interceptores\n */\n configure(config) {\n this.config = { ...this.config, ...config };\n this.contextTypes = config.context || [];\n }\n\n /**\n * Inicializa todos los interceptores\n */\n init() {\n if (this.isInitialized) {\n console.warn('SyntropyFront: Interceptors ya están inicializados');\n return;\n }\n\n if (this.config.captureClicks) {\n this.setupClickInterceptor();\n }\n\n if (this.config.captureFetch) {\n this.setupFetchInterceptor();\n }\n\n if (this.config.captureErrors || this.config.captureUnhandledRejections) {\n this.setupErrorInterceptors();\n }\n\n this.isInitialized = true;\n console.log('SyntropyFront: Interceptors inicializados con Chaining Pattern');\n }\n\n /**\n * Intercepta clics de usuario\n */\n setupClickInterceptor() {\n // Solo configurar en el browser\n if (typeof document === 'undefined') {\n console.log('SyntropyFront: Click interceptor no disponible (no browser)');\n return;\n }\n\n let lastClickTime = 0;\n const THROTTLE_MS = 500;\n\n const clickHandler = (event) => {\n const el = event.target;\n if (!el) return;\n\n // ✅ THROTTLE: Evitar ráfagas de clicks (ej: double clicks accidentales)\n const now = Date.now();\n if (now - lastClickTime < THROTTLE_MS) return;\n lastClickTime = now;\n\n // ✅ FILTER: Solo capturar elementos potencialmente interactivos\n const isInteractive = (element) => {\n if (!element || element.nodeType !== 1) return false;\n const interactiveTags = ['a', 'button', 'input', 'select', 'textarea', 'label', 'summary'];\n const isClickableRole = ['button', 'link', 'checkbox', 'radio', 'menuitem'].includes(element.getAttribute?.('role'));\n\n let hasPointerCursor = false;\n try {\n hasPointerCursor = window.getComputedStyle?.(element)?.cursor === 'pointer';\n } catch (e) {\n // Ignorar errores en entornos donde getComputedStyle falla (ej: JSDOM con mocks incompletos)\n }\n\n return interactiveTags.includes(element.tagName.toLowerCase()) || isClickableRole || hasPointerCursor;\n };\n\n // Si el elemento no es interactivo, buscar hacia arriba en el DOM (bubbling)\n let target = el;\n while (target && target !== document.body) {\n if (isInteractive(target)) break;\n target = target.parentElement;\n }\n\n // Si no encontramos un elemento interactivo, ignoramos el click (reduce ruido)\n if (!target || target === document.body) return;\n\n // Genera un selector CSS simple para identificar el elemento\n let selector = target.tagName.toLowerCase();\n if (target.id) {\n selector += `#${target.id}`;\n } else if (target.className && typeof target.className === 'string') {\n selector += `.${target.className.split(' ').filter(Boolean).join('.')}`;\n }\n\n breadcrumbStore.add({\n category: 'ui',\n message: `Usuario hizo click en '${selector}'`,\n data: {\n selector,\n tagName: target.tagName,\n id: target.id,\n className: target.className,\n text: target.innerText?.substring(0, 30).trim() || target.value?.substring(0, 30)\n }\n });\n };\n\n // Guardar referencia para limpiar después\n this.eventListeners.set('click', clickHandler);\n document.addEventListener('click', clickHandler, true);\n }\n\n /**\n * Intercepta llamadas de red (fetch) con Chaining\n */\n setupFetchInterceptor() {\n // Solo configurar en el browser\n if (typeof window === 'undefined' || !window.fetch) {\n console.log('SyntropyFront: Fetch interceptor no disponible (no browser/fetch)');\n return;\n }\n\n // Guardar referencia original\n this.originalHandlers.fetch = window.fetch;\n\n // Crear nuevo handler que encadena con el original\n const syntropyFetchHandler = (...args) => {\n const url = args[0] instanceof Request ? args[0].url : args[0];\n const method = args[0] instanceof Request ? args[0].method : (args[1]?.method || 'GET');\n\n breadcrumbStore.add({\n category: 'network',\n message: `Request: ${method} ${url}`,\n data: {\n url,\n method,\n timestamp: Date.now()\n }\n });\n\n // ✅ CHAINING: Llamar al handler original\n return this.originalHandlers.fetch.apply(window, args);\n };\n\n // Sobrescribir con el nuevo handler\n window.fetch = syntropyFetchHandler;\n }\n\n /**\n * Intercepta errores globales con Chaining\n */\n setupErrorInterceptors() {\n // Solo configurar en el browser\n if (typeof window === 'undefined') {\n console.log('SyntropyFront: Error interceptors no disponibles (no browser)');\n return;\n }\n\n if (this.config.captureErrors) {\n // Guardar referencia original\n this.originalHandlers.onerror = window.onerror;\n\n // Crear nuevo handler que encadena con el original\n const syntropyErrorHandler = (message, source, lineno, colno, error) => {\n const errorPayload = {\n type: 'uncaught_exception',\n error: {\n message,\n source,\n lineno,\n colno,\n stack: error?.stack\n },\n breadcrumbs: breadcrumbStore.getAll(),\n timestamp: new Date().toISOString()\n };\n\n this.handleError(errorPayload);\n\n // ✅ CHAINING: Llamar al handler original si existe\n if (this.originalHandlers.onerror) {\n try {\n return this.originalHandlers.onerror(message, source, lineno, colno, error);\n } catch (originalError) {\n console.warn('SyntropyFront: Error en handler original:', originalError);\n return false;\n }\n }\n\n return false; // No prevenir el error por defecto\n };\n\n // Sobrescribir con el nuevo handler\n window.onerror = syntropyErrorHandler;\n }\n\n if (this.config.captureUnhandledRejections) {\n // Guardar referencia original\n this.originalHandlers.onunhandledrejection = window.onunhandledrejection;\n\n // Crear nuevo handler que encadena con el original\n const syntropyRejectionHandler = (event) => {\n const errorPayload = {\n type: 'unhandled_rejection',\n error: {\n message: event.reason?.message || 'Rechazo de promesa sin mensaje',\n stack: event.reason?.stack,\n },\n breadcrumbs: breadcrumbStore.getAll(),\n timestamp: new Date().toISOString()\n };\n\n this.handleError(errorPayload);\n\n // ✅ CHAINING: Llamar al handler original si existe\n if (this.originalHandlers.onunhandledrejection) {\n try {\n this.originalHandlers.onunhandledrejection(event);\n } catch (originalError) {\n console.warn('SyntropyFront: Error en handler original de rejection:', originalError);\n }\n }\n };\n\n // Sobrescribir con el nuevo handler\n window.onunhandledrejection = syntropyRejectionHandler;\n }\n }\n\n /**\n * Maneja los errores capturados\n * @param {Object} errorPayload - Payload del error\n */\n handleError(errorPayload) {\n // Recolectar contexto si está configurado\n const context = this.contextTypes.length > 0 ? contextCollector.collect(this.contextTypes) : null;\n\n // Enviar al agent si está configurado\n agent.sendError(errorPayload, context);\n\n // Callback para manejo personalizado de errores\n if (this.onError) {\n this.onError(errorPayload);\n } else {\n // Comportamiento por defecto: log a consola\n console.error('SyntropyFront - Error detectado:', errorPayload);\n }\n }\n\n /**\n * Desactiva todos los interceptores y restaura handlers originales\n */\n destroy() {\n if (!this.isInitialized) return;\n\n console.log('SyntropyFront: Limpiando interceptores...');\n\n // ✅ RESTAURAR: Handlers originales\n if (this.originalHandlers.fetch) {\n window.fetch = this.originalHandlers.fetch;\n console.log('SyntropyFront: fetch original restaurado');\n }\n\n if (this.originalHandlers.onerror) {\n window.onerror = this.originalHandlers.onerror;\n console.log('SyntropyFront: onerror original restaurado');\n }\n\n if (this.originalHandlers.onunhandledrejection) {\n window.onunhandledrejection = this.originalHandlers.onunhandledrejection;\n console.log('SyntropyFront: onunhandledrejection original restaurado');\n }\n\n // ✅ LIMPIAR: Event listeners\n if (typeof document !== 'undefined') {\n this.eventListeners.forEach((handler, eventType) => {\n document.removeEventListener(eventType, handler, true);\n console.log(`SyntropyFront: Event listener ${eventType} removido`);\n });\n }\n\n // Limpiar referencias\n this.originalHandlers = {\n fetch: null,\n onerror: null,\n onunhandledrejection: null\n };\n this.eventListeners.clear();\n this.isInitialized = false;\n\n console.log('SyntropyFront: Interceptors destruidos y handlers restaurados');\n }\n\n /**\n * Obtiene información sobre los handlers originales\n * @returns {Object} Información de handlers\n */\n getHandlerInfo() {\n return {\n isInitialized: this.isInitialized,\n hasOriginalFetch: !!this.originalHandlers.fetch,\n hasOriginalOnError: !!this.originalHandlers.onerror,\n hasOriginalOnUnhandledRejection: !!this.originalHandlers.onunhandledrejection,\n eventListenersCount: this.eventListeners.size\n };\n }\n}\n\n// Instancia singleton\nexport const interceptors = new Interceptors(); ","/**\n * Copyright 2024 Syntropysoft\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * SyntropyFront - Biblioteca de observabilidad con captura automática\n * Actúa como Facade conectando el Agent y los Interceptors modulares\n */\nimport { breadcrumbStore } from './core/breadcrumbs/BreadcrumbStore.js';\nimport { agent } from './core/agent/Agent.js';\nimport { interceptors } from './interceptors/Interceptors.js';\n\nclass SyntropyFront {\n constructor() {\n this.isActive = false;\n this.config = {\n maxEvents: 50,\n endpoint: null,\n headers: {},\n usePersistentBuffer: true,\n captureClicks: true,\n captureFetch: true,\n captureErrors: true,\n captureUnhandledRejections: true,\n onError: null\n };\n\n // Auto-inicializar\n this.init();\n }\n\n /**\n * Inicializa la biblioteca y activa los interceptores\n */\n init() {\n if (this.isActive) return;\n\n // Configurar el agent por defecto\n agent.configure({\n endpoint: this.config.endpoint,\n headers: this.config.headers,\n usePersistentBuffer: this.config.usePersistentBuffer\n });\n\n // Inicializar interceptores\n interceptors.configure({\n captureClicks: this.config.captureClicks,\n captureFetch: this.config.captureFetch,\n captureErrors: this.config.captureErrors,\n captureUnhandledRejections: this.config.captureUnhandledRejections\n });\n\n // Inyectar callback de error si existe\n if (this.config.onError) {\n interceptors.onError = this.config.onError;\n }\n\n interceptors.init();\n\n // Intentar reintentar items fallidos de sesiones previas\n agent.retryFailedItems().catch(err => {\n console.warn('SyntropyFront: Error al intentar recuperar items persistentes:', err);\n });\n\n this.isActive = true;\n console.log('🚀 SyntropyFront: Inicializado con arquitectura modular resiliente');\n }\n\n /**\n * Configura SyntropyFront\n * @param {Object} config - Configuración\n */\n configure(config = {}) {\n // Actualizar configuración local\n this.config = { ...this.config, ...config };\n\n // Si se pasa 'fetch', extraer endpoint y headers por compatibilidad\n if (config.fetch) {\n this.config.endpoint = config.fetch.url;\n this.config.headers = config.fetch.options?.headers || {};\n }\n\n // Re-configurar componentes internos\n agent.configure({\n endpoint: this.config.endpoint,\n headers: this.config.headers,\n usePersistentBuffer: this.config.usePersistentBuffer\n });\n\n interceptors.configure({\n captureClicks: this.config.captureClicks,\n captureFetch: this.config.captureFetch,\n captureErrors: this.config.captureErrors,\n captureUnhandledRejections: this.config.captureUnhandledRejections\n });\n\n if (this.config.onError) {\n interceptors.onError = this.config.onError;\n }\n\n const mode = this.config.endpoint ? `endpoint: ${this.config.endpoint}` : 'console only';\n console.log(`✅ SyntropyFront: Configurado - ${mode}`);\n }\n\n /**\n * Añade un breadcrumb manualmente\n */\n addBreadcrumb(category, message, data = {}) {\n return breadcrumbStore.add({ category, message, data });\n }\n\n /**\n * Obtiene todos los breadcrumbs\n */\n getBreadcrumbs() {\n return breadcrumbStore.getAll();\n }\n\n /**\n * Limpia los breadcrumbs\n */\n clearBreadcrumbs() {\n breadcrumbStore.clear();\n }\n\n /**\n * Envía un error manualmente con contexto\n */\n sendError(error, context = {}) {\n const errorPayload = {\n type: 'manual_error',\n error: {\n message: error.message || String(error),\n name: error.name || 'Error',\n stack: error.stack\n },\n breadcrumbs: this.getBreadcrumbs(),\n timestamp: new Date().toISOString()\n };\n\n agent.sendError(errorPayload, context);\n return errorPayload;\n }\n\n /**\n * Fuerza el envío de datos pendientes\n */\n async flush() {\n await agent.forceFlush();\n }\n\n /**\n * Obtiene estadísticas de uso\n */\n getStats() {\n return {\n isActive: this.isActive,\n breadcrumbs: breadcrumbStore.count(),\n agent: agent.getStats(),\n config: { ...this.config }\n };\n }\n\n /**\n * Desactiva la biblioteca y restaura hooks originales\n */\n destroy() {\n interceptors.destroy();\n agent.disable();\n this.isActive = false;\n console.log('SyntropyFront: Desactivado');\n }\n}\n\n// Instancia única (Singleton)\nconst syntropyFront = new SyntropyFront();\n\n// Exportar la instancia por defecto\nexport default syntropyFront;"],"names":["breadcrumbStore","constructor","maxBreadcrumbs","this","breadcrumbs","agent","setAgent","setMaxBreadcrumbs","length","slice","getMaxBreadcrumbs","add","crumb","breadcrumb","timestamp","Date","toISOString","shift","push","onBreadcrumbAdded","isEnabled","sendBreadcrumbs","error","console","warn","getAll","clear","getByCategory","category","filter","b","ConfigurationManager","endpoint","headers","batchSize","batchTimeout","encrypt","usePersistentBuffer","maxRetries","baseDelay","maxDelay","configure","config","isAgentEnabled","shouldSendBreadcrumbs","getConfig","QueueManager","configManager","queue","batchTimer","flushCallback","item","flush","setTimeout","clearTimer","clearTimeout","getSize","isEmpty","itemsToSend","RetryManager","retryQueue","retryTimer","addToRetryQueue","items","retryCount","persistentId","delay","Math","min","pow","nextRetry","now","scheduleRetry","nextItem","find","processRetryQueue","max","sendCallback","removePersistentCallback","itemsToRetry","q","log","robustSerializer","seen","WeakSet","circularRefs","Map","refCounter","serialize","obj","safeObj","makeSerializable","JSON","stringify","__serializationError","message","originalType","isObject","path","__type","value","Error","name","stack","cause","undefined","RegExp","source","flags","Array","isArray","has","__circular","refId","get","set","map","index","result","key","Object","prototype","hasOwnProperty","call","safeValue","propertyName","getOwnPropertySymbols","symbols","symbol","description","symbolName","toString","substring","String","deserialize","jsonString","parsed","parse","restoreCircularRefs","refs","i","startsWith","serializeForLogging","__logError","originalError","HttpTransport","send","payload","serializedPayload","itemsCount","fallbackData","response","fetch","method","body","ok","status","statusText","json","applyEncryption","data","isConfigured","DatabaseConfigManager","dbName","dbVersion","storeName","validateConfig","validationResult","isValid","errors","checkIndexedDBAvailability","availabilityResult","isAvailable","reason","window","indexedDB","getStoreConfig","keyPath","autoIncrement","DatabaseConnectionManager","db","init","initResult","success","configValidation","join","availabilityCheck","connectionResult","openConnection","Promise","resolve","request","open","onerror","onupgradeneeded","event","target","storeConfig","objectStoreNames","contains","createObjectStore","onsuccess","close","closeResult","isDatabaseAvailable","getDatabase","DatabaseTransactionManager","connectionManager","getReadTransaction","ensureDatabaseAvailable","transaction","getWriteTransaction","getObjectStore","objectStore","executeReadOperation","operation","operationResult","store","executeWriteOperation","getTransactionStatus","DatabaseManager","transactionManager","StorageManager","databaseManager","serializationManager","save","serializationResult","getData","serializationError","retrieve","rawItems","deserializeItems","retrieveById","id","rawItem","deserializeItem","remove","delete","update","updates","currentItem","updatedItem","put","reject","deserializationResult","deserializedItems","deserializationError","RetryLogicManager","storageManager","retryFailedItems","removeCallback","failedItems","removeFailedItem","incrementRetryCount","cleanupExpiredItems","expiredItems","getRetryStats","allItems","stats","totalItems","itemsByRetryCount","averageRetryCount","totalRetries","reduce","sum","forEach","SerializationManager","serializer","serializedData","createSerializationError","createFallbackData","deserializedData","createDeserializationError","type","fallbackPayload","isSuccessful","Boolean","fallback","PersistentBufferManager","retryLogicManager","initPersistentBuffer","getStats","retry","transport","buffer","setupCallbacks","async","sendError","errorPayload","context","payloadWithContext","dataToSend","addToQueue","forceFlush","queueLength","retryQueueLength","disable","contextCollector","defaultContexts","device","userAgent","navigator","language","screen","width","height","timezone","Intl","DateTimeFormat","resolvedOptions","timeZone","url","location","href","viewport","innerWidth","innerHeight","title","document","session","sessionId","generateSessionId","pageLoadTime","performance","ui","visibility","visibilityState","activeElement","tagName","network","online","onLine","connection","effectiveType","allFields","languages","availWidth","availHeight","colorDepth","pixelDepth","cookieEnabled","doNotTrack","pathname","search","hash","referrer","storage","localStorage","keys","size","keyNames","sessionStorage","downlink","rtt","focused","hasFocus","className","memory","used","round","usedJSHeapSize","total","totalJSHeapSize","limit","jsHeapSizeLimit","timing","navigationStart","loadEventEnd","startTime","collect","contextConfig","entries","contextType","collectDefaultContext","collectSpecificFields","defaultContext","field","getter","fields","generateSecureId","crypto","randomUUID","getRandomValues","array","Uint8Array","hex","from","byte","padStart","random","_sessionId","getAvailableTypes","getAvailableFields","getDefaultContextsInfo","info","interceptors","isInitialized","captureClicks","captureFetch","captureErrors","captureUnhandledRejections","contextTypes","originalHandlers","onunhandledrejection","eventListeners","setupClickInterceptor","setupFetchInterceptor","setupErrorInterceptors","lastClickTime","clickHandler","el","isInteractive","element","nodeType","isClickableRole","includes","getAttribute","hasPointerCursor","getComputedStyle","cursor","e","toLowerCase","parentElement","selector","split","text","innerText","trim","addEventListener","args","Request","apply","syntropyErrorHandler","lineno","colno","handleError","syntropyRejectionHandler","onError","destroy","handler","eventType","removeEventListener","getHandlerInfo","hasOriginalFetch","hasOriginalOnError","hasOriginalOnUnhandledRejection","eventListenersCount","isActive","maxEvents","catch","err","options","mode","addBreadcrumb","getBreadcrumbs","clearBreadcrumbs","count"],"mappings":"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"}