@sschepis/magazine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +167 -0
- package/dist/magazine.cjs.js +5 -0
- package/dist/magazine.cjs.js.map +1 -0
- package/dist/magazine.es.js +4149 -0
- package/dist/magazine.es.js.map +1 -0
- package/dist/magazine.umd.js +5 -0
- package/dist/magazine.umd.js.map +1 -0
- package/package.json +74 -0
- package/src/components/ConfigManager.js +202 -0
- package/src/components/ConfigSchema.js +506 -0
- package/src/components/DataCompressor.js +378 -0
- package/src/components/DataTransformer.js +1172 -0
- package/src/components/DebugUtils.js +657 -0
- package/src/components/EventFilter.js +474 -0
- package/src/components/EventMetadata.js +273 -0
- package/src/components/EventStore.js +443 -0
- package/src/components/EventSyncer.js +353 -0
- package/src/components/Logger.js +299 -0
- package/src/components/NetworkManager.js +461 -0
- package/src/components/Paginator.js +343 -0
- package/src/index.js +571 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"magazine.cjs.js","sources":["../src/components/Logger.js","../src/components/ConfigSchema.js","../src/components/ConfigManager.js","../src/components/NetworkManager.js","../src/components/EventFilter.js","../src/components/Paginator.js","../src/components/DataCompressor.js","../src/components/EventStore.js","../src/components/EventSyncer.js","../src/components/EventMetadata.js","../src/components/DebugUtils.js","../src/components/DataTransformer.js","../src/index.js"],"sourcesContent":["/**\n * Logger - Structured logging system with configurable levels\n */\nexport default class Logger {\n constructor(config = {}) {\n this.level = config.level || 'info';\n this.context = config.context || 'Magazine';\n this.enableConsole = config.enableConsole !== false;\n this.enableFile = config.enableFile || false;\n this.filePath = config.filePath || './magazine.log';\n\n // File logging state (lazily initialized)\n this._fsModule = null;\n this._fsAvailable = null; // null = not yet checked, true/false after init\n\n // Log levels with numeric values for comparison\n this.levels = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4\n };\n\n this.currentLevelValue = this.levels[this.level.toLowerCase()] || this.levels.info;\n\n // Initialize file logging if enabled\n if (this.enableFile) {\n this._initFileLogging();\n }\n }\n\n // Create a formatted log entry\n _formatLog(level, message, data = {}) {\n const timestamp = new Date().toISOString();\n const logEntry = {\n timestamp,\n level: level.toUpperCase(),\n context: this.context,\n message,\n ...data\n };\n\n return {\n formatted: `[${timestamp}] ${level.toUpperCase()} [${this.context}] ${message}${\n Object.keys(data).length > 0 ? ' ' + JSON.stringify(data, this._getCircularReplacer()) : ''\n }`,\n structured: logEntry\n };\n }\n\n // Get a replacer function to handle circular references in JSON.stringify\n _getCircularReplacer() {\n const seen = new WeakSet();\n return (key, value) => {\n if (typeof value === \"object\" && value !== null) {\n if (seen.has(value)) {\n return \"[Circular]\";\n }\n seen.add(value);\n }\n return value;\n };\n }\n\n // Check if current level allows logging at specified level\n _shouldLog(level) {\n const levelValue = this.levels[level.toLowerCase()];\n return levelValue !== undefined && levelValue <= this.currentLevelValue;\n }\n\n // Write log to console\n _writeToConsole(level, formatted) {\n if (!this.enableConsole) return;\n \n switch (level.toLowerCase()) {\n case 'error':\n console.error(formatted);\n break;\n case 'warn':\n console.warn(formatted);\n break;\n case 'debug':\n case 'trace':\n console.debug(formatted);\n break;\n default:\n console.log(formatted);\n }\n }\n\n // Initialize file system module for file logging\n _initFileLogging() {\n if (this._fsAvailable !== null) return; // already initialized\n\n try {\n // Use dynamic import to support both Node.js and browser environments.\n // import() returns a promise, so we kick it off here and store the result\n // once resolved. File writes before init completes are silently skipped.\n const fsPromise = import('fs');\n const pathPromise = import('path');\n\n Promise.all([fsPromise, pathPromise]).then(([fsModule, pathModule]) => {\n this._fsModule = fsModule.default || fsModule;\n this._pathModule = pathModule.default || pathModule;\n this._fsAvailable = true;\n }).catch(() => {\n this._fsAvailable = false;\n });\n } catch (_err) {\n // Static import() not available (older environments) - disable file logging\n this._fsAvailable = false;\n }\n }\n\n // Write log entry as a JSON line to the configured file\n _writeToFile(structured) {\n if (!this.enableFile) return;\n if (this._fsAvailable === false) return;\n if (!this._fsModule) return; // fs not yet loaded (async init still pending)\n\n try {\n const line = JSON.stringify(structured, this._getCircularReplacer()) + '\\n';\n this._fsModule.appendFileSync(this.filePath, line, 'utf8');\n } catch (_err) {\n // File logging failures must not crash the application\n }\n }\n\n // Rotate log file if it exceeds maxSizeBytes. Keeps 1 rotated backup.\n rotateLogs(maxSizeBytes = 10 * 1024 * 1024) {\n if (!this._fsModule || this._fsAvailable === false) return;\n\n try {\n if (!this._fsModule.existsSync(this.filePath)) return;\n\n const stats = this._fsModule.statSync(this.filePath);\n if (stats.size < maxSizeBytes) return;\n\n const backupPath = this.filePath + '.1';\n\n // Remove old backup if it exists, then rename current to backup\n if (this._fsModule.existsSync(backupPath)) {\n this._fsModule.unlinkSync(backupPath);\n }\n this._fsModule.renameSync(this.filePath, backupPath);\n\n // Start a fresh log file\n this._fsModule.writeFileSync(this.filePath, '', 'utf8');\n } catch (_err) {\n // Rotation failures must not crash the application\n }\n }\n\n // Core logging method\n _log(level, message, data = {}) {\n if (!this._shouldLog(level)) return;\n \n const { formatted, structured } = this._formatLog(level, message, data);\n \n this._writeToConsole(level, formatted);\n this._writeToFile(structured);\n \n return structured;\n }\n\n // Logging level methods\n error(message, data = {}) {\n return this._log('error', message, data);\n }\n\n warn(message, data = {}) {\n return this._log('warn', message, data);\n }\n\n info(message, data = {}) {\n return this._log('info', message, data);\n }\n\n debug(message, data = {}) {\n return this._log('debug', message, data);\n }\n\n trace(message, data = {}) {\n return this._log('trace', message, data);\n }\n\n // Performance logging - measure function execution time\n async time(operation, fn, context = {}) {\n const startTime = Date.now();\n const startMessage = `Starting operation: ${operation}`;\n \n this.debug(startMessage, context);\n \n try {\n const result = await fn();\n const duration = Date.now() - startTime;\n \n this.info(`Completed operation: ${operation}`, {\n ...context,\n duration: `${duration}ms`,\n success: true\n });\n \n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n \n this.error(`Failed operation: ${operation}`, {\n ...context,\n duration: `${duration}ms`,\n success: false,\n error: error?.message || error?.toString() || 'Unknown error',\n stack: error?.stack\n });\n \n throw error;\n }\n }\n\n // Create a child logger with additional context\n child(additionalContext = {}) {\n return new Logger({\n level: this.level,\n context: this.context,\n enableConsole: this.enableConsole,\n enableFile: this.enableFile,\n filePath: this.filePath,\n ...additionalContext\n });\n }\n\n // Change log level dynamically\n setLevel(level) {\n if (this.levels[level.toLowerCase()] !== undefined) {\n this.level = level.toLowerCase();\n this.currentLevelValue = this.levels[this.level];\n this.info(`Log level changed to: ${level.toUpperCase()}`);\n } else {\n this.warn(`Invalid log level: ${level}. Valid levels: ${Object.keys(this.levels).join(', ')}`);\n }\n }\n\n // Get current configuration\n getConfig() {\n return {\n level: this.level,\n context: this.context,\n enableConsole: this.enableConsole,\n enableFile: this.enableFile,\n filePath: this.filePath\n };\n }\n\n // Log system information\n logSystemInfo(info = {}) {\n this.info('System Information', {\n nodeVersion: process.version,\n platform: process.platform,\n arch: process.arch,\n memoryUsage: process.memoryUsage(),\n uptime: process.uptime(),\n ...info\n });\n }\n\n // Log network request/response\n logNetworkActivity(type, details = {}) {\n this.debug(`Network ${type}`, {\n type,\n timestamp: Date.now(),\n ...details\n });\n }\n\n // Log blockchain interaction\n logBlockchainActivity(operation, details = {}) {\n this.info(`Blockchain: ${operation}`, {\n operation,\n timestamp: Date.now(),\n ...details\n });\n }\n\n // Log Gun.js database activity\n logDatabaseActivity(operation, details = {}) {\n this.debug(`Database: ${operation}`, {\n operation,\n timestamp: Date.now(),\n ...details\n });\n }\n}\n\n// Export a default logger instance\nexport const defaultLogger = new Logger({\n level: 'info',\n context: 'Magazine'\n});","/**\n * ConfigSchema - Configuration schema definition and validation\n */\nexport default class ConfigSchema {\n constructor() {\n // Define the configuration schema\n this.schema = {\n // Required fields\n required: ['name', 'address', 'abi', 'provider'],\n \n // Field definitions\n fields: {\n name: {\n type: 'string',\n description: 'Name of the magazine',\n minLength: 1,\n maxLength: 100,\n pattern: /^[a-zA-Z0-9\\s\\-_]+$/,\n example: 'My Event Magazine'\n },\n \n address: {\n type: 'string',\n description: 'Contract address',\n pattern: /^0x[a-fA-F0-9]{40}$/,\n example: '0x1234567890123456789012345678901234567890'\n },\n \n abi: {\n type: 'array',\n description: 'Contract ABI',\n minItems: 1,\n items: {\n type: 'object',\n required: ['type'],\n properties: {\n type: {\n type: 'string',\n enum: ['function', 'event', 'constructor', 'fallback', 'receive']\n },\n name: { type: 'string' },\n inputs: { type: 'array' },\n outputs: { type: 'array' },\n anonymous: { type: 'boolean' }\n }\n }\n },\n \n provider: {\n type: ['string', 'object'],\n description: 'Ethereum provider URL or object',\n validate: (value) => {\n if (typeof value === 'string') {\n return value.startsWith('http://') || \n value.startsWith('https://') || \n value.startsWith('ws://') || \n value.startsWith('wss://');\n }\n return typeof value === 'object' && value !== null;\n },\n example: 'http://localhost:8545'\n },\n \n networkId: {\n type: 'number',\n description: 'Network ID',\n optional: true,\n min: 1,\n example: 1\n },\n \n gun: {\n type: 'object',\n description: 'Gun.js configuration',\n optional: true,\n properties: {\n peers: {\n type: 'array',\n items: { type: 'string' },\n example: ['http://localhost:8765/gun']\n },\n file: {\n type: 'string',\n example: 'radata'\n },\n localStorage: {\n type: 'boolean',\n default: true\n },\n radisk: {\n type: 'boolean',\n default: true\n },\n multicast: {\n type: ['boolean', 'object'],\n default: false\n },\n compression: {\n type: 'object',\n properties: {\n enabled: {\n type: 'boolean',\n default: true\n },\n strategy: {\n type: 'string',\n enum: ['none', 'json', 'gzip', 'optimized'],\n default: 'optimized'\n }\n }\n }\n }\n },\n \n logLevel: {\n type: 'string',\n description: 'Logging level',\n optional: true,\n enum: ['error', 'warn', 'info', 'debug', 'trace'],\n default: 'info'\n },\n \n maxRetries: {\n type: 'number',\n description: 'Maximum retry attempts',\n optional: true,\n min: 0,\n max: 10,\n default: 3\n },\n \n retryDelay: {\n type: 'number',\n description: 'Delay between retries in milliseconds',\n optional: true,\n min: 100,\n max: 60000,\n default: 1000\n },\n \n timeout: {\n type: 'number',\n description: 'Operation timeout in milliseconds',\n optional: true,\n min: 1000,\n max: 300000,\n default: 30000\n },\n \n batchSize: {\n type: 'number',\n description: 'Event sync batch size',\n optional: true,\n min: 1,\n max: 10000,\n default: 1000\n },\n \n startBlockNumber: {\n type: 'number',\n description: 'Starting block number for sync',\n optional: true,\n min: 0,\n default: 1\n },\n \n autoSync: {\n type: 'boolean',\n description: 'Enable automatic syncing',\n optional: true,\n default: false\n },\n \n syncInterval: {\n type: 'number',\n description: 'Auto-sync interval in milliseconds',\n optional: true,\n min: 10000,\n max: 3600000,\n default: 60000,\n dependsOn: 'autoSync'\n }\n }\n };\n \n // Validation error messages\n this.errorMessages = {\n required: (field) => `${field} is required`,\n type: (field, expected, actual) => `${field} must be of type ${expected}, got ${actual}`,\n minLength: (field, min) => `${field} must be at least ${min} characters long`,\n maxLength: (field, max) => `${field} must be at most ${max} characters long`,\n pattern: (field) => `${field} has invalid format`,\n min: (field, min) => `${field} must be at least ${min}`,\n max: (field, max) => `${field} must be at most ${max}`,\n enum: (field, values) => `${field} must be one of: ${values.join(', ')}`,\n minItems: (field, min) => `${field} must have at least ${min} items`,\n custom: (field, message) => `${field}: ${message}`\n };\n }\n\n /**\n * Validate configuration against schema\n * @param {Object} config - Configuration to validate\n * @returns {Object} Validation result\n */\n validate(config) {\n const errors = [];\n const warnings = [];\n const validated = {};\n \n // Check required fields\n for (const field of this.schema.required) {\n if (!config.hasOwnProperty(field) || config[field] === undefined || config[field] === null) {\n errors.push({\n field,\n type: 'required',\n message: this.errorMessages.required(field)\n });\n }\n }\n \n // Validate each field\n for (const [field, definition] of Object.entries(this.schema.fields)) {\n if (config.hasOwnProperty(field)) {\n const result = this._validateField(field, config[field], definition);\n \n if (result.errors.length > 0) {\n errors.push(...result.errors);\n } else {\n validated[field] = result.value;\n }\n \n if (result.warnings.length > 0) {\n warnings.push(...result.warnings);\n }\n } else if (!definition.optional && !this.schema.required.includes(field)) {\n // Field is not required but has a default value\n if (definition.hasOwnProperty('default')) {\n validated[field] = definition.default;\n }\n }\n }\n \n // Check for unknown fields\n for (const field of Object.keys(config)) {\n if (!this.schema.fields.hasOwnProperty(field)) {\n warnings.push({\n field,\n type: 'unknown',\n message: `Unknown configuration field: ${field}`\n });\n // Include unknown fields in validated config\n validated[field] = config[field];\n }\n }\n \n // Check field dependencies\n for (const [field, definition] of Object.entries(this.schema.fields)) {\n if (definition.dependsOn && validated[field] !== undefined) {\n if (!validated[definition.dependsOn]) {\n warnings.push({\n field,\n type: 'dependency',\n message: `${field} depends on ${definition.dependsOn} being set`\n });\n }\n }\n }\n \n return {\n valid: errors.length === 0,\n errors,\n warnings,\n validated\n };\n }\n\n /**\n * Validate a single field\n * @private\n */\n _validateField(field, value, definition) {\n const errors = [];\n const warnings = [];\n let validatedValue = value;\n \n // Type validation\n const actualType = Array.isArray(value) ? 'array' : typeof value;\n const expectedTypes = Array.isArray(definition.type) ? definition.type : [definition.type];\n \n if (!expectedTypes.includes(actualType)) {\n errors.push({\n field,\n type: 'type',\n message: this.errorMessages.type(field, expectedTypes.join(' or '), actualType)\n });\n return { errors, warnings, value };\n }\n \n // Apply transformation if defined\n if (definition.transform && typeof definition.transform === 'function') {\n validatedValue = definition.transform(validatedValue);\n }\n \n // String validations\n if (actualType === 'string') {\n if (definition.minLength && validatedValue.length < definition.minLength) {\n errors.push({\n field,\n type: 'minLength',\n message: this.errorMessages.minLength(field, definition.minLength)\n });\n }\n \n if (definition.maxLength && validatedValue.length > definition.maxLength) {\n errors.push({\n field,\n type: 'maxLength',\n message: this.errorMessages.maxLength(field, definition.maxLength)\n });\n }\n \n if (definition.pattern && !definition.pattern.test(validatedValue)) {\n errors.push({\n field,\n type: 'pattern',\n message: this.errorMessages.pattern(field)\n });\n }\n \n if (definition.enum && !definition.enum.includes(validatedValue)) {\n errors.push({\n field,\n type: 'enum',\n message: this.errorMessages.enum(field, definition.enum)\n });\n }\n }\n \n // Number validations\n if (actualType === 'number') {\n if (definition.min !== undefined && validatedValue < definition.min) {\n errors.push({\n field,\n type: 'min',\n message: this.errorMessages.min(field, definition.min)\n });\n }\n \n if (definition.max !== undefined && validatedValue > definition.max) {\n errors.push({\n field,\n type: 'max',\n message: this.errorMessages.max(field, definition.max)\n });\n }\n }\n \n // Array validations\n if (actualType === 'array') {\n if (definition.minItems && validatedValue.length < definition.minItems) {\n errors.push({\n field,\n type: 'minItems',\n message: this.errorMessages.minItems(field, definition.minItems)\n });\n }\n \n // Validate array items if schema is provided\n if (definition.items) {\n validatedValue.forEach((item, index) => {\n const itemResult = this._validateField(\n `${field}[${index}]`,\n item,\n definition.items\n );\n errors.push(...itemResult.errors);\n warnings.push(...itemResult.warnings);\n });\n }\n }\n \n // Object validations\n if (actualType === 'object' && definition.properties) {\n for (const [prop, propDef] of Object.entries(definition.properties)) {\n if (validatedValue.hasOwnProperty(prop)) {\n const propResult = this._validateField(\n `${field}.${prop}`,\n validatedValue[prop],\n propDef\n );\n errors.push(...propResult.errors);\n warnings.push(...propResult.warnings);\n }\n }\n }\n \n // Custom validation\n if (definition.validate && typeof definition.validate === 'function') {\n const isValid = definition.validate(validatedValue);\n if (!isValid) {\n errors.push({\n field,\n type: 'custom',\n message: this.errorMessages.custom(field, 'Custom validation failed')\n });\n }\n }\n \n return { errors, warnings, value: validatedValue };\n }\n\n /**\n * Get schema documentation\n * @returns {Object} Schema documentation\n */\n getDocumentation() {\n const docs = {\n description: 'Magazine configuration schema',\n required: this.schema.required,\n fields: {}\n };\n \n for (const [field, definition] of Object.entries(this.schema.fields)) {\n docs.fields[field] = {\n type: definition.type,\n description: definition.description,\n required: this.schema.required.includes(field),\n optional: definition.optional,\n default: definition.default,\n example: definition.example\n };\n \n if (definition.enum) {\n docs.fields[field].enum = definition.enum;\n }\n \n if (definition.min !== undefined || definition.max !== undefined) {\n docs.fields[field].range = {\n min: definition.min,\n max: definition.max\n };\n }\n \n if (definition.pattern) {\n docs.fields[field].pattern = definition.pattern.toString();\n }\n \n if (definition.dependsOn) {\n docs.fields[field].dependsOn = definition.dependsOn;\n }\n }\n \n return docs;\n }\n\n /**\n * Generate example configuration\n * @param {Object} options - Generation options\n * @returns {Object} Example configuration\n */\n generateExample(options = {}) {\n const { includeOptional = true, useDefaults = true } = options;\n const example = {};\n \n for (const [field, definition] of Object.entries(this.schema.fields)) {\n if (this.schema.required.includes(field) || (includeOptional && definition.optional)) {\n if (definition.example !== undefined) {\n example[field] = definition.example;\n } else if (useDefaults && definition.default !== undefined) {\n example[field] = definition.default;\n } else {\n // Generate a placeholder based on type\n example[field] = this._generatePlaceholder(definition);\n }\n }\n }\n \n return example;\n }\n\n /**\n * Generate placeholder value based on type\n * @private\n */\n _generatePlaceholder(definition) {\n const type = Array.isArray(definition.type) ? definition.type[0] : definition.type;\n \n switch (type) {\n case 'string':\n if (definition.enum) return definition.enum[0];\n return 'example-value';\n case 'number':\n if (definition.min !== undefined) return definition.min;\n return 0;\n case 'boolean':\n return false;\n case 'array':\n return [];\n case 'object':\n return {};\n default:\n return null;\n }\n }\n}","import Logger from './Logger.js';\nimport ConfigSchema from './ConfigSchema.js';\n\n/**\n * ConfigManager - Handles configuration validation and management using ConfigSchema\n * \n * @class ConfigManager\n * @description Provides comprehensive configuration validation, management, and documentation\n * using a formal schema-based approach for better error handling and developer experience.\n */\nexport default class ConfigManager {\n /**\n * Create a ConfigManager instance\n * @param {Object} config - Configuration object to validate and manage\n * @throws {Error} If configuration validation fails\n */\n constructor(config) {\n this.schema = new ConfigSchema();\n \n // Initialize logger with basic config for validation logging\n this.logger = new Logger({\n context: 'ConfigManager',\n level: config?.logLevel || 'info'\n });\n \n this.logger.debug('Initializing ConfigManager with schema validation', { \n config: this._sanitizeConfig(config) \n });\n \n // Validate and process configuration using schema\n const validationResult = this.validateConfig(config);\n \n if (!validationResult.valid) {\n const errorMessage = this._formatValidationErrors(validationResult.errors);\n this.logger.error('Configuration validation failed', { \n errors: validationResult.errors,\n warnings: validationResult.warnings \n });\n throw new Error(`Configuration validation failed:\\n${errorMessage}`);\n }\n \n // Log validation warnings if any\n if (validationResult.warnings.length > 0) {\n this.logger.warn('Configuration validation warnings', { \n warnings: validationResult.warnings \n });\n }\n \n // Use validated configuration\n this.config = validationResult.validated;\n \n this.logger.info('ConfigManager initialized successfully', {\n name: this.config.name,\n address: this.config.address,\n networkId: this.config.networkId,\n maxRetries: this.config.maxRetries,\n retryDelay: this.config.retryDelay,\n timeout: this.config.timeout,\n warningsCount: validationResult.warnings.length\n });\n }\n\n /**\n * Sanitize config for logging (remove sensitive data)\n * @private\n * @param {Object} config - Configuration object to sanitize\n * @returns {Object} Sanitized configuration object\n */\n _sanitizeConfig(config) {\n if (!config) return config;\n const sanitized = { ...config };\n // Remove potentially sensitive information\n if (sanitized.gun) {\n sanitized.gun = { ...sanitized.gun };\n delete sanitized.gun.peers; // May contain sensitive URLs\n }\n return sanitized;\n }\n\n /**\n * Validate configuration using ConfigSchema\n * @param {Object} config - Configuration object to validate\n * @returns {Object} Validation result with validated config\n */\n validateConfig(config) {\n if (!config || typeof config !== 'object') {\n return {\n valid: false,\n errors: [{\n field: 'config',\n type: 'required',\n message: 'Configuration must be a non-null object'\n }],\n warnings: [],\n validated: {}\n };\n }\n \n return this.schema.validate(config);\n }\n\n /**\n * Format validation errors into a readable string\n * @private\n * @param {Array} errors - Array of validation errors\n * @returns {string} Formatted error message\n */\n _formatValidationErrors(errors) {\n return errors.map(error => ` - ${error.field}: ${error.message}`).join('\\n');\n }\n\n /**\n * Get schema documentation\n * @returns {Object} Schema documentation object\n */\n getSchemaDocumentation() {\n return this.schema.getDocumentation();\n }\n\n /**\n * Generate example configuration\n * @param {Object} options - Generation options\n * @returns {Object} Example configuration object\n */\n generateExampleConfig(options = {}) {\n return this.schema.generateExample(options);\n }\n\n /**\n * Validate a configuration object without creating an instance\n * @static\n * @param {Object} config - Configuration to validate\n * @returns {Object} Validation result\n */\n static validateConfiguration(config) {\n const schema = new ConfigSchema();\n return schema.validate(config);\n }\n\n /**\n * Validate block number parameters\n * @param {number} blockNumber - Block number to validate\n * @param {string} paramName - Parameter name for error messages\n * @throws {Error} If block number is invalid\n */\n validateBlockNumber(blockNumber, paramName = 'blockNumber') {\n if (!Number.isInteger(blockNumber) || blockNumber < 0) {\n throw new Error(`${paramName} must be a non-negative integer`);\n }\n }\n\n /**\n * Validate options object for API methods\n * @param {Object} options - Options object to validate\n * @param {Array} allowedKeys - Array of allowed option keys\n * @returns {Object} Validated options object\n * @throws {Error} If options are invalid\n */\n validateOptions(options, allowedKeys = []) {\n if (options !== undefined && (typeof options !== 'object' || options === null)) {\n throw new Error('Options must be an object');\n }\n \n if (options && allowedKeys.length > 0) {\n const invalidKeys = Object.keys(options).filter(key => !allowedKeys.includes(key));\n if (invalidKeys.length > 0) {\n throw new Error(`Invalid option keys: ${invalidKeys.join(', ')}. Allowed: ${allowedKeys.join(', ')}`);\n }\n }\n \n return options || {};\n }\n\n /**\n * Get configuration value by key\n * @param {string} key - Configuration key\n * @returns {*} Configuration value\n */\n get(key) {\n return this.config[key];\n }\n\n /**\n * Get all configuration\n * @returns {Object} Complete configuration object\n */\n getAll() {\n return { ...this.config };\n }\n\n /**\n * Get retry options for network operations\n * @returns {Object} Retry configuration object\n */\n getRetryOptions() {\n return {\n maxRetries: this.config.maxRetries,\n retryDelay: this.config.retryDelay,\n timeout: this.config.timeout\n };\n }\n}","import * as ethers from 'ethers';\nimport Logger from './Logger.js';\n\n/**\n * LRUCache - Simple Least Recently Used cache using Map ordering\n */\nclass LRUCache {\n constructor(maxSize = 500) { this.maxSize = maxSize; this.cache = new Map(); }\n get(key) { if (!this.cache.has(key)) return undefined; const v = this.cache.get(key); this.cache.delete(key); this.cache.set(key, v); return v; }\n set(key, value) { if (this.cache.has(key)) this.cache.delete(key); else if (this.cache.size >= this.maxSize) this.cache.delete(this.cache.keys().next().value); this.cache.set(key, value); }\n clear() { this.cache.clear(); }\n get size() { return this.cache.size; }\n}\n\n/**\n * RateLimiter - Token-bucket rate limiter for throttling RPC calls\n */\nclass RateLimiter {\n constructor(maxPerSecond = 25) {\n this.maxPerSecond = maxPerSecond;\n this.tokens = maxPerSecond;\n this.lastRefill = Date.now();\n this.queue = [];\n }\n async acquire() {\n this._refill();\n if (this.tokens > 0) { this.tokens--; return; }\n return new Promise(resolve => this.queue.push(resolve));\n }\n _refill() {\n const now = Date.now();\n const elapsed = (now - this.lastRefill) / 1000;\n this.tokens = Math.min(this.maxPerSecond, this.tokens + elapsed * this.maxPerSecond);\n this.lastRefill = now;\n while (this.queue.length > 0 && this.tokens > 0) { this.tokens--; this.queue.shift()(); }\n }\n}\n\n/**\n * NetworkManager - Handles provider and network management\n *\n * Supports multi-provider failover, LRU caching for blocks/timestamps,\n * and token-bucket rate limiting for RPC calls.\n */\nexport default class NetworkManager {\n constructor(config, retryOperation) {\n this.config = config;\n this.retryOperation = retryOperation;\n this.logger = new Logger({\n context: 'NetworkManager',\n level: config?.logLevel || 'info'\n });\n\n this.logger.debug('Initializing NetworkManager', {\n provider: config.provider,\n networkId: config.networkId\n });\n\n // Multi-provider failover setup\n this.providers = [];\n this.currentProviderIndex = 0;\n this._initializeProviders(config.provider);\n\n // Set the active provider to the first one\n this.provider = this.providers[0];\n\n this.interface = new ethers.Interface(config.abi);\n\n // Initialize LRU caches for blocks and timestamps\n const cacheSize = config.cacheSize || 500;\n this.blockCache = new LRUCache(cacheSize);\n this.timestampCache = new LRUCache(cacheSize);\n this.logger.debug('LRU caches initialized', { cacheSize });\n\n // Initialize rate limiter\n const rateLimit = config.rateLimit || 25;\n this.rateLimiter = new RateLimiter(rateLimit);\n this.logger.debug('Rate limiter initialized', { maxPerSecond: rateLimit });\n\n // Initialize event mappings\n this.events = {};\n this.eventsByTopic = {}; // Map topic hash to event name\n\n this._initializeEvents();\n\n this.logger.info('NetworkManager initialized successfully', {\n eventCount: Object.keys(this.eventsByTopic).length,\n contractAddress: config.address,\n providerCount: this.providers.length\n });\n }\n\n /**\n * Initialize providers from config. Accepts a single provider (string or\n * ethers provider object) or an array of providers.\n */\n _initializeProviders(providerConfig) {\n const providerList = Array.isArray(providerConfig) ? providerConfig : [providerConfig];\n\n for (const entry of providerList) {\n if (typeof entry === 'string') {\n const provider = new ethers.JsonRpcProvider(entry);\n this.providers.push(provider);\n this.logger.debug('Created JsonRpcProvider from URL', { url: entry });\n } else if (entry && typeof entry.getNetwork === 'function') {\n this.providers.push(entry);\n this.logger.debug('Using provided ethers provider object', {\n providerType: entry.constructor.name\n });\n } else {\n throw new Error('Each provider must be either a string URL or an ethers provider object');\n }\n }\n\n if (this.providers.length === 0) {\n throw new Error('At least one provider must be specified');\n }\n\n this.logger.debug('Providers initialized', { count: this.providers.length });\n }\n\n /**\n * Switch to the next provider in the list on failure.\n * Returns true if a new provider was activated, false if all have been tried.\n */\n _switchProvider(error) {\n const previousIndex = this.currentProviderIndex;\n this.currentProviderIndex = (this.currentProviderIndex + 1) % this.providers.length;\n\n // If we've cycled back to the starting provider, all have been tried\n if (this.currentProviderIndex === previousIndex && this.providers.length === 1) {\n this.logger.error('Single provider failed, no failover available', {\n error: error.message\n });\n return false;\n }\n\n this.provider = this.providers[this.currentProviderIndex];\n this.logger.warn('Switching provider due to failure', {\n error: error.message,\n previousIndex,\n newIndex: this.currentProviderIndex,\n totalProviders: this.providers.length\n });\n\n return true;\n }\n\n /**\n * Execute a function through the rate limiter.\n * Acquires a token before executing the call.\n */\n async _throttledCall(fn) {\n await this.rateLimiter.acquire();\n return fn();\n }\n\n /**\n * Execute a provider call with failover support.\n * Tries each provider in sequence before giving up.\n */\n async _callWithFailover(fn, description) {\n const startIndex = this.currentProviderIndex;\n let lastError;\n let attempts = 0;\n\n do {\n try {\n return await this._throttledCall(() => fn(this.provider));\n } catch (error) {\n lastError = error;\n attempts++;\n this.logger.warn('Provider call failed', {\n description,\n providerIndex: this.currentProviderIndex,\n attempt: attempts,\n error: error.message\n });\n\n if (this.providers.length > 1) {\n this._switchProvider(error);\n // If we've rotated back to the start, stop\n if (this.currentProviderIndex === startIndex) {\n break;\n }\n } else {\n break;\n }\n }\n } while (true);\n\n throw lastError;\n }\n\n // Initialize event mappings from ABI\n _initializeEvents() {\n let eventCount = 0;\n\n for (const fragment of this.config.abi) {\n if (fragment.type === 'event') {\n const eventName = fragment.name;\n this.events[eventName] = new ethers.Interface([fragment]);\n\n // Create mapping from topic hash to event name\n try {\n const eventFragment = this.interface.getEvent(eventName);\n const topicHash = eventFragment.topicHash;\n this.eventsByTopic[topicHash] = eventName;\n eventCount++;\n\n this.logger.debug('Event mapping created', {\n eventName,\n topicHash\n });\n } catch (error) {\n this.logger.warn('Failed to get topic hash for event', {\n eventName,\n error: error.message\n });\n }\n }\n }\n\n this.logger.debug('Event initialization completed', { eventCount });\n }\n\n // Get the latest block number from the network\n async getLatestBlockNumber() {\n return this.logger.time('getLatestBlockNumber', async () => {\n const blockNumber = await this.retryOperation(\n () => this._callWithFailover(\n (provider) => provider.getBlockNumber(),\n 'getLatestBlockNumber'\n ),\n 'Getting latest block number'\n );\n\n this.logger.logNetworkActivity('getLatestBlockNumber', { blockNumber });\n return blockNumber;\n });\n }\n\n // Get logs from the blockchain within a block range\n async getLogs(fromBlock, toBlock) {\n return this.logger.time('getLogs', async () => {\n this.logger.logNetworkActivity('getLogs_request', { fromBlock, toBlock, address: this.config.address });\n\n const logs = await this.retryOperation(\n () => this._callWithFailover(\n (provider) => provider.getLogs({\n address: this.config.address,\n fromBlock,\n toBlock\n }),\n 'getLogs'\n ),\n `Getting logs for blocks ${fromBlock}-${toBlock}`\n );\n\n this.logger.logNetworkActivity('getLogs_response', {\n fromBlock,\n toBlock,\n logCount: logs.length\n });\n\n return logs;\n });\n }\n\n // Parse a raw log into structured event data\n parseLog(log) {\n const topicHash = log.topics[0];\n const eventName = this.eventsByTopic[topicHash];\n\n if (!eventName) {\n this.logger.trace('Unknown event topic', { topicHash, availableTopics: Object.keys(this.eventsByTopic) });\n return null;\n }\n\n try {\n const parsedLog = this.interface.parseLog(log);\n const result = {\n eventName,\n parsedLog,\n eventData: {\n ...parsedLog.args,\n blockNumber: log.blockNumber,\n transactionHash: log.transactionHash,\n logIndex: log.logIndex,\n timestamp: Date.now()\n }\n };\n\n this.logger.debug('Successfully parsed log', {\n eventName,\n blockNumber: log.blockNumber,\n transactionHash: log.transactionHash,\n logIndex: log.logIndex\n });\n\n return result;\n } catch (error) {\n this.logger.warn('Failed to parse log for event', {\n eventName,\n blockNumber: log.blockNumber,\n transactionHash: log.transactionHash,\n error: error.message\n });\n return null;\n }\n }\n\n // Create unique event key for deduplication\n createEventKey(log) {\n return `${log.transactionHash}-${log.logIndex}`;\n }\n\n // Get network information\n async getNetworkInfo() {\n return this.retryOperation(async () => {\n const network = await this._callWithFailover(\n (provider) => provider.getNetwork(),\n 'getNetwork'\n );\n const blockNumber = await this._callWithFailover(\n (provider) => provider.getBlockNumber(),\n 'getBlockNumber'\n );\n\n return {\n chainId: Number(network.chainId),\n name: network.name,\n currentBlock: blockNumber,\n expectedNetworkId: this.config.networkId\n };\n }, 'Getting network information');\n }\n\n // Validate network connection and configuration\n async validateNetwork() {\n const networkInfo = await this.getNetworkInfo();\n\n if (networkInfo.chainId !== this.config.networkId) {\n throw new Error(\n `Network mismatch: expected ${this.config.networkId}, got ${networkInfo.chainId}`\n );\n }\n\n return networkInfo;\n }\n\n // Get contract code to verify contract exists\n async validateContract() {\n return this.retryOperation(async () => {\n const code = await this._callWithFailover(\n (provider) => provider.getCode(this.config.address),\n 'getCode'\n );\n if (code === '0x') {\n throw new Error(`No contract found at address ${this.config.address}`);\n }\n return true;\n }, 'Validating contract');\n }\n\n // Get a block by number, with LRU caching\n async getBlock(blockNumber) {\n const cached = this.blockCache.get(blockNumber);\n if (cached !== undefined) {\n this.logger.debug('Block cache hit', { blockNumber });\n return cached;\n }\n\n const block = await this.retryOperation(async () => {\n return this._callWithFailover(\n (provider) => provider.getBlock(blockNumber),\n `getBlock(${blockNumber})`\n );\n }, `Getting block ${blockNumber}`);\n\n if (block) {\n this.blockCache.set(blockNumber, block);\n }\n\n return block;\n }\n\n // Get block timestamp, with LRU caching\n async getBlockTimestamp(blockNumber) {\n const cached = this.timestampCache.get(blockNumber);\n if (cached !== undefined) {\n this.logger.debug('Timestamp cache hit', { blockNumber });\n return cached;\n }\n\n const block = await this.getBlock(blockNumber);\n const timestamp = block ? block.timestamp : null;\n\n if (timestamp !== null) {\n this.timestampCache.set(blockNumber, timestamp);\n }\n\n return timestamp;\n }\n\n // Get transaction receipt\n async getTransactionReceipt(txHash) {\n return this.retryOperation(\n () => this._callWithFailover(\n (provider) => provider.getTransactionReceipt(txHash),\n 'getTransactionReceipt'\n ),\n `Getting transaction receipt for ${txHash}`\n );\n }\n\n // Get gas price information\n async getGasPrice() {\n return this.retryOperation(\n () => this._callWithFailover(\n (provider) => provider.getFeeData(),\n 'getFeeData'\n ),\n 'Getting gas price information'\n );\n }\n\n // Get provider instance for advanced operations\n getProvider() {\n return this.provider;\n }\n\n // Get ethers interface for manual parsing\n getInterface() {\n return this.interface;\n }\n\n // Get event mappings\n getEventMappings() {\n return {\n events: { ...this.events },\n eventsByTopic: { ...this.eventsByTopic }\n };\n }\n\n // Clear all caches\n clearCaches() {\n this.blockCache.clear();\n this.timestampCache.clear();\n this.logger.debug('All caches cleared');\n }\n\n // Get cache statistics\n getCacheStats() {\n return {\n blockCacheSize: this.blockCache.size,\n timestampCacheSize: this.timestampCache.size,\n maxCacheSize: this.blockCache.maxSize\n };\n }\n}\n","/**\n * EventFilter - Advanced filtering and querying for blockchain events\n */\nexport default class EventFilter {\n constructor(logger) {\n this.logger = logger.child({ context: 'EventFilter' });\n this.logger.info('EventFilter initialized');\n }\n\n /**\n * Build filter criteria from user input\n * @param {Object} options - Filter options\n * @param {number} options.fromBlock - Starting block number\n * @param {number} options.toBlock - Ending block number\n * @param {string} options.eventName - Event name to filter\n * @param {Object} options.parameters - Event parameter filters\n * @param {string} options.transactionHash - Filter by transaction hash\n * @param {string} options.address - Filter by contract address\n * @returns {Object} Filter criteria\n */\n buildFilter(options = {}) {\n const filter = {};\n\n // Block range filtering\n if (options.fromBlock !== undefined) {\n filter.fromBlock = options.fromBlock;\n }\n\n if (options.toBlock !== undefined) {\n filter.toBlock = options.toBlock;\n }\n\n // Event name filtering\n if (options.eventName) {\n filter.eventName = options.eventName;\n }\n\n // Parameter filtering\n if (options.parameters && Object.keys(options.parameters).length > 0) {\n filter.parameters = options.parameters;\n }\n\n // Transaction hash filtering\n if (options.transactionHash) {\n filter.transactionHash = options.transactionHash;\n }\n\n // Address filtering\n if (options.address) {\n filter.address = options.address.toLowerCase();\n }\n\n // Pass through logical operators\n if (options.$or) filter.$or = options.$or;\n if (options.$and) filter.$and = options.$and;\n if (options.$nor) filter.$nor = options.$nor;\n\n this.logger.debug('Built filter criteria', { filter });\n return filter;\n }\n\n /**\n * Apply filters to an array of events\n * @param {Array} events - Events to filter\n * @param {Object} filter - Filter criteria\n * @returns {Array} Filtered events\n */\n applyFilter(events, filter) {\n if (!Array.isArray(events)) {\n this.logger.warn('Invalid events array provided to applyFilter');\n return [];\n }\n\n let filtered = [...events];\n\n // Handle top-level logical combinators\n if (filter.$or) {\n filtered = filtered.filter(event =>\n filter.$or.some(condition => {\n const subFilter = this.buildFilter(condition);\n return this.applyFilter([event], subFilter).length > 0;\n })\n );\n }\n\n if (filter.$and) {\n filtered = filtered.filter(event =>\n filter.$and.every(condition => {\n const subFilter = this.buildFilter(condition);\n return this.applyFilter([event], subFilter).length > 0;\n })\n );\n }\n\n if (filter.$nor) {\n filtered = filtered.filter(event =>\n filter.$nor.every(condition => {\n const subFilter = this.buildFilter(condition);\n return this.applyFilter([event], subFilter).length === 0;\n })\n );\n }\n\n // Filter by block range\n if (filter.fromBlock !== undefined) {\n filtered = filtered.filter(event => event.blockNumber >= filter.fromBlock);\n }\n\n if (filter.toBlock !== undefined) {\n filtered = filtered.filter(event => event.blockNumber <= filter.toBlock);\n }\n\n // Filter by event name\n if (filter.eventName) {\n filtered = filtered.filter(event => event.eventName === filter.eventName);\n }\n\n // Filter by transaction hash\n if (filter.transactionHash) {\n filtered = filtered.filter(event =>\n event.transactionHash.toLowerCase() === filter.transactionHash.toLowerCase()\n );\n }\n\n // Filter by address\n if (filter.address) {\n filtered = filtered.filter(event =>\n event.address && event.address.toLowerCase() === filter.address\n );\n }\n\n // Filter by parameters\n if (filter.parameters) {\n filtered = filtered.filter(event =>\n this._matchesParameters(event.args || {}, filter.parameters)\n );\n }\n\n this.logger.debug('Applied filters', {\n originalCount: events.length,\n filteredCount: filtered.length,\n filter\n });\n\n return filtered;\n }\n\n /**\n * Check if event parameters match filter criteria (public API)\n */\n matchesParameters(eventArgs, filterParams) {\n return this._matchesParameters(eventArgs, filterParams);\n }\n\n /**\n * Check if event parameters match filter criteria\n * @private\n */\n _matchesParameters(eventArgs, filterParams) {\n for (const [key, value] of Object.entries(filterParams)) {\n // Handle different value types\n if (typeof value === 'object' && value !== null) {\n // 'exists' operator: check field presence\n if (value.exists !== undefined) {\n const fieldExists = eventArgs.hasOwnProperty(key);\n if (value.exists && !fieldExists) return false;\n if (!value.exists && fieldExists) return false;\n // If exists is the only operator, skip remaining checks for this key\n const otherKeys = Object.keys(value).filter(k => k !== 'exists');\n if (otherKeys.length === 0) continue;\n }\n\n // For all non-exists operators, the field must be present\n if (!eventArgs.hasOwnProperty(key)) {\n return false;\n }\n\n // Range filtering for numbers\n if (value.gte !== undefined && eventArgs[key] < value.gte) {\n return false;\n }\n if (value.lte !== undefined && eventArgs[key] > value.lte) {\n return false;\n }\n if (value.gt !== undefined && eventArgs[key] <= value.gt) {\n return false;\n }\n if (value.lt !== undefined && eventArgs[key] >= value.lt) {\n return false;\n }\n\n // 'in' operator: value must be in array\n if (value.in !== undefined && !value.in.includes(eventArgs[key])) {\n return false;\n }\n\n // 'nin' operator: value must NOT be in array\n if (value.nin !== undefined && value.nin.includes(eventArgs[key])) {\n return false;\n }\n\n // 'not' operator: negate a sub-condition\n if (value.not !== undefined) {\n const subMatch = this._matchesParameters(eventArgs, { [key]: value.not });\n if (subMatch) return false;\n }\n\n // 'regex' operator: pattern matching\n if (value.regex !== undefined) {\n const pattern = new RegExp(value.regex);\n if (!pattern.test(String(eventArgs[key]))) {\n return false;\n }\n }\n\n // 'size' operator: array length check\n if (value.size !== undefined) {\n const arr = eventArgs[key];\n if (!Array.isArray(arr) || arr.length !== value.size) {\n return false;\n }\n }\n } else {\n // Exact match - field must exist\n if (!eventArgs.hasOwnProperty(key)) {\n return false;\n }\n if (eventArgs[key] !== value) {\n return false;\n }\n }\n }\n\n return true;\n }\n\n /**\n * Sort events by specified criteria\n * @param {Array} events - Events to sort\n * @param {Object} options - Sort options\n * @param {string} options.by - Field to sort by (blockNumber, timestamp, etc.)\n * @param {string} options.order - Sort order ('asc' or 'desc')\n * @returns {Array} Sorted events\n */\n sortEvents(events, options = {}) {\n const { by = 'blockNumber', order = 'asc' } = options;\n\n const sorted = [...events].sort((a, b) => {\n let aVal = a[by];\n let bVal = b[by];\n\n // Handle nested properties (e.g., 'args.value')\n if (by.includes('.')) {\n const path = by.split('.');\n aVal = path.reduce((obj, key) => obj?.[key], a);\n bVal = path.reduce((obj, key) => obj?.[key], b);\n }\n\n if (aVal === bVal) return 0;\n\n const comparison = aVal < bVal ? -1 : 1;\n return order === 'asc' ? comparison : -comparison;\n });\n\n this.logger.debug('Sorted events', { by, order, count: sorted.length });\n return sorted;\n }\n\n /**\n * Group events by specified field\n * @param {Array} events - Events to group\n * @param {string} field - Field to group by\n * @returns {Object} Grouped events\n */\n groupEvents(events, field) {\n const grouped = {};\n\n for (const event of events) {\n let key = event[field];\n\n // Handle nested properties\n if (field.includes('.')) {\n const path = field.split('.');\n key = path.reduce((obj, k) => obj?.[k], event);\n }\n\n if (key === undefined) {\n key = 'undefined';\n }\n\n if (!grouped[key]) {\n grouped[key] = [];\n }\n\n grouped[key].push(event);\n }\n\n this.logger.debug('Grouped events', {\n field,\n groups: Object.keys(grouped).length,\n totalEvents: events.length\n });\n\n return grouped;\n }\n\n /**\n * Create a query builder for fluent API\n * @param {Array} events - Events to query\n * @returns {QueryBuilder} Query builder instance\n */\n query(events) {\n return new QueryBuilder(events, this);\n }\n}\n\n/**\n * QueryBuilder - Fluent API for event queries\n */\nclass QueryBuilder {\n constructor(events, eventFilter) {\n this.events = events;\n this.eventFilter = eventFilter;\n this.filters = {};\n this.sortOptions = null;\n this._limit = null;\n this._skip = null;\n }\n\n /**\n * Filter by block range\n */\n blockRange(from, to) {\n if (from !== undefined) this.filters.fromBlock = from;\n if (to !== undefined) this.filters.toBlock = to;\n return this;\n }\n\n /**\n * Filter by event name\n */\n eventName(name) {\n this.filters.eventName = name;\n return this;\n }\n\n /**\n * Filter by transaction hash\n */\n transactionHash(hash) {\n this.filters.transactionHash = hash;\n return this;\n }\n\n /**\n * Filter by contract address\n */\n address(addr) {\n this.filters.address = addr;\n return this;\n }\n\n /**\n * Filter by event parameters\n */\n where(field, value) {\n if (!this.filters.parameters) {\n this.filters.parameters = {};\n }\n this.filters.parameters[field] = value;\n return this;\n }\n\n /**\n * Add an $or condition\n */\n orWhere(field, value) {\n if (!this.filters.$or) {\n this.filters.$or = [];\n }\n this.filters.$or.push({ parameters: { [field]: value } });\n return this;\n }\n\n /**\n * Shorthand for exists check on a field\n */\n whereExists(field) {\n if (!this.filters.parameters) {\n this.filters.parameters = {};\n }\n this.filters.parameters[field] = { exists: true };\n return this;\n }\n\n /**\n * Shorthand for regex match on a field\n */\n whereRegex(field, pattern) {\n if (!this.filters.parameters) {\n this.filters.parameters = {};\n }\n this.filters.parameters[field] = { regex: pattern };\n return this;\n }\n\n /**\n * Limit number of results\n */\n limit(n) {\n this._limit = n;\n return this;\n }\n\n /**\n * Skip first n results\n */\n skip(n) {\n this._skip = n;\n return this;\n }\n\n /**\n * Sort results\n */\n orderBy(field, order = 'asc') {\n this.sortOptions = { by: field, order };\n return this;\n }\n\n /**\n * Execute query and return results\n */\n execute() {\n let results = this.eventFilter.applyFilter(this.events, this.filters);\n\n if (this.sortOptions) {\n results = this.eventFilter.sortEvents(results, this.sortOptions);\n }\n\n if (this._skip !== null) {\n results = results.slice(this._skip);\n }\n\n if (this._limit !== null) {\n results = results.slice(0, this._limit);\n }\n\n return results;\n }\n\n /**\n * Execute query and return first result\n */\n first() {\n const results = this.execute();\n return results.length > 0 ? results[0] : null;\n }\n\n /**\n * Execute query and return count\n */\n count() {\n return this.execute().length;\n }\n\n /**\n * Execute query and group results\n */\n groupBy(field) {\n const results = this.execute();\n return this.eventFilter.groupEvents(results, field);\n }\n}\n","/**\n * Paginator - Efficient pagination for large event datasets\n */\nexport default class Paginator {\n constructor(logger) {\n this.logger = logger.child({ context: 'Paginator' });\n this.logger.info('Paginator initialized');\n }\n\n /**\n * Create a paginated result set\n * @param {Array} items - Items to paginate\n * @param {Object} options - Pagination options\n * @param {number} options.page - Current page (1-based)\n * @param {number} options.pageSize - Items per page\n * @param {boolean} options.includeMeta - Include pagination metadata\n * @returns {Object} Paginated result\n */\n paginate(items, options = {}) {\n const {\n page = 1,\n pageSize = 100,\n includeMeta = true\n } = options;\n\n // Validate inputs\n if (!Array.isArray(items)) {\n this.logger.warn('Invalid items array provided to paginate');\n return this._createEmptyResult(includeMeta);\n }\n\n if (page < 1 || pageSize < 1) {\n this.logger.warn('Invalid pagination parameters', { page, pageSize });\n return this._createEmptyResult(includeMeta);\n }\n\n const totalItems = items.length;\n const totalPages = Math.ceil(totalItems / pageSize);\n const startIndex = (page - 1) * pageSize;\n const endIndex = Math.min(startIndex + pageSize, totalItems);\n\n // Get page items\n const pageItems = items.slice(startIndex, endIndex);\n\n this.logger.debug('Created paginated result', {\n page,\n pageSize,\n totalItems,\n totalPages,\n itemsInPage: pageItems.length\n });\n\n // Build result\n const result = {\n data: pageItems\n };\n\n if (includeMeta) {\n result.meta = {\n page,\n pageSize,\n totalItems,\n totalPages,\n hasNextPage: page < totalPages,\n hasPreviousPage: page > 1,\n startIndex: startIndex + 1, // 1-based for display\n endIndex: endIndex\n };\n }\n\n return result;\n }\n\n /**\n * Create an async iterator for large datasets\n * @param {Array|Function} itemsOrGetter - Items array or async function to get items\n * @param {Object} options - Iterator options\n * @param {number} options.pageSize - Items per page\n * @returns {AsyncIterator} Async iterator\n */\n async *iterate(itemsOrGetter, options = {}) {\n const { pageSize = 100 } = options;\n let page = 1;\n let hasMore = true;\n\n while (hasMore) {\n let items;\n\n // Handle both array and async getter function\n if (typeof itemsOrGetter === 'function') {\n items = await itemsOrGetter(page, pageSize);\n } else if (Array.isArray(itemsOrGetter)) {\n const result = this.paginate(itemsOrGetter, { page, pageSize, includeMeta: true });\n items = result.data;\n hasMore = result.meta.hasNextPage;\n } else {\n this.logger.error('Invalid itemsOrGetter provided to iterate');\n return;\n }\n\n if (!items || items.length === 0) {\n hasMore = false;\n break;\n }\n\n // Yield each item\n for (const item of items) {\n yield item;\n }\n\n // If using array, check if we have more pages\n if (Array.isArray(itemsOrGetter)) {\n page++;\n } else {\n // For async getter, assume no more items if less than pageSize returned\n hasMore = items.length === pageSize;\n page++;\n }\n }\n\n this.logger.debug('Iterator completed', { totalPages: page - 1 });\n }\n\n /**\n * Create a cursor-based pagination result\n * @param {Array} items - Items to paginate\n * @param {Object} options - Cursor pagination options\n * @param {string} options.cursor - Current cursor position\n * @param {number} options.limit - Number of items to return\n * @param {string} options.cursorField - Field to use for cursor (default: 'id')\n * @param {string} options.direction - Pagination direction ('forward' or 'backward')\n * @returns {Object} Cursor-paginated result\n */\n paginateCursor(items, options = {}) {\n const {\n cursor = null,\n limit = 100,\n cursorField = 'id',\n direction = 'forward'\n } = options;\n\n if (!Array.isArray(items)) {\n this.logger.warn('Invalid items array provided to paginateCursor');\n return this._createEmptyCursorResult();\n }\n\n let filteredItems = [...items];\n\n // Apply cursor filter\n if (cursor !== null) {\n filteredItems = filteredItems.filter(item => {\n const itemValue = item[cursorField];\n if (direction === 'forward') {\n return itemValue > cursor;\n } else {\n return itemValue < cursor;\n }\n });\n }\n\n // Sort items based on direction\n filteredItems.sort((a, b) => {\n const aVal = a[cursorField];\n const bVal = b[cursorField];\n if (direction === 'forward') {\n return aVal < bVal ? -1 : 1;\n } else {\n return aVal > bVal ? -1 : 1;\n }\n });\n\n // Get limited items\n const pageItems = filteredItems.slice(0, limit);\n const hasMore = filteredItems.length > limit;\n\n // Determine cursors\n const firstItem = pageItems[0];\n const lastItem = pageItems[pageItems.length - 1];\n\n const result = {\n data: pageItems,\n cursors: {\n before: firstItem ? firstItem[cursorField] : null,\n after: lastItem ? lastItem[cursorField] : null,\n hasNext: hasMore,\n hasPrevious: cursor !== null\n }\n };\n\n this.logger.debug('Created cursor-paginated result', {\n cursor,\n limit,\n cursorField,\n direction,\n itemsReturned: pageItems.length,\n hasMore\n });\n\n return result;\n }\n\n /**\n * Create a page info object for GraphQL-style pagination\n * @param {Object} paginationMeta - Pagination metadata\n * @returns {Object} Page info\n */\n createPageInfo(paginationMeta) {\n return {\n hasNextPage: paginationMeta.hasNextPage || false,\n hasPreviousPage: paginationMeta.hasPreviousPage || false,\n startCursor: paginationMeta.startCursor || null,\n endCursor: paginationMeta.endCursor || null,\n totalCount: paginationMeta.totalItems || 0\n };\n }\n\n /**\n * Calculate optimal page size based on data characteristics\n * @param {Object} options - Options for calculation\n * @param {number} options.totalItems - Total number of items\n * @param {number} options.avgItemSize - Average item size in bytes\n * @param {number} options.maxMemory - Maximum memory to use (bytes)\n * @param {number} options.minPageSize - Minimum page size\n * @param {number} options.maxPageSize - Maximum page size\n * @returns {number} Optimal page size\n */\n calculateOptimalPageSize(options = {}) {\n const {\n totalItems = 1000,\n avgItemSize = 1024, // 1KB default\n maxMemory = 10 * 1024 * 1024, // 10MB default\n minPageSize = 10,\n maxPageSize = 1000\n } = options;\n\n // Calculate based on memory constraints\n let optimalSize = Math.floor(maxMemory / avgItemSize);\n\n // Apply bounds\n optimalSize = Math.max(minPageSize, Math.min(maxPageSize, optimalSize));\n\n // Adjust for total items\n if (totalItems < optimalSize) {\n optimalSize = totalItems;\n }\n\n this.logger.debug('Calculated optimal page size', {\n totalItems,\n avgItemSize,\n maxMemory,\n optimalSize\n });\n\n return optimalSize;\n }\n\n /**\n * Create empty result for error cases\n * @private\n */\n _createEmptyResult(includeMeta) {\n const result = { data: [] };\n if (includeMeta) {\n result.meta = {\n page: 1,\n pageSize: 0,\n totalItems: 0,\n totalPages: 0,\n hasNextPage: false,\n hasPreviousPage: false,\n startIndex: 0,\n endIndex: 0\n };\n }\n return result;\n }\n\n /**\n * Create empty cursor result for error cases\n * @private\n */\n _createEmptyCursorResult() {\n return {\n data: [],\n cursors: {\n before: null,\n after: null,\n hasNext: false,\n hasPrevious: false\n }\n };\n }\n}\n\n/**\n * PaginationHelper - Static utility methods for pagination\n */\nexport class PaginationHelper {\n /**\n * Calculate pagination offset\n */\n static calculateOffset(page, pageSize) {\n return (page - 1) * pageSize;\n }\n\n /**\n * Calculate total pages\n */\n static calculateTotalPages(totalItems, pageSize) {\n return Math.ceil(totalItems / pageSize);\n }\n\n /**\n * Validate page number\n */\n static isValidPage(page, totalPages) {\n return page >= 1 && page <= totalPages;\n }\n\n /**\n * Get page numbers for pagination UI\n */\n static getPageNumbers(currentPage, totalPages, maxVisible = 5) {\n const pages = [];\n const halfVisible = Math.floor(maxVisible / 2);\n \n let start = Math.max(1, currentPage - halfVisible);\n let end = Math.min(totalPages, currentPage + halfVisible);\n \n // Adjust if we're near the beginning or end\n if (currentPage <= halfVisible) {\n end = Math.min(totalPages, maxVisible);\n } else if (currentPage >= totalPages - halfVisible) {\n start = Math.max(1, totalPages - maxVisible + 1);\n }\n \n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n \n return pages;\n }\n}","/**\n * DataCompressor - Handles data compression and decompression for storage optimization\n */\nimport { gzip, ungzip } from 'pako';\n\nconst isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;\n\nfunction toBase64(uint8Array) {\n if (isNode) {\n return Buffer.from(uint8Array).toString('base64');\n }\n return btoa(String.fromCharCode.apply(null, uint8Array));\n}\n\nfunction fromBase64(base64String) {\n if (isNode) {\n const buf = Buffer.from(base64String, 'base64');\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n }\n const binaryString = atob(base64String);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n\nexport default class DataCompressor {\n constructor(logger) {\n this.logger = logger.child({ context: 'DataCompressor' });\n this.logger.info('DataCompressor initialized');\n \n // Compression strategies\n this.strategies = {\n none: {\n compress: (data) => data,\n decompress: (data) => data,\n ratio: 1\n },\n json: {\n compress: (data) => this._compressJSON(data),\n decompress: (data) => this._decompressJSON(data),\n ratio: 0.7 // Approximate\n },\n gzip: {\n compress: (data) => this._compressGzip(data),\n decompress: (data) => this._decompressGzip(data),\n ratio: 0.3 // Approximate\n },\n optimized: {\n compress: (data) => this._compressOptimized(data),\n decompress: (data) => this._decompressOptimized(data),\n ratio: 0.4 // Approximate\n }\n };\n \n this.defaultStrategy = 'optimized';\n }\n\n /**\n * Compress data using specified strategy\n * @param {any} data - Data to compress\n * @param {string} strategy - Compression strategy\n * @returns {Object} Compressed data with metadata\n */\n compress(data, strategy = this.defaultStrategy) {\n try {\n const startTime = Date.now();\n const originalSize = this._calculateSize(data);\n \n if (!this.strategies[strategy]) {\n this.logger.warn('Unknown compression strategy, using default', { strategy });\n strategy = this.defaultStrategy;\n }\n \n const compressed = this.strategies[strategy].compress(data);\n const compressedSize = this._calculateSize(compressed);\n const compressionRatio = compressedSize / originalSize;\n const duration = Date.now() - startTime;\n \n const result = {\n data: compressed,\n metadata: {\n strategy,\n originalSize,\n compressedSize,\n compressionRatio: compressionRatio.toFixed(3),\n spaceSaved: `${((1 - compressionRatio) * 100).toFixed(1)}%`,\n compressionTime: duration,\n timestamp: new Date().toISOString()\n }\n };\n \n this.logger.debug('Data compressed', result.metadata);\n return result;\n \n } catch (error) {\n this.logger.error('Compression failed', { strategy, error: error.message });\n throw error;\n }\n }\n\n /**\n * Decompress data\n * @param {Object} compressedData - Compressed data with metadata\n * @returns {any} Original data\n */\n decompress(compressedData) {\n try {\n if (!compressedData.metadata || !compressedData.metadata.strategy) {\n this.logger.warn('No compression metadata found, assuming no compression');\n return compressedData;\n }\n \n const { strategy } = compressedData.metadata;\n const startTime = Date.now();\n \n if (!this.strategies[strategy]) {\n throw new Error(`Unknown compression strategy: ${strategy}`);\n }\n \n const decompressed = this.strategies[strategy].decompress(compressedData.data);\n const duration = Date.now() - startTime;\n \n this.logger.debug('Data decompressed', {\n strategy,\n decompressionTime: duration,\n originalSize: compressedData.metadata.originalSize\n });\n \n return decompressed;\n \n } catch (error) {\n this.logger.error('Decompression failed', { error: error.message });\n throw error;\n }\n }\n\n /**\n * Compress events for storage\n * @param {Array} events - Events to compress\n * @param {Object} options - Compression options\n * @returns {Object} Compressed events\n */\n compressEvents(events, options = {}) {\n const { strategy = this.defaultStrategy, chunkSize = 100 } = options;\n \n return this.logger.time('compressEvents', () => {\n // Group events into chunks for better compression\n const chunks = [];\n for (let i = 0; i < events.length; i += chunkSize) {\n chunks.push(events.slice(i, i + chunkSize));\n }\n \n // Compress each chunk\n const compressedChunks = chunks.map((chunk, index) => {\n const compressed = this.compress(chunk, strategy);\n return {\n ...compressed,\n metadata: {\n ...compressed.metadata,\n chunkIndex: index,\n eventCount: chunk.length\n }\n };\n });\n \n // Calculate total compression stats\n const totalOriginal = compressedChunks.reduce((sum, c) => sum + c.metadata.originalSize, 0);\n const totalCompressed = compressedChunks.reduce((sum, c) => sum + c.metadata.compressedSize, 0);\n \n const result = {\n chunks: compressedChunks,\n metadata: {\n totalEvents: events.length,\n chunkCount: chunks.length,\n strategy,\n totalOriginalSize: totalOriginal,\n totalCompressedSize: totalCompressed,\n overallCompressionRatio: (totalCompressed / totalOriginal).toFixed(3),\n spaceSaved: `${((1 - totalCompressed / totalOriginal) * 100).toFixed(1)}%`\n }\n };\n \n this.logger.info('Events compressed', result.metadata);\n return result;\n });\n }\n\n /**\n * Decompress events\n * @param {Object} compressedEvents - Compressed events object\n * @returns {Array} Original events\n */\n decompressEvents(compressedEvents) {\n return this.logger.time('decompressEvents', () => {\n if (!compressedEvents.chunks || !Array.isArray(compressedEvents.chunks)) {\n throw new Error('Invalid compressed events format');\n }\n \n const events = [];\n \n // Decompress each chunk\n compressedEvents.chunks.forEach(chunk => {\n const decompressedChunk = this.decompress(chunk);\n events.push(...decompressedChunk);\n });\n \n this.logger.info('Events decompressed', {\n totalEvents: events.length,\n chunks: compressedEvents.chunks.length\n });\n \n return events;\n });\n }\n\n /**\n * JSON compression - removes whitespace and uses short keys\n * @private\n */\n _compressJSON(data) {\n // Create key mapping for common event fields\n const keyMap = {\n eventName: 'e',\n blockNumber: 'b',\n transactionHash: 't',\n address: 'a',\n args: 'r',\n topics: 'p',\n data: 'd',\n logIndex: 'l',\n transactionIndex: 'i',\n blockHash: 'h',\n removed: 'm'\n };\n \n const compressed = this._replaceKeys(data, keyMap);\n return {\n d: compressed,\n k: keyMap\n };\n }\n\n /**\n * JSON decompression\n * @private\n */\n _decompressJSON(compressed) {\n if (!compressed.d || !compressed.k) {\n return compressed;\n }\n \n // Reverse the key mapping\n const reverseMap = {};\n Object.entries(compressed.k).forEach(([k, v]) => {\n reverseMap[v] = k;\n });\n \n return this._replaceKeys(compressed.d, reverseMap);\n }\n\n /**\n * Gzip compression\n * @private\n */\n _compressGzip(data) {\n const jsonString = JSON.stringify(data);\n const compressed = gzip(jsonString);\n return toBase64(compressed);\n }\n\n /**\n * Gzip decompression\n * @private\n */\n _decompressGzip(compressed) {\n const bytes = fromBase64(compressed);\n const decompressed = ungzip(bytes);\n const jsonString = new TextDecoder().decode(decompressed);\n return JSON.parse(jsonString);\n }\n\n /**\n * Optimized compression - combines JSON and gzip\n * @private\n */\n _compressOptimized(data) {\n // First apply JSON compression\n const jsonCompressed = this._compressJSON(data);\n // Then apply gzip\n return this._compressGzip(jsonCompressed);\n }\n\n /**\n * Optimized decompression\n * @private\n */\n _decompressOptimized(compressed) {\n // First decompress gzip\n const gzipDecompressed = this._decompressGzip(compressed);\n // Then decompress JSON\n return this._decompressJSON(gzipDecompressed);\n }\n\n /**\n * Replace keys in object recursively\n * @private\n */\n _replaceKeys(obj, keyMap) {\n if (Array.isArray(obj)) {\n return obj.map(item => this._replaceKeys(item, keyMap));\n } else if (obj !== null && typeof obj === 'object') {\n const result = {};\n Object.entries(obj).forEach(([key, value]) => {\n const newKey = keyMap[key] || key;\n result[newKey] = this._replaceKeys(value, keyMap);\n });\n return result;\n }\n return obj;\n }\n\n /**\n * Calculate size of data in bytes\n * @private\n */\n _calculateSize(data) {\n const jsonString = JSON.stringify(data);\n if (isNode) {\n return Buffer.byteLength(jsonString, 'utf8');\n }\n return new Blob([jsonString]).size;\n }\n\n /**\n * Analyze compression efficiency for different strategies\n * @param {any} data - Data to analyze\n * @returns {Object} Analysis results\n */\n analyzeCompressionStrategies(data) {\n const results = {};\n \n Object.keys(this.strategies).forEach(strategy => {\n try {\n const compressed = this.compress(data, strategy);\n results[strategy] = {\n originalSize: compressed.metadata.originalSize,\n compressedSize: compressed.metadata.compressedSize,\n compressionRatio: compressed.metadata.compressionRatio,\n spaceSaved: compressed.metadata.spaceSaved,\n compressionTime: compressed.metadata.compressionTime\n };\n } catch (error) {\n results[strategy] = {\n error: error.message\n };\n }\n });\n \n // Find best strategy\n let bestStrategy = 'none';\n let bestRatio = 1;\n \n Object.entries(results).forEach(([strategy, result]) => {\n if (!result.error && parseFloat(result.compressionRatio) < bestRatio) {\n bestRatio = parseFloat(result.compressionRatio);\n bestStrategy = strategy;\n }\n });\n \n return {\n strategies: results,\n recommendation: bestStrategy,\n bestCompressionRatio: bestRatio\n };\n }\n}","import Gun from 'gun';\nimport 'gun/lib/load.js';\nimport 'gun/lib/open.js';\nimport Logger from './Logger.js';\nimport EventFilter from './EventFilter.js';\nimport Paginator from './Paginator.js';\nimport DataCompressor from './DataCompressor.js';\n\n/**\n * EventStore - Handles Gun.js data storage operations\n */\nexport default class EventStore {\n constructor(gunConfig, retryOperation, networkManager = null) {\n this.gun = Gun(gunConfig);\n this.retryOperation = retryOperation;\n this.networkManager = networkManager;\n this.logger = new Logger({\n context: 'EventStore',\n level: gunConfig?.logLevel || 'info'\n });\n \n // Initialize components\n this.eventFilter = new EventFilter(this.logger);\n this.paginator = new Paginator(this.logger);\n this.dataCompressor = new DataCompressor(this.logger);\n \n // Compression settings\n this.compressionEnabled = gunConfig?.compression?.enabled ?? true;\n this.compressionStrategy = gunConfig?.compression?.strategy ?? 'optimized';\n\n // Track active Gun listeners for cleanup\n this._activeListeners = [];\n \n this.logger.info('EventStore initialized', {\n gunConfig: this._sanitizeGunConfig(gunConfig),\n compressionEnabled: this.compressionEnabled,\n compressionStrategy: this.compressionStrategy\n });\n }\n\n // Sanitize Gun config for logging\n _sanitizeGunConfig(config) {\n if (!config || typeof config !== 'object') return config;\n // Remove potentially sensitive information\n const sanitized = { ...config };\n delete sanitized.peers;\n delete sanitized.localStorage;\n return sanitized;\n }\n\n // Get the start block number for syncing events from the blockchain\n async getStartBlockNumber() {\n return this.retryOperation(async () => {\n return new Promise((resolve) => {\n this.gun.get('config').get('startBlockNumber').once((data) => {\n resolve(data || 1);\n });\n });\n }, 'Getting start block number');\n }\n\n // Set the start block number for syncing events from the blockchain\n async setStartBlockNumber(startBlockNumber) {\n return this.retryOperation(async () => {\n return new Promise((resolve, reject) => {\n this.gun.get('config').get('startBlockNumber').put(startBlockNumber, (ack) => {\n if (ack.err) {\n reject(new Error(ack.err));\n } else {\n resolve(ack);\n }\n });\n });\n }, `Setting start block number to ${startBlockNumber}`);\n }\n\n // Store an event in the decentralized database\n async storeEvent(eventName, eventKey, eventData) {\n return this.logger.time('storeEvent', async () => {\n this.logger.logDatabaseActivity('storeEvent', {\n eventName,\n eventKey,\n blockNumber: eventData.blockNumber,\n transactionHash: eventData.transactionHash\n });\n \n // Compress data if enabled\n let dataToStore = eventData;\n if (this.compressionEnabled) {\n const compressed = this.dataCompressor.compress(eventData, this.compressionStrategy);\n dataToStore = {\n _compressed: true,\n _data: compressed.data,\n _metadata: compressed.metadata\n };\n }\n \n return this.retryOperation(\n () => new Promise(resolve => {\n this.gun.get('events').get(eventName).get(eventKey).put(dataToStore, resolve);\n }),\n `Storing event ${eventName}`\n );\n }, { eventName, eventKey });\n }\n\n // Get events by name with optional filtering\n async getEvents(eventName, filter = {}) {\n return this.logger.time('getEvents', async () => {\n this.logger.logDatabaseActivity('getEvents', {\n eventName,\n filter: Object.keys(filter)\n });\n \n return this.retryOperation(async () => {\n return new Promise((resolve) => {\n let resolved = false;\n const node = this.gun.get('events').get(eventName);\n\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.logger.debug('getEvents timed out, returning empty', { eventName });\n resolve([]);\n }\n }, 3000);\n\n node.open((data) => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timeout);\n\n const events = [];\n if (data && typeof data === 'object') {\n Object.entries(data).forEach(([key, value]) => {\n if (key === '_' || !value || typeof value !== 'object') return;\n if (this._matchesFilter(value, filter)) {\n events.push({ key, ...value });\n }\n });\n }\n\n this.logger.debug('Events retrieved', {\n eventName,\n eventCount: events.length,\n filterApplied: Object.keys(filter).length > 0\n });\n resolve(events);\n });\n });\n }, `Getting events for ${eventName}`);\n }, { eventName });\n }\n\n // Get all events with optional filtering and pagination\n async getAllEvents(options = {}) {\n return this.logger.time('getAllEvents', async () => {\n const { filter = {}, pagination = {}, sort = {} } = options;\n \n // Get all events from Gun\n const allEventsMap = await this._fetchAllEventsMap();\n \n // Flatten events into array\n const allEvents = [];\n Object.entries(allEventsMap).forEach(([eventName, events]) => {\n events.forEach(event => {\n allEvents.push({\n ...event,\n eventName\n });\n });\n });\n \n // Apply filters\n let filteredEvents = allEvents;\n if (Object.keys(filter).length > 0) {\n const filterCriteria = this.eventFilter.buildFilter(filter);\n filteredEvents = this.eventFilter.applyFilter(allEvents, filterCriteria);\n }\n \n // Apply sorting\n if (sort.by) {\n filteredEvents = this.eventFilter.sortEvents(filteredEvents, sort);\n }\n \n // Apply pagination\n if (pagination.page || pagination.pageSize) {\n const paginatedResult = this.paginator.paginate(filteredEvents, pagination);\n this.logger.debug('Query completed', {\n totalEvents: allEvents.length,\n filteredEvents: filteredEvents.length,\n returnedEvents: paginatedResult.data.length\n });\n return paginatedResult;\n }\n \n // Return unpaginated results\n return {\n data: filteredEvents,\n meta: {\n totalItems: filteredEvents.length\n }\n };\n });\n }\n\n // Internal method to fetch all events as a map\n async _fetchAllEventsMap() {\n return this.retryOperation(async () => {\n return new Promise((resolve) => {\n let resolved = false;\n const node = this.gun.get('events');\n\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.logger.debug('_fetchAllEventsMap timed out, returning empty');\n resolve({});\n }\n }, 5000);\n\n node.open((data) => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timeout);\n\n const allEvents = {};\n if (data && typeof data === 'object') {\n Object.entries(data).forEach(([eventName, eventGroup]) => {\n if (eventName === '_' || !eventGroup || typeof eventGroup !== 'object') return;\n allEvents[eventName] = [];\n Object.entries(eventGroup).forEach(([key, eventData]) => {\n if (key === '_' || !eventData || typeof eventData !== 'object') return;\n let decompressed = eventData;\n if (eventData._compressed && eventData._data) {\n try {\n decompressed = this.dataCompressor.decompress({\n data: eventData._data,\n metadata: eventData._metadata\n });\n } catch (error) {\n this.logger.error('Failed to decompress event', {\n eventName,\n key,\n error: error.message\n });\n }\n }\n allEvents[eventName].push({ key, ...decompressed });\n });\n });\n }\n resolve(allEvents);\n });\n });\n }, 'Getting all events');\n }\n\n // Publish magazine metadata to the decentralized network\n async publishMagazine(alias, magazineData, url) {\n return this.logger.time('publishMagazine', async () => {\n this.logger.info('Publishing magazine', {\n alias,\n url,\n magazineData: {\n name: magazineData.name,\n address: magazineData.address,\n networkId: magazineData.networkId\n }\n });\n \n return this.retryOperation(async () => {\n const magazineNode = this.gun.back(-1).get(alias);\n \n const magazineId = await new Promise((resolve, reject) => {\n magazineNode.put(magazineData, (ack) => {\n if (ack.err) {\n this.logger.error('Failed to publish magazine metadata', {\n alias,\n error: ack.err\n });\n reject(new Error(ack.err));\n } else {\n this.logger.debug('Magazine metadata published', { alias });\n resolve(ack);\n }\n });\n });\n \n await new Promise((resolve, reject) => {\n magazineNode.get('url').put(url, (ack) => {\n if (ack.err) {\n this.logger.error('Failed to publish magazine URL', {\n alias,\n url,\n error: ack.err\n });\n reject(new Error(ack.err));\n } else {\n this.logger.debug('Magazine URL published', { alias, url });\n resolve(ack);\n }\n });\n });\n\n this.logger.info('Magazine published successfully', { alias, url });\n return magazineId;\n }, 'Publishing magazine');\n }, { alias });\n }\n\n // Subscribe to a magazine on the decentralized network\n async subscribeMagazine(magazineId) {\n return this.retryOperation(async () => {\n return new Promise((resolve, reject) => {\n this.gun.get(magazineId).once((data, key) => {\n if (data) {\n resolve(data);\n } else {\n reject(new Error(`Magazine with ID ${magazineId} not found`));\n }\n });\n });\n }, `Subscribing to magazine ${magazineId}`);\n }\n\n // Helper method to check if event data matches filter criteria\n _matchesFilter(data, filter) {\n if (!filter || Object.keys(filter).length === 0) {\n return true;\n }\n\n for (const [key, value] of Object.entries(filter)) {\n if (data[key] !== value) {\n return false;\n }\n }\n\n return true;\n }\n\n // Query events using fluent API\n async query() {\n const allEventsMap = await this._fetchAllEventsMap();\n \n // Flatten events\n const allEvents = [];\n Object.entries(allEventsMap).forEach(([eventName, events]) => {\n events.forEach(event => {\n allEvents.push({\n ...event,\n eventName\n });\n });\n });\n \n return this.eventFilter.query(allEvents);\n }\n\n // Get events by transaction hash\n async getEventsByTransactionHash(transactionHash) {\n return this.logger.time('getEventsByTransactionHash', async () => {\n const result = await this.getAllEvents({\n filter: { transactionHash }\n });\n \n this.logger.debug('Found events by transaction hash', {\n transactionHash,\n count: result.data.length\n });\n \n return result.data;\n });\n }\n\n // Get events by block number\n async getEventsByBlockNumber(blockNumber) {\n return this.logger.time('getEventsByBlockNumber', async () => {\n const result = await this.getAllEvents({\n filter: {\n fromBlock: blockNumber,\n toBlock: blockNumber\n }\n });\n \n this.logger.debug('Found events by block number', {\n blockNumber,\n count: result.data.length\n });\n \n return result.data;\n });\n }\n\n // Create async iterator for events\n async *iterateEvents(options = {}) {\n const { filter = {}, sort = {}, pageSize = 100 } = options;\n \n // Get filtered and sorted events\n const result = await this.getAllEvents({ filter, sort });\n const events = result.data;\n \n // Use paginator's iterator\n yield* this.paginator.iterate(events, { pageSize });\n }\n\n // Get compression statistics\n async getCompressionStats() {\n const allEventsMap = await this._fetchAllEventsMap();\n let totalOriginal = 0;\n let totalCompressed = 0;\n let compressedCount = 0;\n \n Object.values(allEventsMap).forEach(events => {\n events.forEach(event => {\n if (event._compressed && event._metadata) {\n totalOriginal += event._metadata.originalSize || 0;\n totalCompressed += event._metadata.compressedSize || 0;\n compressedCount++;\n }\n });\n });\n \n return {\n compressedEvents: compressedCount,\n totalOriginalSize: totalOriginal,\n totalCompressedSize: totalCompressed,\n compressionRatio: totalOriginal > 0 ? (totalCompressed / totalOriginal).toFixed(3) : '1.000',\n spaceSaved: totalOriginal > 0 ? `${((1 - totalCompressed / totalOriginal) * 100).toFixed(1)}%` : '0%'\n };\n }\n\n // Clean up all active listeners\n destroy() {\n this._activeListeners = [];\n this.logger.info('EventStore destroyed, listeners cleaned up');\n }\n\n // Get Gun instance for advanced operations\n getGunInstance() {\n return this.gun;\n }\n}","import Logger from './Logger.js';\n\n/**\n * EventSyncer - Handles blockchain event synchronization logic\n */\nexport default class EventSyncer {\n constructor(networkManager, eventStore, configManager, retryOperation) {\n this.networkManager = networkManager;\n this.eventStore = eventStore;\n this.configManager = configManager;\n this.retryOperation = retryOperation;\n \n this.logger = new Logger({\n context: 'EventSyncer',\n level: configManager.get('logLevel') || 'info'\n });\n \n // Configuration for batch processing\n this.batchSize = 1000; // Process events in batches of 1000 blocks\n this.lastSyncTime = 0;\n \n this.logger.info('EventSyncer initialized', {\n batchSize: this.batchSize\n });\n }\n\n // Sync events from the blockchain to the magazine\n async syncEvents() {\n if (this._syncing) {\n this.logger.warn('Sync already in progress, skipping');\n return 0;\n }\n this._setSyncing(true);\n try {\n return await this.logger.time('syncEvents', async () => {\n return this.retryOperation(async () => {\n // Get the starting block number and latest block number\n const startBlockNumber = await this.eventStore.getStartBlockNumber();\n const latestBlockNumber = await this.networkManager.getLatestBlockNumber();\n \n if (startBlockNumber > latestBlockNumber) {\n this.logger.info('Already up to date', {\n startBlockNumber,\n latestBlockNumber\n });\n return;\n }\n\n this.logger.info('Starting event synchronization', {\n startBlockNumber,\n latestBlockNumber,\n totalBlocks: latestBlockNumber - startBlockNumber + 1\n });\n \n // Process events in batches to avoid overwhelming the provider\n let currentStart = startBlockNumber;\n let totalEventsProcessed = 0;\n \n while (currentStart <= latestBlockNumber) {\n const currentEnd = Math.min(currentStart + this.batchSize - 1, latestBlockNumber);\n \n const batchEvents = await this._processBatch(currentStart, currentEnd);\n totalEventsProcessed += batchEvents;\n currentStart = currentEnd + 1;\n }\n \n // Update the start block number for next sync\n await this.eventStore.setStartBlockNumber(latestBlockNumber + 1);\n\n this.lastSyncTime = Date.now();\n\n this.logger.info('Event synchronization completed', {\n totalEventsProcessed,\n newStartBlockNumber: latestBlockNumber + 1\n });\n\n return totalEventsProcessed;\n }, 'Event synchronization');\n });\n } finally {\n this._setSyncing(false);\n }\n }\n\n // Process a batch of blocks for events\n async _processBatch(fromBlock, toBlock) {\n return this.logger.time('processBatch', async () => {\n this.logger.debug('Processing batch', { fromBlock, toBlock });\n \n const logs = await this.networkManager.getLogs(fromBlock, toBlock);\n let eventsStored = 0;\n \n // Process each log\n for (const log of logs) {\n const parsedEvent = this.networkManager.parseLog(log);\n \n if (parsedEvent) {\n try {\n // Store event with unique key to prevent duplicates\n const eventKey = this.networkManager.createEventKey(log);\n await this.eventStore.storeEvent(\n parsedEvent.eventName,\n eventKey,\n parsedEvent.eventData\n );\n eventsStored++;\n \n this.logger.trace('Event stored', {\n eventName: parsedEvent.eventName,\n eventKey,\n blockNumber: log.blockNumber\n });\n } catch (error) {\n this.logger.warn('Failed to store event', {\n eventName: parsedEvent.eventName,\n blockNumber: log.blockNumber,\n transactionHash: log.transactionHash,\n error: error.message\n });\n }\n }\n }\n \n this.logger.debug('Batch processing completed', {\n fromBlock,\n toBlock,\n logsFound: logs.length,\n eventsStored\n });\n \n return eventsStored;\n }, { fromBlock, toBlock });\n }\n\n // Sync events from a specific block range\n async syncEventsFromRange(fromBlock, toBlock) {\n this.configManager.validateBlockNumber(fromBlock, 'fromBlock');\n this.configManager.validateBlockNumber(toBlock, 'toBlock');\n\n if (fromBlock > toBlock) {\n throw new Error('fromBlock cannot be greater than toBlock');\n }\n\n if (this._syncing) {\n this.logger.warn('Sync already in progress, skipping range sync');\n return 0;\n }\n this._setSyncing(true);\n try {\n return await this.logger.time('syncEventsFromRange', async () => {\n return this.retryOperation(async () => {\n this.logger.info('Syncing events from specific range', {\n fromBlock,\n toBlock,\n totalBlocks: toBlock - fromBlock + 1\n });\n \n // Process the range in batches\n let currentStart = fromBlock;\n let totalEventsProcessed = 0;\n \n while (currentStart <= toBlock) {\n const currentEnd = Math.min(currentStart + this.batchSize - 1, toBlock);\n const batchEvents = await this._processBatch(currentStart, currentEnd);\n totalEventsProcessed += batchEvents;\n currentStart = currentEnd + 1;\n }\n \n this.lastSyncTime = Date.now();\n\n this.logger.info('Range synchronization completed', {\n fromBlock,\n toBlock,\n totalEventsProcessed\n });\n\n return totalEventsProcessed;\n }, `Event synchronization for range ${fromBlock}-${toBlock}`);\n }, { fromBlock, toBlock });\n } finally {\n this._setSyncing(false);\n }\n }\n\n // Sync events from a specific transaction\n async syncEventsFromTransaction(txHash) {\n if (!txHash || typeof txHash !== 'string') {\n throw new Error('Transaction hash must be a non-empty string');\n }\n\n return this.retryOperation(async () => {\n const receipt = await this.networkManager.getTransactionReceipt(txHash);\n if (!receipt) {\n throw new Error(`Transaction ${txHash} not found`);\n }\n\n const contractAddress = this.configManager.get('address').toLowerCase();\n const relevantLogs = receipt.logs.filter(\n log => log.address.toLowerCase() === contractAddress\n );\n\n for (const log of relevantLogs) {\n const parsedEvent = this.networkManager.parseLog(log);\n\n if (parsedEvent) {\n const eventKey = this.networkManager.createEventKey(log);\n await this.eventStore.storeEvent(\n parsedEvent.eventName,\n eventKey,\n parsedEvent.eventData\n );\n }\n }\n\n this.lastSyncTime = Date.now();\n return relevantLogs.length;\n }, `Syncing events from transaction ${txHash}`);\n }\n\n // Get sync status information\n async getSyncStatus() {\n return this.retryOperation(async () => {\n const startBlockNumber = await this.eventStore.getStartBlockNumber();\n const latestBlockNumber = await this.networkManager.getLatestBlockNumber();\n const networkInfo = await this.networkManager.getNetworkInfo();\n \n return {\n nextSyncBlock: startBlockNumber,\n latestNetworkBlock: latestBlockNumber,\n blocksBehind: Math.max(0, latestBlockNumber - startBlockNumber + 1),\n networkInfo,\n isUpToDate: startBlockNumber > latestBlockNumber\n };\n }, 'Getting sync status');\n }\n\n // Validate network and contract before syncing\n async validateBeforeSync() {\n await this.networkManager.validateNetwork();\n await this.networkManager.validateContract();\n return true;\n }\n\n // Set batch size for processing (useful for performance tuning)\n setBatchSize(size) {\n if (!Number.isInteger(size) || size < 1) {\n throw new Error('Batch size must be a positive integer');\n }\n this.batchSize = size;\n }\n\n // Get current batch size\n getBatchSize() {\n return this.batchSize;\n }\n\n // Reset sync position to a specific block\n async resetSyncPosition(blockNumber) {\n this.configManager.validateBlockNumber(blockNumber, 'blockNumber');\n await this.eventStore.setStartBlockNumber(blockNumber);\n }\n\n // Get events count by name\n async getEventCount(eventName) {\n const events = await this.eventStore.getEvents(eventName);\n return events.length;\n }\n\n /**\n * Start real-time event streaming via WebSocket or EventEmitter provider.\n */\n startRealtimeSync() {\n const provider = this.networkManager.getProvider();\n\n if (!provider || typeof provider.on !== 'function') {\n throw new Error(\n 'Real-time sync requires a provider that supports event subscriptions ' +\n '(e.g., WebSocketProvider). The current provider does not have an .on() method.'\n );\n }\n\n if (this._realtimeListener) {\n this.logger.warn('Real-time sync is already running, call stopRealtimeSync() first');\n return;\n }\n\n const contractAddress = this.configManager.get('address');\n const filter = { address: contractAddress };\n\n this.logger.info('Starting real-time event sync', {\n contractAddress,\n providerType: provider.constructor.name\n });\n\n const listener = async (log) => {\n try {\n const parsedEvent = this.networkManager.parseLog(log);\n if (parsedEvent) {\n const eventKey = this.networkManager.createEventKey(log);\n await this.eventStore.storeEvent(\n parsedEvent.eventName,\n eventKey,\n parsedEvent.eventData\n );\n this.logger.debug('Real-time event stored', {\n eventName: parsedEvent.eventName,\n eventKey,\n blockNumber: log.blockNumber\n });\n }\n } catch (error) {\n this.logger.warn('Failed to process real-time event', {\n blockNumber: log.blockNumber,\n error: error.message\n });\n }\n };\n\n provider.on(filter, listener);\n this._realtimeListener = listener;\n this._realtimeFilter = filter;\n this.logger.info('Real-time event sync started');\n }\n\n /**\n * Stop real-time event streaming and clean up the listener.\n */\n stopRealtimeSync() {\n if (!this._realtimeListener) {\n this.logger.debug('No real-time sync listener to stop');\n return;\n }\n\n const provider = this.networkManager.getProvider();\n if (provider && typeof provider.off === 'function') {\n provider.off(this._realtimeFilter, this._realtimeListener);\n this.logger.info('Real-time event sync stopped');\n }\n\n this._realtimeListener = null;\n this._realtimeFilter = null;\n }\n\n // Check if syncer is busy (for preventing concurrent syncs)\n isSyncing() {\n return this._syncing || false;\n }\n\n // Set syncing state\n _setSyncing(state) {\n this._syncing = state;\n }\n}","/**\n * EventMetadata - Enriches events with additional blockchain metadata\n */\nexport default class EventMetadata {\n constructor(networkManager, logger) {\n this.networkManager = networkManager;\n this.logger = logger.child({ context: 'EventMetadata' });\n this.logger.info('EventMetadata initialized');\n }\n\n /**\n * Enrich event with metadata\n * @param {Object} event - Event to enrich\n * @param {Object} options - Enrichment options\n * @param {boolean} options.includeBlock - Include block data\n * @param {boolean} options.includeTransaction - Include transaction data\n * @param {boolean} options.includeTimestamp - Include block timestamp\n * @param {boolean} options.includeGasCost - Include gas cost\n * @returns {Promise<Object>} Enriched event\n */\n async enrichEvent(event, options = {}) {\n const {\n includeBlock = true,\n includeTransaction = true,\n includeTimestamp = true,\n includeGasCost = true\n } = options;\n\n try {\n const enrichedEvent = { ...event };\n const promises = [];\n\n // Fetch block data if needed\n if ((includeBlock || includeTimestamp) && event.blockNumber) {\n promises.push(\n this.networkManager.provider.getBlock(event.blockNumber)\n .then(block => {\n if (block) {\n if (includeBlock) {\n enrichedEvent.block = {\n number: block.number,\n hash: block.hash,\n parentHash: block.parentHash,\n miner: block.miner,\n difficulty: block.difficulty?.toString(),\n gasLimit: block.gasLimit.toString(),\n gasUsed: block.gasUsed.toString()\n };\n }\n if (includeTimestamp) {\n enrichedEvent.timestamp = block.timestamp;\n enrichedEvent.date = new Date(block.timestamp * 1000).toISOString();\n }\n }\n })\n .catch(err => {\n this.logger.warn('Failed to fetch block data', {\n blockNumber: event.blockNumber,\n error: err.message\n });\n })\n );\n }\n\n // Fetch transaction data if needed\n if ((includeTransaction || includeGasCost) && event.transactionHash) {\n promises.push(\n Promise.all([\n this.networkManager.provider.getTransaction(event.transactionHash),\n includeGasCost ? this.networkManager.provider.getTransactionReceipt(event.transactionHash) : null\n ]).then(([tx, receipt]) => {\n if (tx) {\n if (includeTransaction) {\n enrichedEvent.transaction = {\n hash: tx.hash,\n from: tx.from,\n to: tx.to,\n value: tx.value.toString(),\n nonce: tx.nonce,\n gasLimit: tx.gasLimit.toString(),\n gasPrice: tx.gasPrice?.toString(),\n maxFeePerGas: tx.maxFeePerGas?.toString(),\n maxPriorityFeePerGas: tx.maxPriorityFeePerGas?.toString(),\n data: tx.data.length > 66 ? tx.data.substring(0, 66) + '...' : tx.data\n };\n }\n if (includeGasCost && receipt) {\n const gasUsed = receipt.gasUsed;\n const gasPrice = tx.gasPrice || tx.maxFeePerGas || 0n;\n const gasCost = gasUsed * gasPrice;\n \n enrichedEvent.gas = {\n used: gasUsed.toString(),\n price: gasPrice.toString(),\n cost: gasCost.toString(),\n costInEther: this._formatEther(gasCost)\n };\n }\n }\n }).catch(err => {\n this.logger.warn('Failed to fetch transaction data', {\n transactionHash: event.transactionHash,\n error: err.message\n });\n })\n );\n }\n\n // Wait for all enrichment operations\n await Promise.all(promises);\n\n // Add metadata about the enrichment\n enrichedEvent._metadata = {\n enrichedAt: new Date().toISOString(),\n enrichmentOptions: options\n };\n\n this.logger.debug('Event enriched with metadata', {\n eventName: event.eventName,\n blockNumber: event.blockNumber,\n metadataAdded: Object.keys(enrichedEvent).filter(k => !event.hasOwnProperty(k))\n });\n\n return enrichedEvent;\n\n } catch (error) {\n this.logger.error('Failed to enrich event', {\n event,\n error: error.message\n });\n // Return original event on error\n return event;\n }\n }\n\n /**\n * Enrich multiple events in batch\n * @param {Array} events - Events to enrich\n * @param {Object} options - Enrichment options\n * @param {number} options.batchSize - Number of events to process concurrently\n * @returns {Promise<Array>} Enriched events\n */\n async enrichEvents(events, options = {}) {\n const { batchSize = 10, ...enrichOptions } = options;\n \n return this.logger.time('enrichEvents', async () => {\n const enrichedEvents = [];\n \n // Process in batches to avoid overwhelming the provider\n let failureCount = 0;\n for (let i = 0; i < events.length; i += batchSize) {\n const batch = events.slice(i, i + batchSize);\n const results = await Promise.allSettled(\n batch.map(event => this.enrichEvent(event, enrichOptions))\n );\n for (let j = 0; j < results.length; j++) {\n if (results[j].status === 'fulfilled') {\n enrichedEvents.push(results[j].value);\n } else {\n failureCount++;\n this.logger.warn('Failed to enrich event, using original', {\n error: results[j].reason?.message,\n blockNumber: batch[j]?.blockNumber\n });\n enrichedEvents.push(batch[j]);\n }\n }\n\n this.logger.debug('Enriched event batch', {\n batchIndex: Math.floor(i / batchSize),\n batchSize: batch.length,\n failures: failureCount,\n totalProgress: `${enrichedEvents.length}/${events.length}`\n });\n }\n \n this.logger.info('Completed event enrichment', {\n totalEvents: events.length,\n enrichedEvents: enrichedEvents.length,\n failures: failureCount\n });\n \n return enrichedEvents;\n });\n }\n\n /**\n * Calculate statistics for a set of events\n * @param {Array} events - Events to analyze\n * @returns {Object} Event statistics\n */\n calculateStatistics(events) {\n if (!Array.isArray(events) || events.length === 0) {\n return {\n count: 0,\n blockRange: { min: null, max: null },\n timeRange: { min: null, max: null },\n gasStats: { total: '0', average: '0', min: '0', max: '0' }\n };\n }\n\n const blockNumbers = events\n .map(e => e.blockNumber)\n .filter(n => n != null)\n .sort((a, b) => a - b);\n\n const timestamps = events\n .map(e => e.timestamp)\n .filter(t => t != null)\n .sort((a, b) => a - b);\n\n const gasCosts = events\n .map(e => e.gas?.cost)\n .filter(c => c != null)\n .map(c => BigInt(c));\n\n const stats = {\n count: events.length,\n blockRange: {\n min: blockNumbers[0] || null,\n max: blockNumbers[blockNumbers.length - 1] || null,\n span: blockNumbers.length > 0 ? blockNumbers[blockNumbers.length - 1] - blockNumbers[0] : 0\n },\n timeRange: {\n min: timestamps[0] || null,\n max: timestamps[timestamps.length - 1] || null,\n span: timestamps.length > 0 ? timestamps[timestamps.length - 1] - timestamps[0] : 0\n }\n };\n\n if (gasCosts.length > 0) {\n const totalGas = gasCosts.reduce((sum, cost) => sum + cost, 0n);\n const avgGas = totalGas / BigInt(gasCosts.length);\n const sortedGas = [...gasCosts].sort((a, b) => a < b ? -1 : 1);\n\n stats.gasStats = {\n total: totalGas.toString(),\n average: avgGas.toString(),\n min: sortedGas[0].toString(),\n max: sortedGas[sortedGas.length - 1].toString(),\n totalInEther: this._formatEther(totalGas)\n };\n } else {\n stats.gasStats = { total: '0', average: '0', min: '0', max: '0' };\n }\n\n // Event type distribution\n const eventTypes = {};\n events.forEach(e => {\n if (e.eventName) {\n eventTypes[e.eventName] = (eventTypes[e.eventName] || 0) + 1;\n }\n });\n stats.eventTypes = eventTypes;\n\n this.logger.debug('Calculated event statistics', stats);\n return stats;\n }\n\n /**\n * Format wei to ether string\n * @private\n */\n _formatEther(wei) {\n try {\n const weiString = wei.toString();\n const ethValue = Number(weiString) / 1e18;\n return ethValue.toFixed(6) + ' ETH';\n } catch {\n return '0 ETH';\n }\n }\n}","/**\n * DebugUtils - Debugging utilities and health check endpoints\n */\nexport default class DebugUtils {\n constructor(magazine, logger) {\n this.magazine = magazine;\n this.logger = logger.child({ context: 'DebugUtils' });\n this.logger.info('DebugUtils initialized');\n \n // Debug mode state\n this.debugMode = false;\n \n // Performance metrics\n this.metrics = {\n syncOperations: [],\n queryOperations: [],\n storageOperations: [],\n networkCalls: []\n };\n \n // Log buffer (circular, max 200 entries)\n this._logBuffer = [];\n this._logBufferMax = 200;\n\n // Map to store original methods before instrumentation\n this._originalMethods = new Map();\n\n // Verbose error mode flag\n this._verboseErrors = false;\n\n // Health check thresholds\n this.healthThresholds = {\n syncDelay: 300000, // 5 minutes\n errorRate: 0.1, // 10%\n responseTime: 5000, // 5 seconds\n storageUsage: 0.9 // 90%\n };\n }\n\n /**\n * Perform comprehensive health check\n * @returns {Promise<Object>} Health check results\n */\n async healthCheck() {\n const startTime = Date.now();\n const results = {\n status: 'healthy',\n timestamp: new Date().toISOString(),\n checks: {},\n issues: []\n };\n\n try {\n // Check network connectivity\n results.checks.network = await this._checkNetwork();\n \n // Check Gun.js database\n results.checks.database = await this._checkDatabase();\n \n // Check sync status\n results.checks.sync = await this._checkSyncStatus();\n \n // Check storage\n results.checks.storage = await this._checkStorage();\n \n // Check performance metrics\n results.checks.performance = this._checkPerformance();\n \n // Determine overall status\n const issues = [];\n Object.entries(results.checks).forEach(([check, result]) => {\n if (result.status !== 'healthy') {\n issues.push({\n check,\n status: result.status,\n message: result.message\n });\n }\n });\n \n if (issues.length > 0) {\n results.status = issues.some(i => i.status === 'critical') ? 'critical' : 'degraded';\n results.issues = issues;\n }\n \n results.duration = Date.now() - startTime;\n \n this.logger.info('Health check completed', {\n status: results.status,\n duration: results.duration,\n issueCount: issues.length\n });\n \n return results;\n \n } catch (error) {\n this.logger.error('Health check failed', { error: error.message });\n return {\n status: 'error',\n timestamp: new Date().toISOString(),\n error: error.message,\n duration: Date.now() - startTime\n };\n }\n }\n\n /**\n * Get debug information about the current state\n * @returns {Promise<Object>} Debug information\n */\n async getDebugInfo() {\n const debugInfo = {\n timestamp: new Date().toISOString(),\n configuration: this._getConfigInfo(),\n network: await this._getNetworkInfo(),\n storage: await this._getStorageInfo(),\n performance: this._getPerformanceInfo(),\n logs: this._getRecentLogs()\n };\n \n this.logger.debug('Debug info generated');\n return debugInfo;\n }\n\n /**\n * Record a metric\n * @param {string} type - Metric type\n * @param {Object} data - Metric data\n */\n recordMetric(type, data) {\n const metric = {\n timestamp: Date.now(),\n ...data\n };\n \n if (this.metrics[type]) {\n this.metrics[type].push(metric);\n \n // Keep only last 1000 metrics per type\n if (this.metrics[type].length > 1000) {\n this.metrics[type] = this.metrics[type].slice(-1000);\n }\n }\n }\n\n /**\n * Get performance report\n * @param {Object} options - Report options\n * @returns {Object} Performance report\n */\n getPerformanceReport(options = {}) {\n const { \n timeRange = 3600000, // Last hour\n aggregation = 'average'\n } = options;\n \n const now = Date.now();\n const startTime = now - timeRange;\n \n const report = {};\n \n Object.entries(this.metrics).forEach(([type, metrics]) => {\n const recentMetrics = metrics.filter(m => m.timestamp >= startTime);\n \n if (recentMetrics.length === 0) {\n report[type] = { count: 0, average: 0, min: 0, max: 0 };\n return;\n }\n \n const durations = recentMetrics.map(m => m.duration || 0);\n const errors = recentMetrics.filter(m => m.error).length;\n \n report[type] = {\n count: recentMetrics.length,\n errors,\n errorRate: (errors / recentMetrics.length * 100).toFixed(2) + '%',\n average: Math.round(durations.reduce((a, b) => a + b, 0) / durations.length),\n min: Math.min(...durations),\n max: Math.max(...durations),\n p95: this._calculatePercentile(durations, 95),\n p99: this._calculatePercentile(durations, 99)\n };\n });\n \n return {\n timeRange: {\n start: new Date(startTime).toISOString(),\n end: new Date(now).toISOString(),\n duration: timeRange\n },\n metrics: report\n };\n }\n\n /**\n * Enable debug mode\n * @param {Object} options - Debug options\n */\n enableDebugMode(options = {}) {\n const {\n logLevel = 'debug',\n captureMetrics = true,\n verboseErrors = true\n } = options;\n \n // Set log level\n this.magazine.setLogLevel(logLevel);\n \n // Enable metric capture\n if (captureMetrics) {\n this._instrumentMethods();\n }\n \n // Enable verbose errors\n if (verboseErrors) {\n this._enableVerboseErrors();\n }\n \n this.logger.info('Debug mode enabled', options);\n }\n\n /**\n * Export debug data\n * @returns {Promise<Object>} Exportable debug data\n */\n async exportDebugData() {\n const data = {\n version: '1.0.0',\n exportedAt: new Date().toISOString(),\n debugInfo: await this.getDebugInfo(),\n healthCheck: await this.healthCheck(),\n performanceReport: this.getPerformanceReport(),\n recentMetrics: {\n sync: this.metrics.syncOperations.slice(-100),\n query: this.metrics.queryOperations.slice(-100),\n storage: this.metrics.storageOperations.slice(-100),\n network: this.metrics.networkCalls.slice(-100)\n }\n };\n \n this.logger.info('Debug data exported');\n return data;\n }\n\n /**\n * Check network connectivity\n * @private\n */\n async _checkNetwork() {\n try {\n const startTime = Date.now();\n const blockNumber = await this.magazine.getLatestBlockNumber();\n const duration = Date.now() - startTime;\n \n return {\n status: duration < this.healthThresholds.responseTime ? 'healthy' : 'degraded',\n latestBlock: blockNumber,\n responseTime: duration,\n message: `Network response time: ${duration}ms`\n };\n } catch (error) {\n return {\n status: 'critical',\n error: error.message,\n message: 'Network connection failed'\n };\n }\n }\n\n /**\n * Check database connectivity\n * @private\n */\n async _checkDatabase() {\n try {\n const startTime = Date.now();\n const gun = this.magazine.eventStore.getGunInstance();\n \n // Try to read a test value\n await new Promise((resolve, reject) => {\n gun.get('_health_check').put({ \n timestamp: Date.now() \n }, (ack) => {\n if (ack.err) reject(new Error(ack.err));\n else resolve(ack);\n });\n });\n \n const duration = Date.now() - startTime;\n \n return {\n status: duration < 1000 ? 'healthy' : 'degraded',\n responseTime: duration,\n message: `Database response time: ${duration}ms`\n };\n } catch (error) {\n return {\n status: 'critical',\n error: error.message,\n message: 'Database connection failed'\n };\n }\n }\n\n /**\n * Check sync status\n * @private\n */\n async _checkSyncStatus() {\n try {\n const lastSync = this.magazine.eventSyncer.lastSyncTime || 0;\n const timeSinceSync = Date.now() - lastSync;\n \n if (lastSync === 0) {\n return {\n status: 'warning',\n message: 'No sync performed yet'\n };\n }\n \n return {\n status: timeSinceSync < this.healthThresholds.syncDelay ? 'healthy' : 'warning',\n lastSync: new Date(lastSync).toISOString(),\n timeSinceSync,\n message: `Last sync: ${Math.round(timeSinceSync / 1000)}s ago`\n };\n } catch (error) {\n return {\n status: 'error',\n error: error.message,\n message: 'Could not check sync status'\n };\n }\n }\n\n /**\n * Check storage status\n * @private\n */\n async _checkStorage() {\n try {\n const stats = await this.magazine.getCompressionStats();\n const usage = stats.totalCompressedSize / (100 * 1024 * 1024); // Assume 100MB limit\n \n return {\n status: usage < this.healthThresholds.storageUsage ? 'healthy' : 'warning',\n usage: `${(usage * 100).toFixed(2)}%`,\n compressed: stats.totalCompressedSize,\n saved: stats.spaceSaved,\n message: `Storage usage: ${(usage * 100).toFixed(2)}%`\n };\n } catch (error) {\n return {\n status: 'error',\n error: error.message,\n message: 'Could not check storage status'\n };\n }\n }\n\n /**\n * Check performance metrics\n * @private\n */\n _checkPerformance() {\n const report = this.getPerformanceReport({ timeRange: 300000 }); // Last 5 minutes\n let status = 'healthy';\n const issues = [];\n \n Object.entries(report.metrics).forEach(([type, metrics]) => {\n if (metrics.errorRate && parseFloat(metrics.errorRate) > this.healthThresholds.errorRate * 100) {\n status = 'degraded';\n issues.push(`High error rate in ${type}: ${metrics.errorRate}`);\n }\n \n if (metrics.average > this.healthThresholds.responseTime) {\n status = 'degraded';\n issues.push(`Slow ${type} operations: ${metrics.average}ms average`);\n }\n });\n \n return {\n status,\n metrics: report.metrics,\n message: issues.length > 0 ? issues.join(', ') : 'Performance metrics within normal range'\n };\n }\n\n /**\n * Get configuration info\n * @private\n */\n _getConfigInfo() {\n const config = this.magazine.configManager.getAll();\n return {\n name: config.name,\n address: config.address,\n networkId: config.networkId,\n logLevel: this.magazine.logger.level,\n compression: {\n enabled: this.magazine.eventStore.compressionEnabled,\n strategy: this.magazine.eventStore.compressionStrategy\n }\n };\n }\n\n /**\n * Get network info\n * @private\n */\n async _getNetworkInfo() {\n try {\n const info = await this.magazine.getNetworkInfo();\n return {\n ...info,\n connected: true\n };\n } catch (error) {\n return {\n connected: false,\n error: error.message\n };\n }\n }\n\n /**\n * Get storage info\n * @private\n */\n async _getStorageInfo() {\n try {\n const compressionStats = await this.magazine.getCompressionStats();\n const eventCount = (await this.magazine.getAllEvents({ pagination: { page: 1, pageSize: 1 } })).meta.totalItems;\n \n return {\n eventCount,\n ...compressionStats\n };\n } catch (error) {\n return {\n error: error.message\n };\n }\n }\n\n /**\n * Get performance info\n * @private\n */\n _getPerformanceInfo() {\n return this.getPerformanceReport({ timeRange: 3600000 }); // Last hour\n }\n\n /**\n * Capture a log entry into the circular buffer\n * @param {Object} entry - Log entry to capture\n */\n captureLog(entry) {\n this._logBuffer.push(entry);\n if (this._logBuffer.length > this._logBufferMax) {\n this._logBuffer.shift();\n }\n }\n\n /**\n * Get recent logs from the circular buffer\n * @param {number} [count=50] - Number of recent log entries to return\n * @returns {Array} Recent log entries\n * @private\n */\n _getRecentLogs(count = 50) {\n const n = Math.min(count, this._logBuffer.length);\n return this._logBuffer.slice(-n);\n }\n\n /**\n * Calculate percentile\n * @private\n */\n _calculatePercentile(values, percentile) {\n if (values.length === 0) return 0;\n \n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil((percentile / 100) * sorted.length) - 1;\n return sorted[index];\n }\n\n /**\n * Instrument methods for metric collection\n * @private\n */\n _instrumentMethods() {\n const mag = this.magazine;\n const methodsToInstrument = [\n 'syncEvents',\n 'getAllEvents',\n 'getEvents',\n 'query',\n 'transformEvent'\n ];\n\n for (const methodName of methodsToInstrument) {\n if (typeof mag[methodName] !== 'function') {\n this.logger.debug(`Skipping instrumentation for missing method: ${methodName}`);\n continue;\n }\n\n // Skip if already instrumented\n if (this._originalMethods.has(methodName)) {\n continue;\n }\n\n const original = mag[methodName].bind(mag);\n this._originalMethods.set(methodName, mag[methodName]);\n\n const self = this;\n mag[methodName] = function (...args) {\n const startTime = Date.now();\n let metricType;\n if (methodName === 'syncEvents') {\n metricType = 'syncOperations';\n } else if (methodName === 'getAllEvents' || methodName === 'getEvents' || methodName === 'query') {\n metricType = 'queryOperations';\n } else {\n metricType = 'storageOperations';\n }\n\n try {\n const result = original(...args);\n\n // Handle both sync and async results\n if (result && typeof result.then === 'function') {\n return result.then((value) => {\n const duration = Date.now() - startTime;\n self.recordMetric(metricType, {\n method: methodName,\n duration,\n success: true\n });\n self.logger.debug(`${methodName} completed in ${duration}ms`);\n return value;\n }).catch((error) => {\n const duration = Date.now() - startTime;\n self.recordMetric(metricType, {\n method: methodName,\n duration,\n success: false,\n error: error.message\n });\n self.logger.debug(`${methodName} failed after ${duration}ms: ${error.message}`);\n throw error;\n });\n }\n\n const duration = Date.now() - startTime;\n self.recordMetric(metricType, {\n method: methodName,\n duration,\n success: true\n });\n self.logger.debug(`${methodName} completed in ${duration}ms`);\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n self.recordMetric(metricType, {\n method: methodName,\n duration,\n success: false,\n error: error.message\n });\n self.logger.debug(`${methodName} failed after ${duration}ms: ${error.message}`);\n throw error;\n }\n };\n }\n\n this.logger.debug('Method instrumentation enabled');\n }\n\n /**\n * Enable verbose error logging\n * @private\n */\n _enableVerboseErrors() {\n this._verboseErrors = true;\n\n const mag = this.magazine;\n if (typeof mag.retryOperation === 'function' && !this._originalRetryOperation) {\n const originalRetry = mag.retryOperation.bind(mag);\n this._originalRetryOperation = mag.retryOperation;\n const self = this;\n\n mag.retryOperation = async function (operation, context, ...rest) {\n try {\n return await originalRetry(operation, context, ...rest);\n } catch (error) {\n if (self._verboseErrors) {\n self.logger.error('Verbose error context for retryOperation failure', {\n operationContext: context,\n errorMessage: error.message,\n errorStack: error.stack,\n errorName: error.name,\n timestamp: new Date().toISOString()\n });\n }\n throw error;\n }\n };\n }\n\n this.logger.debug('Verbose error logging enabled');\n }\n\n /**\n * Set debug mode on/off\n * @param {boolean} enabled - Whether to enable debug mode\n */\n setDebugMode(enabled) {\n this.debugMode = !!enabled;\n this.logger.info(`Debug mode ${enabled ? 'enabled' : 'disabled'}`);\n\n if (enabled) {\n this._instrumentMethods();\n this._enableVerboseErrors();\n\n // Monkey-patch the logger's _log method to capture entries\n if (this.logger._log && !this._originalLoggerLog) {\n this._originalLoggerLog = this.logger._log.bind(this.logger);\n const self = this;\n this.logger._log = function (level, message, data) {\n const result = self._originalLoggerLog(level, message, data);\n self.captureLog({\n timestamp: Date.now(),\n level,\n message,\n data\n });\n return result;\n };\n }\n } else {\n // Restore logger _log if it was patched\n if (this._originalLoggerLog) {\n this.logger._log = this._originalLoggerLog;\n this._originalLoggerLog = null;\n }\n }\n }\n\n /**\n * Check if debug mode is enabled\n * @returns {boolean} Debug mode status\n */\n isDebugMode() {\n return !!this.debugMode;\n }\n}","/**\n * DataTransformer - Transforms blockchain events into structured data models using GunDB\n * Inspired by @nomyx/gundb but integrated with Magazine's existing architecture\n */\nimport Logger from './Logger.js';\n\n/**\n * Custom error classes for data transformation\n */\nexport class ValidationError extends Error {\n constructor(message, field = null) {\n super(message);\n this.name = 'ValidationError';\n this.field = field;\n }\n}\n\nexport class ModelError extends Error {\n constructor(message) {\n super(message);\n this.name = 'ModelError';\n }\n}\n\n/**\n * SchemaMigration - Tracks schema versions and migrates documents between versions.\n */\nexport class SchemaMigration {\n constructor(modelName, gunInstance) {\n this.modelName = modelName;\n this.gun = gunInstance;\n this.migrations = new Map();\n this.currentVersion = 1;\n }\n\n version(v) {\n this.currentVersion = v;\n return this;\n }\n\n addMigration(fromVersion, toVersion, migrateFn) {\n this.migrations.set(`${fromVersion}:${toVersion}`, migrateFn);\n return this;\n }\n\n async migrate(document) {\n let docVersion = document._schemaVersion || 1;\n let migrated = { ...document };\n while (docVersion < this.currentVersion) {\n const nextVersion = docVersion + 1;\n const key = `${docVersion}:${nextVersion}`;\n const migrateFn = this.migrations.get(key);\n if (!migrateFn) {\n throw new ModelError(\n `No migration path from version ${docVersion} to ${nextVersion} for model '${this.modelName}'`\n );\n }\n migrated = await migrateFn(migrated);\n migrated._schemaVersion = nextVersion;\n docVersion = nextVersion;\n }\n return migrated;\n }\n\n needsMigration(document) {\n return (document._schemaVersion || 1) < this.currentVersion;\n }\n}\n\n/**\n * Simple schema validator (can be extended to use Joi or other validation libraries)\n */\nclass SchemaValidator {\n static validate(data, schema) {\n const errors = [];\n \n // Check required fields\n for (const field of schema.required || []) {\n if (!(field in data) || data[field] === null || data[field] === undefined) {\n errors.push(`Field '${field}' is required`);\n }\n }\n \n // Check field types\n for (const [field, definition] of Object.entries(schema.properties || {})) {\n if (field in data && data[field] !== null && data[field] !== undefined) {\n const value = data[field];\n const { type, validate: customValidator } = definition;\n \n // Type validation\n if (type && !this.validateType(value, type)) {\n errors.push(`Field '${field}' must be of type ${type}`);\n }\n \n // Custom validation\n if (customValidator && typeof customValidator === 'function') {\n const customResult = customValidator(value);\n if (customResult !== true) {\n errors.push(`Field '${field}': ${customResult || 'validation failed'}`);\n }\n }\n }\n }\n \n return {\n valid: errors.length === 0,\n errors\n };\n }\n \n static validateType(value, type) {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && !isNaN(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n case 'address':\n return typeof value === 'string' && /^0x[a-fA-F0-9]{40}$/.test(value);\n case 'hash':\n return typeof value === 'string' && /^0x[a-fA-F0-9]{64}$/.test(value);\n default:\n return true;\n }\n }\n}\n\n/**\n * DataModel - Represents a structured data model with CRUD operations\n */\nexport class DataModel {\n constructor(name, schema, gunInstance, transformer, options = {}) {\n this.name = name;\n this.schema = schema;\n this.gun = gunInstance;\n this.transformer = transformer;\n this.options = {\n autoId: true,\n timestampFields: ['createdAt', 'updatedAt'],\n ...options\n };\n \n this.logger = new Logger({\n context: `DataModel:${name}`,\n level: options.logLevel || 'info'\n });\n \n // Get model's Gun node\n this.modelNode = this.gun.get('models').get(this.name);\n\n // Lifecycle hooks: { 'pre:save': [fn], 'post:save': [fn], ... }\n this._hooks = {};\n\n // Schema migration instance (set via setMigration)\n this.migration = null;\n\n this.logger.info('DataModel initialized', {\n name: this.name,\n options: this.options\n });\n }\n\n /**\n * Register a lifecycle hook\n * @param {'pre:save'|'post:save'|'pre:update'|'post:update'|'pre:delete'|'post:delete'} event\n * @param {Function} fn - Hook function. Pre-hooks receive (data) and can return modified data. Post-hooks receive (result).\n */\n hook(event, fn) {\n if (!this._hooks[event]) this._hooks[event] = [];\n this._hooks[event].push(fn);\n return this;\n }\n\n /**\n * Attach a SchemaMigration instance so documents are auto-migrated on read.\n * @param {SchemaMigration} schemaMigration\n * @returns {DataModel} this (for chaining)\n */\n setMigration(schemaMigration) {\n this.migration = schemaMigration;\n return this;\n }\n\n async _runHooks(event, data) {\n const hooks = this._hooks[event] || [];\n let result = data;\n for (const fn of hooks) {\n const out = await fn(result);\n if (out !== undefined) result = out;\n }\n return result;\n }\n\n /**\n * Generate a unique ID for a new document\n * @returns {string} Unique ID\n */\n generateId() {\n return `${this.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n /**\n * Validate data against schema\n * @param {Object} data - Data to validate\n * @throws {ValidationError} If validation fails\n */\n validate(data) {\n const result = SchemaValidator.validate(data, this.schema);\n if (!result.valid) {\n throw new ValidationError(`Validation failed: ${result.errors.join(', ')}`);\n }\n }\n\n /**\n * Prepare data for storage (add timestamps, ID, etc.)\n * @param {Object} data - Raw data\n * @param {boolean} isUpdate - Whether this is an update operation\n * @returns {Object} Prepared data\n */\n prepareData(data, isUpdate = false) {\n const prepared = { ...data };\n \n // Add auto-generated ID if needed\n if (this.options.autoId && !prepared.id && !isUpdate) {\n prepared.id = this.generateId();\n }\n \n // Add timestamps\n if (this.options.timestampFields.includes('updatedAt')) {\n prepared.updatedAt = new Date().toISOString();\n }\n \n if (this.options.timestampFields.includes('createdAt') && !isUpdate) {\n prepared.createdAt = new Date().toISOString();\n }\n\n if (this.migration) {\n prepared._schemaVersion = this.migration.currentVersion;\n }\n\n return prepared;\n }\n\n /**\n * Save a document (create or update)\n * @param {Object} data - Document data\n * @returns {Promise<Object>} Saved document\n */\n async save(data) {\n this.logger.debug('Saving document', { data });\n\n try {\n let prepared = this.prepareData(data);\n prepared = await this._runHooks('pre:save', prepared);\n this.validate(prepared);\n\n const id = prepared.id;\n if (!id) {\n throw new ModelError('Document must have an ID');\n }\n\n await new Promise((resolve, reject) => {\n this.modelNode.get(id).put(prepared, (ack) => {\n if (ack.err) {\n reject(new ModelError(`Failed to save document: ${ack.err}`));\n } else {\n resolve();\n }\n });\n });\n\n await this._runHooks('post:save', prepared);\n this.logger.info('Document saved', { id, model: this.name });\n return prepared;\n\n } catch (error) {\n this.logger.error('Failed to save document', { error: error.message, data });\n throw error;\n }\n }\n\n /**\n * Find documents by query\n * @param {Object} query - Query object\n * @param {Object} options - Query options\n * @returns {Promise<Array>} Found documents\n */\n async find(query = {}, options = {}) {\n this.logger.debug('Finding documents', { query, options });\n \n try {\n const { limit = 100, skip = 0 } = options;\n const results = [];\n \n await new Promise((resolve) => {\n let count = 0;\n let skipped = 0;\n \n this.modelNode.map().on((data, key) => {\n if (data && typeof data === 'object') {\n // Simple query matching (can be enhanced with more complex queries)\n if (this.matchesQuery(data, query)) {\n if (skipped < skip) {\n skipped++;\n return;\n }\n \n if (count < limit) {\n results.push({ ...data, _key: key });\n count++;\n }\n \n if (count >= limit) {\n resolve();\n }\n }\n }\n });\n \n // Resolve after a timeout to handle cases with fewer results\n setTimeout(resolve, 1000);\n });\n \n if (this.migration) {\n for (let i = 0; i < results.length; i++) {\n if (this.migration.needsMigration(results[i])) {\n results[i] = await this.migration.migrate(results[i]);\n await this.save(results[i]);\n }\n }\n }\n\n this.logger.debug('Documents found', { count: results.length, query });\n return results;\n \n } catch (error) {\n this.logger.error('Failed to find documents', { error: error.message, query });\n throw new ModelError(`Failed to find documents: ${error.message}`);\n }\n }\n\n /**\n * Find a single document by query\n * @param {Object} query - Query object\n * @returns {Promise<Object|null>} Found document or null\n */\n async findOne(query) {\n const results = await this.find(query, { limit: 1 });\n return results.length > 0 ? results[0] : null;\n }\n\n /**\n * Find a document by ID\n * @param {string} id - Document ID\n * @returns {Promise<Object|null>} Found document or null\n */\n async findById(id) {\n this.logger.debug('Finding document by ID', { id });\n\n try {\n let doc = await new Promise((resolve) => {\n this.modelNode.get(id).once((data) => {\n if (data && typeof data === 'object') {\n resolve({ ...data, _key: id });\n } else {\n resolve(null);\n }\n });\n });\n\n if (doc && this.migration && this.migration.needsMigration(doc)) {\n doc = await this.migration.migrate(doc);\n await this.save(doc);\n }\n\n return doc;\n } catch (error) {\n this.logger.error('Failed to find document by ID', { error: error.message, id });\n throw new ModelError(`Failed to find document: ${error.message}`);\n }\n }\n\n /**\n * Update a document by ID\n * @param {string} id - Document ID\n * @param {Object} updateData - Data to update\n * @returns {Promise<Object>} Updated document\n */\n async update(id, updateData) {\n this.logger.debug('Updating document', { id, updateData });\n\n try {\n const existing = await this.findById(id);\n if (!existing) {\n throw new ModelError(`Document with ID ${id} not found`);\n }\n\n const updated = { ...existing, ...updateData, id };\n let prepared = this.prepareData(updated, true);\n prepared = await this._runHooks('pre:update', prepared);\n this.validate(prepared);\n\n await new Promise((resolve, reject) => {\n this.modelNode.get(id).put(prepared, (ack) => {\n if (ack.err) {\n reject(new ModelError(`Failed to update document: ${ack.err}`));\n } else {\n resolve();\n }\n });\n });\n\n await this._runHooks('post:update', prepared);\n this.logger.info('Document updated', { id, model: this.name });\n return prepared;\n\n } catch (error) {\n this.logger.error('Failed to update document', { error: error.message, id, updateData });\n throw error;\n }\n }\n\n /**\n * Delete a document by ID\n * @param {string} id - Document ID\n * @returns {Promise<boolean>} Success status\n */\n async delete(id) {\n this.logger.debug('Deleting document', { id });\n\n try {\n await this._runHooks('pre:delete', { id });\n\n await new Promise((resolve, reject) => {\n this.modelNode.get(id).put(null, (ack) => {\n if (ack.err) {\n reject(new ModelError(`Failed to delete document: ${ack.err}`));\n } else {\n resolve();\n }\n });\n });\n\n await this._runHooks('post:delete', { id });\n this.logger.info('Document deleted', { id, model: this.name });\n return true;\n\n } catch (error) {\n this.logger.error('Failed to delete document', { error: error.message, id });\n throw error;\n }\n }\n\n /**\n * Count documents matching query\n * @param {Object} query - Query object\n * @returns {Promise<number>} Document count\n */\n async count(query = {}) {\n const results = await this.find(query, { limit: 10000 });\n return results.length;\n }\n\n /**\n * Insert multiple documents\n * @param {Array<Object>} documents - Array of documents to insert\n * @returns {Promise<Array<Object>>} Saved documents\n */\n async insertMany(documents) {\n if (!Array.isArray(documents)) {\n throw new ModelError('insertMany requires an array of documents');\n }\n const results = [];\n const errors = [];\n for (const doc of documents) {\n try {\n results.push(await this.save(doc));\n } catch (error) {\n errors.push({ document: doc, error: error.message });\n }\n }\n if (errors.length > 0) {\n this.logger.warn('Some documents failed to insert', {\n total: documents.length, succeeded: results.length, failed: errors.length\n });\n }\n return { inserted: results, errors };\n }\n\n /**\n * Update multiple documents matching a query\n * @param {Object} query - Query to match documents\n * @param {Object} updateData - Data to update on each matched document\n * @returns {Promise<Object>} Update results\n */\n async updateMany(query, updateData) {\n const docs = await this.find(query, { limit: 100000 });\n const results = [];\n const errors = [];\n for (const doc of docs) {\n const id = doc.id || doc._key;\n if (!id) continue;\n try {\n results.push(await this.update(id, updateData));\n } catch (error) {\n errors.push({ id, error: error.message });\n }\n }\n this.logger.info('updateMany completed', {\n matched: docs.length, updated: results.length, failed: errors.length\n });\n return { matched: docs.length, updated: results, errors };\n }\n\n /**\n * Delete multiple documents matching a query\n * @param {Object} query - Query to match documents for deletion\n * @returns {Promise<Object>} Deletion results\n */\n async deleteMany(query) {\n const docs = await this.find(query, { limit: 100000 });\n let deleted = 0;\n const errors = [];\n for (const doc of docs) {\n const id = doc.id || doc._key;\n if (!id) continue;\n try {\n await this.delete(id);\n deleted++;\n } catch (error) {\n errors.push({ id, error: error.message });\n }\n }\n this.logger.info('deleteMany completed', {\n matched: docs.length, deleted, failed: errors.length\n });\n return { matched: docs.length, deleted, errors };\n }\n\n /**\n * Migrate all documents in this model to the current schema version.\n * @returns {Promise<Object>} Migration results { migrated, errors }\n */\n async migrateAll() {\n if (!this.migration) {\n throw new ModelError('No migration configured for this model. Call setMigration() first.');\n }\n const docs = await this.find({}, { limit: 100000 });\n let migrated = 0;\n const errors = [];\n for (const doc of docs) {\n if (this.migration.needsMigration(doc)) {\n try {\n const updated = await this.migration.migrate(doc);\n await this.save(updated);\n migrated++;\n } catch (error) {\n errors.push({ id: doc.id || doc._key, error: error.message });\n }\n }\n }\n this.logger.info('migrateAll completed', {\n total: docs.length, migrated, failed: errors.length\n });\n return { total: docs.length, migrated, errors };\n }\n\n /**\n * Simple query matching (can be enhanced with MongoDB-like operators)\n * @private\n * @param {Object} document - Document to test\n * @param {Object} query - Query object\n * @returns {boolean} Whether document matches query\n */\n matchesQuery(document, query) {\n for (const [field, value] of Object.entries(query)) {\n if (typeof value === 'object' && value !== null) {\n // Handle operators like { age: { $gte: 18 } }\n for (const [operator, operand] of Object.entries(value)) {\n switch (operator) {\n case '$gte':\n if (!(document[field] >= operand)) return false;\n break;\n case '$lte':\n if (!(document[field] <= operand)) return false;\n break;\n case '$gt':\n if (!(document[field] > operand)) return false;\n break;\n case '$lt':\n if (!(document[field] < operand)) return false;\n break;\n case '$ne':\n if (document[field] === operand) return false;\n break;\n case '$in':\n if (!Array.isArray(operand) || !operand.includes(document[field])) return false;\n break;\n case '$nin':\n if (Array.isArray(operand) && operand.includes(document[field])) return false;\n break;\n case '$regex':\n if (!new RegExp(operand).test(document[field])) return false;\n break;\n default:\n // Unknown operator, treat as exact match\n if (document[field] !== value) return false;\n }\n }\n } else {\n // Exact match\n if (document[field] !== value) return false;\n }\n }\n return true;\n }\n\n /**\n * Create an aggregation pipeline from query results.\n * @param {Object} [query={}] - Optional query to filter documents before aggregation\n * @returns {Promise<AggregationPipeline>} A new AggregationPipeline instance\n */\n async aggregate(query = {}) {\n const results = await this.find(query, { limit: 100000 });\n return new AggregationPipeline(results);\n }\n}\n\n/**\n * AggregationPipeline - Provides aggregate functions, grouping, time-series\n * bucketing, and a fluent API for chaining operations on in-memory datasets.\n */\nexport class AggregationPipeline {\n constructor(data) {\n this.data = Array.isArray(data) ? data : [];\n this.stages = [];\n }\n\n /**\n * Filter/match stage - filter data before aggregation.\n * Uses the same query operators as DataModel.matchesQuery.\n * @param {Object} query - Query object with optional operators ($gte, $lte, etc.)\n * @returns {AggregationPipeline} this (for chaining)\n */\n match(query) {\n this.stages.push({ type: 'match', query });\n return this;\n }\n\n /**\n * Group results by a field.\n * @param {string} field - Field name to group by\n * @returns {AggregationPipeline} this (for chaining)\n */\n group(field) {\n this.stages.push({ type: 'group', field });\n return this;\n }\n\n /**\n * Sum aggregate on a numeric field.\n * @param {string} field - Field to sum\n * @param {string} [alias] - Optional alias for the result key (default: `sum_<field>`)\n * @returns {AggregationPipeline} this (for chaining)\n */\n sum(field, alias) {\n this.stages.push({ type: 'aggregate', op: 'sum', field, alias: alias || `sum_${field}` });\n return this;\n }\n\n /**\n * Average aggregate on a numeric field.\n * @param {string} field - Field to average\n * @param {string} [alias] - Optional alias for the result key (default: `avg_<field>`)\n * @returns {AggregationPipeline} this (for chaining)\n */\n avg(field, alias) {\n this.stages.push({ type: 'aggregate', op: 'avg', field, alias: alias || `avg_${field}` });\n return this;\n }\n\n /**\n * Count aggregate.\n * @param {string} [alias] - Optional alias for the result key (default: `count`)\n * @returns {AggregationPipeline} this (for chaining)\n */\n count(alias) {\n this.stages.push({ type: 'aggregate', op: 'count', alias: alias || 'count' });\n return this;\n }\n\n /**\n * Min aggregate on a numeric field.\n * @param {string} field - Field to find minimum of\n * @param {string} [alias] - Optional alias for the result key (default: `min_<field>`)\n * @returns {AggregationPipeline} this (for chaining)\n */\n min(field, alias) {\n this.stages.push({ type: 'aggregate', op: 'min', field, alias: alias || `min_${field}` });\n return this;\n }\n\n /**\n * Max aggregate on a numeric field.\n * @param {string} field - Field to find maximum of\n * @param {string} [alias] - Optional alias for the result key (default: `max_<field>`)\n * @returns {AggregationPipeline} this (for chaining)\n */\n max(field, alias) {\n this.stages.push({ type: 'aggregate', op: 'max', field, alias: alias || `max_${field}` });\n return this;\n }\n\n /**\n * Time-series bucketing - groups data by time intervals.\n * Acts like a group stage but groups by truncated timestamp buckets.\n * @param {string} timestampField - Field containing a unix timestamp (seconds)\n * @param {'minute'|'hour'|'day'|'week'|'month'} interval - Bucket interval\n * @returns {AggregationPipeline} this (for chaining)\n */\n bucket(timestampField, interval) {\n this.stages.push({ type: 'bucket', timestampField, interval });\n return this;\n }\n\n /**\n * Sort results by a field.\n * @param {string} field - Field to sort by\n * @param {'asc'|'desc'} [order='asc'] - Sort order\n * @returns {AggregationPipeline} this (for chaining)\n */\n sort(field, order = 'asc') {\n this.stages.push({ type: 'sort', field, order });\n return this;\n }\n\n /**\n * Limit the number of results returned.\n * @param {number} n - Maximum number of results\n * @returns {AggregationPipeline} this (for chaining)\n */\n limit(n) {\n this.stages.push({ type: 'limit', n });\n return this;\n }\n\n /**\n * Truncate a Date to the start of the given interval bucket.\n * @private\n * @param {Date} date\n * @param {string} interval\n * @returns {string} ISO string representing the bucket start\n */\n _truncateDate(date, interval) {\n const d = new Date(date);\n switch (interval) {\n case 'minute':\n d.setUTCSeconds(0, 0);\n break;\n case 'hour':\n d.setUTCMinutes(0, 0, 0);\n break;\n case 'day':\n d.setUTCHours(0, 0, 0, 0);\n break;\n case 'week': {\n d.setUTCHours(0, 0, 0, 0);\n // Move back to Monday (ISO week start)\n const day = d.getUTCDay();\n const diff = (day === 0 ? 6 : day - 1);\n d.setUTCDate(d.getUTCDate() - diff);\n break;\n }\n case 'month':\n d.setUTCDate(1);\n d.setUTCHours(0, 0, 0, 0);\n break;\n default:\n break;\n }\n return d.toISOString();\n }\n\n /**\n * Simple query matching, mirroring DataModel.matchesQuery.\n * @private\n * @param {Object} document\n * @param {Object} query\n * @returns {boolean}\n */\n _matchesQuery(document, query) {\n for (const [field, value] of Object.entries(query)) {\n if (typeof value === 'object' && value !== null) {\n for (const [operator, operand] of Object.entries(value)) {\n switch (operator) {\n case '$gte':\n if (!(document[field] >= operand)) return false;\n break;\n case '$lte':\n if (!(document[field] <= operand)) return false;\n break;\n case '$gt':\n if (!(document[field] > operand)) return false;\n break;\n case '$lt':\n if (!(document[field] < operand)) return false;\n break;\n case '$ne':\n if (document[field] === operand) return false;\n break;\n case '$in':\n if (!Array.isArray(operand) || !operand.includes(document[field])) return false;\n break;\n case '$nin':\n if (Array.isArray(operand) && operand.includes(document[field])) return false;\n break;\n case '$regex':\n if (!new RegExp(operand).test(document[field])) return false;\n break;\n default:\n if (document[field] !== value) return false;\n }\n }\n } else {\n if (document[field] !== value) return false;\n }\n }\n return true;\n }\n\n /**\n * Compute a single aggregate value over an array of documents.\n * @private\n * @param {Array} docs - Array of documents\n * @param {Object} stage - Aggregate stage descriptor\n * @returns {number} Computed aggregate value\n */\n _computeAggregate(docs, stage) {\n const { op, field } = stage;\n switch (op) {\n case 'count':\n return docs.length;\n case 'sum': {\n let total = 0;\n for (const doc of docs) {\n const v = Number(doc[field]);\n if (!isNaN(v)) total += v;\n }\n return total;\n }\n case 'avg': {\n let sum = 0;\n let cnt = 0;\n for (const doc of docs) {\n const v = Number(doc[field]);\n if (!isNaN(v)) {\n sum += v;\n cnt++;\n }\n }\n return cnt > 0 ? sum / cnt : 0;\n }\n case 'min': {\n let result = Infinity;\n for (const doc of docs) {\n const v = Number(doc[field]);\n if (!isNaN(v) && v < result) result = v;\n }\n return result === Infinity ? 0 : result;\n }\n case 'max': {\n let result = -Infinity;\n for (const doc of docs) {\n const v = Number(doc[field]);\n if (!isNaN(v) && v > result) result = v;\n }\n return result === -Infinity ? 0 : result;\n }\n default:\n return 0;\n }\n }\n\n /**\n * Execute the aggregation pipeline and return results.\n *\n * Processing order:\n * 1. match stages filter the working dataset\n * 2. group / bucket stages partition data into groups\n * 3. aggregate stages compute values per group (or globally)\n * 4. sort / limit are applied to the final result set\n *\n * @returns {Object|Array} Aggregation results\n */\n execute() {\n let workingData = [...this.data];\n\n // Separate stages by type\n const matchStages = [];\n const aggregateStages = [];\n let groupStage = null;\n let bucketStage = null;\n const postStages = []; // sort, limit\n\n for (const stage of this.stages) {\n switch (stage.type) {\n case 'match':\n matchStages.push(stage);\n break;\n case 'group':\n groupStage = stage;\n break;\n case 'bucket':\n bucketStage = stage;\n break;\n case 'aggregate':\n aggregateStages.push(stage);\n break;\n case 'sort':\n case 'limit':\n postStages.push(stage);\n break;\n }\n }\n\n // 1. Apply match stages (filters)\n for (const stage of matchStages) {\n workingData = workingData.filter(doc => this._matchesQuery(doc, stage.query));\n }\n\n // 2. Determine grouping\n let groups = null; // Map<string, Array>\n\n if (bucketStage) {\n // Bucket by time interval\n groups = new Map();\n const { timestampField, interval } = bucketStage;\n for (const doc of workingData) {\n const ts = doc[timestampField];\n if (ts === undefined || ts === null) continue;\n // Treat as unix seconds; convert to Date\n const date = new Date(typeof ts === 'number' ? ts * 1000 : ts);\n if (isNaN(date.getTime())) continue;\n const bucketKey = this._truncateDate(date, interval);\n if (!groups.has(bucketKey)) {\n groups.set(bucketKey, []);\n }\n groups.get(bucketKey).push(doc);\n }\n } else if (groupStage) {\n groups = new Map();\n const { field } = groupStage;\n for (const doc of workingData) {\n const key = doc[field] !== undefined && doc[field] !== null\n ? String(doc[field])\n : '__null__';\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key).push(doc);\n }\n }\n\n // 3. Compute aggregates\n let results;\n\n if (groups) {\n // Grouped / bucketed results\n results = [];\n for (const [groupKey, docs] of groups) {\n const row = { _id: groupKey === '__null__' ? null : groupKey };\n for (const aggStage of aggregateStages) {\n row[aggStage.alias] = this._computeAggregate(docs, aggStage);\n }\n results.push(row);\n }\n } else if (aggregateStages.length > 0) {\n // Ungrouped global aggregation\n const row = {};\n for (const aggStage of aggregateStages) {\n row[aggStage.alias] = this._computeAggregate(workingData, aggStage);\n }\n results = row;\n } else {\n // No aggregation or grouping -- return filtered data\n results = workingData;\n }\n\n // 4. Apply post-processing (sort, limit) -- only meaningful for arrays\n if (Array.isArray(results)) {\n for (const stage of postStages) {\n if (stage.type === 'sort') {\n const { field, order } = stage;\n const dir = order === 'desc' ? -1 : 1;\n results.sort((a, b) => {\n const va = a[field];\n const vb = b[field];\n if (va < vb) return -1 * dir;\n if (va > vb) return 1 * dir;\n return 0;\n });\n } else if (stage.type === 'limit') {\n results = results.slice(0, stage.n);\n }\n }\n }\n\n return results;\n }\n}\n\n/**\n * Main DataTransformer class\n */\nexport default class DataTransformer {\n constructor(gunInstance, options = {}) {\n this.gun = gunInstance;\n this.options = {\n logLevel: 'info',\n enableAutoTransform: true,\n ...options\n };\n \n this.logger = new Logger({\n context: 'DataTransformer',\n level: this.options.logLevel\n });\n \n this.models = new Map();\n this.transformers = new Map();\n \n this.logger.info('DataTransformer initialized', { options: this.options });\n }\n\n /**\n * Register a data model\n * @param {string} name - Model name\n * @param {Object} schema - Model schema\n * @param {Object} options - Model options\n * @returns {DataModel} Created model\n */\n model(name, schema, options = {}) {\n if (this.models.has(name)) {\n return this.models.get(name);\n }\n \n const model = new DataModel(name, schema, this.gun, this, options);\n this.models.set(name, model);\n \n this.logger.info('Model registered', { name, schema });\n return model;\n }\n\n /**\n * Register an event transformer\n * @param {string} eventName - Event name to transform\n * @param {string} modelName - Target model name\n * @param {Function} transformFn - Transformation function\n */\n registerTransformer(eventName, modelName, transformFn) {\n if (!this.models.has(modelName)) {\n throw new ModelError(`Model '${modelName}' not found. Register the model first.`);\n }\n \n this.transformers.set(eventName, {\n modelName,\n transformFn\n });\n \n this.logger.info('Transformer registered', { eventName, modelName });\n }\n\n /**\n * Transform and store an event\n * @param {Object} event - Blockchain event\n * @returns {Promise<Object|null>} Transformed data or null if no transformer\n */\n async transformEvent(event) {\n if (!event || !event.eventName) {\n return null;\n }\n \n const transformer = this.transformers.get(event.eventName);\n if (!transformer) {\n this.logger.debug('No transformer found for event', { eventName: event.eventName });\n return null;\n }\n \n try {\n const { modelName, transformFn } = transformer;\n const model = this.models.get(modelName);\n \n // Transform the event data\n const transformedData = await transformFn(event);\n \n // Save to the model\n const savedData = await model.save(transformedData);\n \n this.logger.info('Event transformed and saved', { \n eventName: event.eventName, \n modelName,\n id: savedData.id\n });\n \n return savedData;\n \n } catch (error) {\n this.logger.error('Failed to transform event', { \n error: error.message, \n eventName: event.eventName \n });\n throw error;\n }\n }\n\n /**\n * Get a registered model\n * @param {string} name - Model name\n * @returns {DataModel} Model instance\n */\n getModel(name) {\n const model = this.models.get(name);\n if (!model) {\n throw new ModelError(`Model '${name}' not found`);\n }\n return model;\n }\n\n /**\n * Get all registered models\n * @returns {Map<string, DataModel>} All models\n */\n getModels() {\n return new Map(this.models);\n }\n\n /**\n * Get transformation statistics\n * @returns {Object} Statistics\n */\n getStats() {\n return {\n modelsCount: this.models.size,\n transformersCount: this.transformers.size,\n registeredModels: Array.from(this.models.keys()),\n registeredTransformers: Array.from(this.transformers.keys())\n };\n }\n\n /**\n * Create an AggregationPipeline from raw data.\n * @param {Array} data - Array of documents to aggregate\n * @returns {AggregationPipeline} A new AggregationPipeline instance\n */\n aggregate(data) {\n return new AggregationPipeline(data);\n }\n\n /**\n * Create a SchemaMigration instance for a model.\n * @param {string} modelName - Name of the model\n * @returns {SchemaMigration} A new SchemaMigration instance\n */\n migration(modelName) {\n return new SchemaMigration(modelName, this.gun);\n }\n}","// magazine - a decentralized library for ethereum event logging\n// magazine uses gun.js to store events in a decentralized manner\n// events are stored in a graph structure, where each event is a node\n// ethers.js is used to interact with the ethereum blockchain\n// gun.js is used to store events in a decentralized manner\n// \n// Usage:\n// 1. create a new magazine\n// 2. sync history from the blockchain to the magazine\n// 3. publish the magazine\n// 4. subscribe to the magazine\n// 5. read events from the magazine\n\n// Import required libraries and components\nimport ConfigManager from './components/ConfigManager.js';\nimport NetworkManager from './components/NetworkManager.js';\nimport EventStore from './components/EventStore.js';\nimport EventSyncer from './components/EventSyncer.js';\nimport EventMetadata from './components/EventMetadata.js';\nimport DebugUtils from './components/DebugUtils.js';\nimport DataTransformer from './components/DataTransformer.js';\nimport Logger from './components/Logger.js';\n\n// Define Magazine class\nexport default class Magazine {\n constructor(config) {\n // Initialize configuration manager and validate config\n this.configManager = new ConfigManager(config);\n const validatedConfig = this.configManager.getAll();\n \n // Initialize logger\n this.logger = new Logger({\n context: 'Magazine',\n level: validatedConfig.logLevel || 'info'\n });\n \n this.logger.info('Initializing Magazine', {\n name: validatedConfig.name,\n address: validatedConfig.address,\n networkId: validatedConfig.networkId\n });\n \n // Initialize retry operation as a shared utility\n this.retryOptions = this.configManager.getRetryOptions();\n \n // Initialize modular components with dependency injection\n this.networkManager = new NetworkManager(validatedConfig, this.retryOperation.bind(this));\n this.eventStore = new EventStore(validatedConfig.gun, this.retryOperation.bind(this));\n this.eventSyncer = new EventSyncer(\n this.networkManager,\n this.eventStore,\n this.configManager,\n this.retryOperation.bind(this)\n );\n \n // Initialize EventMetadata component\n this.eventMetadata = new EventMetadata(this.networkManager, this.logger);\n \n // Initialize DebugUtils component\n this.debugUtils = new DebugUtils(this, this.logger);\n \n // Initialize DataTransformer component\n this.dataTransformer = new DataTransformer(\n this.eventStore.getGunInstance(),\n {\n logLevel: validatedConfig.logLevel,\n enableAutoTransform: validatedConfig.enableAutoTransform !== false\n }\n );\n \n // Expose configuration for backward compatibility\n this.name = validatedConfig.name;\n this.address = validatedConfig.address;\n this.networkId = validatedConfig.networkId;\n this.abi = validatedConfig.abi;\n \n this.logger.info('Magazine initialized successfully', {\n name: this.name,\n address: this.address,\n networkId: this.networkId,\n eventCount: Object.keys(this.networkManager.eventsByTopic).length,\n componentCount: 6,\n debugModeEnabled: this.debugUtils.isDebugMode(),\n dataTransformerEnabled: true\n });\n }\n\n // Get configuration manager for advanced configuration access\n getConfigManager() {\n return this.configManager;\n }\n\n // Get network manager for advanced network operations\n getNetworkManager() {\n return this.networkManager;\n }\n\n // Get event store for advanced storage operations\n getEventStore() {\n return this.eventStore;\n }\n\n // Get event syncer for advanced synchronization operations\n getEventSyncer() {\n return this.eventSyncer;\n }\n\n // Get logger for external logging operations\n getLogger() {\n return this.logger;\n }\n\n // Set log level dynamically\n setLogLevel(level) {\n this.logger.setLevel(level);\n this.logger.info('Log level updated', { newLevel: level });\n }\n\n // Retry wrapper for async operations\n async retryOperation(operation, context = '') {\n const { maxRetries, retryDelay, timeout } = this.retryOptions;\n let lastError;\n \n this.logger.debug('Starting retry operation', { context, maxRetries, timeout });\n \n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n // Add timeout to the operation\n const timeoutPromise = new Promise((_, reject) =>\n setTimeout(() => reject(new Error(`Operation timeout: ${context}`)), timeout)\n );\n \n const result = await Promise.race([operation(), timeoutPromise]);\n \n if (attempt > 1) {\n this.logger.info('Retry operation succeeded', {\n context,\n attempt,\n maxRetries\n });\n }\n \n return result;\n } catch (error) {\n lastError = error;\n \n this.logger.warn('Retry operation failed', {\n context,\n attempt,\n maxRetries,\n error: error.message\n });\n \n if (attempt < maxRetries) {\n const delay = retryDelay * Math.pow(2, attempt - 1); // Exponential backoff\n this.logger.debug('Retrying operation', {\n context,\n delay: `${delay}ms`,\n nextAttempt: attempt + 1\n });\n await new Promise(resolve => setTimeout(resolve, delay));\n } else {\n this.logger.error('Retry operation exhausted', {\n context,\n totalAttempts: maxRetries,\n finalError: error.message,\n stack: error.stack\n });\n }\n }\n }\n \n throw lastError;\n }\n\n // Start syncing events from the blockchain to the magazine\n startSync() {\n this.logger.info('Starting automatic sync');\n this.stopSync();\n \n this.syncInterval = setInterval(async () => {\n try {\n await this.syncEvents();\n } catch (error) {\n this.logger.error('Automatic sync error', {\n error: error.message,\n stack: error.stack\n });\n // Continue syncing despite errors\n }\n }, 5000);\n \n // Initial sync\n this.syncEvents().catch(error => {\n this.logger.error('Initial sync error', {\n error: error.message,\n stack: error.stack\n });\n });\n \n this.logger.info('Automatic sync started', { interval: '5000ms' });\n }\n\n /**\n * Start real-time event streaming (requires WebSocket provider)\n */\n startRealtimeSync() {\n return this.eventSyncer.startRealtimeSync();\n }\n\n /**\n * Stop real-time event streaming\n */\n stopRealtimeSync() {\n return this.eventSyncer.stopRealtimeSync();\n }\n\n /**\n * Destroy the magazine instance, stopping sync and cleaning up listeners\n */\n destroy() {\n this.stopSync();\n this.stopRealtimeSync();\n this.eventStore.destroy();\n this.logger.info('Magazine instance destroyed');\n }\n\n // Stop syncing events from the blockchain to the magazine\n stopSync() {\n if (this.syncInterval) {\n this.logger.info('Stopping automatic sync');\n clearInterval(this.syncInterval);\n this.syncInterval = undefined;\n }\n }\n\n // Sync events from the blockchain to the magazine - delegates to EventSyncer\n async syncEvents() {\n return this.eventSyncer.syncEvents();\n }\n\n // Sync events from a specific block range\n async syncEventsFromRange(fromBlock, toBlock) {\n return this.eventSyncer.syncEventsFromRange(fromBlock, toBlock);\n }\n\n // Sync events from a specific transaction\n async syncEventsFromTransaction(txHash) {\n return this.eventSyncer.syncEventsFromTransaction(txHash);\n }\n\n // Get sync status information\n async getSyncStatus() {\n return this.eventSyncer.getSyncStatus();\n }\n\n // Get the start block number for syncing events - delegates to EventStore\n async getStartBlockNumber() {\n return this.eventStore.getStartBlockNumber();\n }\n\n // Set the start block number for syncing events - delegates to EventStore\n async setStartBlockNumber(startBlockNumber) {\n this.configManager.validateBlockNumber(startBlockNumber, 'startBlockNumber');\n return this.eventStore.setStartBlockNumber(startBlockNumber);\n }\n\n // Get events by name with optional filtering\n async getEvents(eventName, filter = {}) {\n // Use the new filtering system\n const result = await this.getAllEvents({\n filter: { ...filter, eventName }\n });\n return result.data;\n }\n\n // Get all events with optional filtering and pagination\n async getAllEvents(options = {}) {\n return this.eventStore.getAllEvents(options);\n }\n\n /**\n * Query events using fluent API\n * @returns {Promise<Object>} Query builder\n * @example\n * const results = await magazine.query()\n * .eventName('Transfer')\n * .blockRange(1000, 2000)\n * .where('value', { gte: 1000 })\n * .orderBy('blockNumber', 'desc')\n * .execute();\n */\n async query() {\n return this.eventStore.query();\n }\n\n /**\n * Get events by transaction hash\n * @param {string} transactionHash - Transaction hash to search for\n * @returns {Promise<Array>} Events from the transaction\n */\n async getEventsByTransactionHash(transactionHash) {\n if (!transactionHash || typeof transactionHash !== 'string') {\n throw new Error('Transaction hash must be a non-empty string');\n }\n return this.eventStore.getEventsByTransactionHash(transactionHash);\n }\n\n /**\n * Get events by block number\n * @param {number} blockNumber - Block number to search for\n * @returns {Promise<Array>} Events from the block\n */\n async getEventsByBlockNumber(blockNumber) {\n if (!Number.isInteger(blockNumber) || blockNumber < 0) {\n throw new Error('Block number must be a non-negative integer');\n }\n return this.eventStore.getEventsByBlockNumber(blockNumber);\n }\n\n /**\n * Create async iterator for events\n * @param {Object} options - Iterator options\n * @param {Object} options.filter - Filter criteria\n * @param {Object} options.sort - Sort options\n * @param {number} options.pageSize - Items per iteration batch\n * @returns {AsyncIterator} Async iterator for events\n * @example\n * for await (const event of magazine.iterateEvents({ pageSize: 50 })) {\n * console.log(event);\n * }\n */\n async *iterateEvents(options = {}) {\n yield* this.eventStore.iterateEvents(options);\n }\n\n // Get network information\n async getNetworkInfo() {\n return this.networkManager.getNetworkInfo();\n }\n\n // Validate network and contract\n async validateNetwork() {\n return this.networkManager.validateNetwork();\n }\n\n // Get latest block number\n async getLatestBlockNumber() {\n return this.networkManager.getLatestBlockNumber();\n }\n\n // Publish the magazine to the decentralized network\n async publish(options = {}) {\n const validatedOptions = this.configManager.validateOptions(options, ['alias', 'url']);\n \n // Validate specific option values\n if (validatedOptions.alias && (typeof validatedOptions.alias !== 'string' || validatedOptions.alias.trim().length === 0)) {\n throw new Error('alias must be a non-empty string');\n }\n \n if (validatedOptions.url) {\n if (typeof validatedOptions.url !== 'string') {\n throw new Error('url must be a string');\n }\n try {\n new URL(validatedOptions.url);\n } catch {\n throw new Error('url must be a valid URL');\n }\n }\n \n const alias = validatedOptions.alias ? validatedOptions.alias : this.name.toLowerCase().replace(/\\s/g, '-');\n const url = validatedOptions.url ? validatedOptions.url : `https://gunjs.herokuapp.com/gun`;\n\n const magazineData = {\n name: this.name,\n address: this.address,\n networkId: this.networkId,\n abi: this.abi,\n };\n\n return this.eventStore.publishMagazine(alias, magazineData, url);\n }\n\n // Subscribe to a magazine on the decentralized network\n static async subscribe(magazineId, config) {\n // Validate parameters\n if (!magazineId || typeof magazineId !== 'string') {\n throw new Error('magazineId must be a non-empty string');\n }\n \n if (!config || typeof config !== 'object') {\n throw new Error('config must be an object');\n }\n \n // Validate required config fields for subscription\n const requiredFields = ['gun'];\n for (const field of requiredFields) {\n if (!config[field]) {\n throw new Error(`Config field '${field}' is required for subscription`);\n }\n }\n\n // Create a temporary event store for subscription\n const tempEventStore = new EventStore(config.gun, () => {});\n return tempEventStore.subscribeMagazine(magazineId);\n }\n\n // Read events from the magazine - delegates to EventStore\n on(eventName, callback) {\n if (typeof callback !== 'function') {\n throw new Error('callback must be a function');\n }\n const gunInstance = this.eventStore.getGunInstance();\n const eventNode = gunInstance.get('events').get(eventName);\n eventNode.map().on(callback);\n }\n\n /**\n * Health check endpoint - performs system health checks\n * @returns {Promise<Object>} Health check results\n */\n async healthCheck() {\n return this.debugUtils.healthCheck();\n }\n\n /**\n * Get performance metrics\n * @returns {Promise<Object>} Performance metrics\n */\n async getPerformanceMetrics() {\n return this.debugUtils.getPerformanceReport();\n }\n\n /**\n * Export debug information\n * @param {Object} options - Export options\n * @returns {Promise<Object>} Debug information\n */\n async exportDebugInfo(options = {}) {\n return this.debugUtils.exportDebugData();\n }\n\n /**\n * Enable or disable debug mode\n * @param {boolean} enabled - Whether to enable debug mode\n */\n setDebugMode(enabled) {\n this.debugUtils.setDebugMode(enabled);\n }\n\n /**\n * Check if debug mode is enabled\n * @returns {boolean} Debug mode status\n */\n isDebugMode() {\n return this.debugUtils.isDebugMode();\n }\n\n /**\n * Get configuration schema documentation\n * @returns {Object} Schema documentation\n */\n getConfigSchema() {\n return this.configManager.getSchemaDocumentation();\n }\n\n /**\n * Generate example configuration\n * @param {Object} options - Generation options\n * @returns {Object} Example configuration\n */\n static generateExampleConfig(options = {}) {\n const configManager = new ConfigManager({\n name: 'temp',\n address: '0x0000000000000000000000000000000000000000',\n abi: [],\n provider: 'http://localhost:8545',\n networkId: 1\n });\n return configManager.generateExampleConfig(options);\n }\n\n /**\n * Validate configuration without creating an instance\n * @static\n * @param {Object} config - Configuration to validate\n * @returns {Object} Validation result\n */\n static validateConfig(config) {\n return ConfigManager.validateConfiguration(config);\n }\n\n /**\n * Get compression statistics from the event store\n * @returns {Promise<Object>} Compression stats\n */\n async getCompressionStats() {\n return this.eventStore.getCompressionStats();\n }\n\n // === Data Transformation API ===\n\n /**\n * Create or get a data model for structured storage\n * @param {string} name - Model name\n * @param {Object} schema - Model schema definition\n * @param {Object} options - Model options\n * @returns {Object} DataModel instance\n */\n model(name, schema, options = {}) {\n return this.dataTransformer.model(name, schema, options);\n }\n\n /**\n * Register an event transformer that converts blockchain events to model data\n * @param {string} eventName - Event name to transform\n * @param {string} modelName - Target model name\n * @param {Function} transformFn - Transformation function\n */\n registerTransformer(eventName, modelName, transformFn) {\n return this.dataTransformer.registerTransformer(eventName, modelName, transformFn);\n }\n\n /**\n * Get a registered data model\n * @param {string} name - Model name\n * @returns {Object} DataModel instance\n */\n getModel(name) {\n return this.dataTransformer.getModel(name);\n }\n\n /**\n * Transform an event using registered transformers\n * @param {Object} event - Blockchain event to transform\n * @returns {Promise<Object|null>} Transformed data or null\n */\n async transformEvent(event) {\n return this.dataTransformer.transformEvent(event);\n }\n\n /**\n * Get data transformation statistics\n * @returns {Object} Transformation stats\n */\n getTransformationStats() {\n return this.dataTransformer.getStats();\n }\n\n /**\n * Get all registered models\n * @returns {Map} Map of model name to DataModel instance\n */\n getModels() {\n return this.dataTransformer.getModels();\n }\n}\n\n// Named exports for advanced usage\nexport { default as ConfigManager } from './components/ConfigManager.js';\nexport { default as NetworkManager } from './components/NetworkManager.js';\nexport { default as EventStore } from './components/EventStore.js';\nexport { default as EventSyncer } from './components/EventSyncer.js';\nexport { default as EventMetadata } from './components/EventMetadata.js';\nexport { default as DebugUtils } from './components/DebugUtils.js';\nexport { default as DataTransformer, ValidationError, ModelError, DataModel, AggregationPipeline, SchemaMigration } from './components/DataTransformer.js';\nexport { default as EventFilter } from './components/EventFilter.js';\nexport { default as DataCompressor } from './components/DataCompressor.js';\nexport { default as Paginator, PaginationHelper } from './components/Paginator.js';\nexport { default as Logger } from './components/Logger.js';\n"],"names":["Logger","config","level","message","data","timestamp","logEntry","seen","key","value","levelValue","formatted","fsPromise","pathPromise","fsModule","pathModule","structured","line","maxSizeBytes","backupPath","operation","fn","context","startTime","startMessage","result","duration","error","additionalContext","info","type","details","ConfigSchema","field","expected","actual","min","max","values","errors","warnings","validated","definition","validatedValue","actualType","expectedTypes","item","index","itemResult","prop","propDef","propResult","docs","options","includeOptional","useDefaults","example","ConfigManager","validationResult","errorMessage","sanitized","blockNumber","paramName","allowedKeys","invalidKeys","LRUCache","maxSize","v","RateLimiter","maxPerSecond","resolve","now","elapsed","NetworkManager","retryOperation","ethers","cacheSize","rateLimit","providerConfig","providerList","entry","provider","previousIndex","description","startIndex","lastError","attempts","eventCount","fragment","eventName","topicHash","fromBlock","toBlock","logs","log","parsedLog","network","networkInfo","cached","block","txHash","EventFilter","logger","filter","events","filtered","event","condition","subFilter","eventArgs","filterParams","fieldExists","k","arr","by","order","sorted","a","b","aVal","bVal","path","obj","comparison","grouped","QueryBuilder","eventFilter","from","to","name","hash","addr","pattern","n","results","Paginator","items","page","pageSize","includeMeta","totalItems","totalPages","endIndex","pageItems","itemsOrGetter","hasMore","cursor","limit","cursorField","direction","filteredItems","itemValue","firstItem","lastItem","paginationMeta","avgItemSize","maxMemory","minPageSize","maxPageSize","optimalSize","PaginationHelper","currentPage","maxVisible","pages","halfVisible","start","end","i","isNode","toBase64","uint8Array","fromBase64","base64String","buf","binaryString","bytes","DataCompressor","strategy","originalSize","compressed","compressedSize","compressionRatio","compressedData","decompressed","chunkSize","chunks","compressedChunks","chunk","totalOriginal","sum","c","totalCompressed","compressedEvents","decompressedChunk","keyMap","reverseMap","jsonString","gzip","ungzip","jsonCompressed","gzipDecompressed","newKey","bestStrategy","bestRatio","EventStore","gunConfig","networkManager","Gun","_a","_b","startBlockNumber","reject","ack","eventKey","eventData","dataToStore","resolved","node","timeout","pagination","sort","allEventsMap","allEvents","filteredEvents","filterCriteria","paginatedResult","eventGroup","alias","magazineData","url","magazineNode","magazineId","transactionHash","compressedCount","EventSyncer","eventStore","configManager","latestBlockNumber","currentStart","totalEventsProcessed","currentEnd","batchEvents","eventsStored","parsedEvent","receipt","contractAddress","relevantLogs","size","listener","state","EventMetadata","includeBlock","includeTransaction","includeTimestamp","includeGasCost","enrichedEvent","promises","err","tx","_c","gasUsed","gasPrice","gasCost","batchSize","enrichOptions","enrichedEvents","failureCount","batch","j","blockNumbers","e","timestamps","t","gasCosts","stats","totalGas","cost","avgGas","sortedGas","eventTypes","wei","weiString","DebugUtils","magazine","issues","check","debugInfo","metric","timeRange","aggregation","report","metrics","recentMetrics","m","durations","logLevel","captureMetrics","verboseErrors","gun","lastSync","timeSinceSync","usage","status","compressionStats","count","percentile","mag","methodsToInstrument","methodName","original","self","args","metricType","originalRetry","rest","enabled","ValidationError","ModelError","SchemaMigration","modelName","gunInstance","fromVersion","toVersion","migrateFn","document","docVersion","migrated","nextVersion","SchemaValidator","schema","customValidator","customResult","DataModel","transformer","schemaMigration","hooks","out","isUpdate","prepared","id","query","skip","skipped","doc","updateData","existing","updated","documents","deleted","operator","operand","AggregationPipeline","timestampField","interval","date","d","day","diff","stage","op","total","cnt","workingData","matchStages","aggregateStages","groupStage","bucketStage","postStages","groups","ts","bucketKey","groupKey","row","aggStage","dir","va","vb","DataTransformer","model","transformFn","transformedData","savedData","Magazine","validatedConfig","maxRetries","retryDelay","attempt","timeoutPromise","_","delay","validatedOptions","requiredFields","callback"],"mappings":"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"}
|