@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.
@@ -0,0 +1,4149 @@
1
+ import * as b from "ethers";
2
+ import N from "gun";
3
+ import "gun/lib/load.js";
4
+ import "gun/lib/open.js";
5
+ import { gzip as x, ungzip as I } from "pako";
6
+ class p {
7
+ constructor(e = {}) {
8
+ 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 = {
9
+ error: 0,
10
+ warn: 1,
11
+ info: 2,
12
+ debug: 3,
13
+ trace: 4
14
+ }, this.currentLevelValue = this.levels[this.level.toLowerCase()] || this.levels.info, this.enableFile && this._initFileLogging();
15
+ }
16
+ // Create a formatted log entry
17
+ _formatLog(e, t, r = {}) {
18
+ const s = new Date().toISOString(), n = {
19
+ timestamp: s,
20
+ level: e.toUpperCase(),
21
+ context: this.context,
22
+ message: t,
23
+ ...r
24
+ };
25
+ return {
26
+ formatted: `[${s}] ${e.toUpperCase()} [${this.context}] ${t}${Object.keys(r).length > 0 ? " " + JSON.stringify(r, this._getCircularReplacer()) : ""}`,
27
+ structured: n
28
+ };
29
+ }
30
+ // Get a replacer function to handle circular references in JSON.stringify
31
+ _getCircularReplacer() {
32
+ const e = /* @__PURE__ */ new WeakSet();
33
+ return (t, r) => {
34
+ if (typeof r == "object" && r !== null) {
35
+ if (e.has(r))
36
+ return "[Circular]";
37
+ e.add(r);
38
+ }
39
+ return r;
40
+ };
41
+ }
42
+ // Check if current level allows logging at specified level
43
+ _shouldLog(e) {
44
+ const t = this.levels[e.toLowerCase()];
45
+ return t !== void 0 && t <= this.currentLevelValue;
46
+ }
47
+ // Write log to console
48
+ _writeToConsole(e, t) {
49
+ if (this.enableConsole)
50
+ switch (e.toLowerCase()) {
51
+ case "error":
52
+ console.error(t);
53
+ break;
54
+ case "warn":
55
+ console.warn(t);
56
+ break;
57
+ case "debug":
58
+ case "trace":
59
+ console.debug(t);
60
+ break;
61
+ default:
62
+ console.log(t);
63
+ }
64
+ }
65
+ // Initialize file system module for file logging
66
+ _initFileLogging() {
67
+ if (this._fsAvailable === null)
68
+ try {
69
+ const e = import("fs"), t = import("path");
70
+ Promise.all([e, t]).then(([r, s]) => {
71
+ this._fsModule = r.default || r, this._pathModule = s.default || s, this._fsAvailable = !0;
72
+ }).catch(() => {
73
+ this._fsAvailable = !1;
74
+ });
75
+ } catch {
76
+ this._fsAvailable = !1;
77
+ }
78
+ }
79
+ // Write log entry as a JSON line to the configured file
80
+ _writeToFile(e) {
81
+ if (this.enableFile && this._fsAvailable !== !1 && this._fsModule)
82
+ try {
83
+ const t = JSON.stringify(e, this._getCircularReplacer()) + `
84
+ `;
85
+ this._fsModule.appendFileSync(this.filePath, t, "utf8");
86
+ } catch {
87
+ }
88
+ }
89
+ // Rotate log file if it exceeds maxSizeBytes. Keeps 1 rotated backup.
90
+ rotateLogs(e = 10 * 1024 * 1024) {
91
+ if (!(!this._fsModule || this._fsAvailable === !1))
92
+ try {
93
+ if (!this._fsModule.existsSync(this.filePath) || this._fsModule.statSync(this.filePath).size < e)
94
+ return;
95
+ const r = this.filePath + ".1";
96
+ this._fsModule.existsSync(r) && this._fsModule.unlinkSync(r), this._fsModule.renameSync(this.filePath, r), this._fsModule.writeFileSync(this.filePath, "", "utf8");
97
+ } catch {
98
+ }
99
+ }
100
+ // Core logging method
101
+ _log(e, t, r = {}) {
102
+ if (!this._shouldLog(e))
103
+ return;
104
+ const { formatted: s, structured: n } = this._formatLog(e, t, r);
105
+ return this._writeToConsole(e, s), this._writeToFile(n), n;
106
+ }
107
+ // Logging level methods
108
+ error(e, t = {}) {
109
+ return this._log("error", e, t);
110
+ }
111
+ warn(e, t = {}) {
112
+ return this._log("warn", e, t);
113
+ }
114
+ info(e, t = {}) {
115
+ return this._log("info", e, t);
116
+ }
117
+ debug(e, t = {}) {
118
+ return this._log("debug", e, t);
119
+ }
120
+ trace(e, t = {}) {
121
+ return this._log("trace", e, t);
122
+ }
123
+ // Performance logging - measure function execution time
124
+ async time(e, t, r = {}) {
125
+ const s = Date.now(), n = `Starting operation: ${e}`;
126
+ this.debug(n, r);
127
+ try {
128
+ const i = await t(), a = Date.now() - s;
129
+ return this.info(`Completed operation: ${e}`, {
130
+ ...r,
131
+ duration: `${a}ms`,
132
+ success: !0
133
+ }), i;
134
+ } catch (i) {
135
+ const a = Date.now() - s;
136
+ throw this.error(`Failed operation: ${e}`, {
137
+ ...r,
138
+ duration: `${a}ms`,
139
+ success: !1,
140
+ error: (i == null ? void 0 : i.message) || (i == null ? void 0 : i.toString()) || "Unknown error",
141
+ stack: i == null ? void 0 : i.stack
142
+ }), i;
143
+ }
144
+ }
145
+ // Create a child logger with additional context
146
+ child(e = {}) {
147
+ return new p({
148
+ level: this.level,
149
+ context: this.context,
150
+ enableConsole: this.enableConsole,
151
+ enableFile: this.enableFile,
152
+ filePath: this.filePath,
153
+ ...e
154
+ });
155
+ }
156
+ // Change log level dynamically
157
+ setLevel(e) {
158
+ 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(", ")}`);
159
+ }
160
+ // Get current configuration
161
+ getConfig() {
162
+ return {
163
+ level: this.level,
164
+ context: this.context,
165
+ enableConsole: this.enableConsole,
166
+ enableFile: this.enableFile,
167
+ filePath: this.filePath
168
+ };
169
+ }
170
+ // Log system information
171
+ logSystemInfo(e = {}) {
172
+ this.info("System Information", {
173
+ nodeVersion: process.version,
174
+ platform: process.platform,
175
+ arch: process.arch,
176
+ memoryUsage: process.memoryUsage(),
177
+ uptime: process.uptime(),
178
+ ...e
179
+ });
180
+ }
181
+ // Log network request/response
182
+ logNetworkActivity(e, t = {}) {
183
+ this.debug(`Network ${e}`, {
184
+ type: e,
185
+ timestamp: Date.now(),
186
+ ...t
187
+ });
188
+ }
189
+ // Log blockchain interaction
190
+ logBlockchainActivity(e, t = {}) {
191
+ this.info(`Blockchain: ${e}`, {
192
+ operation: e,
193
+ timestamp: Date.now(),
194
+ ...t
195
+ });
196
+ }
197
+ // Log Gun.js database activity
198
+ logDatabaseActivity(e, t = {}) {
199
+ this.debug(`Database: ${e}`, {
200
+ operation: e,
201
+ timestamp: Date.now(),
202
+ ...t
203
+ });
204
+ }
205
+ }
206
+ new p({
207
+ level: "info",
208
+ context: "Magazine"
209
+ });
210
+ class S {
211
+ constructor() {
212
+ this.schema = {
213
+ // Required fields
214
+ required: ["name", "address", "abi", "provider"],
215
+ // Field definitions
216
+ fields: {
217
+ name: {
218
+ type: "string",
219
+ description: "Name of the magazine",
220
+ minLength: 1,
221
+ maxLength: 100,
222
+ pattern: /^[a-zA-Z0-9\s\-_]+$/,
223
+ example: "My Event Magazine"
224
+ },
225
+ address: {
226
+ type: "string",
227
+ description: "Contract address",
228
+ pattern: /^0x[a-fA-F0-9]{40}$/,
229
+ example: "0x1234567890123456789012345678901234567890"
230
+ },
231
+ abi: {
232
+ type: "array",
233
+ description: "Contract ABI",
234
+ minItems: 1,
235
+ items: {
236
+ type: "object",
237
+ required: ["type"],
238
+ properties: {
239
+ type: {
240
+ type: "string",
241
+ enum: ["function", "event", "constructor", "fallback", "receive"]
242
+ },
243
+ name: { type: "string" },
244
+ inputs: { type: "array" },
245
+ outputs: { type: "array" },
246
+ anonymous: { type: "boolean" }
247
+ }
248
+ }
249
+ },
250
+ provider: {
251
+ type: ["string", "object"],
252
+ description: "Ethereum provider URL or object",
253
+ validate: (e) => typeof e == "string" ? e.startsWith("http://") || e.startsWith("https://") || e.startsWith("ws://") || e.startsWith("wss://") : typeof e == "object" && e !== null,
254
+ example: "http://localhost:8545"
255
+ },
256
+ networkId: {
257
+ type: "number",
258
+ description: "Network ID",
259
+ optional: !0,
260
+ min: 1,
261
+ example: 1
262
+ },
263
+ gun: {
264
+ type: "object",
265
+ description: "Gun.js configuration",
266
+ optional: !0,
267
+ properties: {
268
+ peers: {
269
+ type: "array",
270
+ items: { type: "string" },
271
+ example: ["http://localhost:8765/gun"]
272
+ },
273
+ file: {
274
+ type: "string",
275
+ example: "radata"
276
+ },
277
+ localStorage: {
278
+ type: "boolean",
279
+ default: !0
280
+ },
281
+ radisk: {
282
+ type: "boolean",
283
+ default: !0
284
+ },
285
+ multicast: {
286
+ type: ["boolean", "object"],
287
+ default: !1
288
+ },
289
+ compression: {
290
+ type: "object",
291
+ properties: {
292
+ enabled: {
293
+ type: "boolean",
294
+ default: !0
295
+ },
296
+ strategy: {
297
+ type: "string",
298
+ enum: ["none", "json", "gzip", "optimized"],
299
+ default: "optimized"
300
+ }
301
+ }
302
+ }
303
+ }
304
+ },
305
+ logLevel: {
306
+ type: "string",
307
+ description: "Logging level",
308
+ optional: !0,
309
+ enum: ["error", "warn", "info", "debug", "trace"],
310
+ default: "info"
311
+ },
312
+ maxRetries: {
313
+ type: "number",
314
+ description: "Maximum retry attempts",
315
+ optional: !0,
316
+ min: 0,
317
+ max: 10,
318
+ default: 3
319
+ },
320
+ retryDelay: {
321
+ type: "number",
322
+ description: "Delay between retries in milliseconds",
323
+ optional: !0,
324
+ min: 100,
325
+ max: 6e4,
326
+ default: 1e3
327
+ },
328
+ timeout: {
329
+ type: "number",
330
+ description: "Operation timeout in milliseconds",
331
+ optional: !0,
332
+ min: 1e3,
333
+ max: 3e5,
334
+ default: 3e4
335
+ },
336
+ batchSize: {
337
+ type: "number",
338
+ description: "Event sync batch size",
339
+ optional: !0,
340
+ min: 1,
341
+ max: 1e4,
342
+ default: 1e3
343
+ },
344
+ startBlockNumber: {
345
+ type: "number",
346
+ description: "Starting block number for sync",
347
+ optional: !0,
348
+ min: 0,
349
+ default: 1
350
+ },
351
+ autoSync: {
352
+ type: "boolean",
353
+ description: "Enable automatic syncing",
354
+ optional: !0,
355
+ default: !1
356
+ },
357
+ syncInterval: {
358
+ type: "number",
359
+ description: "Auto-sync interval in milliseconds",
360
+ optional: !0,
361
+ min: 1e4,
362
+ max: 36e5,
363
+ default: 6e4,
364
+ dependsOn: "autoSync"
365
+ }
366
+ }
367
+ }, this.errorMessages = {
368
+ required: (e) => `${e} is required`,
369
+ type: (e, t, r) => `${e} must be of type ${t}, got ${r}`,
370
+ minLength: (e, t) => `${e} must be at least ${t} characters long`,
371
+ maxLength: (e, t) => `${e} must be at most ${t} characters long`,
372
+ pattern: (e) => `${e} has invalid format`,
373
+ min: (e, t) => `${e} must be at least ${t}`,
374
+ max: (e, t) => `${e} must be at most ${t}`,
375
+ enum: (e, t) => `${e} must be one of: ${t.join(", ")}`,
376
+ minItems: (e, t) => `${e} must have at least ${t} items`,
377
+ custom: (e, t) => `${e}: ${t}`
378
+ };
379
+ }
380
+ /**
381
+ * Validate configuration against schema
382
+ * @param {Object} config - Configuration to validate
383
+ * @returns {Object} Validation result
384
+ */
385
+ validate(e) {
386
+ const t = [], r = [], s = {};
387
+ for (const n of this.schema.required)
388
+ (!e.hasOwnProperty(n) || e[n] === void 0 || e[n] === null) && t.push({
389
+ field: n,
390
+ type: "required",
391
+ message: this.errorMessages.required(n)
392
+ });
393
+ for (const [n, i] of Object.entries(this.schema.fields))
394
+ if (e.hasOwnProperty(n)) {
395
+ const a = this._validateField(n, e[n], i);
396
+ a.errors.length > 0 ? t.push(...a.errors) : s[n] = a.value, a.warnings.length > 0 && r.push(...a.warnings);
397
+ } else
398
+ !i.optional && !this.schema.required.includes(n) && i.hasOwnProperty("default") && (s[n] = i.default);
399
+ for (const n of Object.keys(e))
400
+ this.schema.fields.hasOwnProperty(n) || (r.push({
401
+ field: n,
402
+ type: "unknown",
403
+ message: `Unknown configuration field: ${n}`
404
+ }), s[n] = e[n]);
405
+ for (const [n, i] of Object.entries(this.schema.fields))
406
+ i.dependsOn && s[n] !== void 0 && (s[i.dependsOn] || r.push({
407
+ field: n,
408
+ type: "dependency",
409
+ message: `${n} depends on ${i.dependsOn} being set`
410
+ }));
411
+ return {
412
+ valid: t.length === 0,
413
+ errors: t,
414
+ warnings: r,
415
+ validated: s
416
+ };
417
+ }
418
+ /**
419
+ * Validate a single field
420
+ * @private
421
+ */
422
+ _validateField(e, t, r) {
423
+ const s = [], n = [];
424
+ let i = t;
425
+ const a = Array.isArray(t) ? "array" : typeof t, l = Array.isArray(r.type) ? r.type : [r.type];
426
+ if (!l.includes(a))
427
+ return s.push({
428
+ field: e,
429
+ type: "type",
430
+ message: this.errorMessages.type(e, l.join(" or "), a)
431
+ }), { errors: s, warnings: n, value: t };
432
+ if (r.transform && typeof r.transform == "function" && (i = r.transform(i)), a === "string" && (r.minLength && i.length < r.minLength && s.push({
433
+ field: e,
434
+ type: "minLength",
435
+ message: this.errorMessages.minLength(e, r.minLength)
436
+ }), r.maxLength && i.length > r.maxLength && s.push({
437
+ field: e,
438
+ type: "maxLength",
439
+ message: this.errorMessages.maxLength(e, r.maxLength)
440
+ }), r.pattern && !r.pattern.test(i) && s.push({
441
+ field: e,
442
+ type: "pattern",
443
+ message: this.errorMessages.pattern(e)
444
+ }), r.enum && !r.enum.includes(i) && s.push({
445
+ field: e,
446
+ type: "enum",
447
+ message: this.errorMessages.enum(e, r.enum)
448
+ })), a === "number" && (r.min !== void 0 && i < r.min && s.push({
449
+ field: e,
450
+ type: "min",
451
+ message: this.errorMessages.min(e, r.min)
452
+ }), r.max !== void 0 && i > r.max && s.push({
453
+ field: e,
454
+ type: "max",
455
+ message: this.errorMessages.max(e, r.max)
456
+ })), a === "array" && (r.minItems && i.length < r.minItems && s.push({
457
+ field: e,
458
+ type: "minItems",
459
+ message: this.errorMessages.minItems(e, r.minItems)
460
+ }), r.items && i.forEach((o, c) => {
461
+ const h = this._validateField(
462
+ `${e}[${c}]`,
463
+ o,
464
+ r.items
465
+ );
466
+ s.push(...h.errors), n.push(...h.warnings);
467
+ })), a === "object" && r.properties) {
468
+ for (const [o, c] of Object.entries(r.properties))
469
+ if (i.hasOwnProperty(o)) {
470
+ const h = this._validateField(
471
+ `${e}.${o}`,
472
+ i[o],
473
+ c
474
+ );
475
+ s.push(...h.errors), n.push(...h.warnings);
476
+ }
477
+ }
478
+ return r.validate && typeof r.validate == "function" && (r.validate(i) || s.push({
479
+ field: e,
480
+ type: "custom",
481
+ message: this.errorMessages.custom(e, "Custom validation failed")
482
+ })), { errors: s, warnings: n, value: i };
483
+ }
484
+ /**
485
+ * Get schema documentation
486
+ * @returns {Object} Schema documentation
487
+ */
488
+ getDocumentation() {
489
+ const e = {
490
+ description: "Magazine configuration schema",
491
+ required: this.schema.required,
492
+ fields: {}
493
+ };
494
+ for (const [t, r] of Object.entries(this.schema.fields))
495
+ e.fields[t] = {
496
+ type: r.type,
497
+ description: r.description,
498
+ required: this.schema.required.includes(t),
499
+ optional: r.optional,
500
+ default: r.default,
501
+ example: r.example
502
+ }, r.enum && (e.fields[t].enum = r.enum), (r.min !== void 0 || r.max !== void 0) && (e.fields[t].range = {
503
+ min: r.min,
504
+ max: r.max
505
+ }), r.pattern && (e.fields[t].pattern = r.pattern.toString()), r.dependsOn && (e.fields[t].dependsOn = r.dependsOn);
506
+ return e;
507
+ }
508
+ /**
509
+ * Generate example configuration
510
+ * @param {Object} options - Generation options
511
+ * @returns {Object} Example configuration
512
+ */
513
+ generateExample(e = {}) {
514
+ const { includeOptional: t = !0, useDefaults: r = !0 } = e, s = {};
515
+ for (const [n, i] of Object.entries(this.schema.fields))
516
+ (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));
517
+ return s;
518
+ }
519
+ /**
520
+ * Generate placeholder value based on type
521
+ * @private
522
+ */
523
+ _generatePlaceholder(e) {
524
+ switch (Array.isArray(e.type) ? e.type[0] : e.type) {
525
+ case "string":
526
+ return e.enum ? e.enum[0] : "example-value";
527
+ case "number":
528
+ return e.min !== void 0 ? e.min : 0;
529
+ case "boolean":
530
+ return !1;
531
+ case "array":
532
+ return [];
533
+ case "object":
534
+ return {};
535
+ default:
536
+ return null;
537
+ }
538
+ }
539
+ }
540
+ class v {
541
+ /**
542
+ * Create a ConfigManager instance
543
+ * @param {Object} config - Configuration object to validate and manage
544
+ * @throws {Error} If configuration validation fails
545
+ */
546
+ constructor(e) {
547
+ this.schema = new S(), this.logger = new p({
548
+ context: "ConfigManager",
549
+ level: (e == null ? void 0 : e.logLevel) || "info"
550
+ }), this.logger.debug("Initializing ConfigManager with schema validation", {
551
+ config: this._sanitizeConfig(e)
552
+ });
553
+ const t = this.validateConfig(e);
554
+ if (!t.valid) {
555
+ const r = this._formatValidationErrors(t.errors);
556
+ throw this.logger.error("Configuration validation failed", {
557
+ errors: t.errors,
558
+ warnings: t.warnings
559
+ }), new Error(`Configuration validation failed:
560
+ ${r}`);
561
+ }
562
+ t.warnings.length > 0 && this.logger.warn("Configuration validation warnings", {
563
+ warnings: t.warnings
564
+ }), this.config = t.validated, this.logger.info("ConfigManager initialized successfully", {
565
+ name: this.config.name,
566
+ address: this.config.address,
567
+ networkId: this.config.networkId,
568
+ maxRetries: this.config.maxRetries,
569
+ retryDelay: this.config.retryDelay,
570
+ timeout: this.config.timeout,
571
+ warningsCount: t.warnings.length
572
+ });
573
+ }
574
+ /**
575
+ * Sanitize config for logging (remove sensitive data)
576
+ * @private
577
+ * @param {Object} config - Configuration object to sanitize
578
+ * @returns {Object} Sanitized configuration object
579
+ */
580
+ _sanitizeConfig(e) {
581
+ if (!e)
582
+ return e;
583
+ const t = { ...e };
584
+ return t.gun && (t.gun = { ...t.gun }, delete t.gun.peers), t;
585
+ }
586
+ /**
587
+ * Validate configuration using ConfigSchema
588
+ * @param {Object} config - Configuration object to validate
589
+ * @returns {Object} Validation result with validated config
590
+ */
591
+ validateConfig(e) {
592
+ return !e || typeof e != "object" ? {
593
+ valid: !1,
594
+ errors: [{
595
+ field: "config",
596
+ type: "required",
597
+ message: "Configuration must be a non-null object"
598
+ }],
599
+ warnings: [],
600
+ validated: {}
601
+ } : this.schema.validate(e);
602
+ }
603
+ /**
604
+ * Format validation errors into a readable string
605
+ * @private
606
+ * @param {Array} errors - Array of validation errors
607
+ * @returns {string} Formatted error message
608
+ */
609
+ _formatValidationErrors(e) {
610
+ return e.map((t) => ` - ${t.field}: ${t.message}`).join(`
611
+ `);
612
+ }
613
+ /**
614
+ * Get schema documentation
615
+ * @returns {Object} Schema documentation object
616
+ */
617
+ getSchemaDocumentation() {
618
+ return this.schema.getDocumentation();
619
+ }
620
+ /**
621
+ * Generate example configuration
622
+ * @param {Object} options - Generation options
623
+ * @returns {Object} Example configuration object
624
+ */
625
+ generateExampleConfig(e = {}) {
626
+ return this.schema.generateExample(e);
627
+ }
628
+ /**
629
+ * Validate a configuration object without creating an instance
630
+ * @static
631
+ * @param {Object} config - Configuration to validate
632
+ * @returns {Object} Validation result
633
+ */
634
+ static validateConfiguration(e) {
635
+ return new S().validate(e);
636
+ }
637
+ /**
638
+ * Validate block number parameters
639
+ * @param {number} blockNumber - Block number to validate
640
+ * @param {string} paramName - Parameter name for error messages
641
+ * @throws {Error} If block number is invalid
642
+ */
643
+ validateBlockNumber(e, t = "blockNumber") {
644
+ if (!Number.isInteger(e) || e < 0)
645
+ throw new Error(`${t} must be a non-negative integer`);
646
+ }
647
+ /**
648
+ * Validate options object for API methods
649
+ * @param {Object} options - Options object to validate
650
+ * @param {Array} allowedKeys - Array of allowed option keys
651
+ * @returns {Object} Validated options object
652
+ * @throws {Error} If options are invalid
653
+ */
654
+ validateOptions(e, t = []) {
655
+ if (e !== void 0 && (typeof e != "object" || e === null))
656
+ throw new Error("Options must be an object");
657
+ if (e && t.length > 0) {
658
+ const r = Object.keys(e).filter((s) => !t.includes(s));
659
+ if (r.length > 0)
660
+ throw new Error(`Invalid option keys: ${r.join(", ")}. Allowed: ${t.join(", ")}`);
661
+ }
662
+ return e || {};
663
+ }
664
+ /**
665
+ * Get configuration value by key
666
+ * @param {string} key - Configuration key
667
+ * @returns {*} Configuration value
668
+ */
669
+ get(e) {
670
+ return this.config[e];
671
+ }
672
+ /**
673
+ * Get all configuration
674
+ * @returns {Object} Complete configuration object
675
+ */
676
+ getAll() {
677
+ return { ...this.config };
678
+ }
679
+ /**
680
+ * Get retry options for network operations
681
+ * @returns {Object} Retry configuration object
682
+ */
683
+ getRetryOptions() {
684
+ return {
685
+ maxRetries: this.config.maxRetries,
686
+ retryDelay: this.config.retryDelay,
687
+ timeout: this.config.timeout
688
+ };
689
+ }
690
+ }
691
+ class _ {
692
+ constructor(e = 500) {
693
+ this.maxSize = e, this.cache = /* @__PURE__ */ new Map();
694
+ }
695
+ get(e) {
696
+ if (!this.cache.has(e))
697
+ return;
698
+ const t = this.cache.get(e);
699
+ return this.cache.delete(e), this.cache.set(e, t), t;
700
+ }
701
+ set(e, t) {
702
+ 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);
703
+ }
704
+ clear() {
705
+ this.cache.clear();
706
+ }
707
+ get size() {
708
+ return this.cache.size;
709
+ }
710
+ }
711
+ class $ {
712
+ constructor(e = 25) {
713
+ this.maxPerSecond = e, this.tokens = e, this.lastRefill = Date.now(), this.queue = [];
714
+ }
715
+ async acquire() {
716
+ if (this._refill(), this.tokens > 0) {
717
+ this.tokens--;
718
+ return;
719
+ }
720
+ return new Promise((e) => this.queue.push(e));
721
+ }
722
+ _refill() {
723
+ const e = Date.now(), t = (e - this.lastRefill) / 1e3;
724
+ for (this.tokens = Math.min(this.maxPerSecond, this.tokens + t * this.maxPerSecond), this.lastRefill = e; this.queue.length > 0 && this.tokens > 0; )
725
+ this.tokens--, this.queue.shift()();
726
+ }
727
+ }
728
+ class z {
729
+ constructor(e, t) {
730
+ this.config = e, this.retryOperation = t, this.logger = new p({
731
+ context: "NetworkManager",
732
+ level: (e == null ? void 0 : e.logLevel) || "info"
733
+ }), this.logger.debug("Initializing NetworkManager", {
734
+ provider: e.provider,
735
+ networkId: e.networkId
736
+ }), this.providers = [], this.currentProviderIndex = 0, this._initializeProviders(e.provider), this.provider = this.providers[0], this.interface = new b.Interface(e.abi);
737
+ const r = e.cacheSize || 500;
738
+ this.blockCache = new _(r), this.timestampCache = new _(r), this.logger.debug("LRU caches initialized", { cacheSize: r });
739
+ const s = e.rateLimit || 25;
740
+ this.rateLimiter = new $(s), this.logger.debug("Rate limiter initialized", { maxPerSecond: s }), this.events = {}, this.eventsByTopic = {}, this._initializeEvents(), this.logger.info("NetworkManager initialized successfully", {
741
+ eventCount: Object.keys(this.eventsByTopic).length,
742
+ contractAddress: e.address,
743
+ providerCount: this.providers.length
744
+ });
745
+ }
746
+ /**
747
+ * Initialize providers from config. Accepts a single provider (string or
748
+ * ethers provider object) or an array of providers.
749
+ */
750
+ _initializeProviders(e) {
751
+ const t = Array.isArray(e) ? e : [e];
752
+ for (const r of t)
753
+ if (typeof r == "string") {
754
+ const s = new b.JsonRpcProvider(r);
755
+ this.providers.push(s), this.logger.debug("Created JsonRpcProvider from URL", { url: r });
756
+ } else if (r && typeof r.getNetwork == "function")
757
+ this.providers.push(r), this.logger.debug("Using provided ethers provider object", {
758
+ providerType: r.constructor.name
759
+ });
760
+ else
761
+ throw new Error("Each provider must be either a string URL or an ethers provider object");
762
+ if (this.providers.length === 0)
763
+ throw new Error("At least one provider must be specified");
764
+ this.logger.debug("Providers initialized", { count: this.providers.length });
765
+ }
766
+ /**
767
+ * Switch to the next provider in the list on failure.
768
+ * Returns true if a new provider was activated, false if all have been tried.
769
+ */
770
+ _switchProvider(e) {
771
+ const t = this.currentProviderIndex;
772
+ 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", {
773
+ error: e.message
774
+ }), !1) : (this.provider = this.providers[this.currentProviderIndex], this.logger.warn("Switching provider due to failure", {
775
+ error: e.message,
776
+ previousIndex: t,
777
+ newIndex: this.currentProviderIndex,
778
+ totalProviders: this.providers.length
779
+ }), !0);
780
+ }
781
+ /**
782
+ * Execute a function through the rate limiter.
783
+ * Acquires a token before executing the call.
784
+ */
785
+ async _throttledCall(e) {
786
+ return await this.rateLimiter.acquire(), e();
787
+ }
788
+ /**
789
+ * Execute a provider call with failover support.
790
+ * Tries each provider in sequence before giving up.
791
+ */
792
+ async _callWithFailover(e, t) {
793
+ const r = this.currentProviderIndex;
794
+ let s, n = 0;
795
+ do
796
+ try {
797
+ return await this._throttledCall(() => e(this.provider));
798
+ } catch (i) {
799
+ if (s = i, n++, this.logger.warn("Provider call failed", {
800
+ description: t,
801
+ providerIndex: this.currentProviderIndex,
802
+ attempt: n,
803
+ error: i.message
804
+ }), this.providers.length > 1) {
805
+ if (this._switchProvider(i), this.currentProviderIndex === r)
806
+ break;
807
+ } else
808
+ break;
809
+ }
810
+ while (!0);
811
+ throw s;
812
+ }
813
+ // Initialize event mappings from ABI
814
+ _initializeEvents() {
815
+ let e = 0;
816
+ for (const t of this.config.abi)
817
+ if (t.type === "event") {
818
+ const r = t.name;
819
+ this.events[r] = new b.Interface([t]);
820
+ try {
821
+ const n = this.interface.getEvent(r).topicHash;
822
+ this.eventsByTopic[n] = r, e++, this.logger.debug("Event mapping created", {
823
+ eventName: r,
824
+ topicHash: n
825
+ });
826
+ } catch (s) {
827
+ this.logger.warn("Failed to get topic hash for event", {
828
+ eventName: r,
829
+ error: s.message
830
+ });
831
+ }
832
+ }
833
+ this.logger.debug("Event initialization completed", { eventCount: e });
834
+ }
835
+ // Get the latest block number from the network
836
+ async getLatestBlockNumber() {
837
+ return this.logger.time("getLatestBlockNumber", async () => {
838
+ const e = await this.retryOperation(
839
+ () => this._callWithFailover(
840
+ (t) => t.getBlockNumber(),
841
+ "getLatestBlockNumber"
842
+ ),
843
+ "Getting latest block number"
844
+ );
845
+ return this.logger.logNetworkActivity("getLatestBlockNumber", { blockNumber: e }), e;
846
+ });
847
+ }
848
+ // Get logs from the blockchain within a block range
849
+ async getLogs(e, t) {
850
+ return this.logger.time("getLogs", async () => {
851
+ this.logger.logNetworkActivity("getLogs_request", { fromBlock: e, toBlock: t, address: this.config.address });
852
+ const r = await this.retryOperation(
853
+ () => this._callWithFailover(
854
+ (s) => s.getLogs({
855
+ address: this.config.address,
856
+ fromBlock: e,
857
+ toBlock: t
858
+ }),
859
+ "getLogs"
860
+ ),
861
+ `Getting logs for blocks ${e}-${t}`
862
+ );
863
+ return this.logger.logNetworkActivity("getLogs_response", {
864
+ fromBlock: e,
865
+ toBlock: t,
866
+ logCount: r.length
867
+ }), r;
868
+ });
869
+ }
870
+ // Parse a raw log into structured event data
871
+ parseLog(e) {
872
+ const t = e.topics[0], r = this.eventsByTopic[t];
873
+ if (!r)
874
+ return this.logger.trace("Unknown event topic", { topicHash: t, availableTopics: Object.keys(this.eventsByTopic) }), null;
875
+ try {
876
+ const s = this.interface.parseLog(e), n = {
877
+ eventName: r,
878
+ parsedLog: s,
879
+ eventData: {
880
+ ...s.args,
881
+ blockNumber: e.blockNumber,
882
+ transactionHash: e.transactionHash,
883
+ logIndex: e.logIndex,
884
+ timestamp: Date.now()
885
+ }
886
+ };
887
+ return this.logger.debug("Successfully parsed log", {
888
+ eventName: r,
889
+ blockNumber: e.blockNumber,
890
+ transactionHash: e.transactionHash,
891
+ logIndex: e.logIndex
892
+ }), n;
893
+ } catch (s) {
894
+ return this.logger.warn("Failed to parse log for event", {
895
+ eventName: r,
896
+ blockNumber: e.blockNumber,
897
+ transactionHash: e.transactionHash,
898
+ error: s.message
899
+ }), null;
900
+ }
901
+ }
902
+ // Create unique event key for deduplication
903
+ createEventKey(e) {
904
+ return `${e.transactionHash}-${e.logIndex}`;
905
+ }
906
+ // Get network information
907
+ async getNetworkInfo() {
908
+ return this.retryOperation(async () => {
909
+ const e = await this._callWithFailover(
910
+ (r) => r.getNetwork(),
911
+ "getNetwork"
912
+ ), t = await this._callWithFailover(
913
+ (r) => r.getBlockNumber(),
914
+ "getBlockNumber"
915
+ );
916
+ return {
917
+ chainId: Number(e.chainId),
918
+ name: e.name,
919
+ currentBlock: t,
920
+ expectedNetworkId: this.config.networkId
921
+ };
922
+ }, "Getting network information");
923
+ }
924
+ // Validate network connection and configuration
925
+ async validateNetwork() {
926
+ const e = await this.getNetworkInfo();
927
+ if (e.chainId !== this.config.networkId)
928
+ throw new Error(
929
+ `Network mismatch: expected ${this.config.networkId}, got ${e.chainId}`
930
+ );
931
+ return e;
932
+ }
933
+ // Get contract code to verify contract exists
934
+ async validateContract() {
935
+ return this.retryOperation(async () => {
936
+ if (await this._callWithFailover(
937
+ (t) => t.getCode(this.config.address),
938
+ "getCode"
939
+ ) === "0x")
940
+ throw new Error(`No contract found at address ${this.config.address}`);
941
+ return !0;
942
+ }, "Validating contract");
943
+ }
944
+ // Get a block by number, with LRU caching
945
+ async getBlock(e) {
946
+ const t = this.blockCache.get(e);
947
+ if (t !== void 0)
948
+ return this.logger.debug("Block cache hit", { blockNumber: e }), t;
949
+ const r = await this.retryOperation(async () => this._callWithFailover(
950
+ (s) => s.getBlock(e),
951
+ `getBlock(${e})`
952
+ ), `Getting block ${e}`);
953
+ return r && this.blockCache.set(e, r), r;
954
+ }
955
+ // Get block timestamp, with LRU caching
956
+ async getBlockTimestamp(e) {
957
+ const t = this.timestampCache.get(e);
958
+ if (t !== void 0)
959
+ return this.logger.debug("Timestamp cache hit", { blockNumber: e }), t;
960
+ const r = await this.getBlock(e), s = r ? r.timestamp : null;
961
+ return s !== null && this.timestampCache.set(e, s), s;
962
+ }
963
+ // Get transaction receipt
964
+ async getTransactionReceipt(e) {
965
+ return this.retryOperation(
966
+ () => this._callWithFailover(
967
+ (t) => t.getTransactionReceipt(e),
968
+ "getTransactionReceipt"
969
+ ),
970
+ `Getting transaction receipt for ${e}`
971
+ );
972
+ }
973
+ // Get gas price information
974
+ async getGasPrice() {
975
+ return this.retryOperation(
976
+ () => this._callWithFailover(
977
+ (e) => e.getFeeData(),
978
+ "getFeeData"
979
+ ),
980
+ "Getting gas price information"
981
+ );
982
+ }
983
+ // Get provider instance for advanced operations
984
+ getProvider() {
985
+ return this.provider;
986
+ }
987
+ // Get ethers interface for manual parsing
988
+ getInterface() {
989
+ return this.interface;
990
+ }
991
+ // Get event mappings
992
+ getEventMappings() {
993
+ return {
994
+ events: { ...this.events },
995
+ eventsByTopic: { ...this.eventsByTopic }
996
+ };
997
+ }
998
+ // Clear all caches
999
+ clearCaches() {
1000
+ this.blockCache.clear(), this.timestampCache.clear(), this.logger.debug("All caches cleared");
1001
+ }
1002
+ // Get cache statistics
1003
+ getCacheStats() {
1004
+ return {
1005
+ blockCacheSize: this.blockCache.size,
1006
+ timestampCacheSize: this.timestampCache.size,
1007
+ maxCacheSize: this.blockCache.maxSize
1008
+ };
1009
+ }
1010
+ }
1011
+ class C {
1012
+ constructor(e) {
1013
+ this.logger = e.child({ context: "EventFilter" }), this.logger.info("EventFilter initialized");
1014
+ }
1015
+ /**
1016
+ * Build filter criteria from user input
1017
+ * @param {Object} options - Filter options
1018
+ * @param {number} options.fromBlock - Starting block number
1019
+ * @param {number} options.toBlock - Ending block number
1020
+ * @param {string} options.eventName - Event name to filter
1021
+ * @param {Object} options.parameters - Event parameter filters
1022
+ * @param {string} options.transactionHash - Filter by transaction hash
1023
+ * @param {string} options.address - Filter by contract address
1024
+ * @returns {Object} Filter criteria
1025
+ */
1026
+ buildFilter(e = {}) {
1027
+ const t = {};
1028
+ 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;
1029
+ }
1030
+ /**
1031
+ * Apply filters to an array of events
1032
+ * @param {Array} events - Events to filter
1033
+ * @param {Object} filter - Filter criteria
1034
+ * @returns {Array} Filtered events
1035
+ */
1036
+ applyFilter(e, t) {
1037
+ if (!Array.isArray(e))
1038
+ return this.logger.warn("Invalid events array provided to applyFilter"), [];
1039
+ let r = [...e];
1040
+ return t.$or && (r = r.filter(
1041
+ (s) => t.$or.some((n) => {
1042
+ const i = this.buildFilter(n);
1043
+ return this.applyFilter([s], i).length > 0;
1044
+ })
1045
+ )), t.$and && (r = r.filter(
1046
+ (s) => t.$and.every((n) => {
1047
+ const i = this.buildFilter(n);
1048
+ return this.applyFilter([s], i).length > 0;
1049
+ })
1050
+ )), t.$nor && (r = r.filter(
1051
+ (s) => t.$nor.every((n) => {
1052
+ const i = this.buildFilter(n);
1053
+ return this.applyFilter([s], i).length === 0;
1054
+ })
1055
+ )), 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(
1056
+ (s) => s.transactionHash.toLowerCase() === t.transactionHash.toLowerCase()
1057
+ )), t.address && (r = r.filter(
1058
+ (s) => s.address && s.address.toLowerCase() === t.address
1059
+ )), t.parameters && (r = r.filter(
1060
+ (s) => this._matchesParameters(s.args || {}, t.parameters)
1061
+ )), this.logger.debug("Applied filters", {
1062
+ originalCount: e.length,
1063
+ filteredCount: r.length,
1064
+ filter: t
1065
+ }), r;
1066
+ }
1067
+ /**
1068
+ * Check if event parameters match filter criteria (public API)
1069
+ */
1070
+ matchesParameters(e, t) {
1071
+ return this._matchesParameters(e, t);
1072
+ }
1073
+ /**
1074
+ * Check if event parameters match filter criteria
1075
+ * @private
1076
+ */
1077
+ _matchesParameters(e, t) {
1078
+ for (const [r, s] of Object.entries(t))
1079
+ if (typeof s == "object" && s !== null) {
1080
+ if (s.exists !== void 0) {
1081
+ const n = e.hasOwnProperty(r);
1082
+ if (s.exists && !n || !s.exists && n)
1083
+ return !1;
1084
+ if (Object.keys(s).filter((a) => a !== "exists").length === 0)
1085
+ continue;
1086
+ }
1087
+ 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])))
1088
+ return !1;
1089
+ if (s.size !== void 0) {
1090
+ const n = e[r];
1091
+ if (!Array.isArray(n) || n.length !== s.size)
1092
+ return !1;
1093
+ }
1094
+ } else if (!e.hasOwnProperty(r) || e[r] !== s)
1095
+ return !1;
1096
+ return !0;
1097
+ }
1098
+ /**
1099
+ * Sort events by specified criteria
1100
+ * @param {Array} events - Events to sort
1101
+ * @param {Object} options - Sort options
1102
+ * @param {string} options.by - Field to sort by (blockNumber, timestamp, etc.)
1103
+ * @param {string} options.order - Sort order ('asc' or 'desc')
1104
+ * @returns {Array} Sorted events
1105
+ */
1106
+ sortEvents(e, t = {}) {
1107
+ const { by: r = "blockNumber", order: s = "asc" } = t, n = [...e].sort((i, a) => {
1108
+ let l = i[r], o = a[r];
1109
+ if (r.includes(".")) {
1110
+ const h = r.split(".");
1111
+ l = h.reduce((g, d) => g == null ? void 0 : g[d], i), o = h.reduce((g, d) => g == null ? void 0 : g[d], a);
1112
+ }
1113
+ if (l === o)
1114
+ return 0;
1115
+ const c = l < o ? -1 : 1;
1116
+ return s === "asc" ? c : -c;
1117
+ });
1118
+ return this.logger.debug("Sorted events", { by: r, order: s, count: n.length }), n;
1119
+ }
1120
+ /**
1121
+ * Group events by specified field
1122
+ * @param {Array} events - Events to group
1123
+ * @param {string} field - Field to group by
1124
+ * @returns {Object} Grouped events
1125
+ */
1126
+ groupEvents(e, t) {
1127
+ const r = {};
1128
+ for (const s of e) {
1129
+ let n = s[t];
1130
+ 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);
1131
+ }
1132
+ return this.logger.debug("Grouped events", {
1133
+ field: t,
1134
+ groups: Object.keys(r).length,
1135
+ totalEvents: e.length
1136
+ }), r;
1137
+ }
1138
+ /**
1139
+ * Create a query builder for fluent API
1140
+ * @param {Array} events - Events to query
1141
+ * @returns {QueryBuilder} Query builder instance
1142
+ */
1143
+ query(e) {
1144
+ return new O(e, this);
1145
+ }
1146
+ }
1147
+ class O {
1148
+ constructor(e, t) {
1149
+ this.events = e, this.eventFilter = t, this.filters = {}, this.sortOptions = null, this._limit = null, this._skip = null;
1150
+ }
1151
+ /**
1152
+ * Filter by block range
1153
+ */
1154
+ blockRange(e, t) {
1155
+ return e !== void 0 && (this.filters.fromBlock = e), t !== void 0 && (this.filters.toBlock = t), this;
1156
+ }
1157
+ /**
1158
+ * Filter by event name
1159
+ */
1160
+ eventName(e) {
1161
+ return this.filters.eventName = e, this;
1162
+ }
1163
+ /**
1164
+ * Filter by transaction hash
1165
+ */
1166
+ transactionHash(e) {
1167
+ return this.filters.transactionHash = e, this;
1168
+ }
1169
+ /**
1170
+ * Filter by contract address
1171
+ */
1172
+ address(e) {
1173
+ return this.filters.address = e, this;
1174
+ }
1175
+ /**
1176
+ * Filter by event parameters
1177
+ */
1178
+ where(e, t) {
1179
+ return this.filters.parameters || (this.filters.parameters = {}), this.filters.parameters[e] = t, this;
1180
+ }
1181
+ /**
1182
+ * Add an $or condition
1183
+ */
1184
+ orWhere(e, t) {
1185
+ return this.filters.$or || (this.filters.$or = []), this.filters.$or.push({ parameters: { [e]: t } }), this;
1186
+ }
1187
+ /**
1188
+ * Shorthand for exists check on a field
1189
+ */
1190
+ whereExists(e) {
1191
+ return this.filters.parameters || (this.filters.parameters = {}), this.filters.parameters[e] = { exists: !0 }, this;
1192
+ }
1193
+ /**
1194
+ * Shorthand for regex match on a field
1195
+ */
1196
+ whereRegex(e, t) {
1197
+ return this.filters.parameters || (this.filters.parameters = {}), this.filters.parameters[e] = { regex: t }, this;
1198
+ }
1199
+ /**
1200
+ * Limit number of results
1201
+ */
1202
+ limit(e) {
1203
+ return this._limit = e, this;
1204
+ }
1205
+ /**
1206
+ * Skip first n results
1207
+ */
1208
+ skip(e) {
1209
+ return this._skip = e, this;
1210
+ }
1211
+ /**
1212
+ * Sort results
1213
+ */
1214
+ orderBy(e, t = "asc") {
1215
+ return this.sortOptions = { by: e, order: t }, this;
1216
+ }
1217
+ /**
1218
+ * Execute query and return results
1219
+ */
1220
+ execute() {
1221
+ let e = this.eventFilter.applyFilter(this.events, this.filters);
1222
+ 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;
1223
+ }
1224
+ /**
1225
+ * Execute query and return first result
1226
+ */
1227
+ first() {
1228
+ const e = this.execute();
1229
+ return e.length > 0 ? e[0] : null;
1230
+ }
1231
+ /**
1232
+ * Execute query and return count
1233
+ */
1234
+ count() {
1235
+ return this.execute().length;
1236
+ }
1237
+ /**
1238
+ * Execute query and group results
1239
+ */
1240
+ groupBy(e) {
1241
+ const t = this.execute();
1242
+ return this.eventFilter.groupEvents(t, e);
1243
+ }
1244
+ }
1245
+ class P {
1246
+ constructor(e) {
1247
+ this.logger = e.child({ context: "Paginator" }), this.logger.info("Paginator initialized");
1248
+ }
1249
+ /**
1250
+ * Create a paginated result set
1251
+ * @param {Array} items - Items to paginate
1252
+ * @param {Object} options - Pagination options
1253
+ * @param {number} options.page - Current page (1-based)
1254
+ * @param {number} options.pageSize - Items per page
1255
+ * @param {boolean} options.includeMeta - Include pagination metadata
1256
+ * @returns {Object} Paginated result
1257
+ */
1258
+ paginate(e, t = {}) {
1259
+ const {
1260
+ page: r = 1,
1261
+ pageSize: s = 100,
1262
+ includeMeta: n = !0
1263
+ } = t;
1264
+ if (!Array.isArray(e))
1265
+ return this.logger.warn("Invalid items array provided to paginate"), this._createEmptyResult(n);
1266
+ if (r < 1 || s < 1)
1267
+ return this.logger.warn("Invalid pagination parameters", { page: r, pageSize: s }), this._createEmptyResult(n);
1268
+ const i = e.length, a = Math.ceil(i / s), l = (r - 1) * s, o = Math.min(l + s, i), c = e.slice(l, o);
1269
+ this.logger.debug("Created paginated result", {
1270
+ page: r,
1271
+ pageSize: s,
1272
+ totalItems: i,
1273
+ totalPages: a,
1274
+ itemsInPage: c.length
1275
+ });
1276
+ const h = {
1277
+ data: c
1278
+ };
1279
+ return n && (h.meta = {
1280
+ page: r,
1281
+ pageSize: s,
1282
+ totalItems: i,
1283
+ totalPages: a,
1284
+ hasNextPage: r < a,
1285
+ hasPreviousPage: r > 1,
1286
+ startIndex: l + 1,
1287
+ // 1-based for display
1288
+ endIndex: o
1289
+ }), h;
1290
+ }
1291
+ /**
1292
+ * Create an async iterator for large datasets
1293
+ * @param {Array|Function} itemsOrGetter - Items array or async function to get items
1294
+ * @param {Object} options - Iterator options
1295
+ * @param {number} options.pageSize - Items per page
1296
+ * @returns {AsyncIterator} Async iterator
1297
+ */
1298
+ async *iterate(e, t = {}) {
1299
+ const { pageSize: r = 100 } = t;
1300
+ let s = 1, n = !0;
1301
+ for (; n; ) {
1302
+ let i;
1303
+ if (typeof e == "function")
1304
+ i = await e(s, r);
1305
+ else if (Array.isArray(e)) {
1306
+ const a = this.paginate(e, { page: s, pageSize: r, includeMeta: !0 });
1307
+ i = a.data, n = a.meta.hasNextPage;
1308
+ } else {
1309
+ this.logger.error("Invalid itemsOrGetter provided to iterate");
1310
+ return;
1311
+ }
1312
+ if (!i || i.length === 0) {
1313
+ n = !1;
1314
+ break;
1315
+ }
1316
+ for (const a of i)
1317
+ yield a;
1318
+ Array.isArray(e) || (n = i.length === r), s++;
1319
+ }
1320
+ this.logger.debug("Iterator completed", { totalPages: s - 1 });
1321
+ }
1322
+ /**
1323
+ * Create a cursor-based pagination result
1324
+ * @param {Array} items - Items to paginate
1325
+ * @param {Object} options - Cursor pagination options
1326
+ * @param {string} options.cursor - Current cursor position
1327
+ * @param {number} options.limit - Number of items to return
1328
+ * @param {string} options.cursorField - Field to use for cursor (default: 'id')
1329
+ * @param {string} options.direction - Pagination direction ('forward' or 'backward')
1330
+ * @returns {Object} Cursor-paginated result
1331
+ */
1332
+ paginateCursor(e, t = {}) {
1333
+ const {
1334
+ cursor: r = null,
1335
+ limit: s = 100,
1336
+ cursorField: n = "id",
1337
+ direction: i = "forward"
1338
+ } = t;
1339
+ if (!Array.isArray(e))
1340
+ return this.logger.warn("Invalid items array provided to paginateCursor"), this._createEmptyCursorResult();
1341
+ let a = [...e];
1342
+ r !== null && (a = a.filter((d) => {
1343
+ const m = d[n];
1344
+ return i === "forward" ? m > r : m < r;
1345
+ })), a.sort((d, m) => {
1346
+ const y = d[n], w = m[n];
1347
+ return i === "forward" ? y < w ? -1 : 1 : y > w ? -1 : 1;
1348
+ });
1349
+ const l = a.slice(0, s), o = a.length > s, c = l[0], h = l[l.length - 1], g = {
1350
+ data: l,
1351
+ cursors: {
1352
+ before: c ? c[n] : null,
1353
+ after: h ? h[n] : null,
1354
+ hasNext: o,
1355
+ hasPrevious: r !== null
1356
+ }
1357
+ };
1358
+ return this.logger.debug("Created cursor-paginated result", {
1359
+ cursor: r,
1360
+ limit: s,
1361
+ cursorField: n,
1362
+ direction: i,
1363
+ itemsReturned: l.length,
1364
+ hasMore: o
1365
+ }), g;
1366
+ }
1367
+ /**
1368
+ * Create a page info object for GraphQL-style pagination
1369
+ * @param {Object} paginationMeta - Pagination metadata
1370
+ * @returns {Object} Page info
1371
+ */
1372
+ createPageInfo(e) {
1373
+ return {
1374
+ hasNextPage: e.hasNextPage || !1,
1375
+ hasPreviousPage: e.hasPreviousPage || !1,
1376
+ startCursor: e.startCursor || null,
1377
+ endCursor: e.endCursor || null,
1378
+ totalCount: e.totalItems || 0
1379
+ };
1380
+ }
1381
+ /**
1382
+ * Calculate optimal page size based on data characteristics
1383
+ * @param {Object} options - Options for calculation
1384
+ * @param {number} options.totalItems - Total number of items
1385
+ * @param {number} options.avgItemSize - Average item size in bytes
1386
+ * @param {number} options.maxMemory - Maximum memory to use (bytes)
1387
+ * @param {number} options.minPageSize - Minimum page size
1388
+ * @param {number} options.maxPageSize - Maximum page size
1389
+ * @returns {number} Optimal page size
1390
+ */
1391
+ calculateOptimalPageSize(e = {}) {
1392
+ const {
1393
+ totalItems: t = 1e3,
1394
+ avgItemSize: r = 1024,
1395
+ // 1KB default
1396
+ maxMemory: s = 10 * 1024 * 1024,
1397
+ // 10MB default
1398
+ minPageSize: n = 10,
1399
+ maxPageSize: i = 1e3
1400
+ } = e;
1401
+ let a = Math.floor(s / r);
1402
+ return a = Math.max(n, Math.min(i, a)), t < a && (a = t), this.logger.debug("Calculated optimal page size", {
1403
+ totalItems: t,
1404
+ avgItemSize: r,
1405
+ maxMemory: s,
1406
+ optimalSize: a
1407
+ }), a;
1408
+ }
1409
+ /**
1410
+ * Create empty result for error cases
1411
+ * @private
1412
+ */
1413
+ _createEmptyResult(e) {
1414
+ const t = { data: [] };
1415
+ return e && (t.meta = {
1416
+ page: 1,
1417
+ pageSize: 0,
1418
+ totalItems: 0,
1419
+ totalPages: 0,
1420
+ hasNextPage: !1,
1421
+ hasPreviousPage: !1,
1422
+ startIndex: 0,
1423
+ endIndex: 0
1424
+ }), t;
1425
+ }
1426
+ /**
1427
+ * Create empty cursor result for error cases
1428
+ * @private
1429
+ */
1430
+ _createEmptyCursorResult() {
1431
+ return {
1432
+ data: [],
1433
+ cursors: {
1434
+ before: null,
1435
+ after: null,
1436
+ hasNext: !1,
1437
+ hasPrevious: !1
1438
+ }
1439
+ };
1440
+ }
1441
+ }
1442
+ class J {
1443
+ /**
1444
+ * Calculate pagination offset
1445
+ */
1446
+ static calculateOffset(e, t) {
1447
+ return (e - 1) * t;
1448
+ }
1449
+ /**
1450
+ * Calculate total pages
1451
+ */
1452
+ static calculateTotalPages(e, t) {
1453
+ return Math.ceil(e / t);
1454
+ }
1455
+ /**
1456
+ * Validate page number
1457
+ */
1458
+ static isValidPage(e, t) {
1459
+ return e >= 1 && e <= t;
1460
+ }
1461
+ /**
1462
+ * Get page numbers for pagination UI
1463
+ */
1464
+ static getPageNumbers(e, t, r = 5) {
1465
+ const s = [], n = Math.floor(r / 2);
1466
+ let i = Math.max(1, e - n), a = Math.min(t, e + n);
1467
+ e <= n ? a = Math.min(t, r) : e >= t - n && (i = Math.max(1, t - r + 1));
1468
+ for (let l = i; l <= a; l++)
1469
+ s.push(l);
1470
+ return s;
1471
+ }
1472
+ }
1473
+ const k = typeof process < "u" && process.versions != null && process.versions.node != null;
1474
+ function F(u) {
1475
+ return k ? Buffer.from(u).toString("base64") : btoa(String.fromCharCode.apply(null, u));
1476
+ }
1477
+ function L(u) {
1478
+ if (k) {
1479
+ const r = Buffer.from(u, "base64");
1480
+ return new Uint8Array(r.buffer, r.byteOffset, r.byteLength);
1481
+ }
1482
+ const e = atob(u), t = new Uint8Array(e.length);
1483
+ for (let r = 0; r < e.length; r++)
1484
+ t[r] = e.charCodeAt(r);
1485
+ return t;
1486
+ }
1487
+ class D {
1488
+ constructor(e) {
1489
+ this.logger = e.child({ context: "DataCompressor" }), this.logger.info("DataCompressor initialized"), this.strategies = {
1490
+ none: {
1491
+ compress: (t) => t,
1492
+ decompress: (t) => t,
1493
+ ratio: 1
1494
+ },
1495
+ json: {
1496
+ compress: (t) => this._compressJSON(t),
1497
+ decompress: (t) => this._decompressJSON(t),
1498
+ ratio: 0.7
1499
+ // Approximate
1500
+ },
1501
+ gzip: {
1502
+ compress: (t) => this._compressGzip(t),
1503
+ decompress: (t) => this._decompressGzip(t),
1504
+ ratio: 0.3
1505
+ // Approximate
1506
+ },
1507
+ optimized: {
1508
+ compress: (t) => this._compressOptimized(t),
1509
+ decompress: (t) => this._decompressOptimized(t),
1510
+ ratio: 0.4
1511
+ // Approximate
1512
+ }
1513
+ }, this.defaultStrategy = "optimized";
1514
+ }
1515
+ /**
1516
+ * Compress data using specified strategy
1517
+ * @param {any} data - Data to compress
1518
+ * @param {string} strategy - Compression strategy
1519
+ * @returns {Object} Compressed data with metadata
1520
+ */
1521
+ compress(e, t = this.defaultStrategy) {
1522
+ try {
1523
+ const r = Date.now(), s = this._calculateSize(e);
1524
+ this.strategies[t] || (this.logger.warn("Unknown compression strategy, using default", { strategy: t }), t = this.defaultStrategy);
1525
+ const n = this.strategies[t].compress(e), i = this._calculateSize(n), a = i / s, l = Date.now() - r, o = {
1526
+ data: n,
1527
+ metadata: {
1528
+ strategy: t,
1529
+ originalSize: s,
1530
+ compressedSize: i,
1531
+ compressionRatio: a.toFixed(3),
1532
+ spaceSaved: `${((1 - a) * 100).toFixed(1)}%`,
1533
+ compressionTime: l,
1534
+ timestamp: new Date().toISOString()
1535
+ }
1536
+ };
1537
+ return this.logger.debug("Data compressed", o.metadata), o;
1538
+ } catch (r) {
1539
+ throw this.logger.error("Compression failed", { strategy: t, error: r.message }), r;
1540
+ }
1541
+ }
1542
+ /**
1543
+ * Decompress data
1544
+ * @param {Object} compressedData - Compressed data with metadata
1545
+ * @returns {any} Original data
1546
+ */
1547
+ decompress(e) {
1548
+ try {
1549
+ if (!e.metadata || !e.metadata.strategy)
1550
+ return this.logger.warn("No compression metadata found, assuming no compression"), e;
1551
+ const { strategy: t } = e.metadata, r = Date.now();
1552
+ if (!this.strategies[t])
1553
+ throw new Error(`Unknown compression strategy: ${t}`);
1554
+ const s = this.strategies[t].decompress(e.data), n = Date.now() - r;
1555
+ return this.logger.debug("Data decompressed", {
1556
+ strategy: t,
1557
+ decompressionTime: n,
1558
+ originalSize: e.metadata.originalSize
1559
+ }), s;
1560
+ } catch (t) {
1561
+ throw this.logger.error("Decompression failed", { error: t.message }), t;
1562
+ }
1563
+ }
1564
+ /**
1565
+ * Compress events for storage
1566
+ * @param {Array} events - Events to compress
1567
+ * @param {Object} options - Compression options
1568
+ * @returns {Object} Compressed events
1569
+ */
1570
+ compressEvents(e, t = {}) {
1571
+ const { strategy: r = this.defaultStrategy, chunkSize: s = 100 } = t;
1572
+ return this.logger.time("compressEvents", () => {
1573
+ const n = [];
1574
+ for (let c = 0; c < e.length; c += s)
1575
+ n.push(e.slice(c, c + s));
1576
+ const i = n.map((c, h) => {
1577
+ const g = this.compress(c, r);
1578
+ return {
1579
+ ...g,
1580
+ metadata: {
1581
+ ...g.metadata,
1582
+ chunkIndex: h,
1583
+ eventCount: c.length
1584
+ }
1585
+ };
1586
+ }), a = i.reduce((c, h) => c + h.metadata.originalSize, 0), l = i.reduce((c, h) => c + h.metadata.compressedSize, 0), o = {
1587
+ chunks: i,
1588
+ metadata: {
1589
+ totalEvents: e.length,
1590
+ chunkCount: n.length,
1591
+ strategy: r,
1592
+ totalOriginalSize: a,
1593
+ totalCompressedSize: l,
1594
+ overallCompressionRatio: (l / a).toFixed(3),
1595
+ spaceSaved: `${((1 - l / a) * 100).toFixed(1)}%`
1596
+ }
1597
+ };
1598
+ return this.logger.info("Events compressed", o.metadata), o;
1599
+ });
1600
+ }
1601
+ /**
1602
+ * Decompress events
1603
+ * @param {Object} compressedEvents - Compressed events object
1604
+ * @returns {Array} Original events
1605
+ */
1606
+ decompressEvents(e) {
1607
+ return this.logger.time("decompressEvents", () => {
1608
+ if (!e.chunks || !Array.isArray(e.chunks))
1609
+ throw new Error("Invalid compressed events format");
1610
+ const t = [];
1611
+ return e.chunks.forEach((r) => {
1612
+ const s = this.decompress(r);
1613
+ t.push(...s);
1614
+ }), this.logger.info("Events decompressed", {
1615
+ totalEvents: t.length,
1616
+ chunks: e.chunks.length
1617
+ }), t;
1618
+ });
1619
+ }
1620
+ /**
1621
+ * JSON compression - removes whitespace and uses short keys
1622
+ * @private
1623
+ */
1624
+ _compressJSON(e) {
1625
+ const t = {
1626
+ eventName: "e",
1627
+ blockNumber: "b",
1628
+ transactionHash: "t",
1629
+ address: "a",
1630
+ args: "r",
1631
+ topics: "p",
1632
+ data: "d",
1633
+ logIndex: "l",
1634
+ transactionIndex: "i",
1635
+ blockHash: "h",
1636
+ removed: "m"
1637
+ };
1638
+ return {
1639
+ d: this._replaceKeys(e, t),
1640
+ k: t
1641
+ };
1642
+ }
1643
+ /**
1644
+ * JSON decompression
1645
+ * @private
1646
+ */
1647
+ _decompressJSON(e) {
1648
+ if (!e.d || !e.k)
1649
+ return e;
1650
+ const t = {};
1651
+ return Object.entries(e.k).forEach(([r, s]) => {
1652
+ t[s] = r;
1653
+ }), this._replaceKeys(e.d, t);
1654
+ }
1655
+ /**
1656
+ * Gzip compression
1657
+ * @private
1658
+ */
1659
+ _compressGzip(e) {
1660
+ const t = JSON.stringify(e), r = x(t);
1661
+ return F(r);
1662
+ }
1663
+ /**
1664
+ * Gzip decompression
1665
+ * @private
1666
+ */
1667
+ _decompressGzip(e) {
1668
+ const t = L(e), r = I(t), s = new TextDecoder().decode(r);
1669
+ return JSON.parse(s);
1670
+ }
1671
+ /**
1672
+ * Optimized compression - combines JSON and gzip
1673
+ * @private
1674
+ */
1675
+ _compressOptimized(e) {
1676
+ const t = this._compressJSON(e);
1677
+ return this._compressGzip(t);
1678
+ }
1679
+ /**
1680
+ * Optimized decompression
1681
+ * @private
1682
+ */
1683
+ _decompressOptimized(e) {
1684
+ const t = this._decompressGzip(e);
1685
+ return this._decompressJSON(t);
1686
+ }
1687
+ /**
1688
+ * Replace keys in object recursively
1689
+ * @private
1690
+ */
1691
+ _replaceKeys(e, t) {
1692
+ if (Array.isArray(e))
1693
+ return e.map((r) => this._replaceKeys(r, t));
1694
+ if (e !== null && typeof e == "object") {
1695
+ const r = {};
1696
+ return Object.entries(e).forEach(([s, n]) => {
1697
+ const i = t[s] || s;
1698
+ r[i] = this._replaceKeys(n, t);
1699
+ }), r;
1700
+ }
1701
+ return e;
1702
+ }
1703
+ /**
1704
+ * Calculate size of data in bytes
1705
+ * @private
1706
+ */
1707
+ _calculateSize(e) {
1708
+ const t = JSON.stringify(e);
1709
+ return k ? Buffer.byteLength(t, "utf8") : new Blob([t]).size;
1710
+ }
1711
+ /**
1712
+ * Analyze compression efficiency for different strategies
1713
+ * @param {any} data - Data to analyze
1714
+ * @returns {Object} Analysis results
1715
+ */
1716
+ analyzeCompressionStrategies(e) {
1717
+ const t = {};
1718
+ Object.keys(this.strategies).forEach((n) => {
1719
+ try {
1720
+ const i = this.compress(e, n);
1721
+ t[n] = {
1722
+ originalSize: i.metadata.originalSize,
1723
+ compressedSize: i.metadata.compressedSize,
1724
+ compressionRatio: i.metadata.compressionRatio,
1725
+ spaceSaved: i.metadata.spaceSaved,
1726
+ compressionTime: i.metadata.compressionTime
1727
+ };
1728
+ } catch (i) {
1729
+ t[n] = {
1730
+ error: i.message
1731
+ };
1732
+ }
1733
+ });
1734
+ let r = "none", s = 1;
1735
+ return Object.entries(t).forEach(([n, i]) => {
1736
+ !i.error && parseFloat(i.compressionRatio) < s && (s = parseFloat(i.compressionRatio), r = n);
1737
+ }), {
1738
+ strategies: t,
1739
+ recommendation: r,
1740
+ bestCompressionRatio: s
1741
+ };
1742
+ }
1743
+ }
1744
+ class E {
1745
+ constructor(e, t, r = null) {
1746
+ var s, n;
1747
+ this.gun = N(e), this.retryOperation = t, this.networkManager = r, this.logger = new p({
1748
+ context: "EventStore",
1749
+ level: (e == null ? void 0 : e.logLevel) || "info"
1750
+ }), this.eventFilter = new C(this.logger), this.paginator = new P(this.logger), this.dataCompressor = new D(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", {
1751
+ gunConfig: this._sanitizeGunConfig(e),
1752
+ compressionEnabled: this.compressionEnabled,
1753
+ compressionStrategy: this.compressionStrategy
1754
+ });
1755
+ }
1756
+ // Sanitize Gun config for logging
1757
+ _sanitizeGunConfig(e) {
1758
+ if (!e || typeof e != "object")
1759
+ return e;
1760
+ const t = { ...e };
1761
+ return delete t.peers, delete t.localStorage, t;
1762
+ }
1763
+ // Get the start block number for syncing events from the blockchain
1764
+ async getStartBlockNumber() {
1765
+ return this.retryOperation(async () => new Promise((e) => {
1766
+ this.gun.get("config").get("startBlockNumber").once((t) => {
1767
+ e(t || 1);
1768
+ });
1769
+ }), "Getting start block number");
1770
+ }
1771
+ // Set the start block number for syncing events from the blockchain
1772
+ async setStartBlockNumber(e) {
1773
+ return this.retryOperation(async () => new Promise((t, r) => {
1774
+ this.gun.get("config").get("startBlockNumber").put(e, (s) => {
1775
+ s.err ? r(new Error(s.err)) : t(s);
1776
+ });
1777
+ }), `Setting start block number to ${e}`);
1778
+ }
1779
+ // Store an event in the decentralized database
1780
+ async storeEvent(e, t, r) {
1781
+ return this.logger.time("storeEvent", async () => {
1782
+ this.logger.logDatabaseActivity("storeEvent", {
1783
+ eventName: e,
1784
+ eventKey: t,
1785
+ blockNumber: r.blockNumber,
1786
+ transactionHash: r.transactionHash
1787
+ });
1788
+ let s = r;
1789
+ if (this.compressionEnabled) {
1790
+ const n = this.dataCompressor.compress(r, this.compressionStrategy);
1791
+ s = {
1792
+ _compressed: !0,
1793
+ _data: n.data,
1794
+ _metadata: n.metadata
1795
+ };
1796
+ }
1797
+ return this.retryOperation(
1798
+ () => new Promise((n) => {
1799
+ this.gun.get("events").get(e).get(t).put(s, n);
1800
+ }),
1801
+ `Storing event ${e}`
1802
+ );
1803
+ }, { eventName: e, eventKey: t });
1804
+ }
1805
+ // Get events by name with optional filtering
1806
+ async getEvents(e, t = {}) {
1807
+ return this.logger.time("getEvents", async () => (this.logger.logDatabaseActivity("getEvents", {
1808
+ eventName: e,
1809
+ filter: Object.keys(t)
1810
+ }), this.retryOperation(async () => new Promise((r) => {
1811
+ let s = !1;
1812
+ const n = this.gun.get("events").get(e), i = setTimeout(() => {
1813
+ s || (s = !0, this.logger.debug("getEvents timed out, returning empty", { eventName: e }), r([]));
1814
+ }, 3e3);
1815
+ n.open((a) => {
1816
+ if (s)
1817
+ return;
1818
+ s = !0, clearTimeout(i);
1819
+ const l = [];
1820
+ a && typeof a == "object" && Object.entries(a).forEach(([o, c]) => {
1821
+ o === "_" || !c || typeof c != "object" || this._matchesFilter(c, t) && l.push({ key: o, ...c });
1822
+ }), this.logger.debug("Events retrieved", {
1823
+ eventName: e,
1824
+ eventCount: l.length,
1825
+ filterApplied: Object.keys(t).length > 0
1826
+ }), r(l);
1827
+ });
1828
+ }), `Getting events for ${e}`)), { eventName: e });
1829
+ }
1830
+ // Get all events with optional filtering and pagination
1831
+ async getAllEvents(e = {}) {
1832
+ return this.logger.time("getAllEvents", async () => {
1833
+ const { filter: t = {}, pagination: r = {}, sort: s = {} } = e, n = await this._fetchAllEventsMap(), i = [];
1834
+ Object.entries(n).forEach(([l, o]) => {
1835
+ o.forEach((c) => {
1836
+ i.push({
1837
+ ...c,
1838
+ eventName: l
1839
+ });
1840
+ });
1841
+ });
1842
+ let a = i;
1843
+ if (Object.keys(t).length > 0) {
1844
+ const l = this.eventFilter.buildFilter(t);
1845
+ a = this.eventFilter.applyFilter(i, l);
1846
+ }
1847
+ if (s.by && (a = this.eventFilter.sortEvents(a, s)), r.page || r.pageSize) {
1848
+ const l = this.paginator.paginate(a, r);
1849
+ return this.logger.debug("Query completed", {
1850
+ totalEvents: i.length,
1851
+ filteredEvents: a.length,
1852
+ returnedEvents: l.data.length
1853
+ }), l;
1854
+ }
1855
+ return {
1856
+ data: a,
1857
+ meta: {
1858
+ totalItems: a.length
1859
+ }
1860
+ };
1861
+ });
1862
+ }
1863
+ // Internal method to fetch all events as a map
1864
+ async _fetchAllEventsMap() {
1865
+ return this.retryOperation(async () => new Promise((e) => {
1866
+ let t = !1;
1867
+ const r = this.gun.get("events"), s = setTimeout(() => {
1868
+ t || (t = !0, this.logger.debug("_fetchAllEventsMap timed out, returning empty"), e({}));
1869
+ }, 5e3);
1870
+ r.open((n) => {
1871
+ if (t)
1872
+ return;
1873
+ t = !0, clearTimeout(s);
1874
+ const i = {};
1875
+ n && typeof n == "object" && Object.entries(n).forEach(([a, l]) => {
1876
+ a === "_" || !l || typeof l != "object" || (i[a] = [], Object.entries(l).forEach(([o, c]) => {
1877
+ if (o === "_" || !c || typeof c != "object")
1878
+ return;
1879
+ let h = c;
1880
+ if (c._compressed && c._data)
1881
+ try {
1882
+ h = this.dataCompressor.decompress({
1883
+ data: c._data,
1884
+ metadata: c._metadata
1885
+ });
1886
+ } catch (g) {
1887
+ this.logger.error("Failed to decompress event", {
1888
+ eventName: a,
1889
+ key: o,
1890
+ error: g.message
1891
+ });
1892
+ }
1893
+ i[a].push({ key: o, ...h });
1894
+ }));
1895
+ }), e(i);
1896
+ });
1897
+ }), "Getting all events");
1898
+ }
1899
+ // Publish magazine metadata to the decentralized network
1900
+ async publishMagazine(e, t, r) {
1901
+ return this.logger.time("publishMagazine", async () => (this.logger.info("Publishing magazine", {
1902
+ alias: e,
1903
+ url: r,
1904
+ magazineData: {
1905
+ name: t.name,
1906
+ address: t.address,
1907
+ networkId: t.networkId
1908
+ }
1909
+ }), this.retryOperation(async () => {
1910
+ const s = this.gun.back(-1).get(e), n = await new Promise((i, a) => {
1911
+ s.put(t, (l) => {
1912
+ l.err ? (this.logger.error("Failed to publish magazine metadata", {
1913
+ alias: e,
1914
+ error: l.err
1915
+ }), a(new Error(l.err))) : (this.logger.debug("Magazine metadata published", { alias: e }), i(l));
1916
+ });
1917
+ });
1918
+ return await new Promise((i, a) => {
1919
+ s.get("url").put(r, (l) => {
1920
+ l.err ? (this.logger.error("Failed to publish magazine URL", {
1921
+ alias: e,
1922
+ url: r,
1923
+ error: l.err
1924
+ }), a(new Error(l.err))) : (this.logger.debug("Magazine URL published", { alias: e, url: r }), i(l));
1925
+ });
1926
+ }), this.logger.info("Magazine published successfully", { alias: e, url: r }), n;
1927
+ }, "Publishing magazine")), { alias: e });
1928
+ }
1929
+ // Subscribe to a magazine on the decentralized network
1930
+ async subscribeMagazine(e) {
1931
+ return this.retryOperation(async () => new Promise((t, r) => {
1932
+ this.gun.get(e).once((s, n) => {
1933
+ s ? t(s) : r(new Error(`Magazine with ID ${e} not found`));
1934
+ });
1935
+ }), `Subscribing to magazine ${e}`);
1936
+ }
1937
+ // Helper method to check if event data matches filter criteria
1938
+ _matchesFilter(e, t) {
1939
+ if (!t || Object.keys(t).length === 0)
1940
+ return !0;
1941
+ for (const [r, s] of Object.entries(t))
1942
+ if (e[r] !== s)
1943
+ return !1;
1944
+ return !0;
1945
+ }
1946
+ // Query events using fluent API
1947
+ async query() {
1948
+ const e = await this._fetchAllEventsMap(), t = [];
1949
+ return Object.entries(e).forEach(([r, s]) => {
1950
+ s.forEach((n) => {
1951
+ t.push({
1952
+ ...n,
1953
+ eventName: r
1954
+ });
1955
+ });
1956
+ }), this.eventFilter.query(t);
1957
+ }
1958
+ // Get events by transaction hash
1959
+ async getEventsByTransactionHash(e) {
1960
+ return this.logger.time("getEventsByTransactionHash", async () => {
1961
+ const t = await this.getAllEvents({
1962
+ filter: { transactionHash: e }
1963
+ });
1964
+ return this.logger.debug("Found events by transaction hash", {
1965
+ transactionHash: e,
1966
+ count: t.data.length
1967
+ }), t.data;
1968
+ });
1969
+ }
1970
+ // Get events by block number
1971
+ async getEventsByBlockNumber(e) {
1972
+ return this.logger.time("getEventsByBlockNumber", async () => {
1973
+ const t = await this.getAllEvents({
1974
+ filter: {
1975
+ fromBlock: e,
1976
+ toBlock: e
1977
+ }
1978
+ });
1979
+ return this.logger.debug("Found events by block number", {
1980
+ blockNumber: e,
1981
+ count: t.data.length
1982
+ }), t.data;
1983
+ });
1984
+ }
1985
+ // Create async iterator for events
1986
+ async *iterateEvents(e = {}) {
1987
+ const { filter: t = {}, sort: r = {}, pageSize: s = 100 } = e, i = (await this.getAllEvents({ filter: t, sort: r })).data;
1988
+ yield* this.paginator.iterate(i, { pageSize: s });
1989
+ }
1990
+ // Get compression statistics
1991
+ async getCompressionStats() {
1992
+ const e = await this._fetchAllEventsMap();
1993
+ let t = 0, r = 0, s = 0;
1994
+ return Object.values(e).forEach((n) => {
1995
+ n.forEach((i) => {
1996
+ i._compressed && i._metadata && (t += i._metadata.originalSize || 0, r += i._metadata.compressedSize || 0, s++);
1997
+ });
1998
+ }), {
1999
+ compressedEvents: s,
2000
+ totalOriginalSize: t,
2001
+ totalCompressedSize: r,
2002
+ compressionRatio: t > 0 ? (r / t).toFixed(3) : "1.000",
2003
+ spaceSaved: t > 0 ? `${((1 - r / t) * 100).toFixed(1)}%` : "0%"
2004
+ };
2005
+ }
2006
+ // Clean up all active listeners
2007
+ destroy() {
2008
+ this._activeListeners = [], this.logger.info("EventStore destroyed, listeners cleaned up");
2009
+ }
2010
+ // Get Gun instance for advanced operations
2011
+ getGunInstance() {
2012
+ return this.gun;
2013
+ }
2014
+ }
2015
+ class T {
2016
+ constructor(e, t, r, s) {
2017
+ this.networkManager = e, this.eventStore = t, this.configManager = r, this.retryOperation = s, this.logger = new p({
2018
+ context: "EventSyncer",
2019
+ level: r.get("logLevel") || "info"
2020
+ }), this.batchSize = 1e3, this.lastSyncTime = 0, this.logger.info("EventSyncer initialized", {
2021
+ batchSize: this.batchSize
2022
+ });
2023
+ }
2024
+ // Sync events from the blockchain to the magazine
2025
+ async syncEvents() {
2026
+ if (this._syncing)
2027
+ return this.logger.warn("Sync already in progress, skipping"), 0;
2028
+ this._setSyncing(!0);
2029
+ try {
2030
+ return await this.logger.time("syncEvents", async () => this.retryOperation(async () => {
2031
+ const e = await this.eventStore.getStartBlockNumber(), t = await this.networkManager.getLatestBlockNumber();
2032
+ if (e > t) {
2033
+ this.logger.info("Already up to date", {
2034
+ startBlockNumber: e,
2035
+ latestBlockNumber: t
2036
+ });
2037
+ return;
2038
+ }
2039
+ this.logger.info("Starting event synchronization", {
2040
+ startBlockNumber: e,
2041
+ latestBlockNumber: t,
2042
+ totalBlocks: t - e + 1
2043
+ });
2044
+ let r = e, s = 0;
2045
+ for (; r <= t; ) {
2046
+ const n = Math.min(r + this.batchSize - 1, t), i = await this._processBatch(r, n);
2047
+ s += i, r = n + 1;
2048
+ }
2049
+ return await this.eventStore.setStartBlockNumber(t + 1), this.lastSyncTime = Date.now(), this.logger.info("Event synchronization completed", {
2050
+ totalEventsProcessed: s,
2051
+ newStartBlockNumber: t + 1
2052
+ }), s;
2053
+ }, "Event synchronization"));
2054
+ } finally {
2055
+ this._setSyncing(!1);
2056
+ }
2057
+ }
2058
+ // Process a batch of blocks for events
2059
+ async _processBatch(e, t) {
2060
+ return this.logger.time("processBatch", async () => {
2061
+ this.logger.debug("Processing batch", { fromBlock: e, toBlock: t });
2062
+ const r = await this.networkManager.getLogs(e, t);
2063
+ let s = 0;
2064
+ for (const n of r) {
2065
+ const i = this.networkManager.parseLog(n);
2066
+ if (i)
2067
+ try {
2068
+ const a = this.networkManager.createEventKey(n);
2069
+ await this.eventStore.storeEvent(
2070
+ i.eventName,
2071
+ a,
2072
+ i.eventData
2073
+ ), s++, this.logger.trace("Event stored", {
2074
+ eventName: i.eventName,
2075
+ eventKey: a,
2076
+ blockNumber: n.blockNumber
2077
+ });
2078
+ } catch (a) {
2079
+ this.logger.warn("Failed to store event", {
2080
+ eventName: i.eventName,
2081
+ blockNumber: n.blockNumber,
2082
+ transactionHash: n.transactionHash,
2083
+ error: a.message
2084
+ });
2085
+ }
2086
+ }
2087
+ return this.logger.debug("Batch processing completed", {
2088
+ fromBlock: e,
2089
+ toBlock: t,
2090
+ logsFound: r.length,
2091
+ eventsStored: s
2092
+ }), s;
2093
+ }, { fromBlock: e, toBlock: t });
2094
+ }
2095
+ // Sync events from a specific block range
2096
+ async syncEventsFromRange(e, t) {
2097
+ if (this.configManager.validateBlockNumber(e, "fromBlock"), this.configManager.validateBlockNumber(t, "toBlock"), e > t)
2098
+ throw new Error("fromBlock cannot be greater than toBlock");
2099
+ if (this._syncing)
2100
+ return this.logger.warn("Sync already in progress, skipping range sync"), 0;
2101
+ this._setSyncing(!0);
2102
+ try {
2103
+ return await this.logger.time("syncEventsFromRange", async () => this.retryOperation(async () => {
2104
+ this.logger.info("Syncing events from specific range", {
2105
+ fromBlock: e,
2106
+ toBlock: t,
2107
+ totalBlocks: t - e + 1
2108
+ });
2109
+ let r = e, s = 0;
2110
+ for (; r <= t; ) {
2111
+ const n = Math.min(r + this.batchSize - 1, t), i = await this._processBatch(r, n);
2112
+ s += i, r = n + 1;
2113
+ }
2114
+ return this.lastSyncTime = Date.now(), this.logger.info("Range synchronization completed", {
2115
+ fromBlock: e,
2116
+ toBlock: t,
2117
+ totalEventsProcessed: s
2118
+ }), s;
2119
+ }, `Event synchronization for range ${e}-${t}`), { fromBlock: e, toBlock: t });
2120
+ } finally {
2121
+ this._setSyncing(!1);
2122
+ }
2123
+ }
2124
+ // Sync events from a specific transaction
2125
+ async syncEventsFromTransaction(e) {
2126
+ if (!e || typeof e != "string")
2127
+ throw new Error("Transaction hash must be a non-empty string");
2128
+ return this.retryOperation(async () => {
2129
+ const t = await this.networkManager.getTransactionReceipt(e);
2130
+ if (!t)
2131
+ throw new Error(`Transaction ${e} not found`);
2132
+ const r = this.configManager.get("address").toLowerCase(), s = t.logs.filter(
2133
+ (n) => n.address.toLowerCase() === r
2134
+ );
2135
+ for (const n of s) {
2136
+ const i = this.networkManager.parseLog(n);
2137
+ if (i) {
2138
+ const a = this.networkManager.createEventKey(n);
2139
+ await this.eventStore.storeEvent(
2140
+ i.eventName,
2141
+ a,
2142
+ i.eventData
2143
+ );
2144
+ }
2145
+ }
2146
+ return this.lastSyncTime = Date.now(), s.length;
2147
+ }, `Syncing events from transaction ${e}`);
2148
+ }
2149
+ // Get sync status information
2150
+ async getSyncStatus() {
2151
+ return this.retryOperation(async () => {
2152
+ const e = await this.eventStore.getStartBlockNumber(), t = await this.networkManager.getLatestBlockNumber(), r = await this.networkManager.getNetworkInfo();
2153
+ return {
2154
+ nextSyncBlock: e,
2155
+ latestNetworkBlock: t,
2156
+ blocksBehind: Math.max(0, t - e + 1),
2157
+ networkInfo: r,
2158
+ isUpToDate: e > t
2159
+ };
2160
+ }, "Getting sync status");
2161
+ }
2162
+ // Validate network and contract before syncing
2163
+ async validateBeforeSync() {
2164
+ return await this.networkManager.validateNetwork(), await this.networkManager.validateContract(), !0;
2165
+ }
2166
+ // Set batch size for processing (useful for performance tuning)
2167
+ setBatchSize(e) {
2168
+ if (!Number.isInteger(e) || e < 1)
2169
+ throw new Error("Batch size must be a positive integer");
2170
+ this.batchSize = e;
2171
+ }
2172
+ // Get current batch size
2173
+ getBatchSize() {
2174
+ return this.batchSize;
2175
+ }
2176
+ // Reset sync position to a specific block
2177
+ async resetSyncPosition(e) {
2178
+ this.configManager.validateBlockNumber(e, "blockNumber"), await this.eventStore.setStartBlockNumber(e);
2179
+ }
2180
+ // Get events count by name
2181
+ async getEventCount(e) {
2182
+ return (await this.eventStore.getEvents(e)).length;
2183
+ }
2184
+ /**
2185
+ * Start real-time event streaming via WebSocket or EventEmitter provider.
2186
+ */
2187
+ startRealtimeSync() {
2188
+ const e = this.networkManager.getProvider();
2189
+ if (!e || typeof e.on != "function")
2190
+ throw new Error(
2191
+ "Real-time sync requires a provider that supports event subscriptions (e.g., WebSocketProvider). The current provider does not have an .on() method."
2192
+ );
2193
+ if (this._realtimeListener) {
2194
+ this.logger.warn("Real-time sync is already running, call stopRealtimeSync() first");
2195
+ return;
2196
+ }
2197
+ const t = this.configManager.get("address"), r = { address: t };
2198
+ this.logger.info("Starting real-time event sync", {
2199
+ contractAddress: t,
2200
+ providerType: e.constructor.name
2201
+ });
2202
+ const s = async (n) => {
2203
+ try {
2204
+ const i = this.networkManager.parseLog(n);
2205
+ if (i) {
2206
+ const a = this.networkManager.createEventKey(n);
2207
+ await this.eventStore.storeEvent(
2208
+ i.eventName,
2209
+ a,
2210
+ i.eventData
2211
+ ), this.logger.debug("Real-time event stored", {
2212
+ eventName: i.eventName,
2213
+ eventKey: a,
2214
+ blockNumber: n.blockNumber
2215
+ });
2216
+ }
2217
+ } catch (i) {
2218
+ this.logger.warn("Failed to process real-time event", {
2219
+ blockNumber: n.blockNumber,
2220
+ error: i.message
2221
+ });
2222
+ }
2223
+ };
2224
+ e.on(r, s), this._realtimeListener = s, this._realtimeFilter = r, this.logger.info("Real-time event sync started");
2225
+ }
2226
+ /**
2227
+ * Stop real-time event streaming and clean up the listener.
2228
+ */
2229
+ stopRealtimeSync() {
2230
+ if (!this._realtimeListener) {
2231
+ this.logger.debug("No real-time sync listener to stop");
2232
+ return;
2233
+ }
2234
+ const e = this.networkManager.getProvider();
2235
+ 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;
2236
+ }
2237
+ // Check if syncer is busy (for preventing concurrent syncs)
2238
+ isSyncing() {
2239
+ return this._syncing || !1;
2240
+ }
2241
+ // Set syncing state
2242
+ _setSyncing(e) {
2243
+ this._syncing = e;
2244
+ }
2245
+ }
2246
+ class A {
2247
+ constructor(e, t) {
2248
+ this.networkManager = e, this.logger = t.child({ context: "EventMetadata" }), this.logger.info("EventMetadata initialized");
2249
+ }
2250
+ /**
2251
+ * Enrich event with metadata
2252
+ * @param {Object} event - Event to enrich
2253
+ * @param {Object} options - Enrichment options
2254
+ * @param {boolean} options.includeBlock - Include block data
2255
+ * @param {boolean} options.includeTransaction - Include transaction data
2256
+ * @param {boolean} options.includeTimestamp - Include block timestamp
2257
+ * @param {boolean} options.includeGasCost - Include gas cost
2258
+ * @returns {Promise<Object>} Enriched event
2259
+ */
2260
+ async enrichEvent(e, t = {}) {
2261
+ const {
2262
+ includeBlock: r = !0,
2263
+ includeTransaction: s = !0,
2264
+ includeTimestamp: n = !0,
2265
+ includeGasCost: i = !0
2266
+ } = t;
2267
+ try {
2268
+ const a = { ...e }, l = [];
2269
+ return (r || n) && e.blockNumber && l.push(
2270
+ this.networkManager.provider.getBlock(e.blockNumber).then((o) => {
2271
+ var c;
2272
+ o && (r && (a.block = {
2273
+ number: o.number,
2274
+ hash: o.hash,
2275
+ parentHash: o.parentHash,
2276
+ miner: o.miner,
2277
+ difficulty: (c = o.difficulty) == null ? void 0 : c.toString(),
2278
+ gasLimit: o.gasLimit.toString(),
2279
+ gasUsed: o.gasUsed.toString()
2280
+ }), n && (a.timestamp = o.timestamp, a.date = new Date(o.timestamp * 1e3).toISOString()));
2281
+ }).catch((o) => {
2282
+ this.logger.warn("Failed to fetch block data", {
2283
+ blockNumber: e.blockNumber,
2284
+ error: o.message
2285
+ });
2286
+ })
2287
+ ), (s || i) && e.transactionHash && l.push(
2288
+ Promise.all([
2289
+ this.networkManager.provider.getTransaction(e.transactionHash),
2290
+ i ? this.networkManager.provider.getTransactionReceipt(e.transactionHash) : null
2291
+ ]).then(([o, c]) => {
2292
+ var h, g, d;
2293
+ if (o && (s && (a.transaction = {
2294
+ hash: o.hash,
2295
+ from: o.from,
2296
+ to: o.to,
2297
+ value: o.value.toString(),
2298
+ nonce: o.nonce,
2299
+ gasLimit: o.gasLimit.toString(),
2300
+ gasPrice: (h = o.gasPrice) == null ? void 0 : h.toString(),
2301
+ maxFeePerGas: (g = o.maxFeePerGas) == null ? void 0 : g.toString(),
2302
+ maxPriorityFeePerGas: (d = o.maxPriorityFeePerGas) == null ? void 0 : d.toString(),
2303
+ data: o.data.length > 66 ? o.data.substring(0, 66) + "..." : o.data
2304
+ }), i && c)) {
2305
+ const m = c.gasUsed, y = o.gasPrice || o.maxFeePerGas || 0n, w = m * y;
2306
+ a.gas = {
2307
+ used: m.toString(),
2308
+ price: y.toString(),
2309
+ cost: w.toString(),
2310
+ costInEther: this._formatEther(w)
2311
+ };
2312
+ }
2313
+ }).catch((o) => {
2314
+ this.logger.warn("Failed to fetch transaction data", {
2315
+ transactionHash: e.transactionHash,
2316
+ error: o.message
2317
+ });
2318
+ })
2319
+ ), await Promise.all(l), a._metadata = {
2320
+ enrichedAt: new Date().toISOString(),
2321
+ enrichmentOptions: t
2322
+ }, this.logger.debug("Event enriched with metadata", {
2323
+ eventName: e.eventName,
2324
+ blockNumber: e.blockNumber,
2325
+ metadataAdded: Object.keys(a).filter((o) => !e.hasOwnProperty(o))
2326
+ }), a;
2327
+ } catch (a) {
2328
+ return this.logger.error("Failed to enrich event", {
2329
+ event: e,
2330
+ error: a.message
2331
+ }), e;
2332
+ }
2333
+ }
2334
+ /**
2335
+ * Enrich multiple events in batch
2336
+ * @param {Array} events - Events to enrich
2337
+ * @param {Object} options - Enrichment options
2338
+ * @param {number} options.batchSize - Number of events to process concurrently
2339
+ * @returns {Promise<Array>} Enriched events
2340
+ */
2341
+ async enrichEvents(e, t = {}) {
2342
+ const { batchSize: r = 10, ...s } = t;
2343
+ return this.logger.time("enrichEvents", async () => {
2344
+ var a, l;
2345
+ const n = [];
2346
+ let i = 0;
2347
+ for (let o = 0; o < e.length; o += r) {
2348
+ const c = e.slice(o, o + r), h = await Promise.allSettled(
2349
+ c.map((g) => this.enrichEvent(g, s))
2350
+ );
2351
+ for (let g = 0; g < h.length; g++)
2352
+ h[g].status === "fulfilled" ? n.push(h[g].value) : (i++, this.logger.warn("Failed to enrich event, using original", {
2353
+ error: (a = h[g].reason) == null ? void 0 : a.message,
2354
+ blockNumber: (l = c[g]) == null ? void 0 : l.blockNumber
2355
+ }), n.push(c[g]));
2356
+ this.logger.debug("Enriched event batch", {
2357
+ batchIndex: Math.floor(o / r),
2358
+ batchSize: c.length,
2359
+ failures: i,
2360
+ totalProgress: `${n.length}/${e.length}`
2361
+ });
2362
+ }
2363
+ return this.logger.info("Completed event enrichment", {
2364
+ totalEvents: e.length,
2365
+ enrichedEvents: n.length,
2366
+ failures: i
2367
+ }), n;
2368
+ });
2369
+ }
2370
+ /**
2371
+ * Calculate statistics for a set of events
2372
+ * @param {Array} events - Events to analyze
2373
+ * @returns {Object} Event statistics
2374
+ */
2375
+ calculateStatistics(e) {
2376
+ if (!Array.isArray(e) || e.length === 0)
2377
+ return {
2378
+ count: 0,
2379
+ blockRange: { min: null, max: null },
2380
+ timeRange: { min: null, max: null },
2381
+ gasStats: { total: "0", average: "0", min: "0", max: "0" }
2382
+ };
2383
+ 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) => {
2384
+ var l;
2385
+ return (l = a.gas) == null ? void 0 : l.cost;
2386
+ }).filter((a) => a != null).map((a) => BigInt(a)), n = {
2387
+ count: e.length,
2388
+ blockRange: {
2389
+ min: t[0] || null,
2390
+ max: t[t.length - 1] || null,
2391
+ span: t.length > 0 ? t[t.length - 1] - t[0] : 0
2392
+ },
2393
+ timeRange: {
2394
+ min: r[0] || null,
2395
+ max: r[r.length - 1] || null,
2396
+ span: r.length > 0 ? r[r.length - 1] - r[0] : 0
2397
+ }
2398
+ };
2399
+ if (s.length > 0) {
2400
+ const a = s.reduce((c, h) => c + h, 0n), l = a / BigInt(s.length), o = [...s].sort((c, h) => c < h ? -1 : 1);
2401
+ n.gasStats = {
2402
+ total: a.toString(),
2403
+ average: l.toString(),
2404
+ min: o[0].toString(),
2405
+ max: o[o.length - 1].toString(),
2406
+ totalInEther: this._formatEther(a)
2407
+ };
2408
+ } else
2409
+ n.gasStats = { total: "0", average: "0", min: "0", max: "0" };
2410
+ const i = {};
2411
+ return e.forEach((a) => {
2412
+ a.eventName && (i[a.eventName] = (i[a.eventName] || 0) + 1);
2413
+ }), n.eventTypes = i, this.logger.debug("Calculated event statistics", n), n;
2414
+ }
2415
+ /**
2416
+ * Format wei to ether string
2417
+ * @private
2418
+ */
2419
+ _formatEther(e) {
2420
+ try {
2421
+ const t = e.toString();
2422
+ return (Number(t) / 1e18).toFixed(6) + " ETH";
2423
+ } catch {
2424
+ return "0 ETH";
2425
+ }
2426
+ }
2427
+ }
2428
+ class R {
2429
+ constructor(e, t) {
2430
+ this.magazine = e, this.logger = t.child({ context: "DebugUtils" }), this.logger.info("DebugUtils initialized"), this.debugMode = !1, this.metrics = {
2431
+ syncOperations: [],
2432
+ queryOperations: [],
2433
+ storageOperations: [],
2434
+ networkCalls: []
2435
+ }, this._logBuffer = [], this._logBufferMax = 200, this._originalMethods = /* @__PURE__ */ new Map(), this._verboseErrors = !1, this.healthThresholds = {
2436
+ syncDelay: 3e5,
2437
+ // 5 minutes
2438
+ errorRate: 0.1,
2439
+ // 10%
2440
+ responseTime: 5e3,
2441
+ // 5 seconds
2442
+ storageUsage: 0.9
2443
+ // 90%
2444
+ };
2445
+ }
2446
+ /**
2447
+ * Perform comprehensive health check
2448
+ * @returns {Promise<Object>} Health check results
2449
+ */
2450
+ async healthCheck() {
2451
+ const e = Date.now(), t = {
2452
+ status: "healthy",
2453
+ timestamp: new Date().toISOString(),
2454
+ checks: {},
2455
+ issues: []
2456
+ };
2457
+ try {
2458
+ 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();
2459
+ const r = [];
2460
+ return Object.entries(t.checks).forEach(([s, n]) => {
2461
+ n.status !== "healthy" && r.push({
2462
+ check: s,
2463
+ status: n.status,
2464
+ message: n.message
2465
+ });
2466
+ }), 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", {
2467
+ status: t.status,
2468
+ duration: t.duration,
2469
+ issueCount: r.length
2470
+ }), t;
2471
+ } catch (r) {
2472
+ return this.logger.error("Health check failed", { error: r.message }), {
2473
+ status: "error",
2474
+ timestamp: new Date().toISOString(),
2475
+ error: r.message,
2476
+ duration: Date.now() - e
2477
+ };
2478
+ }
2479
+ }
2480
+ /**
2481
+ * Get debug information about the current state
2482
+ * @returns {Promise<Object>} Debug information
2483
+ */
2484
+ async getDebugInfo() {
2485
+ const e = {
2486
+ timestamp: new Date().toISOString(),
2487
+ configuration: this._getConfigInfo(),
2488
+ network: await this._getNetworkInfo(),
2489
+ storage: await this._getStorageInfo(),
2490
+ performance: this._getPerformanceInfo(),
2491
+ logs: this._getRecentLogs()
2492
+ };
2493
+ return this.logger.debug("Debug info generated"), e;
2494
+ }
2495
+ /**
2496
+ * Record a metric
2497
+ * @param {string} type - Metric type
2498
+ * @param {Object} data - Metric data
2499
+ */
2500
+ recordMetric(e, t) {
2501
+ const r = {
2502
+ timestamp: Date.now(),
2503
+ ...t
2504
+ };
2505
+ this.metrics[e] && (this.metrics[e].push(r), this.metrics[e].length > 1e3 && (this.metrics[e] = this.metrics[e].slice(-1e3)));
2506
+ }
2507
+ /**
2508
+ * Get performance report
2509
+ * @param {Object} options - Report options
2510
+ * @returns {Object} Performance report
2511
+ */
2512
+ getPerformanceReport(e = {}) {
2513
+ const {
2514
+ timeRange: t = 36e5,
2515
+ // Last hour
2516
+ aggregation: r = "average"
2517
+ } = e, s = Date.now(), n = s - t, i = {};
2518
+ return Object.entries(this.metrics).forEach(([a, l]) => {
2519
+ const o = l.filter((g) => g.timestamp >= n);
2520
+ if (o.length === 0) {
2521
+ i[a] = { count: 0, average: 0, min: 0, max: 0 };
2522
+ return;
2523
+ }
2524
+ const c = o.map((g) => g.duration || 0), h = o.filter((g) => g.error).length;
2525
+ i[a] = {
2526
+ count: o.length,
2527
+ errors: h,
2528
+ errorRate: (h / o.length * 100).toFixed(2) + "%",
2529
+ average: Math.round(c.reduce((g, d) => g + d, 0) / c.length),
2530
+ min: Math.min(...c),
2531
+ max: Math.max(...c),
2532
+ p95: this._calculatePercentile(c, 95),
2533
+ p99: this._calculatePercentile(c, 99)
2534
+ };
2535
+ }), {
2536
+ timeRange: {
2537
+ start: new Date(n).toISOString(),
2538
+ end: new Date(s).toISOString(),
2539
+ duration: t
2540
+ },
2541
+ metrics: i
2542
+ };
2543
+ }
2544
+ /**
2545
+ * Enable debug mode
2546
+ * @param {Object} options - Debug options
2547
+ */
2548
+ enableDebugMode(e = {}) {
2549
+ const {
2550
+ logLevel: t = "debug",
2551
+ captureMetrics: r = !0,
2552
+ verboseErrors: s = !0
2553
+ } = e;
2554
+ this.magazine.setLogLevel(t), r && this._instrumentMethods(), s && this._enableVerboseErrors(), this.logger.info("Debug mode enabled", e);
2555
+ }
2556
+ /**
2557
+ * Export debug data
2558
+ * @returns {Promise<Object>} Exportable debug data
2559
+ */
2560
+ async exportDebugData() {
2561
+ const e = {
2562
+ version: "1.0.0",
2563
+ exportedAt: new Date().toISOString(),
2564
+ debugInfo: await this.getDebugInfo(),
2565
+ healthCheck: await this.healthCheck(),
2566
+ performanceReport: this.getPerformanceReport(),
2567
+ recentMetrics: {
2568
+ sync: this.metrics.syncOperations.slice(-100),
2569
+ query: this.metrics.queryOperations.slice(-100),
2570
+ storage: this.metrics.storageOperations.slice(-100),
2571
+ network: this.metrics.networkCalls.slice(-100)
2572
+ }
2573
+ };
2574
+ return this.logger.info("Debug data exported"), e;
2575
+ }
2576
+ /**
2577
+ * Check network connectivity
2578
+ * @private
2579
+ */
2580
+ async _checkNetwork() {
2581
+ try {
2582
+ const e = Date.now(), t = await this.magazine.getLatestBlockNumber(), r = Date.now() - e;
2583
+ return {
2584
+ status: r < this.healthThresholds.responseTime ? "healthy" : "degraded",
2585
+ latestBlock: t,
2586
+ responseTime: r,
2587
+ message: `Network response time: ${r}ms`
2588
+ };
2589
+ } catch (e) {
2590
+ return {
2591
+ status: "critical",
2592
+ error: e.message,
2593
+ message: "Network connection failed"
2594
+ };
2595
+ }
2596
+ }
2597
+ /**
2598
+ * Check database connectivity
2599
+ * @private
2600
+ */
2601
+ async _checkDatabase() {
2602
+ try {
2603
+ const e = Date.now(), t = this.magazine.eventStore.getGunInstance();
2604
+ await new Promise((s, n) => {
2605
+ t.get("_health_check").put({
2606
+ timestamp: Date.now()
2607
+ }, (i) => {
2608
+ i.err ? n(new Error(i.err)) : s(i);
2609
+ });
2610
+ });
2611
+ const r = Date.now() - e;
2612
+ return {
2613
+ status: r < 1e3 ? "healthy" : "degraded",
2614
+ responseTime: r,
2615
+ message: `Database response time: ${r}ms`
2616
+ };
2617
+ } catch (e) {
2618
+ return {
2619
+ status: "critical",
2620
+ error: e.message,
2621
+ message: "Database connection failed"
2622
+ };
2623
+ }
2624
+ }
2625
+ /**
2626
+ * Check sync status
2627
+ * @private
2628
+ */
2629
+ async _checkSyncStatus() {
2630
+ try {
2631
+ const e = this.magazine.eventSyncer.lastSyncTime || 0, t = Date.now() - e;
2632
+ return e === 0 ? {
2633
+ status: "warning",
2634
+ message: "No sync performed yet"
2635
+ } : {
2636
+ status: t < this.healthThresholds.syncDelay ? "healthy" : "warning",
2637
+ lastSync: new Date(e).toISOString(),
2638
+ timeSinceSync: t,
2639
+ message: `Last sync: ${Math.round(t / 1e3)}s ago`
2640
+ };
2641
+ } catch (e) {
2642
+ return {
2643
+ status: "error",
2644
+ error: e.message,
2645
+ message: "Could not check sync status"
2646
+ };
2647
+ }
2648
+ }
2649
+ /**
2650
+ * Check storage status
2651
+ * @private
2652
+ */
2653
+ async _checkStorage() {
2654
+ try {
2655
+ const e = await this.magazine.getCompressionStats(), t = e.totalCompressedSize / (100 * 1024 * 1024);
2656
+ return {
2657
+ status: t < this.healthThresholds.storageUsage ? "healthy" : "warning",
2658
+ usage: `${(t * 100).toFixed(2)}%`,
2659
+ compressed: e.totalCompressedSize,
2660
+ saved: e.spaceSaved,
2661
+ message: `Storage usage: ${(t * 100).toFixed(2)}%`
2662
+ };
2663
+ } catch (e) {
2664
+ return {
2665
+ status: "error",
2666
+ error: e.message,
2667
+ message: "Could not check storage status"
2668
+ };
2669
+ }
2670
+ }
2671
+ /**
2672
+ * Check performance metrics
2673
+ * @private
2674
+ */
2675
+ _checkPerformance() {
2676
+ const e = this.getPerformanceReport({ timeRange: 3e5 });
2677
+ let t = "healthy";
2678
+ const r = [];
2679
+ return Object.entries(e.metrics).forEach(([s, n]) => {
2680
+ 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`));
2681
+ }), {
2682
+ status: t,
2683
+ metrics: e.metrics,
2684
+ message: r.length > 0 ? r.join(", ") : "Performance metrics within normal range"
2685
+ };
2686
+ }
2687
+ /**
2688
+ * Get configuration info
2689
+ * @private
2690
+ */
2691
+ _getConfigInfo() {
2692
+ const e = this.magazine.configManager.getAll();
2693
+ return {
2694
+ name: e.name,
2695
+ address: e.address,
2696
+ networkId: e.networkId,
2697
+ logLevel: this.magazine.logger.level,
2698
+ compression: {
2699
+ enabled: this.magazine.eventStore.compressionEnabled,
2700
+ strategy: this.magazine.eventStore.compressionStrategy
2701
+ }
2702
+ };
2703
+ }
2704
+ /**
2705
+ * Get network info
2706
+ * @private
2707
+ */
2708
+ async _getNetworkInfo() {
2709
+ try {
2710
+ return {
2711
+ ...await this.magazine.getNetworkInfo(),
2712
+ connected: !0
2713
+ };
2714
+ } catch (e) {
2715
+ return {
2716
+ connected: !1,
2717
+ error: e.message
2718
+ };
2719
+ }
2720
+ }
2721
+ /**
2722
+ * Get storage info
2723
+ * @private
2724
+ */
2725
+ async _getStorageInfo() {
2726
+ try {
2727
+ const e = await this.magazine.getCompressionStats();
2728
+ return {
2729
+ eventCount: (await this.magazine.getAllEvents({ pagination: { page: 1, pageSize: 1 } })).meta.totalItems,
2730
+ ...e
2731
+ };
2732
+ } catch (e) {
2733
+ return {
2734
+ error: e.message
2735
+ };
2736
+ }
2737
+ }
2738
+ /**
2739
+ * Get performance info
2740
+ * @private
2741
+ */
2742
+ _getPerformanceInfo() {
2743
+ return this.getPerformanceReport({ timeRange: 36e5 });
2744
+ }
2745
+ /**
2746
+ * Capture a log entry into the circular buffer
2747
+ * @param {Object} entry - Log entry to capture
2748
+ */
2749
+ captureLog(e) {
2750
+ this._logBuffer.push(e), this._logBuffer.length > this._logBufferMax && this._logBuffer.shift();
2751
+ }
2752
+ /**
2753
+ * Get recent logs from the circular buffer
2754
+ * @param {number} [count=50] - Number of recent log entries to return
2755
+ * @returns {Array} Recent log entries
2756
+ * @private
2757
+ */
2758
+ _getRecentLogs(e = 50) {
2759
+ const t = Math.min(e, this._logBuffer.length);
2760
+ return this._logBuffer.slice(-t);
2761
+ }
2762
+ /**
2763
+ * Calculate percentile
2764
+ * @private
2765
+ */
2766
+ _calculatePercentile(e, t) {
2767
+ if (e.length === 0)
2768
+ return 0;
2769
+ const r = [...e].sort((n, i) => n - i), s = Math.ceil(t / 100 * r.length) - 1;
2770
+ return r[s];
2771
+ }
2772
+ /**
2773
+ * Instrument methods for metric collection
2774
+ * @private
2775
+ */
2776
+ _instrumentMethods() {
2777
+ const e = this.magazine, t = [
2778
+ "syncEvents",
2779
+ "getAllEvents",
2780
+ "getEvents",
2781
+ "query",
2782
+ "transformEvent"
2783
+ ];
2784
+ for (const r of t) {
2785
+ if (typeof e[r] != "function") {
2786
+ this.logger.debug(`Skipping instrumentation for missing method: ${r}`);
2787
+ continue;
2788
+ }
2789
+ if (this._originalMethods.has(r))
2790
+ continue;
2791
+ const s = e[r].bind(e);
2792
+ this._originalMethods.set(r, e[r]);
2793
+ const n = this;
2794
+ e[r] = function(...i) {
2795
+ const a = Date.now();
2796
+ let l;
2797
+ r === "syncEvents" ? l = "syncOperations" : r === "getAllEvents" || r === "getEvents" || r === "query" ? l = "queryOperations" : l = "storageOperations";
2798
+ try {
2799
+ const o = s(...i);
2800
+ if (o && typeof o.then == "function")
2801
+ return o.then((h) => {
2802
+ const g = Date.now() - a;
2803
+ return n.recordMetric(l, {
2804
+ method: r,
2805
+ duration: g,
2806
+ success: !0
2807
+ }), n.logger.debug(`${r} completed in ${g}ms`), h;
2808
+ }).catch((h) => {
2809
+ const g = Date.now() - a;
2810
+ throw n.recordMetric(l, {
2811
+ method: r,
2812
+ duration: g,
2813
+ success: !1,
2814
+ error: h.message
2815
+ }), n.logger.debug(`${r} failed after ${g}ms: ${h.message}`), h;
2816
+ });
2817
+ const c = Date.now() - a;
2818
+ return n.recordMetric(l, {
2819
+ method: r,
2820
+ duration: c,
2821
+ success: !0
2822
+ }), n.logger.debug(`${r} completed in ${c}ms`), o;
2823
+ } catch (o) {
2824
+ const c = Date.now() - a;
2825
+ throw n.recordMetric(l, {
2826
+ method: r,
2827
+ duration: c,
2828
+ success: !1,
2829
+ error: o.message
2830
+ }), n.logger.debug(`${r} failed after ${c}ms: ${o.message}`), o;
2831
+ }
2832
+ };
2833
+ }
2834
+ this.logger.debug("Method instrumentation enabled");
2835
+ }
2836
+ /**
2837
+ * Enable verbose error logging
2838
+ * @private
2839
+ */
2840
+ _enableVerboseErrors() {
2841
+ this._verboseErrors = !0;
2842
+ const e = this.magazine;
2843
+ if (typeof e.retryOperation == "function" && !this._originalRetryOperation) {
2844
+ const t = e.retryOperation.bind(e);
2845
+ this._originalRetryOperation = e.retryOperation;
2846
+ const r = this;
2847
+ e.retryOperation = async function(s, n, ...i) {
2848
+ try {
2849
+ return await t(s, n, ...i);
2850
+ } catch (a) {
2851
+ throw r._verboseErrors && r.logger.error("Verbose error context for retryOperation failure", {
2852
+ operationContext: n,
2853
+ errorMessage: a.message,
2854
+ errorStack: a.stack,
2855
+ errorName: a.name,
2856
+ timestamp: new Date().toISOString()
2857
+ }), a;
2858
+ }
2859
+ };
2860
+ }
2861
+ this.logger.debug("Verbose error logging enabled");
2862
+ }
2863
+ /**
2864
+ * Set debug mode on/off
2865
+ * @param {boolean} enabled - Whether to enable debug mode
2866
+ */
2867
+ setDebugMode(e) {
2868
+ if (this.debugMode = !!e, this.logger.info(`Debug mode ${e ? "enabled" : "disabled"}`), e) {
2869
+ if (this._instrumentMethods(), this._enableVerboseErrors(), this.logger._log && !this._originalLoggerLog) {
2870
+ this._originalLoggerLog = this.logger._log.bind(this.logger);
2871
+ const t = this;
2872
+ this.logger._log = function(r, s, n) {
2873
+ const i = t._originalLoggerLog(r, s, n);
2874
+ return t.captureLog({
2875
+ timestamp: Date.now(),
2876
+ level: r,
2877
+ message: s,
2878
+ data: n
2879
+ }), i;
2880
+ };
2881
+ }
2882
+ } else
2883
+ this._originalLoggerLog && (this.logger._log = this._originalLoggerLog, this._originalLoggerLog = null);
2884
+ }
2885
+ /**
2886
+ * Check if debug mode is enabled
2887
+ * @returns {boolean} Debug mode status
2888
+ */
2889
+ isDebugMode() {
2890
+ return !!this.debugMode;
2891
+ }
2892
+ }
2893
+ class B extends Error {
2894
+ constructor(e, t = null) {
2895
+ super(e), this.name = "ValidationError", this.field = t;
2896
+ }
2897
+ }
2898
+ class f extends Error {
2899
+ constructor(e) {
2900
+ super(e), this.name = "ModelError";
2901
+ }
2902
+ }
2903
+ class j {
2904
+ constructor(e, t) {
2905
+ this.modelName = e, this.gun = t, this.migrations = /* @__PURE__ */ new Map(), this.currentVersion = 1;
2906
+ }
2907
+ version(e) {
2908
+ return this.currentVersion = e, this;
2909
+ }
2910
+ addMigration(e, t, r) {
2911
+ return this.migrations.set(`${e}:${t}`, r), this;
2912
+ }
2913
+ async migrate(e) {
2914
+ let t = e._schemaVersion || 1, r = { ...e };
2915
+ for (; t < this.currentVersion; ) {
2916
+ const s = t + 1, n = `${t}:${s}`, i = this.migrations.get(n);
2917
+ if (!i)
2918
+ throw new f(
2919
+ `No migration path from version ${t} to ${s} for model '${this.modelName}'`
2920
+ );
2921
+ r = await i(r), r._schemaVersion = s, t = s;
2922
+ }
2923
+ return r;
2924
+ }
2925
+ needsMigration(e) {
2926
+ return (e._schemaVersion || 1) < this.currentVersion;
2927
+ }
2928
+ }
2929
+ class U {
2930
+ static validate(e, t) {
2931
+ const r = [];
2932
+ for (const s of t.required || [])
2933
+ (!(s in e) || e[s] === null || e[s] === void 0) && r.push(`Field '${s}' is required`);
2934
+ for (const [s, n] of Object.entries(t.properties || {}))
2935
+ if (s in e && e[s] !== null && e[s] !== void 0) {
2936
+ const i = e[s], { type: a, validate: l } = n;
2937
+ if (a && !this.validateType(i, a) && r.push(`Field '${s}' must be of type ${a}`), l && typeof l == "function") {
2938
+ const o = l(i);
2939
+ o !== !0 && r.push(`Field '${s}': ${o || "validation failed"}`);
2940
+ }
2941
+ }
2942
+ return {
2943
+ valid: r.length === 0,
2944
+ errors: r
2945
+ };
2946
+ }
2947
+ static validateType(e, t) {
2948
+ switch (t) {
2949
+ case "string":
2950
+ return typeof e == "string";
2951
+ case "number":
2952
+ return typeof e == "number" && !isNaN(e);
2953
+ case "boolean":
2954
+ return typeof e == "boolean";
2955
+ case "array":
2956
+ return Array.isArray(e);
2957
+ case "object":
2958
+ return typeof e == "object" && e !== null && !Array.isArray(e);
2959
+ case "address":
2960
+ return typeof e == "string" && /^0x[a-fA-F0-9]{40}$/.test(e);
2961
+ case "hash":
2962
+ return typeof e == "string" && /^0x[a-fA-F0-9]{64}$/.test(e);
2963
+ default:
2964
+ return !0;
2965
+ }
2966
+ }
2967
+ }
2968
+ class H {
2969
+ constructor(e, t, r, s, n = {}) {
2970
+ this.name = e, this.schema = t, this.gun = r, this.transformer = s, this.options = {
2971
+ autoId: !0,
2972
+ timestampFields: ["createdAt", "updatedAt"],
2973
+ ...n
2974
+ }, this.logger = new p({
2975
+ context: `DataModel:${e}`,
2976
+ level: n.logLevel || "info"
2977
+ }), this.modelNode = this.gun.get("models").get(this.name), this._hooks = {}, this.migration = null, this.logger.info("DataModel initialized", {
2978
+ name: this.name,
2979
+ options: this.options
2980
+ });
2981
+ }
2982
+ /**
2983
+ * Register a lifecycle hook
2984
+ * @param {'pre:save'|'post:save'|'pre:update'|'post:update'|'pre:delete'|'post:delete'} event
2985
+ * @param {Function} fn - Hook function. Pre-hooks receive (data) and can return modified data. Post-hooks receive (result).
2986
+ */
2987
+ hook(e, t) {
2988
+ return this._hooks[e] || (this._hooks[e] = []), this._hooks[e].push(t), this;
2989
+ }
2990
+ /**
2991
+ * Attach a SchemaMigration instance so documents are auto-migrated on read.
2992
+ * @param {SchemaMigration} schemaMigration
2993
+ * @returns {DataModel} this (for chaining)
2994
+ */
2995
+ setMigration(e) {
2996
+ return this.migration = e, this;
2997
+ }
2998
+ async _runHooks(e, t) {
2999
+ const r = this._hooks[e] || [];
3000
+ let s = t;
3001
+ for (const n of r) {
3002
+ const i = await n(s);
3003
+ i !== void 0 && (s = i);
3004
+ }
3005
+ return s;
3006
+ }
3007
+ /**
3008
+ * Generate a unique ID for a new document
3009
+ * @returns {string} Unique ID
3010
+ */
3011
+ generateId() {
3012
+ return `${this.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3013
+ }
3014
+ /**
3015
+ * Validate data against schema
3016
+ * @param {Object} data - Data to validate
3017
+ * @throws {ValidationError} If validation fails
3018
+ */
3019
+ validate(e) {
3020
+ const t = U.validate(e, this.schema);
3021
+ if (!t.valid)
3022
+ throw new B(`Validation failed: ${t.errors.join(", ")}`);
3023
+ }
3024
+ /**
3025
+ * Prepare data for storage (add timestamps, ID, etc.)
3026
+ * @param {Object} data - Raw data
3027
+ * @param {boolean} isUpdate - Whether this is an update operation
3028
+ * @returns {Object} Prepared data
3029
+ */
3030
+ prepareData(e, t = !1) {
3031
+ const r = { ...e };
3032
+ 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;
3033
+ }
3034
+ /**
3035
+ * Save a document (create or update)
3036
+ * @param {Object} data - Document data
3037
+ * @returns {Promise<Object>} Saved document
3038
+ */
3039
+ async save(e) {
3040
+ this.logger.debug("Saving document", { data: e });
3041
+ try {
3042
+ let t = this.prepareData(e);
3043
+ t = await this._runHooks("pre:save", t), this.validate(t);
3044
+ const r = t.id;
3045
+ if (!r)
3046
+ throw new f("Document must have an ID");
3047
+ return await new Promise((s, n) => {
3048
+ this.modelNode.get(r).put(t, (i) => {
3049
+ i.err ? n(new f(`Failed to save document: ${i.err}`)) : s();
3050
+ });
3051
+ }), await this._runHooks("post:save", t), this.logger.info("Document saved", { id: r, model: this.name }), t;
3052
+ } catch (t) {
3053
+ throw this.logger.error("Failed to save document", { error: t.message, data: e }), t;
3054
+ }
3055
+ }
3056
+ /**
3057
+ * Find documents by query
3058
+ * @param {Object} query - Query object
3059
+ * @param {Object} options - Query options
3060
+ * @returns {Promise<Array>} Found documents
3061
+ */
3062
+ async find(e = {}, t = {}) {
3063
+ this.logger.debug("Finding documents", { query: e, options: t });
3064
+ try {
3065
+ const { limit: r = 100, skip: s = 0 } = t, n = [];
3066
+ if (await new Promise((i) => {
3067
+ let a = 0, l = 0;
3068
+ this.modelNode.map().on((o, c) => {
3069
+ if (o && typeof o == "object" && this.matchesQuery(o, e)) {
3070
+ if (l < s) {
3071
+ l++;
3072
+ return;
3073
+ }
3074
+ a < r && (n.push({ ...o, _key: c }), a++), a >= r && i();
3075
+ }
3076
+ }), setTimeout(i, 1e3);
3077
+ }), this.migration)
3078
+ for (let i = 0; i < n.length; i++)
3079
+ this.migration.needsMigration(n[i]) && (n[i] = await this.migration.migrate(n[i]), await this.save(n[i]));
3080
+ return this.logger.debug("Documents found", { count: n.length, query: e }), n;
3081
+ } catch (r) {
3082
+ throw this.logger.error("Failed to find documents", { error: r.message, query: e }), new f(`Failed to find documents: ${r.message}`);
3083
+ }
3084
+ }
3085
+ /**
3086
+ * Find a single document by query
3087
+ * @param {Object} query - Query object
3088
+ * @returns {Promise<Object|null>} Found document or null
3089
+ */
3090
+ async findOne(e) {
3091
+ const t = await this.find(e, { limit: 1 });
3092
+ return t.length > 0 ? t[0] : null;
3093
+ }
3094
+ /**
3095
+ * Find a document by ID
3096
+ * @param {string} id - Document ID
3097
+ * @returns {Promise<Object|null>} Found document or null
3098
+ */
3099
+ async findById(e) {
3100
+ this.logger.debug("Finding document by ID", { id: e });
3101
+ try {
3102
+ let t = await new Promise((r) => {
3103
+ this.modelNode.get(e).once((s) => {
3104
+ r(s && typeof s == "object" ? { ...s, _key: e } : null);
3105
+ });
3106
+ });
3107
+ return t && this.migration && this.migration.needsMigration(t) && (t = await this.migration.migrate(t), await this.save(t)), t;
3108
+ } catch (t) {
3109
+ throw this.logger.error("Failed to find document by ID", { error: t.message, id: e }), new f(`Failed to find document: ${t.message}`);
3110
+ }
3111
+ }
3112
+ /**
3113
+ * Update a document by ID
3114
+ * @param {string} id - Document ID
3115
+ * @param {Object} updateData - Data to update
3116
+ * @returns {Promise<Object>} Updated document
3117
+ */
3118
+ async update(e, t) {
3119
+ this.logger.debug("Updating document", { id: e, updateData: t });
3120
+ try {
3121
+ const r = await this.findById(e);
3122
+ if (!r)
3123
+ throw new f(`Document with ID ${e} not found`);
3124
+ const s = { ...r, ...t, id: e };
3125
+ let n = this.prepareData(s, !0);
3126
+ return n = await this._runHooks("pre:update", n), this.validate(n), await new Promise((i, a) => {
3127
+ this.modelNode.get(e).put(n, (l) => {
3128
+ l.err ? a(new f(`Failed to update document: ${l.err}`)) : i();
3129
+ });
3130
+ }), await this._runHooks("post:update", n), this.logger.info("Document updated", { id: e, model: this.name }), n;
3131
+ } catch (r) {
3132
+ throw this.logger.error("Failed to update document", { error: r.message, id: e, updateData: t }), r;
3133
+ }
3134
+ }
3135
+ /**
3136
+ * Delete a document by ID
3137
+ * @param {string} id - Document ID
3138
+ * @returns {Promise<boolean>} Success status
3139
+ */
3140
+ async delete(e) {
3141
+ this.logger.debug("Deleting document", { id: e });
3142
+ try {
3143
+ return await this._runHooks("pre:delete", { id: e }), await new Promise((t, r) => {
3144
+ this.modelNode.get(e).put(null, (s) => {
3145
+ s.err ? r(new f(`Failed to delete document: ${s.err}`)) : t();
3146
+ });
3147
+ }), await this._runHooks("post:delete", { id: e }), this.logger.info("Document deleted", { id: e, model: this.name }), !0;
3148
+ } catch (t) {
3149
+ throw this.logger.error("Failed to delete document", { error: t.message, id: e }), t;
3150
+ }
3151
+ }
3152
+ /**
3153
+ * Count documents matching query
3154
+ * @param {Object} query - Query object
3155
+ * @returns {Promise<number>} Document count
3156
+ */
3157
+ async count(e = {}) {
3158
+ return (await this.find(e, { limit: 1e4 })).length;
3159
+ }
3160
+ /**
3161
+ * Insert multiple documents
3162
+ * @param {Array<Object>} documents - Array of documents to insert
3163
+ * @returns {Promise<Array<Object>>} Saved documents
3164
+ */
3165
+ async insertMany(e) {
3166
+ if (!Array.isArray(e))
3167
+ throw new f("insertMany requires an array of documents");
3168
+ const t = [], r = [];
3169
+ for (const s of e)
3170
+ try {
3171
+ t.push(await this.save(s));
3172
+ } catch (n) {
3173
+ r.push({ document: s, error: n.message });
3174
+ }
3175
+ return r.length > 0 && this.logger.warn("Some documents failed to insert", {
3176
+ total: e.length,
3177
+ succeeded: t.length,
3178
+ failed: r.length
3179
+ }), { inserted: t, errors: r };
3180
+ }
3181
+ /**
3182
+ * Update multiple documents matching a query
3183
+ * @param {Object} query - Query to match documents
3184
+ * @param {Object} updateData - Data to update on each matched document
3185
+ * @returns {Promise<Object>} Update results
3186
+ */
3187
+ async updateMany(e, t) {
3188
+ const r = await this.find(e, { limit: 1e5 }), s = [], n = [];
3189
+ for (const i of r) {
3190
+ const a = i.id || i._key;
3191
+ if (a)
3192
+ try {
3193
+ s.push(await this.update(a, t));
3194
+ } catch (l) {
3195
+ n.push({ id: a, error: l.message });
3196
+ }
3197
+ }
3198
+ return this.logger.info("updateMany completed", {
3199
+ matched: r.length,
3200
+ updated: s.length,
3201
+ failed: n.length
3202
+ }), { matched: r.length, updated: s, errors: n };
3203
+ }
3204
+ /**
3205
+ * Delete multiple documents matching a query
3206
+ * @param {Object} query - Query to match documents for deletion
3207
+ * @returns {Promise<Object>} Deletion results
3208
+ */
3209
+ async deleteMany(e) {
3210
+ const t = await this.find(e, { limit: 1e5 });
3211
+ let r = 0;
3212
+ const s = [];
3213
+ for (const n of t) {
3214
+ const i = n.id || n._key;
3215
+ if (i)
3216
+ try {
3217
+ await this.delete(i), r++;
3218
+ } catch (a) {
3219
+ s.push({ id: i, error: a.message });
3220
+ }
3221
+ }
3222
+ return this.logger.info("deleteMany completed", {
3223
+ matched: t.length,
3224
+ deleted: r,
3225
+ failed: s.length
3226
+ }), { matched: t.length, deleted: r, errors: s };
3227
+ }
3228
+ /**
3229
+ * Migrate all documents in this model to the current schema version.
3230
+ * @returns {Promise<Object>} Migration results { migrated, errors }
3231
+ */
3232
+ async migrateAll() {
3233
+ if (!this.migration)
3234
+ throw new f("No migration configured for this model. Call setMigration() first.");
3235
+ const e = await this.find({}, { limit: 1e5 });
3236
+ let t = 0;
3237
+ const r = [];
3238
+ for (const s of e)
3239
+ if (this.migration.needsMigration(s))
3240
+ try {
3241
+ const n = await this.migration.migrate(s);
3242
+ await this.save(n), t++;
3243
+ } catch (n) {
3244
+ r.push({ id: s.id || s._key, error: n.message });
3245
+ }
3246
+ return this.logger.info("migrateAll completed", {
3247
+ total: e.length,
3248
+ migrated: t,
3249
+ failed: r.length
3250
+ }), { total: e.length, migrated: t, errors: r };
3251
+ }
3252
+ /**
3253
+ * Simple query matching (can be enhanced with MongoDB-like operators)
3254
+ * @private
3255
+ * @param {Object} document - Document to test
3256
+ * @param {Object} query - Query object
3257
+ * @returns {boolean} Whether document matches query
3258
+ */
3259
+ matchesQuery(e, t) {
3260
+ for (const [r, s] of Object.entries(t))
3261
+ if (typeof s == "object" && s !== null)
3262
+ for (const [n, i] of Object.entries(s))
3263
+ switch (n) {
3264
+ case "$gte":
3265
+ if (!(e[r] >= i))
3266
+ return !1;
3267
+ break;
3268
+ case "$lte":
3269
+ if (!(e[r] <= i))
3270
+ return !1;
3271
+ break;
3272
+ case "$gt":
3273
+ if (!(e[r] > i))
3274
+ return !1;
3275
+ break;
3276
+ case "$lt":
3277
+ if (!(e[r] < i))
3278
+ return !1;
3279
+ break;
3280
+ case "$ne":
3281
+ if (e[r] === i)
3282
+ return !1;
3283
+ break;
3284
+ case "$in":
3285
+ if (!Array.isArray(i) || !i.includes(e[r]))
3286
+ return !1;
3287
+ break;
3288
+ case "$nin":
3289
+ if (Array.isArray(i) && i.includes(e[r]))
3290
+ return !1;
3291
+ break;
3292
+ case "$regex":
3293
+ if (!new RegExp(i).test(e[r]))
3294
+ return !1;
3295
+ break;
3296
+ default:
3297
+ if (e[r] !== s)
3298
+ return !1;
3299
+ }
3300
+ else if (e[r] !== s)
3301
+ return !1;
3302
+ return !0;
3303
+ }
3304
+ /**
3305
+ * Create an aggregation pipeline from query results.
3306
+ * @param {Object} [query={}] - Optional query to filter documents before aggregation
3307
+ * @returns {Promise<AggregationPipeline>} A new AggregationPipeline instance
3308
+ */
3309
+ async aggregate(e = {}) {
3310
+ const t = await this.find(e, { limit: 1e5 });
3311
+ return new M(t);
3312
+ }
3313
+ }
3314
+ class M {
3315
+ constructor(e) {
3316
+ this.data = Array.isArray(e) ? e : [], this.stages = [];
3317
+ }
3318
+ /**
3319
+ * Filter/match stage - filter data before aggregation.
3320
+ * Uses the same query operators as DataModel.matchesQuery.
3321
+ * @param {Object} query - Query object with optional operators ($gte, $lte, etc.)
3322
+ * @returns {AggregationPipeline} this (for chaining)
3323
+ */
3324
+ match(e) {
3325
+ return this.stages.push({ type: "match", query: e }), this;
3326
+ }
3327
+ /**
3328
+ * Group results by a field.
3329
+ * @param {string} field - Field name to group by
3330
+ * @returns {AggregationPipeline} this (for chaining)
3331
+ */
3332
+ group(e) {
3333
+ return this.stages.push({ type: "group", field: e }), this;
3334
+ }
3335
+ /**
3336
+ * Sum aggregate on a numeric field.
3337
+ * @param {string} field - Field to sum
3338
+ * @param {string} [alias] - Optional alias for the result key (default: `sum_<field>`)
3339
+ * @returns {AggregationPipeline} this (for chaining)
3340
+ */
3341
+ sum(e, t) {
3342
+ return this.stages.push({ type: "aggregate", op: "sum", field: e, alias: t || `sum_${e}` }), this;
3343
+ }
3344
+ /**
3345
+ * Average aggregate on a numeric field.
3346
+ * @param {string} field - Field to average
3347
+ * @param {string} [alias] - Optional alias for the result key (default: `avg_<field>`)
3348
+ * @returns {AggregationPipeline} this (for chaining)
3349
+ */
3350
+ avg(e, t) {
3351
+ return this.stages.push({ type: "aggregate", op: "avg", field: e, alias: t || `avg_${e}` }), this;
3352
+ }
3353
+ /**
3354
+ * Count aggregate.
3355
+ * @param {string} [alias] - Optional alias for the result key (default: `count`)
3356
+ * @returns {AggregationPipeline} this (for chaining)
3357
+ */
3358
+ count(e) {
3359
+ return this.stages.push({ type: "aggregate", op: "count", alias: e || "count" }), this;
3360
+ }
3361
+ /**
3362
+ * Min aggregate on a numeric field.
3363
+ * @param {string} field - Field to find minimum of
3364
+ * @param {string} [alias] - Optional alias for the result key (default: `min_<field>`)
3365
+ * @returns {AggregationPipeline} this (for chaining)
3366
+ */
3367
+ min(e, t) {
3368
+ return this.stages.push({ type: "aggregate", op: "min", field: e, alias: t || `min_${e}` }), this;
3369
+ }
3370
+ /**
3371
+ * Max aggregate on a numeric field.
3372
+ * @param {string} field - Field to find maximum of
3373
+ * @param {string} [alias] - Optional alias for the result key (default: `max_<field>`)
3374
+ * @returns {AggregationPipeline} this (for chaining)
3375
+ */
3376
+ max(e, t) {
3377
+ return this.stages.push({ type: "aggregate", op: "max", field: e, alias: t || `max_${e}` }), this;
3378
+ }
3379
+ /**
3380
+ * Time-series bucketing - groups data by time intervals.
3381
+ * Acts like a group stage but groups by truncated timestamp buckets.
3382
+ * @param {string} timestampField - Field containing a unix timestamp (seconds)
3383
+ * @param {'minute'|'hour'|'day'|'week'|'month'} interval - Bucket interval
3384
+ * @returns {AggregationPipeline} this (for chaining)
3385
+ */
3386
+ bucket(e, t) {
3387
+ return this.stages.push({ type: "bucket", timestampField: e, interval: t }), this;
3388
+ }
3389
+ /**
3390
+ * Sort results by a field.
3391
+ * @param {string} field - Field to sort by
3392
+ * @param {'asc'|'desc'} [order='asc'] - Sort order
3393
+ * @returns {AggregationPipeline} this (for chaining)
3394
+ */
3395
+ sort(e, t = "asc") {
3396
+ return this.stages.push({ type: "sort", field: e, order: t }), this;
3397
+ }
3398
+ /**
3399
+ * Limit the number of results returned.
3400
+ * @param {number} n - Maximum number of results
3401
+ * @returns {AggregationPipeline} this (for chaining)
3402
+ */
3403
+ limit(e) {
3404
+ return this.stages.push({ type: "limit", n: e }), this;
3405
+ }
3406
+ /**
3407
+ * Truncate a Date to the start of the given interval bucket.
3408
+ * @private
3409
+ * @param {Date} date
3410
+ * @param {string} interval
3411
+ * @returns {string} ISO string representing the bucket start
3412
+ */
3413
+ _truncateDate(e, t) {
3414
+ const r = new Date(e);
3415
+ switch (t) {
3416
+ case "minute":
3417
+ r.setUTCSeconds(0, 0);
3418
+ break;
3419
+ case "hour":
3420
+ r.setUTCMinutes(0, 0, 0);
3421
+ break;
3422
+ case "day":
3423
+ r.setUTCHours(0, 0, 0, 0);
3424
+ break;
3425
+ case "week": {
3426
+ r.setUTCHours(0, 0, 0, 0);
3427
+ const s = r.getUTCDay(), n = s === 0 ? 6 : s - 1;
3428
+ r.setUTCDate(r.getUTCDate() - n);
3429
+ break;
3430
+ }
3431
+ case "month":
3432
+ r.setUTCDate(1), r.setUTCHours(0, 0, 0, 0);
3433
+ break;
3434
+ }
3435
+ return r.toISOString();
3436
+ }
3437
+ /**
3438
+ * Simple query matching, mirroring DataModel.matchesQuery.
3439
+ * @private
3440
+ * @param {Object} document
3441
+ * @param {Object} query
3442
+ * @returns {boolean}
3443
+ */
3444
+ _matchesQuery(e, t) {
3445
+ for (const [r, s] of Object.entries(t))
3446
+ if (typeof s == "object" && s !== null)
3447
+ for (const [n, i] of Object.entries(s))
3448
+ switch (n) {
3449
+ case "$gte":
3450
+ if (!(e[r] >= i))
3451
+ return !1;
3452
+ break;
3453
+ case "$lte":
3454
+ if (!(e[r] <= i))
3455
+ return !1;
3456
+ break;
3457
+ case "$gt":
3458
+ if (!(e[r] > i))
3459
+ return !1;
3460
+ break;
3461
+ case "$lt":
3462
+ if (!(e[r] < i))
3463
+ return !1;
3464
+ break;
3465
+ case "$ne":
3466
+ if (e[r] === i)
3467
+ return !1;
3468
+ break;
3469
+ case "$in":
3470
+ if (!Array.isArray(i) || !i.includes(e[r]))
3471
+ return !1;
3472
+ break;
3473
+ case "$nin":
3474
+ if (Array.isArray(i) && i.includes(e[r]))
3475
+ return !1;
3476
+ break;
3477
+ case "$regex":
3478
+ if (!new RegExp(i).test(e[r]))
3479
+ return !1;
3480
+ break;
3481
+ default:
3482
+ if (e[r] !== s)
3483
+ return !1;
3484
+ }
3485
+ else if (e[r] !== s)
3486
+ return !1;
3487
+ return !0;
3488
+ }
3489
+ /**
3490
+ * Compute a single aggregate value over an array of documents.
3491
+ * @private
3492
+ * @param {Array} docs - Array of documents
3493
+ * @param {Object} stage - Aggregate stage descriptor
3494
+ * @returns {number} Computed aggregate value
3495
+ */
3496
+ _computeAggregate(e, t) {
3497
+ const { op: r, field: s } = t;
3498
+ switch (r) {
3499
+ case "count":
3500
+ return e.length;
3501
+ case "sum": {
3502
+ let n = 0;
3503
+ for (const i of e) {
3504
+ const a = Number(i[s]);
3505
+ isNaN(a) || (n += a);
3506
+ }
3507
+ return n;
3508
+ }
3509
+ case "avg": {
3510
+ let n = 0, i = 0;
3511
+ for (const a of e) {
3512
+ const l = Number(a[s]);
3513
+ isNaN(l) || (n += l, i++);
3514
+ }
3515
+ return i > 0 ? n / i : 0;
3516
+ }
3517
+ case "min": {
3518
+ let n = 1 / 0;
3519
+ for (const i of e) {
3520
+ const a = Number(i[s]);
3521
+ !isNaN(a) && a < n && (n = a);
3522
+ }
3523
+ return n === 1 / 0 ? 0 : n;
3524
+ }
3525
+ case "max": {
3526
+ let n = -1 / 0;
3527
+ for (const i of e) {
3528
+ const a = Number(i[s]);
3529
+ !isNaN(a) && a > n && (n = a);
3530
+ }
3531
+ return n === -1 / 0 ? 0 : n;
3532
+ }
3533
+ default:
3534
+ return 0;
3535
+ }
3536
+ }
3537
+ /**
3538
+ * Execute the aggregation pipeline and return results.
3539
+ *
3540
+ * Processing order:
3541
+ * 1. match stages filter the working dataset
3542
+ * 2. group / bucket stages partition data into groups
3543
+ * 3. aggregate stages compute values per group (or globally)
3544
+ * 4. sort / limit are applied to the final result set
3545
+ *
3546
+ * @returns {Object|Array} Aggregation results
3547
+ */
3548
+ execute() {
3549
+ let e = [...this.data];
3550
+ const t = [], r = [];
3551
+ let s = null, n = null;
3552
+ const i = [];
3553
+ for (const o of this.stages)
3554
+ switch (o.type) {
3555
+ case "match":
3556
+ t.push(o);
3557
+ break;
3558
+ case "group":
3559
+ s = o;
3560
+ break;
3561
+ case "bucket":
3562
+ n = o;
3563
+ break;
3564
+ case "aggregate":
3565
+ r.push(o);
3566
+ break;
3567
+ case "sort":
3568
+ case "limit":
3569
+ i.push(o);
3570
+ break;
3571
+ }
3572
+ for (const o of t)
3573
+ e = e.filter((c) => this._matchesQuery(c, o.query));
3574
+ let a = null;
3575
+ if (n) {
3576
+ a = /* @__PURE__ */ new Map();
3577
+ const { timestampField: o, interval: c } = n;
3578
+ for (const h of e) {
3579
+ const g = h[o];
3580
+ if (g == null)
3581
+ continue;
3582
+ const d = new Date(typeof g == "number" ? g * 1e3 : g);
3583
+ if (isNaN(d.getTime()))
3584
+ continue;
3585
+ const m = this._truncateDate(d, c);
3586
+ a.has(m) || a.set(m, []), a.get(m).push(h);
3587
+ }
3588
+ } else if (s) {
3589
+ a = /* @__PURE__ */ new Map();
3590
+ const { field: o } = s;
3591
+ for (const c of e) {
3592
+ const h = c[o] !== void 0 && c[o] !== null ? String(c[o]) : "__null__";
3593
+ a.has(h) || a.set(h, []), a.get(h).push(c);
3594
+ }
3595
+ }
3596
+ let l;
3597
+ if (a) {
3598
+ l = [];
3599
+ for (const [o, c] of a) {
3600
+ const h = { _id: o === "__null__" ? null : o };
3601
+ for (const g of r)
3602
+ h[g.alias] = this._computeAggregate(c, g);
3603
+ l.push(h);
3604
+ }
3605
+ } else if (r.length > 0) {
3606
+ const o = {};
3607
+ for (const c of r)
3608
+ o[c.alias] = this._computeAggregate(e, c);
3609
+ l = o;
3610
+ } else
3611
+ l = e;
3612
+ if (Array.isArray(l))
3613
+ for (const o of i)
3614
+ if (o.type === "sort") {
3615
+ const { field: c, order: h } = o, g = h === "desc" ? -1 : 1;
3616
+ l.sort((d, m) => {
3617
+ const y = d[c], w = m[c];
3618
+ return y < w ? -1 * g : y > w ? 1 * g : 0;
3619
+ });
3620
+ } else
3621
+ o.type === "limit" && (l = l.slice(0, o.n));
3622
+ return l;
3623
+ }
3624
+ }
3625
+ class V {
3626
+ constructor(e, t = {}) {
3627
+ this.gun = e, this.options = {
3628
+ logLevel: "info",
3629
+ enableAutoTransform: !0,
3630
+ ...t
3631
+ }, this.logger = new p({
3632
+ context: "DataTransformer",
3633
+ level: this.options.logLevel
3634
+ }), this.models = /* @__PURE__ */ new Map(), this.transformers = /* @__PURE__ */ new Map(), this.logger.info("DataTransformer initialized", { options: this.options });
3635
+ }
3636
+ /**
3637
+ * Register a data model
3638
+ * @param {string} name - Model name
3639
+ * @param {Object} schema - Model schema
3640
+ * @param {Object} options - Model options
3641
+ * @returns {DataModel} Created model
3642
+ */
3643
+ model(e, t, r = {}) {
3644
+ if (this.models.has(e))
3645
+ return this.models.get(e);
3646
+ const s = new H(e, t, this.gun, this, r);
3647
+ return this.models.set(e, s), this.logger.info("Model registered", { name: e, schema: t }), s;
3648
+ }
3649
+ /**
3650
+ * Register an event transformer
3651
+ * @param {string} eventName - Event name to transform
3652
+ * @param {string} modelName - Target model name
3653
+ * @param {Function} transformFn - Transformation function
3654
+ */
3655
+ registerTransformer(e, t, r) {
3656
+ if (!this.models.has(t))
3657
+ throw new f(`Model '${t}' not found. Register the model first.`);
3658
+ this.transformers.set(e, {
3659
+ modelName: t,
3660
+ transformFn: r
3661
+ }), this.logger.info("Transformer registered", { eventName: e, modelName: t });
3662
+ }
3663
+ /**
3664
+ * Transform and store an event
3665
+ * @param {Object} event - Blockchain event
3666
+ * @returns {Promise<Object|null>} Transformed data or null if no transformer
3667
+ */
3668
+ async transformEvent(e) {
3669
+ if (!e || !e.eventName)
3670
+ return null;
3671
+ const t = this.transformers.get(e.eventName);
3672
+ if (!t)
3673
+ return this.logger.debug("No transformer found for event", { eventName: e.eventName }), null;
3674
+ try {
3675
+ const { modelName: r, transformFn: s } = t, n = this.models.get(r), i = await s(e), a = await n.save(i);
3676
+ return this.logger.info("Event transformed and saved", {
3677
+ eventName: e.eventName,
3678
+ modelName: r,
3679
+ id: a.id
3680
+ }), a;
3681
+ } catch (r) {
3682
+ throw this.logger.error("Failed to transform event", {
3683
+ error: r.message,
3684
+ eventName: e.eventName
3685
+ }), r;
3686
+ }
3687
+ }
3688
+ /**
3689
+ * Get a registered model
3690
+ * @param {string} name - Model name
3691
+ * @returns {DataModel} Model instance
3692
+ */
3693
+ getModel(e) {
3694
+ const t = this.models.get(e);
3695
+ if (!t)
3696
+ throw new f(`Model '${e}' not found`);
3697
+ return t;
3698
+ }
3699
+ /**
3700
+ * Get all registered models
3701
+ * @returns {Map<string, DataModel>} All models
3702
+ */
3703
+ getModels() {
3704
+ return new Map(this.models);
3705
+ }
3706
+ /**
3707
+ * Get transformation statistics
3708
+ * @returns {Object} Statistics
3709
+ */
3710
+ getStats() {
3711
+ return {
3712
+ modelsCount: this.models.size,
3713
+ transformersCount: this.transformers.size,
3714
+ registeredModels: Array.from(this.models.keys()),
3715
+ registeredTransformers: Array.from(this.transformers.keys())
3716
+ };
3717
+ }
3718
+ /**
3719
+ * Create an AggregationPipeline from raw data.
3720
+ * @param {Array} data - Array of documents to aggregate
3721
+ * @returns {AggregationPipeline} A new AggregationPipeline instance
3722
+ */
3723
+ aggregate(e) {
3724
+ return new M(e);
3725
+ }
3726
+ /**
3727
+ * Create a SchemaMigration instance for a model.
3728
+ * @param {string} modelName - Name of the model
3729
+ * @returns {SchemaMigration} A new SchemaMigration instance
3730
+ */
3731
+ migration(e) {
3732
+ return new j(e, this.gun);
3733
+ }
3734
+ }
3735
+ class Q {
3736
+ constructor(e) {
3737
+ this.configManager = new v(e);
3738
+ const t = this.configManager.getAll();
3739
+ this.logger = new p({
3740
+ context: "Magazine",
3741
+ level: t.logLevel || "info"
3742
+ }), this.logger.info("Initializing Magazine", {
3743
+ name: t.name,
3744
+ address: t.address,
3745
+ networkId: t.networkId
3746
+ }), this.retryOptions = this.configManager.getRetryOptions(), this.networkManager = new z(t, this.retryOperation.bind(this)), this.eventStore = new E(t.gun, this.retryOperation.bind(this)), this.eventSyncer = new T(
3747
+ this.networkManager,
3748
+ this.eventStore,
3749
+ this.configManager,
3750
+ this.retryOperation.bind(this)
3751
+ ), this.eventMetadata = new A(this.networkManager, this.logger), this.debugUtils = new R(this, this.logger), this.dataTransformer = new V(
3752
+ this.eventStore.getGunInstance(),
3753
+ {
3754
+ logLevel: t.logLevel,
3755
+ enableAutoTransform: t.enableAutoTransform !== !1
3756
+ }
3757
+ ), this.name = t.name, this.address = t.address, this.networkId = t.networkId, this.abi = t.abi, this.logger.info("Magazine initialized successfully", {
3758
+ name: this.name,
3759
+ address: this.address,
3760
+ networkId: this.networkId,
3761
+ eventCount: Object.keys(this.networkManager.eventsByTopic).length,
3762
+ componentCount: 6,
3763
+ debugModeEnabled: this.debugUtils.isDebugMode(),
3764
+ dataTransformerEnabled: !0
3765
+ });
3766
+ }
3767
+ // Get configuration manager for advanced configuration access
3768
+ getConfigManager() {
3769
+ return this.configManager;
3770
+ }
3771
+ // Get network manager for advanced network operations
3772
+ getNetworkManager() {
3773
+ return this.networkManager;
3774
+ }
3775
+ // Get event store for advanced storage operations
3776
+ getEventStore() {
3777
+ return this.eventStore;
3778
+ }
3779
+ // Get event syncer for advanced synchronization operations
3780
+ getEventSyncer() {
3781
+ return this.eventSyncer;
3782
+ }
3783
+ // Get logger for external logging operations
3784
+ getLogger() {
3785
+ return this.logger;
3786
+ }
3787
+ // Set log level dynamically
3788
+ setLogLevel(e) {
3789
+ this.logger.setLevel(e), this.logger.info("Log level updated", { newLevel: e });
3790
+ }
3791
+ // Retry wrapper for async operations
3792
+ async retryOperation(e, t = "") {
3793
+ const { maxRetries: r, retryDelay: s, timeout: n } = this.retryOptions;
3794
+ let i;
3795
+ this.logger.debug("Starting retry operation", { context: t, maxRetries: r, timeout: n });
3796
+ for (let a = 1; a <= r; a++)
3797
+ try {
3798
+ const l = new Promise(
3799
+ (c, h) => setTimeout(() => h(new Error(`Operation timeout: ${t}`)), n)
3800
+ ), o = await Promise.race([e(), l]);
3801
+ return a > 1 && this.logger.info("Retry operation succeeded", {
3802
+ context: t,
3803
+ attempt: a,
3804
+ maxRetries: r
3805
+ }), o;
3806
+ } catch (l) {
3807
+ if (i = l, this.logger.warn("Retry operation failed", {
3808
+ context: t,
3809
+ attempt: a,
3810
+ maxRetries: r,
3811
+ error: l.message
3812
+ }), a < r) {
3813
+ const o = s * Math.pow(2, a - 1);
3814
+ this.logger.debug("Retrying operation", {
3815
+ context: t,
3816
+ delay: `${o}ms`,
3817
+ nextAttempt: a + 1
3818
+ }), await new Promise((c) => setTimeout(c, o));
3819
+ } else
3820
+ this.logger.error("Retry operation exhausted", {
3821
+ context: t,
3822
+ totalAttempts: r,
3823
+ finalError: l.message,
3824
+ stack: l.stack
3825
+ });
3826
+ }
3827
+ throw i;
3828
+ }
3829
+ // Start syncing events from the blockchain to the magazine
3830
+ startSync() {
3831
+ this.logger.info("Starting automatic sync"), this.stopSync(), this.syncInterval = setInterval(async () => {
3832
+ try {
3833
+ await this.syncEvents();
3834
+ } catch (e) {
3835
+ this.logger.error("Automatic sync error", {
3836
+ error: e.message,
3837
+ stack: e.stack
3838
+ });
3839
+ }
3840
+ }, 5e3), this.syncEvents().catch((e) => {
3841
+ this.logger.error("Initial sync error", {
3842
+ error: e.message,
3843
+ stack: e.stack
3844
+ });
3845
+ }), this.logger.info("Automatic sync started", { interval: "5000ms" });
3846
+ }
3847
+ /**
3848
+ * Start real-time event streaming (requires WebSocket provider)
3849
+ */
3850
+ startRealtimeSync() {
3851
+ return this.eventSyncer.startRealtimeSync();
3852
+ }
3853
+ /**
3854
+ * Stop real-time event streaming
3855
+ */
3856
+ stopRealtimeSync() {
3857
+ return this.eventSyncer.stopRealtimeSync();
3858
+ }
3859
+ /**
3860
+ * Destroy the magazine instance, stopping sync and cleaning up listeners
3861
+ */
3862
+ destroy() {
3863
+ this.stopSync(), this.stopRealtimeSync(), this.eventStore.destroy(), this.logger.info("Magazine instance destroyed");
3864
+ }
3865
+ // Stop syncing events from the blockchain to the magazine
3866
+ stopSync() {
3867
+ this.syncInterval && (this.logger.info("Stopping automatic sync"), clearInterval(this.syncInterval), this.syncInterval = void 0);
3868
+ }
3869
+ // Sync events from the blockchain to the magazine - delegates to EventSyncer
3870
+ async syncEvents() {
3871
+ return this.eventSyncer.syncEvents();
3872
+ }
3873
+ // Sync events from a specific block range
3874
+ async syncEventsFromRange(e, t) {
3875
+ return this.eventSyncer.syncEventsFromRange(e, t);
3876
+ }
3877
+ // Sync events from a specific transaction
3878
+ async syncEventsFromTransaction(e) {
3879
+ return this.eventSyncer.syncEventsFromTransaction(e);
3880
+ }
3881
+ // Get sync status information
3882
+ async getSyncStatus() {
3883
+ return this.eventSyncer.getSyncStatus();
3884
+ }
3885
+ // Get the start block number for syncing events - delegates to EventStore
3886
+ async getStartBlockNumber() {
3887
+ return this.eventStore.getStartBlockNumber();
3888
+ }
3889
+ // Set the start block number for syncing events - delegates to EventStore
3890
+ async setStartBlockNumber(e) {
3891
+ return this.configManager.validateBlockNumber(e, "startBlockNumber"), this.eventStore.setStartBlockNumber(e);
3892
+ }
3893
+ // Get events by name with optional filtering
3894
+ async getEvents(e, t = {}) {
3895
+ return (await this.getAllEvents({
3896
+ filter: { ...t, eventName: e }
3897
+ })).data;
3898
+ }
3899
+ // Get all events with optional filtering and pagination
3900
+ async getAllEvents(e = {}) {
3901
+ return this.eventStore.getAllEvents(e);
3902
+ }
3903
+ /**
3904
+ * Query events using fluent API
3905
+ * @returns {Promise<Object>} Query builder
3906
+ * @example
3907
+ * const results = await magazine.query()
3908
+ * .eventName('Transfer')
3909
+ * .blockRange(1000, 2000)
3910
+ * .where('value', { gte: 1000 })
3911
+ * .orderBy('blockNumber', 'desc')
3912
+ * .execute();
3913
+ */
3914
+ async query() {
3915
+ return this.eventStore.query();
3916
+ }
3917
+ /**
3918
+ * Get events by transaction hash
3919
+ * @param {string} transactionHash - Transaction hash to search for
3920
+ * @returns {Promise<Array>} Events from the transaction
3921
+ */
3922
+ async getEventsByTransactionHash(e) {
3923
+ if (!e || typeof e != "string")
3924
+ throw new Error("Transaction hash must be a non-empty string");
3925
+ return this.eventStore.getEventsByTransactionHash(e);
3926
+ }
3927
+ /**
3928
+ * Get events by block number
3929
+ * @param {number} blockNumber - Block number to search for
3930
+ * @returns {Promise<Array>} Events from the block
3931
+ */
3932
+ async getEventsByBlockNumber(e) {
3933
+ if (!Number.isInteger(e) || e < 0)
3934
+ throw new Error("Block number must be a non-negative integer");
3935
+ return this.eventStore.getEventsByBlockNumber(e);
3936
+ }
3937
+ /**
3938
+ * Create async iterator for events
3939
+ * @param {Object} options - Iterator options
3940
+ * @param {Object} options.filter - Filter criteria
3941
+ * @param {Object} options.sort - Sort options
3942
+ * @param {number} options.pageSize - Items per iteration batch
3943
+ * @returns {AsyncIterator} Async iterator for events
3944
+ * @example
3945
+ * for await (const event of magazine.iterateEvents({ pageSize: 50 })) {
3946
+ * console.log(event);
3947
+ * }
3948
+ */
3949
+ async *iterateEvents(e = {}) {
3950
+ yield* this.eventStore.iterateEvents(e);
3951
+ }
3952
+ // Get network information
3953
+ async getNetworkInfo() {
3954
+ return this.networkManager.getNetworkInfo();
3955
+ }
3956
+ // Validate network and contract
3957
+ async validateNetwork() {
3958
+ return this.networkManager.validateNetwork();
3959
+ }
3960
+ // Get latest block number
3961
+ async getLatestBlockNumber() {
3962
+ return this.networkManager.getLatestBlockNumber();
3963
+ }
3964
+ // Publish the magazine to the decentralized network
3965
+ async publish(e = {}) {
3966
+ const t = this.configManager.validateOptions(e, ["alias", "url"]);
3967
+ if (t.alias && (typeof t.alias != "string" || t.alias.trim().length === 0))
3968
+ throw new Error("alias must be a non-empty string");
3969
+ if (t.url) {
3970
+ if (typeof t.url != "string")
3971
+ throw new Error("url must be a string");
3972
+ try {
3973
+ new URL(t.url);
3974
+ } catch {
3975
+ throw new Error("url must be a valid URL");
3976
+ }
3977
+ }
3978
+ const r = t.alias ? t.alias : this.name.toLowerCase().replace(/\s/g, "-"), s = t.url ? t.url : "https://gunjs.herokuapp.com/gun", n = {
3979
+ name: this.name,
3980
+ address: this.address,
3981
+ networkId: this.networkId,
3982
+ abi: this.abi
3983
+ };
3984
+ return this.eventStore.publishMagazine(r, n, s);
3985
+ }
3986
+ // Subscribe to a magazine on the decentralized network
3987
+ static async subscribe(e, t) {
3988
+ if (!e || typeof e != "string")
3989
+ throw new Error("magazineId must be a non-empty string");
3990
+ if (!t || typeof t != "object")
3991
+ throw new Error("config must be an object");
3992
+ const r = ["gun"];
3993
+ for (const n of r)
3994
+ if (!t[n])
3995
+ throw new Error(`Config field '${n}' is required for subscription`);
3996
+ return new E(t.gun, () => {
3997
+ }).subscribeMagazine(e);
3998
+ }
3999
+ // Read events from the magazine - delegates to EventStore
4000
+ on(e, t) {
4001
+ if (typeof t != "function")
4002
+ throw new Error("callback must be a function");
4003
+ this.eventStore.getGunInstance().get("events").get(e).map().on(t);
4004
+ }
4005
+ /**
4006
+ * Health check endpoint - performs system health checks
4007
+ * @returns {Promise<Object>} Health check results
4008
+ */
4009
+ async healthCheck() {
4010
+ return this.debugUtils.healthCheck();
4011
+ }
4012
+ /**
4013
+ * Get performance metrics
4014
+ * @returns {Promise<Object>} Performance metrics
4015
+ */
4016
+ async getPerformanceMetrics() {
4017
+ return this.debugUtils.getPerformanceReport();
4018
+ }
4019
+ /**
4020
+ * Export debug information
4021
+ * @param {Object} options - Export options
4022
+ * @returns {Promise<Object>} Debug information
4023
+ */
4024
+ async exportDebugInfo(e = {}) {
4025
+ return this.debugUtils.exportDebugData();
4026
+ }
4027
+ /**
4028
+ * Enable or disable debug mode
4029
+ * @param {boolean} enabled - Whether to enable debug mode
4030
+ */
4031
+ setDebugMode(e) {
4032
+ this.debugUtils.setDebugMode(e);
4033
+ }
4034
+ /**
4035
+ * Check if debug mode is enabled
4036
+ * @returns {boolean} Debug mode status
4037
+ */
4038
+ isDebugMode() {
4039
+ return this.debugUtils.isDebugMode();
4040
+ }
4041
+ /**
4042
+ * Get configuration schema documentation
4043
+ * @returns {Object} Schema documentation
4044
+ */
4045
+ getConfigSchema() {
4046
+ return this.configManager.getSchemaDocumentation();
4047
+ }
4048
+ /**
4049
+ * Generate example configuration
4050
+ * @param {Object} options - Generation options
4051
+ * @returns {Object} Example configuration
4052
+ */
4053
+ static generateExampleConfig(e = {}) {
4054
+ return new v({
4055
+ name: "temp",
4056
+ address: "0x0000000000000000000000000000000000000000",
4057
+ abi: [],
4058
+ provider: "http://localhost:8545",
4059
+ networkId: 1
4060
+ }).generateExampleConfig(e);
4061
+ }
4062
+ /**
4063
+ * Validate configuration without creating an instance
4064
+ * @static
4065
+ * @param {Object} config - Configuration to validate
4066
+ * @returns {Object} Validation result
4067
+ */
4068
+ static validateConfig(e) {
4069
+ return v.validateConfiguration(e);
4070
+ }
4071
+ /**
4072
+ * Get compression statistics from the event store
4073
+ * @returns {Promise<Object>} Compression stats
4074
+ */
4075
+ async getCompressionStats() {
4076
+ return this.eventStore.getCompressionStats();
4077
+ }
4078
+ // === Data Transformation API ===
4079
+ /**
4080
+ * Create or get a data model for structured storage
4081
+ * @param {string} name - Model name
4082
+ * @param {Object} schema - Model schema definition
4083
+ * @param {Object} options - Model options
4084
+ * @returns {Object} DataModel instance
4085
+ */
4086
+ model(e, t, r = {}) {
4087
+ return this.dataTransformer.model(e, t, r);
4088
+ }
4089
+ /**
4090
+ * Register an event transformer that converts blockchain events to model data
4091
+ * @param {string} eventName - Event name to transform
4092
+ * @param {string} modelName - Target model name
4093
+ * @param {Function} transformFn - Transformation function
4094
+ */
4095
+ registerTransformer(e, t, r) {
4096
+ return this.dataTransformer.registerTransformer(e, t, r);
4097
+ }
4098
+ /**
4099
+ * Get a registered data model
4100
+ * @param {string} name - Model name
4101
+ * @returns {Object} DataModel instance
4102
+ */
4103
+ getModel(e) {
4104
+ return this.dataTransformer.getModel(e);
4105
+ }
4106
+ /**
4107
+ * Transform an event using registered transformers
4108
+ * @param {Object} event - Blockchain event to transform
4109
+ * @returns {Promise<Object|null>} Transformed data or null
4110
+ */
4111
+ async transformEvent(e) {
4112
+ return this.dataTransformer.transformEvent(e);
4113
+ }
4114
+ /**
4115
+ * Get data transformation statistics
4116
+ * @returns {Object} Transformation stats
4117
+ */
4118
+ getTransformationStats() {
4119
+ return this.dataTransformer.getStats();
4120
+ }
4121
+ /**
4122
+ * Get all registered models
4123
+ * @returns {Map} Map of model name to DataModel instance
4124
+ */
4125
+ getModels() {
4126
+ return this.dataTransformer.getModels();
4127
+ }
4128
+ }
4129
+ export {
4130
+ M as AggregationPipeline,
4131
+ v as ConfigManager,
4132
+ D as DataCompressor,
4133
+ H as DataModel,
4134
+ V as DataTransformer,
4135
+ R as DebugUtils,
4136
+ C as EventFilter,
4137
+ A as EventMetadata,
4138
+ E as EventStore,
4139
+ T as EventSyncer,
4140
+ p as Logger,
4141
+ f as ModelError,
4142
+ z as NetworkManager,
4143
+ J as PaginationHelper,
4144
+ P as Paginator,
4145
+ j as SchemaMigration,
4146
+ B as ValidationError,
4147
+ Q as default
4148
+ };
4149
+ //# sourceMappingURL=magazine.es.js.map