@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sebastian Schepis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # Magazine
2
+
3
+ A decentralized library for Ethereum event logging, syncing, and querying — built on [ethers.js](https://docs.ethers.org/) and [GunDB](https://gun.eco/).
4
+
5
+ Magazine gives you a complete pipeline: sync events from any EVM chain, store them in a decentralized peer-to-peer network, transform them into structured data models, and query them with a fluent API.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npm install magazine
11
+ ```
12
+
13
+ ```js
14
+ import Magazine from 'magazine';
15
+
16
+ const magazine = new Magazine({
17
+ name: 'My Token Tracker',
18
+ address: '0x1234567890123456789012345678901234567890',
19
+ abi: [
20
+ 'event Transfer(address indexed from, address indexed to, uint256 value)',
21
+ 'event Approval(address indexed owner, address indexed spender, uint256 value)'
22
+ ],
23
+ provider: 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
24
+ networkId: 1,
25
+ gun: { peers: ['https://gun-manhattan.herokuapp.com/gun'] }
26
+ });
27
+
28
+ // Sync events from the blockchain
29
+ await magazine.syncEvents();
30
+
31
+ // Listen to events in real-time
32
+ magazine.on('Transfer', (event) => {
33
+ console.log(`Transfer: ${event.args.value} from ${event.args.from}`);
34
+ });
35
+ ```
36
+
37
+ ## Features
38
+
39
+ - **Event Syncing** — automatic, manual, range-based, transaction-specific, and real-time WebSocket sync
40
+ - **Data Models** — schema-based storage with validation, CRUD, bulk operations, lifecycle hooks, and schema migration
41
+ - **Advanced Querying** — MongoDB-style operators (`$gt`, `$in`, `$regex`, `$or`, `$and`, ...), fluent QueryBuilder, async iteration
42
+ - **Aggregation Pipeline** — group, bucket (time-series), sum, avg, count, min, max, sort
43
+ - **Network Resilience** — multi-provider failover, token-bucket rate limiting, LRU caching
44
+ - **Compression** — gzip, JSON, and optimized strategies for efficient storage
45
+ - **Decentralized Storage** — GunDB integration for peer-to-peer data sharing
46
+ - **Debug Tools** — health checks, performance metrics (p95/p99), structured logging with file output
47
+
48
+ ## Documentation
49
+
50
+ | Guide | Description |
51
+ |-------|-------------|
52
+ | [Getting Started](docs/getting-started.md) | Installation, first sync, first query |
53
+ | [Architecture](docs/architecture.md) | Component diagram, data flow, storage model |
54
+ | [Configuration](docs/configuration.md) | Full config reference with all options |
55
+
56
+ ### Guides
57
+
58
+ | Guide | Description |
59
+ |-------|-------------|
60
+ | [Event Syncing](docs/guides/event-syncing.md) | Auto-sync, manual, range, WebSocket real-time |
61
+ | [Data Models](docs/guides/data-models.md) | Schemas, CRUD, hooks, bulk ops, transformers |
62
+ | [Querying](docs/guides/querying.md) | QueryBuilder, operators, logical combinators |
63
+ | [Aggregation](docs/guides/aggregation.md) | Pipelines, grouping, time-series bucketing |
64
+ | [Schema Migration](docs/guides/schema-migration.md) | Versioned schemas, migration paths |
65
+ | [Pagination](docs/guides/pagination.md) | Offset, cursor, async iteration |
66
+ | [Network Resilience](docs/guides/network-resilience.md) | Failover, rate limiting, caching |
67
+ | [Debugging](docs/guides/debugging.md) | Logger, health checks, performance metrics |
68
+ | [Compression & Pub/Sub](docs/guides/compression-and-pub-sub.md) | Storage optimization, publishing |
69
+
70
+ ### API Reference
71
+
72
+ | Class | Description |
73
+ |-------|-------------|
74
+ | [Magazine](docs/api/magazine.md) | Main entry point — syncing, querying, models |
75
+ | [DataModel](docs/api/data-model.md) | Schema-based CRUD with hooks and bulk ops |
76
+ | [AggregationPipeline](docs/api/aggregation-pipeline.md) | Analytics and time-series aggregation |
77
+ | [SchemaMigration](docs/api/schema-migration.md) | Document version migration |
78
+ | [QueryBuilder](docs/api/query-builder.md) | Fluent query API for events |
79
+ | [EventFilter](docs/api/event-filter.md) | Parameter matching and filtering |
80
+ | [NetworkManager](docs/api/network-manager.md) | Provider failover, caching, rate limiting |
81
+ | [DataCompressor](docs/api/data-compressor.md) | Compression strategies |
82
+ | [Paginator](docs/api/paginator.md) | Offset and cursor-based pagination |
83
+ | [Logger](docs/api/logger.md) | Structured logging |
84
+ | [EventSyncer](docs/api/event-syncer.md) | Blockchain sync engine |
85
+ | [DebugUtils](docs/api/debug-utils.md) | Health checks, performance reports |
86
+ | [Errors](docs/api/errors.md) | ValidationError, ModelError |
87
+
88
+ ## Examples
89
+
90
+ The [`examples/`](examples/) directory contains runnable scripts:
91
+
92
+ | Example | What it covers |
93
+ |---------|---------------|
94
+ | [quick-start.js](examples/quick-start.js) | Minimal setup, sync, query |
95
+ | [data-transformation.js](examples/data-transformation.js) | Models, schemas, event transformers |
96
+ | [filtering-pagination.js](examples/filtering-pagination.js) | Pagination, QueryBuilder, async iteration |
97
+ | [query-builder-advanced.js](examples/query-builder-advanced.js) | Complex queries, `$or`/`$and`/`$nor`, regex |
98
+ | [aggregation-pipeline.js](examples/aggregation-pipeline.js) | Grouping, time-series bucketing, analytics |
99
+ | [lifecycle-hooks.js](examples/lifecycle-hooks.js) | Pre/post save, update, delete hooks |
100
+ | [schema-migration.js](examples/schema-migration.js) | Versioned schemas, migration paths |
101
+ | [bulk-operations.js](examples/bulk-operations.js) | insertMany, updateMany, deleteMany |
102
+ | [realtime-sync.js](examples/realtime-sync.js) | WebSocket real-time event streaming |
103
+ | [multi-provider-failover.js](examples/multi-provider-failover.js) | Provider rotation and caching |
104
+ | [metadata-compression.js](examples/metadata-compression.js) | Event enrichment, compression strategies |
105
+ | [debug-config.js](examples/debug-config.js) | Config validation, health checks, debug mode |
106
+ | [Decentralized USDC Indexer](examples/decentralized-usdc-indexer/) | Full production app with peer coordination |
107
+
108
+ ## Named Exports
109
+
110
+ For advanced usage, all components are individually importable:
111
+
112
+ ```js
113
+ import Magazine, {
114
+ DataModel,
115
+ AggregationPipeline,
116
+ SchemaMigration,
117
+ ValidationError,
118
+ ModelError,
119
+ DataTransformer,
120
+ EventFilter,
121
+ ConfigManager,
122
+ NetworkManager,
123
+ EventStore,
124
+ EventSyncer,
125
+ EventMetadata,
126
+ DataCompressor,
127
+ Paginator,
128
+ PaginationHelper,
129
+ Logger,
130
+ DebugUtils
131
+ } from 'magazine';
132
+ ```
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ # Install dependencies
138
+ npm install
139
+
140
+ # Build (ES, UMD, CJS with source maps)
141
+ npm run build
142
+
143
+ # Unit tests (no blockchain needed)
144
+ npm run test:unit
145
+
146
+ # Full test suite (starts Hardhat node)
147
+ npm test
148
+ ```
149
+
150
+ ## Requirements
151
+
152
+ - Node.js 20+ (ES modules)
153
+ - Ethereum provider (Infura, Alchemy, or local node)
154
+
155
+ ## License
156
+
157
+ MIT — see [LICENSE](LICENSE)
158
+
159
+ ## Contributing
160
+
161
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines.
162
+
163
+ ## Links
164
+
165
+ - [GitHub](https://github.com/sschepis/magazine)
166
+ - [Issue Tracker](https://github.com/sschepis/magazine/issues)
167
+ - [Changelog](CHANGELOG.md)
@@ -0,0 +1,5 @@
1
+ "use strict";var B=Object.create;var E=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var H=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var V=(u,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of U(e))!q.call(u,s)&&s!==t&&E(u,s,{get:()=>e[s],enumerable:!(r=j(e,s))||r.enumerable});return u};var M=(u,e,t)=>(t=u!=null?B(H(u)):{},V(e||!u||!u.__esModule?E(t,"default",{value:u,enumerable:!0}):t,u));Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const G=require("ethers"),W=require("gun");require("gun/lib/load.js");require("gun/lib/open.js");const N=require("pako");function K(u){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(u){for(const t in u)if(t!=="default"){const r=Object.getOwnPropertyDescriptor(u,t);Object.defineProperty(e,t,r.get?r:{enumerable:!0,get:()=>u[t]})}}return e.default=u,Object.freeze(e)}const v=K(G);class p{constructor(e={}){this.level=e.level||"info",this.context=e.context||"Magazine",this.enableConsole=e.enableConsole!==!1,this.enableFile=e.enableFile||!1,this.filePath=e.filePath||"./magazine.log",this._fsModule=null,this._fsAvailable=null,this.levels={error:0,warn:1,info:2,debug:3,trace:4},this.currentLevelValue=this.levels[this.level.toLowerCase()]||this.levels.info,this.enableFile&&this._initFileLogging()}_formatLog(e,t,r={}){const s=new Date().toISOString(),n={timestamp:s,level:e.toUpperCase(),context:this.context,message:t,...r};return{formatted:`[${s}] ${e.toUpperCase()} [${this.context}] ${t}${Object.keys(r).length>0?" "+JSON.stringify(r,this._getCircularReplacer()):""}`,structured:n}}_getCircularReplacer(){const e=new WeakSet;return(t,r)=>{if(typeof r=="object"&&r!==null){if(e.has(r))return"[Circular]";e.add(r)}return r}}_shouldLog(e){const t=this.levels[e.toLowerCase()];return t!==void 0&&t<=this.currentLevelValue}_writeToConsole(e,t){if(this.enableConsole)switch(e.toLowerCase()){case"error":console.error(t);break;case"warn":console.warn(t);break;case"debug":case"trace":console.debug(t);break;default:console.log(t)}}_initFileLogging(){if(this._fsAvailable===null)try{const e=import("fs"),t=import("path");Promise.all([e,t]).then(([r,s])=>{this._fsModule=r.default||r,this._pathModule=s.default||s,this._fsAvailable=!0}).catch(()=>{this._fsAvailable=!1})}catch{this._fsAvailable=!1}}_writeToFile(e){if(this.enableFile&&this._fsAvailable!==!1&&this._fsModule)try{const t=JSON.stringify(e,this._getCircularReplacer())+`
2
+ `;this._fsModule.appendFileSync(this.filePath,t,"utf8")}catch{}}rotateLogs(e=10*1024*1024){if(!(!this._fsModule||this._fsAvailable===!1))try{if(!this._fsModule.existsSync(this.filePath)||this._fsModule.statSync(this.filePath).size<e)return;const r=this.filePath+".1";this._fsModule.existsSync(r)&&this._fsModule.unlinkSync(r),this._fsModule.renameSync(this.filePath,r),this._fsModule.writeFileSync(this.filePath,"","utf8")}catch{}}_log(e,t,r={}){if(!this._shouldLog(e))return;const{formatted:s,structured:n}=this._formatLog(e,t,r);return this._writeToConsole(e,s),this._writeToFile(n),n}error(e,t={}){return this._log("error",e,t)}warn(e,t={}){return this._log("warn",e,t)}info(e,t={}){return this._log("info",e,t)}debug(e,t={}){return this._log("debug",e,t)}trace(e,t={}){return this._log("trace",e,t)}async time(e,t,r={}){const s=Date.now(),n=`Starting operation: ${e}`;this.debug(n,r);try{const i=await t(),a=Date.now()-s;return this.info(`Completed operation: ${e}`,{...r,duration:`${a}ms`,success:!0}),i}catch(i){const a=Date.now()-s;throw this.error(`Failed operation: ${e}`,{...r,duration:`${a}ms`,success:!1,error:(i==null?void 0:i.message)||(i==null?void 0:i.toString())||"Unknown error",stack:i==null?void 0:i.stack}),i}}child(e={}){return new p({level:this.level,context:this.context,enableConsole:this.enableConsole,enableFile:this.enableFile,filePath:this.filePath,...e})}setLevel(e){this.levels[e.toLowerCase()]!==void 0?(this.level=e.toLowerCase(),this.currentLevelValue=this.levels[this.level],this.info(`Log level changed to: ${e.toUpperCase()}`)):this.warn(`Invalid log level: ${e}. Valid levels: ${Object.keys(this.levels).join(", ")}`)}getConfig(){return{level:this.level,context:this.context,enableConsole:this.enableConsole,enableFile:this.enableFile,filePath:this.filePath}}logSystemInfo(e={}){this.info("System Information",{nodeVersion:process.version,platform:process.platform,arch:process.arch,memoryUsage:process.memoryUsage(),uptime:process.uptime(),...e})}logNetworkActivity(e,t={}){this.debug(`Network ${e}`,{type:e,timestamp:Date.now(),...t})}logBlockchainActivity(e,t={}){this.info(`Blockchain: ${e}`,{operation:e,timestamp:Date.now(),...t})}logDatabaseActivity(e,t={}){this.debug(`Database: ${e}`,{operation:e,timestamp:Date.now(),...t})}}new p({level:"info",context:"Magazine"});class x{constructor(){this.schema={required:["name","address","abi","provider"],fields:{name:{type:"string",description:"Name of the magazine",minLength:1,maxLength:100,pattern:/^[a-zA-Z0-9\s\-_]+$/,example:"My Event Magazine"},address:{type:"string",description:"Contract address",pattern:/^0x[a-fA-F0-9]{40}$/,example:"0x1234567890123456789012345678901234567890"},abi:{type:"array",description:"Contract ABI",minItems:1,items:{type:"object",required:["type"],properties:{type:{type:"string",enum:["function","event","constructor","fallback","receive"]},name:{type:"string"},inputs:{type:"array"},outputs:{type:"array"},anonymous:{type:"boolean"}}}},provider:{type:["string","object"],description:"Ethereum provider URL or object",validate:e=>typeof e=="string"?e.startsWith("http://")||e.startsWith("https://")||e.startsWith("ws://")||e.startsWith("wss://"):typeof e=="object"&&e!==null,example:"http://localhost:8545"},networkId:{type:"number",description:"Network ID",optional:!0,min:1,example:1},gun:{type:"object",description:"Gun.js configuration",optional:!0,properties:{peers:{type:"array",items:{type:"string"},example:["http://localhost:8765/gun"]},file:{type:"string",example:"radata"},localStorage:{type:"boolean",default:!0},radisk:{type:"boolean",default:!0},multicast:{type:["boolean","object"],default:!1},compression:{type:"object",properties:{enabled:{type:"boolean",default:!0},strategy:{type:"string",enum:["none","json","gzip","optimized"],default:"optimized"}}}}},logLevel:{type:"string",description:"Logging level",optional:!0,enum:["error","warn","info","debug","trace"],default:"info"},maxRetries:{type:"number",description:"Maximum retry attempts",optional:!0,min:0,max:10,default:3},retryDelay:{type:"number",description:"Delay between retries in milliseconds",optional:!0,min:100,max:6e4,default:1e3},timeout:{type:"number",description:"Operation timeout in milliseconds",optional:!0,min:1e3,max:3e5,default:3e4},batchSize:{type:"number",description:"Event sync batch size",optional:!0,min:1,max:1e4,default:1e3},startBlockNumber:{type:"number",description:"Starting block number for sync",optional:!0,min:0,default:1},autoSync:{type:"boolean",description:"Enable automatic syncing",optional:!0,default:!1},syncInterval:{type:"number",description:"Auto-sync interval in milliseconds",optional:!0,min:1e4,max:36e5,default:6e4,dependsOn:"autoSync"}}},this.errorMessages={required:e=>`${e} is required`,type:(e,t,r)=>`${e} must be of type ${t}, got ${r}`,minLength:(e,t)=>`${e} must be at least ${t} characters long`,maxLength:(e,t)=>`${e} must be at most ${t} characters long`,pattern:e=>`${e} has invalid format`,min:(e,t)=>`${e} must be at least ${t}`,max:(e,t)=>`${e} must be at most ${t}`,enum:(e,t)=>`${e} must be one of: ${t.join(", ")}`,minItems:(e,t)=>`${e} must have at least ${t} items`,custom:(e,t)=>`${e}: ${t}`}}validate(e){const t=[],r=[],s={};for(const n of this.schema.required)(!e.hasOwnProperty(n)||e[n]===void 0||e[n]===null)&&t.push({field:n,type:"required",message:this.errorMessages.required(n)});for(const[n,i]of Object.entries(this.schema.fields))if(e.hasOwnProperty(n)){const a=this._validateField(n,e[n],i);a.errors.length>0?t.push(...a.errors):s[n]=a.value,a.warnings.length>0&&r.push(...a.warnings)}else!i.optional&&!this.schema.required.includes(n)&&i.hasOwnProperty("default")&&(s[n]=i.default);for(const n of Object.keys(e))this.schema.fields.hasOwnProperty(n)||(r.push({field:n,type:"unknown",message:`Unknown configuration field: ${n}`}),s[n]=e[n]);for(const[n,i]of Object.entries(this.schema.fields))i.dependsOn&&s[n]!==void 0&&(s[i.dependsOn]||r.push({field:n,type:"dependency",message:`${n} depends on ${i.dependsOn} being set`}));return{valid:t.length===0,errors:t,warnings:r,validated:s}}_validateField(e,t,r){const s=[],n=[];let i=t;const a=Array.isArray(t)?"array":typeof t,l=Array.isArray(r.type)?r.type:[r.type];if(!l.includes(a))return s.push({field:e,type:"type",message:this.errorMessages.type(e,l.join(" or "),a)}),{errors:s,warnings:n,value:t};if(r.transform&&typeof r.transform=="function"&&(i=r.transform(i)),a==="string"&&(r.minLength&&i.length<r.minLength&&s.push({field:e,type:"minLength",message:this.errorMessages.minLength(e,r.minLength)}),r.maxLength&&i.length>r.maxLength&&s.push({field:e,type:"maxLength",message:this.errorMessages.maxLength(e,r.maxLength)}),r.pattern&&!r.pattern.test(i)&&s.push({field:e,type:"pattern",message:this.errorMessages.pattern(e)}),r.enum&&!r.enum.includes(i)&&s.push({field:e,type:"enum",message:this.errorMessages.enum(e,r.enum)})),a==="number"&&(r.min!==void 0&&i<r.min&&s.push({field:e,type:"min",message:this.errorMessages.min(e,r.min)}),r.max!==void 0&&i>r.max&&s.push({field:e,type:"max",message:this.errorMessages.max(e,r.max)})),a==="array"&&(r.minItems&&i.length<r.minItems&&s.push({field:e,type:"minItems",message:this.errorMessages.minItems(e,r.minItems)}),r.items&&i.forEach((o,c)=>{const h=this._validateField(`${e}[${c}]`,o,r.items);s.push(...h.errors),n.push(...h.warnings)})),a==="object"&&r.properties){for(const[o,c]of Object.entries(r.properties))if(i.hasOwnProperty(o)){const h=this._validateField(`${e}.${o}`,i[o],c);s.push(...h.errors),n.push(...h.warnings)}}return r.validate&&typeof r.validate=="function"&&(r.validate(i)||s.push({field:e,type:"custom",message:this.errorMessages.custom(e,"Custom validation failed")})),{errors:s,warnings:n,value:i}}getDocumentation(){const e={description:"Magazine configuration schema",required:this.schema.required,fields:{}};for(const[t,r]of Object.entries(this.schema.fields))e.fields[t]={type:r.type,description:r.description,required:this.schema.required.includes(t),optional:r.optional,default:r.default,example:r.example},r.enum&&(e.fields[t].enum=r.enum),(r.min!==void 0||r.max!==void 0)&&(e.fields[t].range={min:r.min,max:r.max}),r.pattern&&(e.fields[t].pattern=r.pattern.toString()),r.dependsOn&&(e.fields[t].dependsOn=r.dependsOn);return e}generateExample(e={}){const{includeOptional:t=!0,useDefaults:r=!0}=e,s={};for(const[n,i]of Object.entries(this.schema.fields))(this.schema.required.includes(n)||t&&i.optional)&&(i.example!==void 0?s[n]=i.example:r&&i.default!==void 0?s[n]=i.default:s[n]=this._generatePlaceholder(i));return s}_generatePlaceholder(e){switch(Array.isArray(e.type)?e.type[0]:e.type){case"string":return e.enum?e.enum[0]:"example-value";case"number":return e.min!==void 0?e.min:0;case"boolean":return!1;case"array":return[];case"object":return{};default:return null}}}class w{constructor(e){this.schema=new x,this.logger=new p({context:"ConfigManager",level:(e==null?void 0:e.logLevel)||"info"}),this.logger.debug("Initializing ConfigManager with schema validation",{config:this._sanitizeConfig(e)});const t=this.validateConfig(e);if(!t.valid){const r=this._formatValidationErrors(t.errors);throw this.logger.error("Configuration validation failed",{errors:t.errors,warnings:t.warnings}),new Error(`Configuration validation failed:
3
+ ${r}`)}t.warnings.length>0&&this.logger.warn("Configuration validation warnings",{warnings:t.warnings}),this.config=t.validated,this.logger.info("ConfigManager initialized successfully",{name:this.config.name,address:this.config.address,networkId:this.config.networkId,maxRetries:this.config.maxRetries,retryDelay:this.config.retryDelay,timeout:this.config.timeout,warningsCount:t.warnings.length})}_sanitizeConfig(e){if(!e)return e;const t={...e};return t.gun&&(t.gun={...t.gun},delete t.gun.peers),t}validateConfig(e){return!e||typeof e!="object"?{valid:!1,errors:[{field:"config",type:"required",message:"Configuration must be a non-null object"}],warnings:[],validated:{}}:this.schema.validate(e)}_formatValidationErrors(e){return e.map(t=>` - ${t.field}: ${t.message}`).join(`
4
+ `)}getSchemaDocumentation(){return this.schema.getDocumentation()}generateExampleConfig(e={}){return this.schema.generateExample(e)}static validateConfiguration(e){return new x().validate(e)}validateBlockNumber(e,t="blockNumber"){if(!Number.isInteger(e)||e<0)throw new Error(`${t} must be a non-negative integer`)}validateOptions(e,t=[]){if(e!==void 0&&(typeof e!="object"||e===null))throw new Error("Options must be an object");if(e&&t.length>0){const r=Object.keys(e).filter(s=>!t.includes(s));if(r.length>0)throw new Error(`Invalid option keys: ${r.join(", ")}. Allowed: ${t.join(", ")}`)}return e||{}}get(e){return this.config[e]}getAll(){return{...this.config}}getRetryOptions(){return{maxRetries:this.config.maxRetries,retryDelay:this.config.retryDelay,timeout:this.config.timeout}}}class I{constructor(e=500){this.maxSize=e,this.cache=new Map}get(e){if(!this.cache.has(e))return;const t=this.cache.get(e);return this.cache.delete(e),this.cache.set(e,t),t}set(e,t){this.cache.has(e)?this.cache.delete(e):this.cache.size>=this.maxSize&&this.cache.delete(this.cache.keys().next().value),this.cache.set(e,t)}clear(){this.cache.clear()}get size(){return this.cache.size}}class J{constructor(e=25){this.maxPerSecond=e,this.tokens=e,this.lastRefill=Date.now(),this.queue=[]}async acquire(){if(this._refill(),this.tokens>0){this.tokens--;return}return new Promise(e=>this.queue.push(e))}_refill(){const e=Date.now(),t=(e-this.lastRefill)/1e3;for(this.tokens=Math.min(this.maxPerSecond,this.tokens+t*this.maxPerSecond),this.lastRefill=e;this.queue.length>0&&this.tokens>0;)this.tokens--,this.queue.shift()()}}class ${constructor(e,t){this.config=e,this.retryOperation=t,this.logger=new p({context:"NetworkManager",level:(e==null?void 0:e.logLevel)||"info"}),this.logger.debug("Initializing NetworkManager",{provider:e.provider,networkId:e.networkId}),this.providers=[],this.currentProviderIndex=0,this._initializeProviders(e.provider),this.provider=this.providers[0],this.interface=new v.Interface(e.abi);const r=e.cacheSize||500;this.blockCache=new I(r),this.timestampCache=new I(r),this.logger.debug("LRU caches initialized",{cacheSize:r});const s=e.rateLimit||25;this.rateLimiter=new J(s),this.logger.debug("Rate limiter initialized",{maxPerSecond:s}),this.events={},this.eventsByTopic={},this._initializeEvents(),this.logger.info("NetworkManager initialized successfully",{eventCount:Object.keys(this.eventsByTopic).length,contractAddress:e.address,providerCount:this.providers.length})}_initializeProviders(e){const t=Array.isArray(e)?e:[e];for(const r of t)if(typeof r=="string"){const s=new v.JsonRpcProvider(r);this.providers.push(s),this.logger.debug("Created JsonRpcProvider from URL",{url:r})}else if(r&&typeof r.getNetwork=="function")this.providers.push(r),this.logger.debug("Using provided ethers provider object",{providerType:r.constructor.name});else throw new Error("Each provider must be either a string URL or an ethers provider object");if(this.providers.length===0)throw new Error("At least one provider must be specified");this.logger.debug("Providers initialized",{count:this.providers.length})}_switchProvider(e){const t=this.currentProviderIndex;return this.currentProviderIndex=(this.currentProviderIndex+1)%this.providers.length,this.currentProviderIndex===t&&this.providers.length===1?(this.logger.error("Single provider failed, no failover available",{error:e.message}),!1):(this.provider=this.providers[this.currentProviderIndex],this.logger.warn("Switching provider due to failure",{error:e.message,previousIndex:t,newIndex:this.currentProviderIndex,totalProviders:this.providers.length}),!0)}async _throttledCall(e){return await this.rateLimiter.acquire(),e()}async _callWithFailover(e,t){const r=this.currentProviderIndex;let s,n=0;do try{return await this._throttledCall(()=>e(this.provider))}catch(i){if(s=i,n++,this.logger.warn("Provider call failed",{description:t,providerIndex:this.currentProviderIndex,attempt:n,error:i.message}),this.providers.length>1){if(this._switchProvider(i),this.currentProviderIndex===r)break}else break}while(!0);throw s}_initializeEvents(){let e=0;for(const t of this.config.abi)if(t.type==="event"){const r=t.name;this.events[r]=new v.Interface([t]);try{const n=this.interface.getEvent(r).topicHash;this.eventsByTopic[n]=r,e++,this.logger.debug("Event mapping created",{eventName:r,topicHash:n})}catch(s){this.logger.warn("Failed to get topic hash for event",{eventName:r,error:s.message})}}this.logger.debug("Event initialization completed",{eventCount:e})}async getLatestBlockNumber(){return this.logger.time("getLatestBlockNumber",async()=>{const e=await this.retryOperation(()=>this._callWithFailover(t=>t.getBlockNumber(),"getLatestBlockNumber"),"Getting latest block number");return this.logger.logNetworkActivity("getLatestBlockNumber",{blockNumber:e}),e})}async getLogs(e,t){return this.logger.time("getLogs",async()=>{this.logger.logNetworkActivity("getLogs_request",{fromBlock:e,toBlock:t,address:this.config.address});const r=await this.retryOperation(()=>this._callWithFailover(s=>s.getLogs({address:this.config.address,fromBlock:e,toBlock:t}),"getLogs"),`Getting logs for blocks ${e}-${t}`);return this.logger.logNetworkActivity("getLogs_response",{fromBlock:e,toBlock:t,logCount:r.length}),r})}parseLog(e){const t=e.topics[0],r=this.eventsByTopic[t];if(!r)return this.logger.trace("Unknown event topic",{topicHash:t,availableTopics:Object.keys(this.eventsByTopic)}),null;try{const s=this.interface.parseLog(e),n={eventName:r,parsedLog:s,eventData:{...s.args,blockNumber:e.blockNumber,transactionHash:e.transactionHash,logIndex:e.logIndex,timestamp:Date.now()}};return this.logger.debug("Successfully parsed log",{eventName:r,blockNumber:e.blockNumber,transactionHash:e.transactionHash,logIndex:e.logIndex}),n}catch(s){return this.logger.warn("Failed to parse log for event",{eventName:r,blockNumber:e.blockNumber,transactionHash:e.transactionHash,error:s.message}),null}}createEventKey(e){return`${e.transactionHash}-${e.logIndex}`}async getNetworkInfo(){return this.retryOperation(async()=>{const e=await this._callWithFailover(r=>r.getNetwork(),"getNetwork"),t=await this._callWithFailover(r=>r.getBlockNumber(),"getBlockNumber");return{chainId:Number(e.chainId),name:e.name,currentBlock:t,expectedNetworkId:this.config.networkId}},"Getting network information")}async validateNetwork(){const e=await this.getNetworkInfo();if(e.chainId!==this.config.networkId)throw new Error(`Network mismatch: expected ${this.config.networkId}, got ${e.chainId}`);return e}async validateContract(){return this.retryOperation(async()=>{if(await this._callWithFailover(t=>t.getCode(this.config.address),"getCode")==="0x")throw new Error(`No contract found at address ${this.config.address}`);return!0},"Validating contract")}async getBlock(e){const t=this.blockCache.get(e);if(t!==void 0)return this.logger.debug("Block cache hit",{blockNumber:e}),t;const r=await this.retryOperation(async()=>this._callWithFailover(s=>s.getBlock(e),`getBlock(${e})`),`Getting block ${e}`);return r&&this.blockCache.set(e,r),r}async getBlockTimestamp(e){const t=this.timestampCache.get(e);if(t!==void 0)return this.logger.debug("Timestamp cache hit",{blockNumber:e}),t;const r=await this.getBlock(e),s=r?r.timestamp:null;return s!==null&&this.timestampCache.set(e,s),s}async getTransactionReceipt(e){return this.retryOperation(()=>this._callWithFailover(t=>t.getTransactionReceipt(e),"getTransactionReceipt"),`Getting transaction receipt for ${e}`)}async getGasPrice(){return this.retryOperation(()=>this._callWithFailover(e=>e.getFeeData(),"getFeeData"),"Getting gas price information")}getProvider(){return this.provider}getInterface(){return this.interface}getEventMappings(){return{events:{...this.events},eventsByTopic:{...this.eventsByTopic}}}clearCaches(){this.blockCache.clear(),this.timestampCache.clear(),this.logger.debug("All caches cleared")}getCacheStats(){return{blockCacheSize:this.blockCache.size,timestampCacheSize:this.timestampCache.size,maxCacheSize:this.blockCache.maxSize}}}class z{constructor(e){this.logger=e.child({context:"EventFilter"}),this.logger.info("EventFilter initialized")}buildFilter(e={}){const t={};return e.fromBlock!==void 0&&(t.fromBlock=e.fromBlock),e.toBlock!==void 0&&(t.toBlock=e.toBlock),e.eventName&&(t.eventName=e.eventName),e.parameters&&Object.keys(e.parameters).length>0&&(t.parameters=e.parameters),e.transactionHash&&(t.transactionHash=e.transactionHash),e.address&&(t.address=e.address.toLowerCase()),e.$or&&(t.$or=e.$or),e.$and&&(t.$and=e.$and),e.$nor&&(t.$nor=e.$nor),this.logger.debug("Built filter criteria",{filter:t}),t}applyFilter(e,t){if(!Array.isArray(e))return this.logger.warn("Invalid events array provided to applyFilter"),[];let r=[...e];return t.$or&&(r=r.filter(s=>t.$or.some(n=>{const i=this.buildFilter(n);return this.applyFilter([s],i).length>0}))),t.$and&&(r=r.filter(s=>t.$and.every(n=>{const i=this.buildFilter(n);return this.applyFilter([s],i).length>0}))),t.$nor&&(r=r.filter(s=>t.$nor.every(n=>{const i=this.buildFilter(n);return this.applyFilter([s],i).length===0}))),t.fromBlock!==void 0&&(r=r.filter(s=>s.blockNumber>=t.fromBlock)),t.toBlock!==void 0&&(r=r.filter(s=>s.blockNumber<=t.toBlock)),t.eventName&&(r=r.filter(s=>s.eventName===t.eventName)),t.transactionHash&&(r=r.filter(s=>s.transactionHash.toLowerCase()===t.transactionHash.toLowerCase())),t.address&&(r=r.filter(s=>s.address&&s.address.toLowerCase()===t.address)),t.parameters&&(r=r.filter(s=>this._matchesParameters(s.args||{},t.parameters))),this.logger.debug("Applied filters",{originalCount:e.length,filteredCount:r.length,filter:t}),r}matchesParameters(e,t){return this._matchesParameters(e,t)}_matchesParameters(e,t){for(const[r,s]of Object.entries(t))if(typeof s=="object"&&s!==null){if(s.exists!==void 0){const n=e.hasOwnProperty(r);if(s.exists&&!n||!s.exists&&n)return!1;if(Object.keys(s).filter(a=>a!=="exists").length===0)continue}if(!e.hasOwnProperty(r)||s.gte!==void 0&&e[r]<s.gte||s.lte!==void 0&&e[r]>s.lte||s.gt!==void 0&&e[r]<=s.gt||s.lt!==void 0&&e[r]>=s.lt||s.in!==void 0&&!s.in.includes(e[r])||s.nin!==void 0&&s.nin.includes(e[r])||s.not!==void 0&&this._matchesParameters(e,{[r]:s.not})||s.regex!==void 0&&!new RegExp(s.regex).test(String(e[r])))return!1;if(s.size!==void 0){const n=e[r];if(!Array.isArray(n)||n.length!==s.size)return!1}}else if(!e.hasOwnProperty(r)||e[r]!==s)return!1;return!0}sortEvents(e,t={}){const{by:r="blockNumber",order:s="asc"}=t,n=[...e].sort((i,a)=>{let l=i[r],o=a[r];if(r.includes(".")){const h=r.split(".");l=h.reduce((g,d)=>g==null?void 0:g[d],i),o=h.reduce((g,d)=>g==null?void 0:g[d],a)}if(l===o)return 0;const c=l<o?-1:1;return s==="asc"?c:-c});return this.logger.debug("Sorted events",{by:r,order:s,count:n.length}),n}groupEvents(e,t){const r={};for(const s of e){let n=s[t];t.includes(".")&&(n=t.split(".").reduce((a,l)=>a==null?void 0:a[l],s)),n===void 0&&(n="undefined"),r[n]||(r[n]=[]),r[n].push(s)}return this.logger.debug("Grouped events",{field:t,groups:Object.keys(r).length,totalEvents:e.length}),r}query(e){return new Q(e,this)}}class Q{constructor(e,t){this.events=e,this.eventFilter=t,this.filters={},this.sortOptions=null,this._limit=null,this._skip=null}blockRange(e,t){return e!==void 0&&(this.filters.fromBlock=e),t!==void 0&&(this.filters.toBlock=t),this}eventName(e){return this.filters.eventName=e,this}transactionHash(e){return this.filters.transactionHash=e,this}address(e){return this.filters.address=e,this}where(e,t){return this.filters.parameters||(this.filters.parameters={}),this.filters.parameters[e]=t,this}orWhere(e,t){return this.filters.$or||(this.filters.$or=[]),this.filters.$or.push({parameters:{[e]:t}}),this}whereExists(e){return this.filters.parameters||(this.filters.parameters={}),this.filters.parameters[e]={exists:!0},this}whereRegex(e,t){return this.filters.parameters||(this.filters.parameters={}),this.filters.parameters[e]={regex:t},this}limit(e){return this._limit=e,this}skip(e){return this._skip=e,this}orderBy(e,t="asc"){return this.sortOptions={by:e,order:t},this}execute(){let e=this.eventFilter.applyFilter(this.events,this.filters);return this.sortOptions&&(e=this.eventFilter.sortEvents(e,this.sortOptions)),this._skip!==null&&(e=e.slice(this._skip)),this._limit!==null&&(e=e.slice(0,this._limit)),e}first(){const e=this.execute();return e.length>0?e[0]:null}count(){return this.execute().length}groupBy(e){const t=this.execute();return this.eventFilter.groupEvents(t,e)}}class O{constructor(e){this.logger=e.child({context:"Paginator"}),this.logger.info("Paginator initialized")}paginate(e,t={}){const{page:r=1,pageSize:s=100,includeMeta:n=!0}=t;if(!Array.isArray(e))return this.logger.warn("Invalid items array provided to paginate"),this._createEmptyResult(n);if(r<1||s<1)return this.logger.warn("Invalid pagination parameters",{page:r,pageSize:s}),this._createEmptyResult(n);const i=e.length,a=Math.ceil(i/s),l=(r-1)*s,o=Math.min(l+s,i),c=e.slice(l,o);this.logger.debug("Created paginated result",{page:r,pageSize:s,totalItems:i,totalPages:a,itemsInPage:c.length});const h={data:c};return n&&(h.meta={page:r,pageSize:s,totalItems:i,totalPages:a,hasNextPage:r<a,hasPreviousPage:r>1,startIndex:l+1,endIndex:o}),h}async*iterate(e,t={}){const{pageSize:r=100}=t;let s=1,n=!0;for(;n;){let i;if(typeof e=="function")i=await e(s,r);else if(Array.isArray(e)){const a=this.paginate(e,{page:s,pageSize:r,includeMeta:!0});i=a.data,n=a.meta.hasNextPage}else{this.logger.error("Invalid itemsOrGetter provided to iterate");return}if(!i||i.length===0){n=!1;break}for(const a of i)yield a;Array.isArray(e)||(n=i.length===r),s++}this.logger.debug("Iterator completed",{totalPages:s-1})}paginateCursor(e,t={}){const{cursor:r=null,limit:s=100,cursorField:n="id",direction:i="forward"}=t;if(!Array.isArray(e))return this.logger.warn("Invalid items array provided to paginateCursor"),this._createEmptyCursorResult();let a=[...e];r!==null&&(a=a.filter(d=>{const m=d[n];return i==="forward"?m>r:m<r})),a.sort((d,m)=>{const y=d[n],b=m[n];return i==="forward"?y<b?-1:1:y>b?-1:1});const l=a.slice(0,s),o=a.length>s,c=l[0],h=l[l.length-1],g={data:l,cursors:{before:c?c[n]:null,after:h?h[n]:null,hasNext:o,hasPrevious:r!==null}};return this.logger.debug("Created cursor-paginated result",{cursor:r,limit:s,cursorField:n,direction:i,itemsReturned:l.length,hasMore:o}),g}createPageInfo(e){return{hasNextPage:e.hasNextPage||!1,hasPreviousPage:e.hasPreviousPage||!1,startCursor:e.startCursor||null,endCursor:e.endCursor||null,totalCount:e.totalItems||0}}calculateOptimalPageSize(e={}){const{totalItems:t=1e3,avgItemSize:r=1024,maxMemory:s=10*1024*1024,minPageSize:n=10,maxPageSize:i=1e3}=e;let a=Math.floor(s/r);return a=Math.max(n,Math.min(i,a)),t<a&&(a=t),this.logger.debug("Calculated optimal page size",{totalItems:t,avgItemSize:r,maxMemory:s,optimalSize:a}),a}_createEmptyResult(e){const t={data:[]};return e&&(t.meta={page:1,pageSize:0,totalItems:0,totalPages:0,hasNextPage:!1,hasPreviousPage:!1,startIndex:0,endIndex:0}),t}_createEmptyCursorResult(){return{data:[],cursors:{before:null,after:null,hasNext:!1,hasPrevious:!1}}}}class Z{static calculateOffset(e,t){return(e-1)*t}static calculateTotalPages(e,t){return Math.ceil(e/t)}static isValidPage(e,t){return e>=1&&e<=t}static getPageNumbers(e,t,r=5){const s=[],n=Math.floor(r/2);let i=Math.max(1,e-n),a=Math.min(t,e+n);e<=n?a=Math.min(t,r):e>=t-n&&(i=Math.max(1,t-r+1));for(let l=i;l<=a;l++)s.push(l);return s}}const k=typeof process<"u"&&process.versions!=null&&process.versions.node!=null;function X(u){return k?Buffer.from(u).toString("base64"):btoa(String.fromCharCode.apply(null,u))}function Y(u){if(k){const r=Buffer.from(u,"base64");return new Uint8Array(r.buffer,r.byteOffset,r.byteLength)}const e=atob(u),t=new Uint8Array(e.length);for(let r=0;r<e.length;r++)t[r]=e.charCodeAt(r);return t}class C{constructor(e){this.logger=e.child({context:"DataCompressor"}),this.logger.info("DataCompressor initialized"),this.strategies={none:{compress:t=>t,decompress:t=>t,ratio:1},json:{compress:t=>this._compressJSON(t),decompress:t=>this._decompressJSON(t),ratio:.7},gzip:{compress:t=>this._compressGzip(t),decompress:t=>this._decompressGzip(t),ratio:.3},optimized:{compress:t=>this._compressOptimized(t),decompress:t=>this._decompressOptimized(t),ratio:.4}},this.defaultStrategy="optimized"}compress(e,t=this.defaultStrategy){try{const r=Date.now(),s=this._calculateSize(e);this.strategies[t]||(this.logger.warn("Unknown compression strategy, using default",{strategy:t}),t=this.defaultStrategy);const n=this.strategies[t].compress(e),i=this._calculateSize(n),a=i/s,l=Date.now()-r,o={data:n,metadata:{strategy:t,originalSize:s,compressedSize:i,compressionRatio:a.toFixed(3),spaceSaved:`${((1-a)*100).toFixed(1)}%`,compressionTime:l,timestamp:new Date().toISOString()}};return this.logger.debug("Data compressed",o.metadata),o}catch(r){throw this.logger.error("Compression failed",{strategy:t,error:r.message}),r}}decompress(e){try{if(!e.metadata||!e.metadata.strategy)return this.logger.warn("No compression metadata found, assuming no compression"),e;const{strategy:t}=e.metadata,r=Date.now();if(!this.strategies[t])throw new Error(`Unknown compression strategy: ${t}`);const s=this.strategies[t].decompress(e.data),n=Date.now()-r;return this.logger.debug("Data decompressed",{strategy:t,decompressionTime:n,originalSize:e.metadata.originalSize}),s}catch(t){throw this.logger.error("Decompression failed",{error:t.message}),t}}compressEvents(e,t={}){const{strategy:r=this.defaultStrategy,chunkSize:s=100}=t;return this.logger.time("compressEvents",()=>{const n=[];for(let c=0;c<e.length;c+=s)n.push(e.slice(c,c+s));const i=n.map((c,h)=>{const g=this.compress(c,r);return{...g,metadata:{...g.metadata,chunkIndex:h,eventCount:c.length}}}),a=i.reduce((c,h)=>c+h.metadata.originalSize,0),l=i.reduce((c,h)=>c+h.metadata.compressedSize,0),o={chunks:i,metadata:{totalEvents:e.length,chunkCount:n.length,strategy:r,totalOriginalSize:a,totalCompressedSize:l,overallCompressionRatio:(l/a).toFixed(3),spaceSaved:`${((1-l/a)*100).toFixed(1)}%`}};return this.logger.info("Events compressed",o.metadata),o})}decompressEvents(e){return this.logger.time("decompressEvents",()=>{if(!e.chunks||!Array.isArray(e.chunks))throw new Error("Invalid compressed events format");const t=[];return e.chunks.forEach(r=>{const s=this.decompress(r);t.push(...s)}),this.logger.info("Events decompressed",{totalEvents:t.length,chunks:e.chunks.length}),t})}_compressJSON(e){const t={eventName:"e",blockNumber:"b",transactionHash:"t",address:"a",args:"r",topics:"p",data:"d",logIndex:"l",transactionIndex:"i",blockHash:"h",removed:"m"};return{d:this._replaceKeys(e,t),k:t}}_decompressJSON(e){if(!e.d||!e.k)return e;const t={};return Object.entries(e.k).forEach(([r,s])=>{t[s]=r}),this._replaceKeys(e.d,t)}_compressGzip(e){const t=JSON.stringify(e),r=N.gzip(t);return X(r)}_decompressGzip(e){const t=Y(e),r=N.ungzip(t),s=new TextDecoder().decode(r);return JSON.parse(s)}_compressOptimized(e){const t=this._compressJSON(e);return this._compressGzip(t)}_decompressOptimized(e){const t=this._decompressGzip(e);return this._decompressJSON(t)}_replaceKeys(e,t){if(Array.isArray(e))return e.map(r=>this._replaceKeys(r,t));if(e!==null&&typeof e=="object"){const r={};return Object.entries(e).forEach(([s,n])=>{const i=t[s]||s;r[i]=this._replaceKeys(n,t)}),r}return e}_calculateSize(e){const t=JSON.stringify(e);return k?Buffer.byteLength(t,"utf8"):new Blob([t]).size}analyzeCompressionStrategies(e){const t={};Object.keys(this.strategies).forEach(n=>{try{const i=this.compress(e,n);t[n]={originalSize:i.metadata.originalSize,compressedSize:i.metadata.compressedSize,compressionRatio:i.metadata.compressionRatio,spaceSaved:i.metadata.spaceSaved,compressionTime:i.metadata.compressionTime}}catch(i){t[n]={error:i.message}}});let r="none",s=1;return Object.entries(t).forEach(([n,i])=>{!i.error&&parseFloat(i.compressionRatio)<s&&(s=parseFloat(i.compressionRatio),r=n)}),{strategies:t,recommendation:r,bestCompressionRatio:s}}}class S{constructor(e,t,r=null){var s,n;this.gun=W(e),this.retryOperation=t,this.networkManager=r,this.logger=new p({context:"EventStore",level:(e==null?void 0:e.logLevel)||"info"}),this.eventFilter=new z(this.logger),this.paginator=new O(this.logger),this.dataCompressor=new C(this.logger),this.compressionEnabled=((s=e==null?void 0:e.compression)==null?void 0:s.enabled)??!0,this.compressionStrategy=((n=e==null?void 0:e.compression)==null?void 0:n.strategy)??"optimized",this._activeListeners=[],this.logger.info("EventStore initialized",{gunConfig:this._sanitizeGunConfig(e),compressionEnabled:this.compressionEnabled,compressionStrategy:this.compressionStrategy})}_sanitizeGunConfig(e){if(!e||typeof e!="object")return e;const t={...e};return delete t.peers,delete t.localStorage,t}async getStartBlockNumber(){return this.retryOperation(async()=>new Promise(e=>{this.gun.get("config").get("startBlockNumber").once(t=>{e(t||1)})}),"Getting start block number")}async setStartBlockNumber(e){return this.retryOperation(async()=>new Promise((t,r)=>{this.gun.get("config").get("startBlockNumber").put(e,s=>{s.err?r(new Error(s.err)):t(s)})}),`Setting start block number to ${e}`)}async storeEvent(e,t,r){return this.logger.time("storeEvent",async()=>{this.logger.logDatabaseActivity("storeEvent",{eventName:e,eventKey:t,blockNumber:r.blockNumber,transactionHash:r.transactionHash});let s=r;if(this.compressionEnabled){const n=this.dataCompressor.compress(r,this.compressionStrategy);s={_compressed:!0,_data:n.data,_metadata:n.metadata}}return this.retryOperation(()=>new Promise(n=>{this.gun.get("events").get(e).get(t).put(s,n)}),`Storing event ${e}`)},{eventName:e,eventKey:t})}async getEvents(e,t={}){return this.logger.time("getEvents",async()=>(this.logger.logDatabaseActivity("getEvents",{eventName:e,filter:Object.keys(t)}),this.retryOperation(async()=>new Promise(r=>{let s=!1;const n=this.gun.get("events").get(e),i=setTimeout(()=>{s||(s=!0,this.logger.debug("getEvents timed out, returning empty",{eventName:e}),r([]))},3e3);n.open(a=>{if(s)return;s=!0,clearTimeout(i);const l=[];a&&typeof a=="object"&&Object.entries(a).forEach(([o,c])=>{o==="_"||!c||typeof c!="object"||this._matchesFilter(c,t)&&l.push({key:o,...c})}),this.logger.debug("Events retrieved",{eventName:e,eventCount:l.length,filterApplied:Object.keys(t).length>0}),r(l)})}),`Getting events for ${e}`)),{eventName:e})}async getAllEvents(e={}){return this.logger.time("getAllEvents",async()=>{const{filter:t={},pagination:r={},sort:s={}}=e,n=await this._fetchAllEventsMap(),i=[];Object.entries(n).forEach(([l,o])=>{o.forEach(c=>{i.push({...c,eventName:l})})});let a=i;if(Object.keys(t).length>0){const l=this.eventFilter.buildFilter(t);a=this.eventFilter.applyFilter(i,l)}if(s.by&&(a=this.eventFilter.sortEvents(a,s)),r.page||r.pageSize){const l=this.paginator.paginate(a,r);return this.logger.debug("Query completed",{totalEvents:i.length,filteredEvents:a.length,returnedEvents:l.data.length}),l}return{data:a,meta:{totalItems:a.length}}})}async _fetchAllEventsMap(){return this.retryOperation(async()=>new Promise(e=>{let t=!1;const r=this.gun.get("events"),s=setTimeout(()=>{t||(t=!0,this.logger.debug("_fetchAllEventsMap timed out, returning empty"),e({}))},5e3);r.open(n=>{if(t)return;t=!0,clearTimeout(s);const i={};n&&typeof n=="object"&&Object.entries(n).forEach(([a,l])=>{a==="_"||!l||typeof l!="object"||(i[a]=[],Object.entries(l).forEach(([o,c])=>{if(o==="_"||!c||typeof c!="object")return;let h=c;if(c._compressed&&c._data)try{h=this.dataCompressor.decompress({data:c._data,metadata:c._metadata})}catch(g){this.logger.error("Failed to decompress event",{eventName:a,key:o,error:g.message})}i[a].push({key:o,...h})}))}),e(i)})}),"Getting all events")}async publishMagazine(e,t,r){return this.logger.time("publishMagazine",async()=>(this.logger.info("Publishing magazine",{alias:e,url:r,magazineData:{name:t.name,address:t.address,networkId:t.networkId}}),this.retryOperation(async()=>{const s=this.gun.back(-1).get(e),n=await new Promise((i,a)=>{s.put(t,l=>{l.err?(this.logger.error("Failed to publish magazine metadata",{alias:e,error:l.err}),a(new Error(l.err))):(this.logger.debug("Magazine metadata published",{alias:e}),i(l))})});return await new Promise((i,a)=>{s.get("url").put(r,l=>{l.err?(this.logger.error("Failed to publish magazine URL",{alias:e,url:r,error:l.err}),a(new Error(l.err))):(this.logger.debug("Magazine URL published",{alias:e,url:r}),i(l))})}),this.logger.info("Magazine published successfully",{alias:e,url:r}),n},"Publishing magazine")),{alias:e})}async subscribeMagazine(e){return this.retryOperation(async()=>new Promise((t,r)=>{this.gun.get(e).once((s,n)=>{s?t(s):r(new Error(`Magazine with ID ${e} not found`))})}),`Subscribing to magazine ${e}`)}_matchesFilter(e,t){if(!t||Object.keys(t).length===0)return!0;for(const[r,s]of Object.entries(t))if(e[r]!==s)return!1;return!0}async query(){const e=await this._fetchAllEventsMap(),t=[];return Object.entries(e).forEach(([r,s])=>{s.forEach(n=>{t.push({...n,eventName:r})})}),this.eventFilter.query(t)}async getEventsByTransactionHash(e){return this.logger.time("getEventsByTransactionHash",async()=>{const t=await this.getAllEvents({filter:{transactionHash:e}});return this.logger.debug("Found events by transaction hash",{transactionHash:e,count:t.data.length}),t.data})}async getEventsByBlockNumber(e){return this.logger.time("getEventsByBlockNumber",async()=>{const t=await this.getAllEvents({filter:{fromBlock:e,toBlock:e}});return this.logger.debug("Found events by block number",{blockNumber:e,count:t.data.length}),t.data})}async*iterateEvents(e={}){const{filter:t={},sort:r={},pageSize:s=100}=e,i=(await this.getAllEvents({filter:t,sort:r})).data;yield*this.paginator.iterate(i,{pageSize:s})}async getCompressionStats(){const e=await this._fetchAllEventsMap();let t=0,r=0,s=0;return Object.values(e).forEach(n=>{n.forEach(i=>{i._compressed&&i._metadata&&(t+=i._metadata.originalSize||0,r+=i._metadata.compressedSize||0,s++)})}),{compressedEvents:s,totalOriginalSize:t,totalCompressedSize:r,compressionRatio:t>0?(r/t).toFixed(3):"1.000",spaceSaved:t>0?`${((1-r/t)*100).toFixed(1)}%`:"0%"}}destroy(){this._activeListeners=[],this.logger.info("EventStore destroyed, listeners cleaned up")}getGunInstance(){return this.gun}}class P{constructor(e,t,r,s){this.networkManager=e,this.eventStore=t,this.configManager=r,this.retryOperation=s,this.logger=new p({context:"EventSyncer",level:r.get("logLevel")||"info"}),this.batchSize=1e3,this.lastSyncTime=0,this.logger.info("EventSyncer initialized",{batchSize:this.batchSize})}async syncEvents(){if(this._syncing)return this.logger.warn("Sync already in progress, skipping"),0;this._setSyncing(!0);try{return await this.logger.time("syncEvents",async()=>this.retryOperation(async()=>{const e=await this.eventStore.getStartBlockNumber(),t=await this.networkManager.getLatestBlockNumber();if(e>t){this.logger.info("Already up to date",{startBlockNumber:e,latestBlockNumber:t});return}this.logger.info("Starting event synchronization",{startBlockNumber:e,latestBlockNumber:t,totalBlocks:t-e+1});let r=e,s=0;for(;r<=t;){const n=Math.min(r+this.batchSize-1,t),i=await this._processBatch(r,n);s+=i,r=n+1}return await this.eventStore.setStartBlockNumber(t+1),this.lastSyncTime=Date.now(),this.logger.info("Event synchronization completed",{totalEventsProcessed:s,newStartBlockNumber:t+1}),s},"Event synchronization"))}finally{this._setSyncing(!1)}}async _processBatch(e,t){return this.logger.time("processBatch",async()=>{this.logger.debug("Processing batch",{fromBlock:e,toBlock:t});const r=await this.networkManager.getLogs(e,t);let s=0;for(const n of r){const i=this.networkManager.parseLog(n);if(i)try{const a=this.networkManager.createEventKey(n);await this.eventStore.storeEvent(i.eventName,a,i.eventData),s++,this.logger.trace("Event stored",{eventName:i.eventName,eventKey:a,blockNumber:n.blockNumber})}catch(a){this.logger.warn("Failed to store event",{eventName:i.eventName,blockNumber:n.blockNumber,transactionHash:n.transactionHash,error:a.message})}}return this.logger.debug("Batch processing completed",{fromBlock:e,toBlock:t,logsFound:r.length,eventsStored:s}),s},{fromBlock:e,toBlock:t})}async syncEventsFromRange(e,t){if(this.configManager.validateBlockNumber(e,"fromBlock"),this.configManager.validateBlockNumber(t,"toBlock"),e>t)throw new Error("fromBlock cannot be greater than toBlock");if(this._syncing)return this.logger.warn("Sync already in progress, skipping range sync"),0;this._setSyncing(!0);try{return await this.logger.time("syncEventsFromRange",async()=>this.retryOperation(async()=>{this.logger.info("Syncing events from specific range",{fromBlock:e,toBlock:t,totalBlocks:t-e+1});let r=e,s=0;for(;r<=t;){const n=Math.min(r+this.batchSize-1,t),i=await this._processBatch(r,n);s+=i,r=n+1}return this.lastSyncTime=Date.now(),this.logger.info("Range synchronization completed",{fromBlock:e,toBlock:t,totalEventsProcessed:s}),s},`Event synchronization for range ${e}-${t}`),{fromBlock:e,toBlock:t})}finally{this._setSyncing(!1)}}async syncEventsFromTransaction(e){if(!e||typeof e!="string")throw new Error("Transaction hash must be a non-empty string");return this.retryOperation(async()=>{const t=await this.networkManager.getTransactionReceipt(e);if(!t)throw new Error(`Transaction ${e} not found`);const r=this.configManager.get("address").toLowerCase(),s=t.logs.filter(n=>n.address.toLowerCase()===r);for(const n of s){const i=this.networkManager.parseLog(n);if(i){const a=this.networkManager.createEventKey(n);await this.eventStore.storeEvent(i.eventName,a,i.eventData)}}return this.lastSyncTime=Date.now(),s.length},`Syncing events from transaction ${e}`)}async getSyncStatus(){return this.retryOperation(async()=>{const e=await this.eventStore.getStartBlockNumber(),t=await this.networkManager.getLatestBlockNumber(),r=await this.networkManager.getNetworkInfo();return{nextSyncBlock:e,latestNetworkBlock:t,blocksBehind:Math.max(0,t-e+1),networkInfo:r,isUpToDate:e>t}},"Getting sync status")}async validateBeforeSync(){return await this.networkManager.validateNetwork(),await this.networkManager.validateContract(),!0}setBatchSize(e){if(!Number.isInteger(e)||e<1)throw new Error("Batch size must be a positive integer");this.batchSize=e}getBatchSize(){return this.batchSize}async resetSyncPosition(e){this.configManager.validateBlockNumber(e,"blockNumber"),await this.eventStore.setStartBlockNumber(e)}async getEventCount(e){return(await this.eventStore.getEvents(e)).length}startRealtimeSync(){const e=this.networkManager.getProvider();if(!e||typeof e.on!="function")throw new Error("Real-time sync requires a provider that supports event subscriptions (e.g., WebSocketProvider). The current provider does not have an .on() method.");if(this._realtimeListener){this.logger.warn("Real-time sync is already running, call stopRealtimeSync() first");return}const t=this.configManager.get("address"),r={address:t};this.logger.info("Starting real-time event sync",{contractAddress:t,providerType:e.constructor.name});const s=async n=>{try{const i=this.networkManager.parseLog(n);if(i){const a=this.networkManager.createEventKey(n);await this.eventStore.storeEvent(i.eventName,a,i.eventData),this.logger.debug("Real-time event stored",{eventName:i.eventName,eventKey:a,blockNumber:n.blockNumber})}}catch(i){this.logger.warn("Failed to process real-time event",{blockNumber:n.blockNumber,error:i.message})}};e.on(r,s),this._realtimeListener=s,this._realtimeFilter=r,this.logger.info("Real-time event sync started")}stopRealtimeSync(){if(!this._realtimeListener){this.logger.debug("No real-time sync listener to stop");return}const e=this.networkManager.getProvider();e&&typeof e.off=="function"&&(e.off(this._realtimeFilter,this._realtimeListener),this.logger.info("Real-time event sync stopped")),this._realtimeListener=null,this._realtimeFilter=null}isSyncing(){return this._syncing||!1}_setSyncing(e){this._syncing=e}}class F{constructor(e,t){this.networkManager=e,this.logger=t.child({context:"EventMetadata"}),this.logger.info("EventMetadata initialized")}async enrichEvent(e,t={}){const{includeBlock:r=!0,includeTransaction:s=!0,includeTimestamp:n=!0,includeGasCost:i=!0}=t;try{const a={...e},l=[];return(r||n)&&e.blockNumber&&l.push(this.networkManager.provider.getBlock(e.blockNumber).then(o=>{var c;o&&(r&&(a.block={number:o.number,hash:o.hash,parentHash:o.parentHash,miner:o.miner,difficulty:(c=o.difficulty)==null?void 0:c.toString(),gasLimit:o.gasLimit.toString(),gasUsed:o.gasUsed.toString()}),n&&(a.timestamp=o.timestamp,a.date=new Date(o.timestamp*1e3).toISOString()))}).catch(o=>{this.logger.warn("Failed to fetch block data",{blockNumber:e.blockNumber,error:o.message})})),(s||i)&&e.transactionHash&&l.push(Promise.all([this.networkManager.provider.getTransaction(e.transactionHash),i?this.networkManager.provider.getTransactionReceipt(e.transactionHash):null]).then(([o,c])=>{var h,g,d;if(o&&(s&&(a.transaction={hash:o.hash,from:o.from,to:o.to,value:o.value.toString(),nonce:o.nonce,gasLimit:o.gasLimit.toString(),gasPrice:(h=o.gasPrice)==null?void 0:h.toString(),maxFeePerGas:(g=o.maxFeePerGas)==null?void 0:g.toString(),maxPriorityFeePerGas:(d=o.maxPriorityFeePerGas)==null?void 0:d.toString(),data:o.data.length>66?o.data.substring(0,66)+"...":o.data}),i&&c)){const m=c.gasUsed,y=o.gasPrice||o.maxFeePerGas||0n,b=m*y;a.gas={used:m.toString(),price:y.toString(),cost:b.toString(),costInEther:this._formatEther(b)}}}).catch(o=>{this.logger.warn("Failed to fetch transaction data",{transactionHash:e.transactionHash,error:o.message})})),await Promise.all(l),a._metadata={enrichedAt:new Date().toISOString(),enrichmentOptions:t},this.logger.debug("Event enriched with metadata",{eventName:e.eventName,blockNumber:e.blockNumber,metadataAdded:Object.keys(a).filter(o=>!e.hasOwnProperty(o))}),a}catch(a){return this.logger.error("Failed to enrich event",{event:e,error:a.message}),e}}async enrichEvents(e,t={}){const{batchSize:r=10,...s}=t;return this.logger.time("enrichEvents",async()=>{var a,l;const n=[];let i=0;for(let o=0;o<e.length;o+=r){const c=e.slice(o,o+r),h=await Promise.allSettled(c.map(g=>this.enrichEvent(g,s)));for(let g=0;g<h.length;g++)h[g].status==="fulfilled"?n.push(h[g].value):(i++,this.logger.warn("Failed to enrich event, using original",{error:(a=h[g].reason)==null?void 0:a.message,blockNumber:(l=c[g])==null?void 0:l.blockNumber}),n.push(c[g]));this.logger.debug("Enriched event batch",{batchIndex:Math.floor(o/r),batchSize:c.length,failures:i,totalProgress:`${n.length}/${e.length}`})}return this.logger.info("Completed event enrichment",{totalEvents:e.length,enrichedEvents:n.length,failures:i}),n})}calculateStatistics(e){if(!Array.isArray(e)||e.length===0)return{count:0,blockRange:{min:null,max:null},timeRange:{min:null,max:null},gasStats:{total:"0",average:"0",min:"0",max:"0"}};const t=e.map(a=>a.blockNumber).filter(a=>a!=null).sort((a,l)=>a-l),r=e.map(a=>a.timestamp).filter(a=>a!=null).sort((a,l)=>a-l),s=e.map(a=>{var l;return(l=a.gas)==null?void 0:l.cost}).filter(a=>a!=null).map(a=>BigInt(a)),n={count:e.length,blockRange:{min:t[0]||null,max:t[t.length-1]||null,span:t.length>0?t[t.length-1]-t[0]:0},timeRange:{min:r[0]||null,max:r[r.length-1]||null,span:r.length>0?r[r.length-1]-r[0]:0}};if(s.length>0){const a=s.reduce((c,h)=>c+h,0n),l=a/BigInt(s.length),o=[...s].sort((c,h)=>c<h?-1:1);n.gasStats={total:a.toString(),average:l.toString(),min:o[0].toString(),max:o[o.length-1].toString(),totalInEther:this._formatEther(a)}}else n.gasStats={total:"0",average:"0",min:"0",max:"0"};const i={};return e.forEach(a=>{a.eventName&&(i[a.eventName]=(i[a.eventName]||0)+1)}),n.eventTypes=i,this.logger.debug("Calculated event statistics",n),n}_formatEther(e){try{const t=e.toString();return(Number(t)/1e18).toFixed(6)+" ETH"}catch{return"0 ETH"}}}class D{constructor(e,t){this.magazine=e,this.logger=t.child({context:"DebugUtils"}),this.logger.info("DebugUtils initialized"),this.debugMode=!1,this.metrics={syncOperations:[],queryOperations:[],storageOperations:[],networkCalls:[]},this._logBuffer=[],this._logBufferMax=200,this._originalMethods=new Map,this._verboseErrors=!1,this.healthThresholds={syncDelay:3e5,errorRate:.1,responseTime:5e3,storageUsage:.9}}async healthCheck(){const e=Date.now(),t={status:"healthy",timestamp:new Date().toISOString(),checks:{},issues:[]};try{t.checks.network=await this._checkNetwork(),t.checks.database=await this._checkDatabase(),t.checks.sync=await this._checkSyncStatus(),t.checks.storage=await this._checkStorage(),t.checks.performance=this._checkPerformance();const r=[];return Object.entries(t.checks).forEach(([s,n])=>{n.status!=="healthy"&&r.push({check:s,status:n.status,message:n.message})}),r.length>0&&(t.status=r.some(s=>s.status==="critical")?"critical":"degraded",t.issues=r),t.duration=Date.now()-e,this.logger.info("Health check completed",{status:t.status,duration:t.duration,issueCount:r.length}),t}catch(r){return this.logger.error("Health check failed",{error:r.message}),{status:"error",timestamp:new Date().toISOString(),error:r.message,duration:Date.now()-e}}}async getDebugInfo(){const e={timestamp:new Date().toISOString(),configuration:this._getConfigInfo(),network:await this._getNetworkInfo(),storage:await this._getStorageInfo(),performance:this._getPerformanceInfo(),logs:this._getRecentLogs()};return this.logger.debug("Debug info generated"),e}recordMetric(e,t){const r={timestamp:Date.now(),...t};this.metrics[e]&&(this.metrics[e].push(r),this.metrics[e].length>1e3&&(this.metrics[e]=this.metrics[e].slice(-1e3)))}getPerformanceReport(e={}){const{timeRange:t=36e5,aggregation:r="average"}=e,s=Date.now(),n=s-t,i={};return Object.entries(this.metrics).forEach(([a,l])=>{const o=l.filter(g=>g.timestamp>=n);if(o.length===0){i[a]={count:0,average:0,min:0,max:0};return}const c=o.map(g=>g.duration||0),h=o.filter(g=>g.error).length;i[a]={count:o.length,errors:h,errorRate:(h/o.length*100).toFixed(2)+"%",average:Math.round(c.reduce((g,d)=>g+d,0)/c.length),min:Math.min(...c),max:Math.max(...c),p95:this._calculatePercentile(c,95),p99:this._calculatePercentile(c,99)}}),{timeRange:{start:new Date(n).toISOString(),end:new Date(s).toISOString(),duration:t},metrics:i}}enableDebugMode(e={}){const{logLevel:t="debug",captureMetrics:r=!0,verboseErrors:s=!0}=e;this.magazine.setLogLevel(t),r&&this._instrumentMethods(),s&&this._enableVerboseErrors(),this.logger.info("Debug mode enabled",e)}async exportDebugData(){const e={version:"1.0.0",exportedAt:new Date().toISOString(),debugInfo:await this.getDebugInfo(),healthCheck:await this.healthCheck(),performanceReport:this.getPerformanceReport(),recentMetrics:{sync:this.metrics.syncOperations.slice(-100),query:this.metrics.queryOperations.slice(-100),storage:this.metrics.storageOperations.slice(-100),network:this.metrics.networkCalls.slice(-100)}};return this.logger.info("Debug data exported"),e}async _checkNetwork(){try{const e=Date.now(),t=await this.magazine.getLatestBlockNumber(),r=Date.now()-e;return{status:r<this.healthThresholds.responseTime?"healthy":"degraded",latestBlock:t,responseTime:r,message:`Network response time: ${r}ms`}}catch(e){return{status:"critical",error:e.message,message:"Network connection failed"}}}async _checkDatabase(){try{const e=Date.now(),t=this.magazine.eventStore.getGunInstance();await new Promise((s,n)=>{t.get("_health_check").put({timestamp:Date.now()},i=>{i.err?n(new Error(i.err)):s(i)})});const r=Date.now()-e;return{status:r<1e3?"healthy":"degraded",responseTime:r,message:`Database response time: ${r}ms`}}catch(e){return{status:"critical",error:e.message,message:"Database connection failed"}}}async _checkSyncStatus(){try{const e=this.magazine.eventSyncer.lastSyncTime||0,t=Date.now()-e;return e===0?{status:"warning",message:"No sync performed yet"}:{status:t<this.healthThresholds.syncDelay?"healthy":"warning",lastSync:new Date(e).toISOString(),timeSinceSync:t,message:`Last sync: ${Math.round(t/1e3)}s ago`}}catch(e){return{status:"error",error:e.message,message:"Could not check sync status"}}}async _checkStorage(){try{const e=await this.magazine.getCompressionStats(),t=e.totalCompressedSize/(100*1024*1024);return{status:t<this.healthThresholds.storageUsage?"healthy":"warning",usage:`${(t*100).toFixed(2)}%`,compressed:e.totalCompressedSize,saved:e.spaceSaved,message:`Storage usage: ${(t*100).toFixed(2)}%`}}catch(e){return{status:"error",error:e.message,message:"Could not check storage status"}}}_checkPerformance(){const e=this.getPerformanceReport({timeRange:3e5});let t="healthy";const r=[];return Object.entries(e.metrics).forEach(([s,n])=>{n.errorRate&&parseFloat(n.errorRate)>this.healthThresholds.errorRate*100&&(t="degraded",r.push(`High error rate in ${s}: ${n.errorRate}`)),n.average>this.healthThresholds.responseTime&&(t="degraded",r.push(`Slow ${s} operations: ${n.average}ms average`))}),{status:t,metrics:e.metrics,message:r.length>0?r.join(", "):"Performance metrics within normal range"}}_getConfigInfo(){const e=this.magazine.configManager.getAll();return{name:e.name,address:e.address,networkId:e.networkId,logLevel:this.magazine.logger.level,compression:{enabled:this.magazine.eventStore.compressionEnabled,strategy:this.magazine.eventStore.compressionStrategy}}}async _getNetworkInfo(){try{return{...await this.magazine.getNetworkInfo(),connected:!0}}catch(e){return{connected:!1,error:e.message}}}async _getStorageInfo(){try{const e=await this.magazine.getCompressionStats();return{eventCount:(await this.magazine.getAllEvents({pagination:{page:1,pageSize:1}})).meta.totalItems,...e}}catch(e){return{error:e.message}}}_getPerformanceInfo(){return this.getPerformanceReport({timeRange:36e5})}captureLog(e){this._logBuffer.push(e),this._logBuffer.length>this._logBufferMax&&this._logBuffer.shift()}_getRecentLogs(e=50){const t=Math.min(e,this._logBuffer.length);return this._logBuffer.slice(-t)}_calculatePercentile(e,t){if(e.length===0)return 0;const r=[...e].sort((n,i)=>n-i),s=Math.ceil(t/100*r.length)-1;return r[s]}_instrumentMethods(){const e=this.magazine,t=["syncEvents","getAllEvents","getEvents","query","transformEvent"];for(const r of t){if(typeof e[r]!="function"){this.logger.debug(`Skipping instrumentation for missing method: ${r}`);continue}if(this._originalMethods.has(r))continue;const s=e[r].bind(e);this._originalMethods.set(r,e[r]);const n=this;e[r]=function(...i){const a=Date.now();let l;r==="syncEvents"?l="syncOperations":r==="getAllEvents"||r==="getEvents"||r==="query"?l="queryOperations":l="storageOperations";try{const o=s(...i);if(o&&typeof o.then=="function")return o.then(h=>{const g=Date.now()-a;return n.recordMetric(l,{method:r,duration:g,success:!0}),n.logger.debug(`${r} completed in ${g}ms`),h}).catch(h=>{const g=Date.now()-a;throw n.recordMetric(l,{method:r,duration:g,success:!1,error:h.message}),n.logger.debug(`${r} failed after ${g}ms: ${h.message}`),h});const c=Date.now()-a;return n.recordMetric(l,{method:r,duration:c,success:!0}),n.logger.debug(`${r} completed in ${c}ms`),o}catch(o){const c=Date.now()-a;throw n.recordMetric(l,{method:r,duration:c,success:!1,error:o.message}),n.logger.debug(`${r} failed after ${c}ms: ${o.message}`),o}}}this.logger.debug("Method instrumentation enabled")}_enableVerboseErrors(){this._verboseErrors=!0;const e=this.magazine;if(typeof e.retryOperation=="function"&&!this._originalRetryOperation){const t=e.retryOperation.bind(e);this._originalRetryOperation=e.retryOperation;const r=this;e.retryOperation=async function(s,n,...i){try{return await t(s,n,...i)}catch(a){throw r._verboseErrors&&r.logger.error("Verbose error context for retryOperation failure",{operationContext:n,errorMessage:a.message,errorStack:a.stack,errorName:a.name,timestamp:new Date().toISOString()}),a}}}this.logger.debug("Verbose error logging enabled")}setDebugMode(e){if(this.debugMode=!!e,this.logger.info(`Debug mode ${e?"enabled":"disabled"}`),e){if(this._instrumentMethods(),this._enableVerboseErrors(),this.logger._log&&!this._originalLoggerLog){this._originalLoggerLog=this.logger._log.bind(this.logger);const t=this;this.logger._log=function(r,s,n){const i=t._originalLoggerLog(r,s,n);return t.captureLog({timestamp:Date.now(),level:r,message:s,data:n}),i}}}else this._originalLoggerLog&&(this.logger._log=this._originalLoggerLog,this._originalLoggerLog=null)}isDebugMode(){return!!this.debugMode}}class L extends Error{constructor(e,t=null){super(e),this.name="ValidationError",this.field=t}}class f extends Error{constructor(e){super(e),this.name="ModelError"}}class T{constructor(e,t){this.modelName=e,this.gun=t,this.migrations=new Map,this.currentVersion=1}version(e){return this.currentVersion=e,this}addMigration(e,t,r){return this.migrations.set(`${e}:${t}`,r),this}async migrate(e){let t=e._schemaVersion||1,r={...e};for(;t<this.currentVersion;){const s=t+1,n=`${t}:${s}`,i=this.migrations.get(n);if(!i)throw new f(`No migration path from version ${t} to ${s} for model '${this.modelName}'`);r=await i(r),r._schemaVersion=s,t=s}return r}needsMigration(e){return(e._schemaVersion||1)<this.currentVersion}}class ee{static validate(e,t){const r=[];for(const s of t.required||[])(!(s in e)||e[s]===null||e[s]===void 0)&&r.push(`Field '${s}' is required`);for(const[s,n]of Object.entries(t.properties||{}))if(s in e&&e[s]!==null&&e[s]!==void 0){const i=e[s],{type:a,validate:l}=n;if(a&&!this.validateType(i,a)&&r.push(`Field '${s}' must be of type ${a}`),l&&typeof l=="function"){const o=l(i);o!==!0&&r.push(`Field '${s}': ${o||"validation failed"}`)}}return{valid:r.length===0,errors:r}}static validateType(e,t){switch(t){case"string":return typeof e=="string";case"number":return typeof e=="number"&&!isNaN(e);case"boolean":return typeof e=="boolean";case"array":return Array.isArray(e);case"object":return typeof e=="object"&&e!==null&&!Array.isArray(e);case"address":return typeof e=="string"&&/^0x[a-fA-F0-9]{40}$/.test(e);case"hash":return typeof e=="string"&&/^0x[a-fA-F0-9]{64}$/.test(e);default:return!0}}}class A{constructor(e,t,r,s,n={}){this.name=e,this.schema=t,this.gun=r,this.transformer=s,this.options={autoId:!0,timestampFields:["createdAt","updatedAt"],...n},this.logger=new p({context:`DataModel:${e}`,level:n.logLevel||"info"}),this.modelNode=this.gun.get("models").get(this.name),this._hooks={},this.migration=null,this.logger.info("DataModel initialized",{name:this.name,options:this.options})}hook(e,t){return this._hooks[e]||(this._hooks[e]=[]),this._hooks[e].push(t),this}setMigration(e){return this.migration=e,this}async _runHooks(e,t){const r=this._hooks[e]||[];let s=t;for(const n of r){const i=await n(s);i!==void 0&&(s=i)}return s}generateId(){return`${this.name}_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}validate(e){const t=ee.validate(e,this.schema);if(!t.valid)throw new L(`Validation failed: ${t.errors.join(", ")}`)}prepareData(e,t=!1){const r={...e};return this.options.autoId&&!r.id&&!t&&(r.id=this.generateId()),this.options.timestampFields.includes("updatedAt")&&(r.updatedAt=new Date().toISOString()),this.options.timestampFields.includes("createdAt")&&!t&&(r.createdAt=new Date().toISOString()),this.migration&&(r._schemaVersion=this.migration.currentVersion),r}async save(e){this.logger.debug("Saving document",{data:e});try{let t=this.prepareData(e);t=await this._runHooks("pre:save",t),this.validate(t);const r=t.id;if(!r)throw new f("Document must have an ID");return await new Promise((s,n)=>{this.modelNode.get(r).put(t,i=>{i.err?n(new f(`Failed to save document: ${i.err}`)):s()})}),await this._runHooks("post:save",t),this.logger.info("Document saved",{id:r,model:this.name}),t}catch(t){throw this.logger.error("Failed to save document",{error:t.message,data:e}),t}}async find(e={},t={}){this.logger.debug("Finding documents",{query:e,options:t});try{const{limit:r=100,skip:s=0}=t,n=[];if(await new Promise(i=>{let a=0,l=0;this.modelNode.map().on((o,c)=>{if(o&&typeof o=="object"&&this.matchesQuery(o,e)){if(l<s){l++;return}a<r&&(n.push({...o,_key:c}),a++),a>=r&&i()}}),setTimeout(i,1e3)}),this.migration)for(let i=0;i<n.length;i++)this.migration.needsMigration(n[i])&&(n[i]=await this.migration.migrate(n[i]),await this.save(n[i]));return this.logger.debug("Documents found",{count:n.length,query:e}),n}catch(r){throw this.logger.error("Failed to find documents",{error:r.message,query:e}),new f(`Failed to find documents: ${r.message}`)}}async findOne(e){const t=await this.find(e,{limit:1});return t.length>0?t[0]:null}async findById(e){this.logger.debug("Finding document by ID",{id:e});try{let t=await new Promise(r=>{this.modelNode.get(e).once(s=>{r(s&&typeof s=="object"?{...s,_key:e}:null)})});return t&&this.migration&&this.migration.needsMigration(t)&&(t=await this.migration.migrate(t),await this.save(t)),t}catch(t){throw this.logger.error("Failed to find document by ID",{error:t.message,id:e}),new f(`Failed to find document: ${t.message}`)}}async update(e,t){this.logger.debug("Updating document",{id:e,updateData:t});try{const r=await this.findById(e);if(!r)throw new f(`Document with ID ${e} not found`);const s={...r,...t,id:e};let n=this.prepareData(s,!0);return n=await this._runHooks("pre:update",n),this.validate(n),await new Promise((i,a)=>{this.modelNode.get(e).put(n,l=>{l.err?a(new f(`Failed to update document: ${l.err}`)):i()})}),await this._runHooks("post:update",n),this.logger.info("Document updated",{id:e,model:this.name}),n}catch(r){throw this.logger.error("Failed to update document",{error:r.message,id:e,updateData:t}),r}}async delete(e){this.logger.debug("Deleting document",{id:e});try{return await this._runHooks("pre:delete",{id:e}),await new Promise((t,r)=>{this.modelNode.get(e).put(null,s=>{s.err?r(new f(`Failed to delete document: ${s.err}`)):t()})}),await this._runHooks("post:delete",{id:e}),this.logger.info("Document deleted",{id:e,model:this.name}),!0}catch(t){throw this.logger.error("Failed to delete document",{error:t.message,id:e}),t}}async count(e={}){return(await this.find(e,{limit:1e4})).length}async insertMany(e){if(!Array.isArray(e))throw new f("insertMany requires an array of documents");const t=[],r=[];for(const s of e)try{t.push(await this.save(s))}catch(n){r.push({document:s,error:n.message})}return r.length>0&&this.logger.warn("Some documents failed to insert",{total:e.length,succeeded:t.length,failed:r.length}),{inserted:t,errors:r}}async updateMany(e,t){const r=await this.find(e,{limit:1e5}),s=[],n=[];for(const i of r){const a=i.id||i._key;if(a)try{s.push(await this.update(a,t))}catch(l){n.push({id:a,error:l.message})}}return this.logger.info("updateMany completed",{matched:r.length,updated:s.length,failed:n.length}),{matched:r.length,updated:s,errors:n}}async deleteMany(e){const t=await this.find(e,{limit:1e5});let r=0;const s=[];for(const n of t){const i=n.id||n._key;if(i)try{await this.delete(i),r++}catch(a){s.push({id:i,error:a.message})}}return this.logger.info("deleteMany completed",{matched:t.length,deleted:r,failed:s.length}),{matched:t.length,deleted:r,errors:s}}async migrateAll(){if(!this.migration)throw new f("No migration configured for this model. Call setMigration() first.");const e=await this.find({},{limit:1e5});let t=0;const r=[];for(const s of e)if(this.migration.needsMigration(s))try{const n=await this.migration.migrate(s);await this.save(n),t++}catch(n){r.push({id:s.id||s._key,error:n.message})}return this.logger.info("migrateAll completed",{total:e.length,migrated:t,failed:r.length}),{total:e.length,migrated:t,errors:r}}matchesQuery(e,t){for(const[r,s]of Object.entries(t))if(typeof s=="object"&&s!==null)for(const[n,i]of Object.entries(s))switch(n){case"$gte":if(!(e[r]>=i))return!1;break;case"$lte":if(!(e[r]<=i))return!1;break;case"$gt":if(!(e[r]>i))return!1;break;case"$lt":if(!(e[r]<i))return!1;break;case"$ne":if(e[r]===i)return!1;break;case"$in":if(!Array.isArray(i)||!i.includes(e[r]))return!1;break;case"$nin":if(Array.isArray(i)&&i.includes(e[r]))return!1;break;case"$regex":if(!new RegExp(i).test(e[r]))return!1;break;default:if(e[r]!==s)return!1}else if(e[r]!==s)return!1;return!0}async aggregate(e={}){const t=await this.find(e,{limit:1e5});return new _(t)}}class _{constructor(e){this.data=Array.isArray(e)?e:[],this.stages=[]}match(e){return this.stages.push({type:"match",query:e}),this}group(e){return this.stages.push({type:"group",field:e}),this}sum(e,t){return this.stages.push({type:"aggregate",op:"sum",field:e,alias:t||`sum_${e}`}),this}avg(e,t){return this.stages.push({type:"aggregate",op:"avg",field:e,alias:t||`avg_${e}`}),this}count(e){return this.stages.push({type:"aggregate",op:"count",alias:e||"count"}),this}min(e,t){return this.stages.push({type:"aggregate",op:"min",field:e,alias:t||`min_${e}`}),this}max(e,t){return this.stages.push({type:"aggregate",op:"max",field:e,alias:t||`max_${e}`}),this}bucket(e,t){return this.stages.push({type:"bucket",timestampField:e,interval:t}),this}sort(e,t="asc"){return this.stages.push({type:"sort",field:e,order:t}),this}limit(e){return this.stages.push({type:"limit",n:e}),this}_truncateDate(e,t){const r=new Date(e);switch(t){case"minute":r.setUTCSeconds(0,0);break;case"hour":r.setUTCMinutes(0,0,0);break;case"day":r.setUTCHours(0,0,0,0);break;case"week":{r.setUTCHours(0,0,0,0);const s=r.getUTCDay(),n=s===0?6:s-1;r.setUTCDate(r.getUTCDate()-n);break}case"month":r.setUTCDate(1),r.setUTCHours(0,0,0,0);break}return r.toISOString()}_matchesQuery(e,t){for(const[r,s]of Object.entries(t))if(typeof s=="object"&&s!==null)for(const[n,i]of Object.entries(s))switch(n){case"$gte":if(!(e[r]>=i))return!1;break;case"$lte":if(!(e[r]<=i))return!1;break;case"$gt":if(!(e[r]>i))return!1;break;case"$lt":if(!(e[r]<i))return!1;break;case"$ne":if(e[r]===i)return!1;break;case"$in":if(!Array.isArray(i)||!i.includes(e[r]))return!1;break;case"$nin":if(Array.isArray(i)&&i.includes(e[r]))return!1;break;case"$regex":if(!new RegExp(i).test(e[r]))return!1;break;default:if(e[r]!==s)return!1}else if(e[r]!==s)return!1;return!0}_computeAggregate(e,t){const{op:r,field:s}=t;switch(r){case"count":return e.length;case"sum":{let n=0;for(const i of e){const a=Number(i[s]);isNaN(a)||(n+=a)}return n}case"avg":{let n=0,i=0;for(const a of e){const l=Number(a[s]);isNaN(l)||(n+=l,i++)}return i>0?n/i:0}case"min":{let n=1/0;for(const i of e){const a=Number(i[s]);!isNaN(a)&&a<n&&(n=a)}return n===1/0?0:n}case"max":{let n=-1/0;for(const i of e){const a=Number(i[s]);!isNaN(a)&&a>n&&(n=a)}return n===-1/0?0:n}default:return 0}}execute(){let e=[...this.data];const t=[],r=[];let s=null,n=null;const i=[];for(const o of this.stages)switch(o.type){case"match":t.push(o);break;case"group":s=o;break;case"bucket":n=o;break;case"aggregate":r.push(o);break;case"sort":case"limit":i.push(o);break}for(const o of t)e=e.filter(c=>this._matchesQuery(c,o.query));let a=null;if(n){a=new Map;const{timestampField:o,interval:c}=n;for(const h of e){const g=h[o];if(g==null)continue;const d=new Date(typeof g=="number"?g*1e3:g);if(isNaN(d.getTime()))continue;const m=this._truncateDate(d,c);a.has(m)||a.set(m,[]),a.get(m).push(h)}}else if(s){a=new Map;const{field:o}=s;for(const c of e){const h=c[o]!==void 0&&c[o]!==null?String(c[o]):"__null__";a.has(h)||a.set(h,[]),a.get(h).push(c)}}let l;if(a){l=[];for(const[o,c]of a){const h={_id:o==="__null__"?null:o};for(const g of r)h[g.alias]=this._computeAggregate(c,g);l.push(h)}}else if(r.length>0){const o={};for(const c of r)o[c.alias]=this._computeAggregate(e,c);l=o}else l=e;if(Array.isArray(l))for(const o of i)if(o.type==="sort"){const{field:c,order:h}=o,g=h==="desc"?-1:1;l.sort((d,m)=>{const y=d[c],b=m[c];return y<b?-1*g:y>b?1*g:0})}else o.type==="limit"&&(l=l.slice(0,o.n));return l}}class R{constructor(e,t={}){this.gun=e,this.options={logLevel:"info",enableAutoTransform:!0,...t},this.logger=new p({context:"DataTransformer",level:this.options.logLevel}),this.models=new Map,this.transformers=new Map,this.logger.info("DataTransformer initialized",{options:this.options})}model(e,t,r={}){if(this.models.has(e))return this.models.get(e);const s=new A(e,t,this.gun,this,r);return this.models.set(e,s),this.logger.info("Model registered",{name:e,schema:t}),s}registerTransformer(e,t,r){if(!this.models.has(t))throw new f(`Model '${t}' not found. Register the model first.`);this.transformers.set(e,{modelName:t,transformFn:r}),this.logger.info("Transformer registered",{eventName:e,modelName:t})}async transformEvent(e){if(!e||!e.eventName)return null;const t=this.transformers.get(e.eventName);if(!t)return this.logger.debug("No transformer found for event",{eventName:e.eventName}),null;try{const{modelName:r,transformFn:s}=t,n=this.models.get(r),i=await s(e),a=await n.save(i);return this.logger.info("Event transformed and saved",{eventName:e.eventName,modelName:r,id:a.id}),a}catch(r){throw this.logger.error("Failed to transform event",{error:r.message,eventName:e.eventName}),r}}getModel(e){const t=this.models.get(e);if(!t)throw new f(`Model '${e}' not found`);return t}getModels(){return new Map(this.models)}getStats(){return{modelsCount:this.models.size,transformersCount:this.transformers.size,registeredModels:Array.from(this.models.keys()),registeredTransformers:Array.from(this.transformers.keys())}}aggregate(e){return new _(e)}migration(e){return new T(e,this.gun)}}class te{constructor(e){this.configManager=new w(e);const t=this.configManager.getAll();this.logger=new p({context:"Magazine",level:t.logLevel||"info"}),this.logger.info("Initializing Magazine",{name:t.name,address:t.address,networkId:t.networkId}),this.retryOptions=this.configManager.getRetryOptions(),this.networkManager=new $(t,this.retryOperation.bind(this)),this.eventStore=new S(t.gun,this.retryOperation.bind(this)),this.eventSyncer=new P(this.networkManager,this.eventStore,this.configManager,this.retryOperation.bind(this)),this.eventMetadata=new F(this.networkManager,this.logger),this.debugUtils=new D(this,this.logger),this.dataTransformer=new R(this.eventStore.getGunInstance(),{logLevel:t.logLevel,enableAutoTransform:t.enableAutoTransform!==!1}),this.name=t.name,this.address=t.address,this.networkId=t.networkId,this.abi=t.abi,this.logger.info("Magazine initialized successfully",{name:this.name,address:this.address,networkId:this.networkId,eventCount:Object.keys(this.networkManager.eventsByTopic).length,componentCount:6,debugModeEnabled:this.debugUtils.isDebugMode(),dataTransformerEnabled:!0})}getConfigManager(){return this.configManager}getNetworkManager(){return this.networkManager}getEventStore(){return this.eventStore}getEventSyncer(){return this.eventSyncer}getLogger(){return this.logger}setLogLevel(e){this.logger.setLevel(e),this.logger.info("Log level updated",{newLevel:e})}async retryOperation(e,t=""){const{maxRetries:r,retryDelay:s,timeout:n}=this.retryOptions;let i;this.logger.debug("Starting retry operation",{context:t,maxRetries:r,timeout:n});for(let a=1;a<=r;a++)try{const l=new Promise((c,h)=>setTimeout(()=>h(new Error(`Operation timeout: ${t}`)),n)),o=await Promise.race([e(),l]);return a>1&&this.logger.info("Retry operation succeeded",{context:t,attempt:a,maxRetries:r}),o}catch(l){if(i=l,this.logger.warn("Retry operation failed",{context:t,attempt:a,maxRetries:r,error:l.message}),a<r){const o=s*Math.pow(2,a-1);this.logger.debug("Retrying operation",{context:t,delay:`${o}ms`,nextAttempt:a+1}),await new Promise(c=>setTimeout(c,o))}else this.logger.error("Retry operation exhausted",{context:t,totalAttempts:r,finalError:l.message,stack:l.stack})}throw i}startSync(){this.logger.info("Starting automatic sync"),this.stopSync(),this.syncInterval=setInterval(async()=>{try{await this.syncEvents()}catch(e){this.logger.error("Automatic sync error",{error:e.message,stack:e.stack})}},5e3),this.syncEvents().catch(e=>{this.logger.error("Initial sync error",{error:e.message,stack:e.stack})}),this.logger.info("Automatic sync started",{interval:"5000ms"})}startRealtimeSync(){return this.eventSyncer.startRealtimeSync()}stopRealtimeSync(){return this.eventSyncer.stopRealtimeSync()}destroy(){this.stopSync(),this.stopRealtimeSync(),this.eventStore.destroy(),this.logger.info("Magazine instance destroyed")}stopSync(){this.syncInterval&&(this.logger.info("Stopping automatic sync"),clearInterval(this.syncInterval),this.syncInterval=void 0)}async syncEvents(){return this.eventSyncer.syncEvents()}async syncEventsFromRange(e,t){return this.eventSyncer.syncEventsFromRange(e,t)}async syncEventsFromTransaction(e){return this.eventSyncer.syncEventsFromTransaction(e)}async getSyncStatus(){return this.eventSyncer.getSyncStatus()}async getStartBlockNumber(){return this.eventStore.getStartBlockNumber()}async setStartBlockNumber(e){return this.configManager.validateBlockNumber(e,"startBlockNumber"),this.eventStore.setStartBlockNumber(e)}async getEvents(e,t={}){return(await this.getAllEvents({filter:{...t,eventName:e}})).data}async getAllEvents(e={}){return this.eventStore.getAllEvents(e)}async query(){return this.eventStore.query()}async getEventsByTransactionHash(e){if(!e||typeof e!="string")throw new Error("Transaction hash must be a non-empty string");return this.eventStore.getEventsByTransactionHash(e)}async getEventsByBlockNumber(e){if(!Number.isInteger(e)||e<0)throw new Error("Block number must be a non-negative integer");return this.eventStore.getEventsByBlockNumber(e)}async*iterateEvents(e={}){yield*this.eventStore.iterateEvents(e)}async getNetworkInfo(){return this.networkManager.getNetworkInfo()}async validateNetwork(){return this.networkManager.validateNetwork()}async getLatestBlockNumber(){return this.networkManager.getLatestBlockNumber()}async publish(e={}){const t=this.configManager.validateOptions(e,["alias","url"]);if(t.alias&&(typeof t.alias!="string"||t.alias.trim().length===0))throw new Error("alias must be a non-empty string");if(t.url){if(typeof t.url!="string")throw new Error("url must be a string");try{new URL(t.url)}catch{throw new Error("url must be a valid URL")}}const r=t.alias?t.alias:this.name.toLowerCase().replace(/\s/g,"-"),s=t.url?t.url:"https://gunjs.herokuapp.com/gun",n={name:this.name,address:this.address,networkId:this.networkId,abi:this.abi};return this.eventStore.publishMagazine(r,n,s)}static async subscribe(e,t){if(!e||typeof e!="string")throw new Error("magazineId must be a non-empty string");if(!t||typeof t!="object")throw new Error("config must be an object");const r=["gun"];for(const n of r)if(!t[n])throw new Error(`Config field '${n}' is required for subscription`);return new S(t.gun,()=>{}).subscribeMagazine(e)}on(e,t){if(typeof t!="function")throw new Error("callback must be a function");this.eventStore.getGunInstance().get("events").get(e).map().on(t)}async healthCheck(){return this.debugUtils.healthCheck()}async getPerformanceMetrics(){return this.debugUtils.getPerformanceReport()}async exportDebugInfo(e={}){return this.debugUtils.exportDebugData()}setDebugMode(e){this.debugUtils.setDebugMode(e)}isDebugMode(){return this.debugUtils.isDebugMode()}getConfigSchema(){return this.configManager.getSchemaDocumentation()}static generateExampleConfig(e={}){return new w({name:"temp",address:"0x0000000000000000000000000000000000000000",abi:[],provider:"http://localhost:8545",networkId:1}).generateExampleConfig(e)}static validateConfig(e){return w.validateConfiguration(e)}async getCompressionStats(){return this.eventStore.getCompressionStats()}model(e,t,r={}){return this.dataTransformer.model(e,t,r)}registerTransformer(e,t,r){return this.dataTransformer.registerTransformer(e,t,r)}getModel(e){return this.dataTransformer.getModel(e)}async transformEvent(e){return this.dataTransformer.transformEvent(e)}getTransformationStats(){return this.dataTransformer.getStats()}getModels(){return this.dataTransformer.getModels()}}exports.AggregationPipeline=_;exports.ConfigManager=w;exports.DataCompressor=C;exports.DataModel=A;exports.DataTransformer=R;exports.DebugUtils=D;exports.EventFilter=z;exports.EventMetadata=F;exports.EventStore=S;exports.EventSyncer=P;exports.Logger=p;exports.ModelError=f;exports.NetworkManager=$;exports.PaginationHelper=Z;exports.Paginator=O;exports.SchemaMigration=T;exports.ValidationError=L;exports.default=te;
5
+ //# sourceMappingURL=magazine.cjs.js.map