@affectively/aeon 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4632 @@
1
+ import { EventEmitter } from 'eventemitter3';
2
+
3
+ // src/utils/logger.ts
4
+ var consoleLogger = {
5
+ debug: (...args) => {
6
+ console.debug("[AEON:DEBUG]", ...args);
7
+ },
8
+ info: (...args) => {
9
+ console.info("[AEON:INFO]", ...args);
10
+ },
11
+ warn: (...args) => {
12
+ console.warn("[AEON:WARN]", ...args);
13
+ },
14
+ error: (...args) => {
15
+ console.error("[AEON:ERROR]", ...args);
16
+ }
17
+ };
18
+ var noopLogger = {
19
+ debug: () => {
20
+ },
21
+ info: () => {
22
+ },
23
+ warn: () => {
24
+ },
25
+ error: () => {
26
+ }
27
+ };
28
+ var currentLogger = consoleLogger;
29
+ function getLogger() {
30
+ return currentLogger;
31
+ }
32
+ function setLogger(logger9) {
33
+ currentLogger = logger9;
34
+ }
35
+ function resetLogger() {
36
+ currentLogger = consoleLogger;
37
+ }
38
+ function disableLogging() {
39
+ currentLogger = noopLogger;
40
+ }
41
+ function createNamespacedLogger(namespace) {
42
+ const logger9 = getLogger();
43
+ return {
44
+ debug: (...args) => logger9.debug(`[${namespace}]`, ...args),
45
+ info: (...args) => logger9.info(`[${namespace}]`, ...args),
46
+ warn: (...args) => logger9.warn(`[${namespace}]`, ...args),
47
+ error: (...args) => logger9.error(`[${namespace}]`, ...args)
48
+ };
49
+ }
50
+ var logger = {
51
+ debug: (...args) => getLogger().debug(...args),
52
+ info: (...args) => getLogger().info(...args),
53
+ warn: (...args) => getLogger().warn(...args),
54
+ error: (...args) => getLogger().error(...args)
55
+ };
56
+
57
+ // src/versioning/SchemaVersionManager.ts
58
+ var SchemaVersionManager = class {
59
+ versions = /* @__PURE__ */ new Map();
60
+ versionHistory = [];
61
+ compatibilityMatrix = /* @__PURE__ */ new Map();
62
+ currentVersion = null;
63
+ constructor() {
64
+ this.initializeDefaultVersions();
65
+ }
66
+ /**
67
+ * Initialize default versions
68
+ */
69
+ initializeDefaultVersions() {
70
+ const v1_0_0 = {
71
+ major: 1,
72
+ minor: 0,
73
+ patch: 0,
74
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
75
+ description: "Initial schema version",
76
+ breaking: false
77
+ };
78
+ this.registerVersion(v1_0_0);
79
+ this.currentVersion = v1_0_0;
80
+ }
81
+ /**
82
+ * Register a new schema version
83
+ */
84
+ registerVersion(version) {
85
+ const versionString = this.versionToString(version);
86
+ this.versions.set(versionString, version);
87
+ this.versionHistory.push(version);
88
+ logger.debug("[SchemaVersionManager] Version registered", {
89
+ version: versionString,
90
+ breaking: version.breaking,
91
+ description: version.description
92
+ });
93
+ }
94
+ /**
95
+ * Get current version
96
+ */
97
+ getCurrentVersion() {
98
+ if (!this.currentVersion) {
99
+ throw new Error("No current version set");
100
+ }
101
+ return this.currentVersion;
102
+ }
103
+ /**
104
+ * Set current version
105
+ */
106
+ setCurrentVersion(version) {
107
+ if (!this.versions.has(this.versionToString(version))) {
108
+ throw new Error(`Version ${this.versionToString(version)} not registered`);
109
+ }
110
+ this.currentVersion = version;
111
+ logger.debug("[SchemaVersionManager] Current version set", {
112
+ version: this.versionToString(version)
113
+ });
114
+ }
115
+ /**
116
+ * Get version history
117
+ */
118
+ getVersionHistory() {
119
+ return [...this.versionHistory];
120
+ }
121
+ /**
122
+ * Check if version exists
123
+ */
124
+ hasVersion(version) {
125
+ return this.versions.has(this.versionToString(version));
126
+ }
127
+ /**
128
+ * Get version by string (e.g., "1.2.3")
129
+ */
130
+ getVersion(versionString) {
131
+ return this.versions.get(versionString);
132
+ }
133
+ /**
134
+ * Register compatibility rule
135
+ */
136
+ registerCompatibility(rule) {
137
+ if (!this.compatibilityMatrix.has(rule.from)) {
138
+ this.compatibilityMatrix.set(rule.from, []);
139
+ }
140
+ const rules = this.compatibilityMatrix.get(rule.from);
141
+ if (rules) {
142
+ rules.push(rule);
143
+ }
144
+ logger.debug("[SchemaVersionManager] Compatibility rule registered", {
145
+ from: rule.from,
146
+ to: rule.to,
147
+ compatible: rule.compatible,
148
+ requiresMigration: rule.requiresMigration
149
+ });
150
+ }
151
+ /**
152
+ * Check if migration path exists
153
+ */
154
+ canMigrate(fromVersion, toVersion) {
155
+ const fromStr = typeof fromVersion === "string" ? fromVersion : this.versionToString(fromVersion);
156
+ const toStr = typeof toVersion === "string" ? toVersion : this.versionToString(toVersion);
157
+ const rules = this.compatibilityMatrix.get(fromStr) || [];
158
+ return rules.some((r) => r.to === toStr && r.requiresMigration);
159
+ }
160
+ /**
161
+ * Get migration path
162
+ */
163
+ getMigrationPath(fromVersion, toVersion) {
164
+ const path = [];
165
+ let current = fromVersion;
166
+ const maxSteps = 100;
167
+ let steps = 0;
168
+ while (this.compareVersions(current, toVersion) !== 0 && steps < maxSteps) {
169
+ const fromStr = this.versionToString(current);
170
+ const rules = this.compatibilityMatrix.get(fromStr) || [];
171
+ let found = false;
172
+ for (const rule of rules) {
173
+ const nextVersion = this.getVersion(rule.to);
174
+ if (nextVersion) {
175
+ if (this.compareVersions(nextVersion, toVersion) <= 0 || this.compareVersions(current, nextVersion) < this.compareVersions(current, toVersion)) {
176
+ current = nextVersion;
177
+ path.push(current);
178
+ found = true;
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ if (!found) {
184
+ break;
185
+ }
186
+ steps++;
187
+ }
188
+ return path;
189
+ }
190
+ /**
191
+ * Compare two versions
192
+ * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
193
+ */
194
+ compareVersions(v1, v2) {
195
+ const ver1 = typeof v1 === "string" ? this.parseVersion(v1) : v1;
196
+ const ver2 = typeof v2 === "string" ? this.parseVersion(v2) : v2;
197
+ if (ver1.major !== ver2.major) {
198
+ return ver1.major < ver2.major ? -1 : 1;
199
+ }
200
+ if (ver1.minor !== ver2.minor) {
201
+ return ver1.minor < ver2.minor ? -1 : 1;
202
+ }
203
+ if (ver1.patch !== ver2.patch) {
204
+ return ver1.patch < ver2.patch ? -1 : 1;
205
+ }
206
+ return 0;
207
+ }
208
+ /**
209
+ * Parse version string to SchemaVersion
210
+ */
211
+ parseVersion(versionString) {
212
+ const parts = versionString.split(".").map(Number);
213
+ return {
214
+ major: parts[0] || 0,
215
+ minor: parts[1] || 0,
216
+ patch: parts[2] || 0,
217
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
218
+ description: "",
219
+ breaking: false
220
+ };
221
+ }
222
+ /**
223
+ * Create new version
224
+ */
225
+ createVersion(major, minor, patch, description, breaking = false) {
226
+ return {
227
+ major,
228
+ minor,
229
+ patch,
230
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
231
+ description,
232
+ breaking
233
+ };
234
+ }
235
+ /**
236
+ * Convert version to string
237
+ */
238
+ versionToString(version) {
239
+ return `${version.major}.${version.minor}.${version.patch}`;
240
+ }
241
+ /**
242
+ * Get version metadata
243
+ */
244
+ getVersionMetadata(version) {
245
+ const history = this.versionHistory;
246
+ const currentIndex = history.findIndex(
247
+ (v) => this.versionToString(v) === this.versionToString(version)
248
+ );
249
+ return {
250
+ version,
251
+ previousVersion: currentIndex > 0 ? history[currentIndex - 1] : void 0,
252
+ changes: [version.description],
253
+ migrationsRequired: this.canMigrate(
254
+ this.currentVersion || version,
255
+ version
256
+ ) ? [this.versionToString(version)] : [],
257
+ rollbackPossible: currentIndex > 0
258
+ };
259
+ }
260
+ /**
261
+ * Get all registered versions
262
+ */
263
+ getAllVersions() {
264
+ return Array.from(this.versions.values()).sort(
265
+ (a, b) => this.compareVersions(a, b)
266
+ );
267
+ }
268
+ /**
269
+ * Clear all versions (for testing)
270
+ */
271
+ clear() {
272
+ this.versions.clear();
273
+ this.versionHistory = [];
274
+ this.compatibilityMatrix.clear();
275
+ this.currentVersion = null;
276
+ }
277
+ };
278
+
279
+ // src/versioning/MigrationEngine.ts
280
+ var MigrationEngine = class {
281
+ migrations = /* @__PURE__ */ new Map();
282
+ executedMigrations = [];
283
+ state = {
284
+ currentVersion: "1.0.0",
285
+ appliedMigrations: [],
286
+ failedMigrations: [],
287
+ lastMigrationTime: (/* @__PURE__ */ new Date()).toISOString(),
288
+ totalMigrationsRun: 0
289
+ };
290
+ /**
291
+ * Register a migration
292
+ */
293
+ registerMigration(migration) {
294
+ this.migrations.set(migration.id, migration);
295
+ logger.debug("[MigrationEngine] Migration registered", {
296
+ id: migration.id,
297
+ version: migration.version,
298
+ name: migration.name
299
+ });
300
+ }
301
+ /**
302
+ * Execute a migration
303
+ */
304
+ async executeMigration(migrationId, data) {
305
+ const migration = this.migrations.get(migrationId);
306
+ if (!migration) {
307
+ throw new Error(`Migration ${migrationId} not found`);
308
+ }
309
+ const startTime = Date.now();
310
+ const result = {
311
+ migrationId,
312
+ success: false,
313
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
314
+ duration: 0,
315
+ itemsAffected: 0,
316
+ errors: []
317
+ };
318
+ try {
319
+ logger.debug("[MigrationEngine] Executing migration", {
320
+ id: migrationId,
321
+ version: migration.version
322
+ });
323
+ migration.up(data);
324
+ result.success = true;
325
+ result.itemsAffected = Array.isArray(data) ? data.length : 1;
326
+ result.duration = Date.now() - startTime;
327
+ this.state.appliedMigrations.push(migrationId);
328
+ this.state.currentVersion = migration.version;
329
+ this.state.totalMigrationsRun++;
330
+ this.state.lastMigrationTime = result.timestamp;
331
+ this.executedMigrations.push(result);
332
+ logger.debug("[MigrationEngine] Migration executed successfully", {
333
+ id: migrationId,
334
+ duration: result.duration,
335
+ itemsAffected: result.itemsAffected
336
+ });
337
+ return result;
338
+ } catch (error) {
339
+ result.errors = [error instanceof Error ? error.message : String(error)];
340
+ this.state.failedMigrations.push(migrationId);
341
+ this.executedMigrations.push(result);
342
+ logger.error("[MigrationEngine] Migration failed", {
343
+ id: migrationId,
344
+ error: result.errors[0]
345
+ });
346
+ throw new Error(`Migration ${migrationId} failed: ${result.errors[0]}`);
347
+ }
348
+ }
349
+ /**
350
+ * Rollback a migration
351
+ */
352
+ async rollbackMigration(migrationId, data) {
353
+ const migration = this.migrations.get(migrationId);
354
+ if (!migration) {
355
+ throw new Error(`Migration ${migrationId} not found`);
356
+ }
357
+ if (!migration.down) {
358
+ throw new Error(`Migration ${migrationId} does not support rollback`);
359
+ }
360
+ const startTime = Date.now();
361
+ const result = {
362
+ migrationId,
363
+ success: false,
364
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
365
+ duration: 0,
366
+ itemsAffected: 0,
367
+ errors: []
368
+ };
369
+ try {
370
+ logger.debug("[MigrationEngine] Rolling back migration", {
371
+ id: migrationId,
372
+ version: migration.version
373
+ });
374
+ migration.down(data);
375
+ result.success = true;
376
+ result.itemsAffected = Array.isArray(data) ? data.length : 1;
377
+ result.duration = Date.now() - startTime;
378
+ this.state.appliedMigrations = this.state.appliedMigrations.filter(
379
+ (id) => id !== migrationId
380
+ );
381
+ this.executedMigrations.push(result);
382
+ logger.debug("[MigrationEngine] Migration rolled back", {
383
+ id: migrationId,
384
+ duration: result.duration
385
+ });
386
+ return result;
387
+ } catch (error) {
388
+ result.errors = [error instanceof Error ? error.message : String(error)];
389
+ this.executedMigrations.push(result);
390
+ logger.error("[MigrationEngine] Rollback failed", {
391
+ id: migrationId,
392
+ error: result.errors[0]
393
+ });
394
+ throw new Error(`Rollback for ${migrationId} failed: ${result.errors[0]}`);
395
+ }
396
+ }
397
+ /**
398
+ * Get migration state
399
+ */
400
+ getState() {
401
+ return { ...this.state };
402
+ }
403
+ /**
404
+ * Get migration execution history
405
+ */
406
+ getExecutionHistory() {
407
+ return [...this.executedMigrations];
408
+ }
409
+ /**
410
+ * Get migration by ID
411
+ */
412
+ getMigration(migrationId) {
413
+ return this.migrations.get(migrationId);
414
+ }
415
+ /**
416
+ * Get all registered migrations
417
+ */
418
+ getAllMigrations() {
419
+ return Array.from(this.migrations.values());
420
+ }
421
+ /**
422
+ * Get applied migrations
423
+ */
424
+ getAppliedMigrations() {
425
+ return [...this.state.appliedMigrations];
426
+ }
427
+ /**
428
+ * Get failed migrations
429
+ */
430
+ getFailedMigrations() {
431
+ return [...this.state.failedMigrations];
432
+ }
433
+ /**
434
+ * Get pending migrations
435
+ */
436
+ getPendingMigrations() {
437
+ return this.getAllMigrations().filter(
438
+ (m) => !this.state.appliedMigrations.includes(m.id)
439
+ );
440
+ }
441
+ /**
442
+ * Get migration statistics
443
+ */
444
+ getStatistics() {
445
+ const successful = this.executedMigrations.filter((m) => m.success).length;
446
+ const failed = this.executedMigrations.filter((m) => !m.success).length;
447
+ const totalDuration = this.executedMigrations.reduce((sum, m) => sum + m.duration, 0);
448
+ const totalAffected = this.executedMigrations.reduce((sum, m) => sum + m.itemsAffected, 0);
449
+ return {
450
+ totalExecuted: this.executedMigrations.length,
451
+ successful,
452
+ failed,
453
+ successRate: this.executedMigrations.length > 0 ? successful / this.executedMigrations.length * 100 : 0,
454
+ totalDurationMs: totalDuration,
455
+ averageDurationMs: this.executedMigrations.length > 0 ? totalDuration / this.executedMigrations.length : 0,
456
+ totalAffected
457
+ };
458
+ }
459
+ /**
460
+ * Clear history (for testing)
461
+ */
462
+ clear() {
463
+ this.migrations.clear();
464
+ this.executedMigrations = [];
465
+ this.state = {
466
+ currentVersion: "1.0.0",
467
+ appliedMigrations: [],
468
+ failedMigrations: [],
469
+ lastMigrationTime: (/* @__PURE__ */ new Date()).toISOString(),
470
+ totalMigrationsRun: 0
471
+ };
472
+ }
473
+ };
474
+
475
+ // src/versioning/DataTransformer.ts
476
+ var DataTransformer = class {
477
+ rules = /* @__PURE__ */ new Map();
478
+ transformationHistory = [];
479
+ /**
480
+ * Register a transformation rule
481
+ */
482
+ registerRule(rule) {
483
+ this.rules.set(rule.field, rule);
484
+ logger.debug("[DataTransformer] Rule registered", {
485
+ field: rule.field,
486
+ required: rule.required,
487
+ hasDefault: rule.defaultValue !== void 0
488
+ });
489
+ }
490
+ /**
491
+ * Transform a single field value
492
+ */
493
+ transformField(field, value) {
494
+ const rule = this.rules.get(field);
495
+ if (!rule) {
496
+ return value;
497
+ }
498
+ try {
499
+ return rule.transformer(value);
500
+ } catch (error) {
501
+ if (rule.required) {
502
+ throw new Error(`Failed to transform required field ${field}: ${error instanceof Error ? error.message : String(error)}`);
503
+ }
504
+ return rule.defaultValue !== void 0 ? rule.defaultValue : value;
505
+ }
506
+ }
507
+ /**
508
+ * Transform a single object
509
+ */
510
+ transformObject(data) {
511
+ const transformed = {};
512
+ for (const [key, value] of Object.entries(data)) {
513
+ try {
514
+ transformed[key] = this.transformField(key, value);
515
+ } catch (error) {
516
+ logger.warn("[DataTransformer] Field transformation failed", {
517
+ field: key,
518
+ error: error instanceof Error ? error.message : String(error)
519
+ });
520
+ const rule = this.rules.get(key);
521
+ if (!rule || !rule.required) {
522
+ transformed[key] = value;
523
+ }
524
+ }
525
+ }
526
+ return transformed;
527
+ }
528
+ /**
529
+ * Transform a collection of items
530
+ */
531
+ transformCollection(items) {
532
+ const startTime = Date.now();
533
+ const result = {
534
+ success: true,
535
+ itemsTransformed: 0,
536
+ itemsFailed: 0,
537
+ errors: [],
538
+ warnings: [],
539
+ duration: 0
540
+ };
541
+ for (let i = 0; i < items.length; i++) {
542
+ const item = items[i];
543
+ try {
544
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
545
+ this.transformObject(item);
546
+ result.itemsTransformed++;
547
+ } else {
548
+ result.warnings.push(`Item ${i} is not a transformable object`);
549
+ }
550
+ } catch (error) {
551
+ result.errors.push({
552
+ item,
553
+ error: error instanceof Error ? error.message : String(error)
554
+ });
555
+ result.itemsFailed++;
556
+ }
557
+ }
558
+ result.duration = Date.now() - startTime;
559
+ result.success = result.itemsFailed === 0;
560
+ this.transformationHistory.push(result);
561
+ logger.debug("[DataTransformer] Collection transformed", {
562
+ total: items.length,
563
+ transformed: result.itemsTransformed,
564
+ failed: result.itemsFailed,
565
+ duration: result.duration
566
+ });
567
+ return result;
568
+ }
569
+ /**
570
+ * Validate transformed data
571
+ */
572
+ validateTransformation(original, transformed) {
573
+ const issues = [];
574
+ if (original.length !== transformed.length) {
575
+ issues.push(`Item count mismatch: ${original.length} -> ${transformed.length}`);
576
+ }
577
+ for (let i = 0; i < Math.min(original.length, transformed.length); i++) {
578
+ const orig = original[i];
579
+ const trans = transformed[i];
580
+ if (!this.validateItem(orig, trans)) {
581
+ issues.push(`Item ${i} validation failed`);
582
+ }
583
+ }
584
+ return {
585
+ valid: issues.length === 0,
586
+ issues
587
+ };
588
+ }
589
+ /**
590
+ * Validate a single item transformation
591
+ */
592
+ validateItem(original, transformed) {
593
+ if (original === null || original === void 0) {
594
+ return true;
595
+ }
596
+ if (typeof original === "object" && typeof transformed !== "object") {
597
+ return false;
598
+ }
599
+ return true;
600
+ }
601
+ /**
602
+ * Get transformation history
603
+ */
604
+ getTransformationHistory() {
605
+ return [...this.transformationHistory];
606
+ }
607
+ /**
608
+ * Get transformation statistics
609
+ */
610
+ getStatistics() {
611
+ const totalTransformed = this.transformationHistory.reduce(
612
+ (sum, r) => sum + r.itemsTransformed,
613
+ 0
614
+ );
615
+ const totalFailed = this.transformationHistory.reduce(
616
+ (sum, r) => sum + r.itemsFailed,
617
+ 0
618
+ );
619
+ const totalDuration = this.transformationHistory.reduce(
620
+ (sum, r) => sum + r.duration,
621
+ 0
622
+ );
623
+ return {
624
+ totalBatches: this.transformationHistory.length,
625
+ totalTransformed,
626
+ totalFailed,
627
+ successRate: totalTransformed + totalFailed > 0 ? totalTransformed / (totalTransformed + totalFailed) * 100 : 0,
628
+ totalDurationMs: totalDuration,
629
+ averageBatchDurationMs: this.transformationHistory.length > 0 ? totalDuration / this.transformationHistory.length : 0
630
+ };
631
+ }
632
+ /**
633
+ * Get registered rules
634
+ */
635
+ getRules() {
636
+ return Array.from(this.rules.values());
637
+ }
638
+ /**
639
+ * Get rule for field
640
+ */
641
+ getRule(field) {
642
+ return this.rules.get(field);
643
+ }
644
+ /**
645
+ * Clear all rules (for testing)
646
+ */
647
+ clearRules() {
648
+ this.rules.clear();
649
+ }
650
+ /**
651
+ * Clear history (for testing)
652
+ */
653
+ clearHistory() {
654
+ this.transformationHistory = [];
655
+ }
656
+ /**
657
+ * Clear all state (for testing)
658
+ */
659
+ clear() {
660
+ this.clearRules();
661
+ this.clearHistory();
662
+ }
663
+ };
664
+
665
+ // src/versioning/MigrationTracker.ts
666
+ var MigrationTracker = class {
667
+ migrations = [];
668
+ snapshots = /* @__PURE__ */ new Map();
669
+ /**
670
+ * Track a new migration
671
+ */
672
+ recordMigration(record) {
673
+ this.migrations.push({ ...record });
674
+ logger.debug("[MigrationTracker] Migration recorded", {
675
+ id: record.id,
676
+ migrationId: record.migrationId,
677
+ version: record.version,
678
+ status: record.status
679
+ });
680
+ }
681
+ /**
682
+ * Track migration with snapshot
683
+ */
684
+ trackMigration(migrationId, version, beforeHash, afterHash, itemCount, duration, itemsAffected, appliedBy = "system") {
685
+ const record = {
686
+ id: `${migrationId}-${Date.now()}`,
687
+ migrationId,
688
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
689
+ version,
690
+ direction: "up",
691
+ status: "applied",
692
+ duration,
693
+ itemsAffected,
694
+ dataSnapshot: {
695
+ beforeHash,
696
+ afterHash,
697
+ itemCount
698
+ },
699
+ appliedBy
700
+ };
701
+ this.recordMigration(record);
702
+ this.snapshots.set(record.id, {
703
+ beforeHash,
704
+ afterHash,
705
+ itemCount
706
+ });
707
+ }
708
+ /**
709
+ * Get all migration records
710
+ */
711
+ getMigrations() {
712
+ return this.migrations.map((m) => ({ ...m }));
713
+ }
714
+ /**
715
+ * Get migrations for a specific version
716
+ */
717
+ getMigrationsForVersion(version) {
718
+ return this.migrations.filter((m) => m.version === version);
719
+ }
720
+ /**
721
+ * Get migration by ID
722
+ */
723
+ getMigration(id) {
724
+ return this.migrations.find((m) => m.id === id);
725
+ }
726
+ /**
727
+ * Check if can rollback
728
+ */
729
+ canRollback(fromVersion, toVersion) {
730
+ const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
731
+ const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
732
+ if (fromIndex === -1 || toIndex === -1) {
733
+ return false;
734
+ }
735
+ if (toIndex >= fromIndex) {
736
+ return false;
737
+ }
738
+ for (let i = fromIndex; i > toIndex; i--) {
739
+ if (!this.migrations[i]?.dataSnapshot) {
740
+ return false;
741
+ }
742
+ }
743
+ return true;
744
+ }
745
+ /**
746
+ * Get rollback path
747
+ */
748
+ getRollbackPath(fromVersion, toVersion) {
749
+ const canRollback = this.canRollback(fromVersion, toVersion);
750
+ const path = [];
751
+ const affectedVersions = [];
752
+ let estimatedDuration = 0;
753
+ if (canRollback) {
754
+ const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
755
+ const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
756
+ for (let i = fromIndex; i > toIndex; i--) {
757
+ const migration = this.migrations[i];
758
+ if (migration) {
759
+ path.push(migration.migrationId);
760
+ affectedVersions.push(migration.version);
761
+ estimatedDuration += migration.duration;
762
+ }
763
+ }
764
+ }
765
+ return {
766
+ path,
767
+ canRollback,
768
+ affectedVersions,
769
+ estimatedDuration
770
+ };
771
+ }
772
+ /**
773
+ * Get applied migrations
774
+ */
775
+ getAppliedMigrations() {
776
+ return this.migrations.filter((m) => m.status === "applied");
777
+ }
778
+ /**
779
+ * Get failed migrations
780
+ */
781
+ getFailedMigrations() {
782
+ return this.migrations.filter((m) => m.status === "failed");
783
+ }
784
+ /**
785
+ * Get pending migrations
786
+ */
787
+ getPendingMigrations() {
788
+ return this.migrations.filter((m) => m.status === "pending");
789
+ }
790
+ /**
791
+ * Get latest migration
792
+ */
793
+ getLatestMigration() {
794
+ return this.migrations[this.migrations.length - 1];
795
+ }
796
+ /**
797
+ * Get migration timeline
798
+ */
799
+ getTimeline() {
800
+ return this.migrations.map((m) => ({
801
+ timestamp: m.timestamp,
802
+ version: m.version,
803
+ status: m.status
804
+ }));
805
+ }
806
+ /**
807
+ * Get migration statistics
808
+ */
809
+ getStatistics() {
810
+ const applied = this.migrations.filter((m) => m.status === "applied").length;
811
+ const failed = this.migrations.filter((m) => m.status === "failed").length;
812
+ const pending = this.migrations.filter((m) => m.status === "pending").length;
813
+ const rolledBack = this.migrations.filter((m) => m.status === "rolled-back").length;
814
+ const totalDuration = this.migrations.reduce((sum, m) => sum + m.duration, 0);
815
+ const totalAffected = this.migrations.reduce((sum, m) => sum + m.itemsAffected, 0);
816
+ return {
817
+ total: this.migrations.length,
818
+ applied,
819
+ failed,
820
+ pending,
821
+ rolledBack,
822
+ successRate: this.migrations.length > 0 ? applied / this.migrations.length * 100 : 0,
823
+ totalDurationMs: totalDuration,
824
+ averageDurationMs: this.migrations.length > 0 ? totalDuration / this.migrations.length : 0,
825
+ totalItemsAffected: totalAffected
826
+ };
827
+ }
828
+ /**
829
+ * Get audit trail
830
+ */
831
+ getAuditTrail(migrationId) {
832
+ const filtered = migrationId ? this.migrations.filter((m) => m.migrationId === migrationId) : this.migrations;
833
+ return filtered.map((m) => ({
834
+ id: m.id,
835
+ timestamp: m.timestamp,
836
+ migrationId: m.migrationId,
837
+ version: m.version,
838
+ status: m.status,
839
+ appliedBy: m.appliedBy,
840
+ duration: m.duration,
841
+ itemsAffected: m.itemsAffected,
842
+ error: m.errorMessage
843
+ }));
844
+ }
845
+ /**
846
+ * Get data snapshot for recovery
847
+ */
848
+ getSnapshot(recordId) {
849
+ return this.snapshots.get(recordId);
850
+ }
851
+ /**
852
+ * Update migration status
853
+ */
854
+ updateMigrationStatus(recordId, status, error) {
855
+ const migration = this.migrations.find((m) => m.id === recordId);
856
+ if (migration) {
857
+ migration.status = status;
858
+ if (error) {
859
+ migration.errorMessage = error;
860
+ }
861
+ logger.debug("[MigrationTracker] Migration status updated", {
862
+ recordId,
863
+ status,
864
+ hasError: !!error
865
+ });
866
+ }
867
+ }
868
+ /**
869
+ * Clear history (for testing)
870
+ */
871
+ clear() {
872
+ this.migrations = [];
873
+ this.snapshots.clear();
874
+ }
875
+ /**
876
+ * Get total migrations tracked
877
+ */
878
+ getTotalMigrations() {
879
+ return this.migrations.length;
880
+ }
881
+ /**
882
+ * Find migrations by time range
883
+ */
884
+ getMigrationsByTimeRange(startTime, endTime) {
885
+ const start = new Date(startTime).getTime();
886
+ const end = new Date(endTime).getTime();
887
+ return this.migrations.filter((m) => {
888
+ const time = new Date(m.timestamp).getTime();
889
+ return time >= start && time <= end;
890
+ });
891
+ }
892
+ };
893
+ var SyncCoordinator = class extends EventEmitter {
894
+ nodes = /* @__PURE__ */ new Map();
895
+ sessions = /* @__PURE__ */ new Map();
896
+ syncEvents = [];
897
+ nodeHeartbeats = /* @__PURE__ */ new Map();
898
+ heartbeatInterval = null;
899
+ // Crypto support
900
+ cryptoProvider = null;
901
+ nodesByDID = /* @__PURE__ */ new Map();
902
+ // DID -> nodeId
903
+ constructor() {
904
+ super();
905
+ }
906
+ /**
907
+ * Configure cryptographic provider for authenticated sync
908
+ */
909
+ configureCrypto(provider) {
910
+ this.cryptoProvider = provider;
911
+ logger.debug("[SyncCoordinator] Crypto configured", {
912
+ initialized: provider.isInitialized()
913
+ });
914
+ }
915
+ /**
916
+ * Check if crypto is configured
917
+ */
918
+ isCryptoEnabled() {
919
+ return this.cryptoProvider !== null && this.cryptoProvider.isInitialized();
920
+ }
921
+ /**
922
+ * Register a node with DID-based identity
923
+ */
924
+ async registerAuthenticatedNode(nodeInfo) {
925
+ const node = {
926
+ ...nodeInfo
927
+ };
928
+ this.nodes.set(node.id, node);
929
+ this.nodeHeartbeats.set(node.id, Date.now());
930
+ this.nodesByDID.set(nodeInfo.did, node.id);
931
+ if (this.cryptoProvider) {
932
+ await this.cryptoProvider.registerRemoteNode({
933
+ id: node.id,
934
+ did: nodeInfo.did,
935
+ publicSigningKey: nodeInfo.publicSigningKey,
936
+ publicEncryptionKey: nodeInfo.publicEncryptionKey
937
+ });
938
+ }
939
+ const event = {
940
+ type: "node-joined",
941
+ nodeId: node.id,
942
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
943
+ data: { did: nodeInfo.did, authenticated: true }
944
+ };
945
+ this.syncEvents.push(event);
946
+ this.emit("node-joined", node);
947
+ logger.debug("[SyncCoordinator] Authenticated node registered", {
948
+ nodeId: node.id,
949
+ did: nodeInfo.did,
950
+ version: node.version
951
+ });
952
+ return node;
953
+ }
954
+ /**
955
+ * Get node by DID
956
+ */
957
+ getNodeByDID(did) {
958
+ const nodeId = this.nodesByDID.get(did);
959
+ if (!nodeId) return void 0;
960
+ return this.nodes.get(nodeId);
961
+ }
962
+ /**
963
+ * Get all authenticated nodes (nodes with DIDs)
964
+ */
965
+ getAuthenticatedNodes() {
966
+ return Array.from(this.nodes.values()).filter((n) => n.did);
967
+ }
968
+ /**
969
+ * Create an authenticated sync session with UCAN-based authorization
970
+ */
971
+ async createAuthenticatedSyncSession(initiatorDID, participantDIDs, options) {
972
+ const initiatorNodeId = this.nodesByDID.get(initiatorDID);
973
+ if (!initiatorNodeId) {
974
+ throw new Error(`Initiator node with DID ${initiatorDID} not found`);
975
+ }
976
+ const participantIds = [];
977
+ for (const did of participantDIDs) {
978
+ const nodeId = this.nodesByDID.get(did);
979
+ if (nodeId) {
980
+ participantIds.push(nodeId);
981
+ }
982
+ }
983
+ let sessionToken;
984
+ if (this.cryptoProvider && this.cryptoProvider.isInitialized()) {
985
+ const capabilities = (options?.requiredCapabilities || ["aeon:sync:read", "aeon:sync:write"]).map((cap) => ({ can: cap, with: "*" }));
986
+ if (participantDIDs.length > 0) {
987
+ sessionToken = await this.cryptoProvider.createUCAN(
988
+ participantDIDs[0],
989
+ capabilities,
990
+ { expirationSeconds: 3600 }
991
+ // 1 hour
992
+ );
993
+ }
994
+ }
995
+ const session = {
996
+ id: `sync-${Date.now()}-${Math.random().toString(36).slice(2)}`,
997
+ initiatorId: initiatorNodeId,
998
+ participantIds,
999
+ status: "pending",
1000
+ startTime: (/* @__PURE__ */ new Date()).toISOString(),
1001
+ itemsSynced: 0,
1002
+ itemsFailed: 0,
1003
+ conflictsDetected: 0,
1004
+ initiatorDID,
1005
+ participantDIDs,
1006
+ encryptionMode: options?.encryptionMode || "none",
1007
+ requiredCapabilities: options?.requiredCapabilities,
1008
+ sessionToken
1009
+ };
1010
+ this.sessions.set(session.id, session);
1011
+ const event = {
1012
+ type: "sync-started",
1013
+ sessionId: session.id,
1014
+ nodeId: initiatorNodeId,
1015
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1016
+ data: {
1017
+ authenticated: true,
1018
+ initiatorDID,
1019
+ participantCount: participantDIDs.length,
1020
+ encryptionMode: session.encryptionMode
1021
+ }
1022
+ };
1023
+ this.syncEvents.push(event);
1024
+ this.emit("sync-started", session);
1025
+ logger.debug("[SyncCoordinator] Authenticated sync session created", {
1026
+ sessionId: session.id,
1027
+ initiatorDID,
1028
+ participants: participantDIDs.length,
1029
+ encryptionMode: session.encryptionMode
1030
+ });
1031
+ return session;
1032
+ }
1033
+ /**
1034
+ * Verify a node's UCAN capabilities for a session
1035
+ */
1036
+ async verifyNodeCapabilities(sessionId, nodeDID, token) {
1037
+ if (!this.cryptoProvider) {
1038
+ return { authorized: true };
1039
+ }
1040
+ const session = this.sessions.get(sessionId);
1041
+ if (!session) {
1042
+ return { authorized: false, error: `Session ${sessionId} not found` };
1043
+ }
1044
+ const result = await this.cryptoProvider.verifyUCAN(token, {
1045
+ requiredCapabilities: session.requiredCapabilities?.map((cap) => ({
1046
+ can: cap,
1047
+ with: "*"
1048
+ }))
1049
+ });
1050
+ if (!result.authorized) {
1051
+ logger.warn("[SyncCoordinator] Node capability verification failed", {
1052
+ sessionId,
1053
+ nodeDID,
1054
+ error: result.error
1055
+ });
1056
+ }
1057
+ return result;
1058
+ }
1059
+ /**
1060
+ * Register a node in the cluster
1061
+ */
1062
+ registerNode(node) {
1063
+ this.nodes.set(node.id, node);
1064
+ this.nodeHeartbeats.set(node.id, Date.now());
1065
+ const event = {
1066
+ type: "node-joined",
1067
+ nodeId: node.id,
1068
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1069
+ };
1070
+ this.syncEvents.push(event);
1071
+ this.emit("node-joined", node);
1072
+ logger.debug("[SyncCoordinator] Node registered", {
1073
+ nodeId: node.id,
1074
+ address: node.address,
1075
+ version: node.version
1076
+ });
1077
+ }
1078
+ /**
1079
+ * Deregister a node from the cluster
1080
+ */
1081
+ deregisterNode(nodeId) {
1082
+ const node = this.nodes.get(nodeId);
1083
+ if (!node) {
1084
+ throw new Error(`Node ${nodeId} not found`);
1085
+ }
1086
+ this.nodes.delete(nodeId);
1087
+ this.nodeHeartbeats.delete(nodeId);
1088
+ const event = {
1089
+ type: "node-left",
1090
+ nodeId,
1091
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1092
+ };
1093
+ this.syncEvents.push(event);
1094
+ this.emit("node-left", node);
1095
+ logger.debug("[SyncCoordinator] Node deregistered", { nodeId });
1096
+ }
1097
+ /**
1098
+ * Create a new sync session
1099
+ */
1100
+ createSyncSession(initiatorId, participantIds) {
1101
+ const node = this.nodes.get(initiatorId);
1102
+ if (!node) {
1103
+ throw new Error(`Initiator node ${initiatorId} not found`);
1104
+ }
1105
+ const session = {
1106
+ id: `sync-${Date.now()}-${Math.random().toString(36).slice(2)}`,
1107
+ initiatorId,
1108
+ participantIds,
1109
+ status: "pending",
1110
+ startTime: (/* @__PURE__ */ new Date()).toISOString(),
1111
+ itemsSynced: 0,
1112
+ itemsFailed: 0,
1113
+ conflictsDetected: 0
1114
+ };
1115
+ this.sessions.set(session.id, session);
1116
+ const event = {
1117
+ type: "sync-started",
1118
+ sessionId: session.id,
1119
+ nodeId: initiatorId,
1120
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1121
+ };
1122
+ this.syncEvents.push(event);
1123
+ this.emit("sync-started", session);
1124
+ logger.debug("[SyncCoordinator] Sync session created", {
1125
+ sessionId: session.id,
1126
+ initiator: initiatorId,
1127
+ participants: participantIds.length
1128
+ });
1129
+ return session;
1130
+ }
1131
+ /**
1132
+ * Update sync session
1133
+ */
1134
+ updateSyncSession(sessionId, updates) {
1135
+ const session = this.sessions.get(sessionId);
1136
+ if (!session) {
1137
+ throw new Error(`Session ${sessionId} not found`);
1138
+ }
1139
+ Object.assign(session, updates);
1140
+ if (updates.status === "completed" || updates.status === "failed") {
1141
+ session.endTime = (/* @__PURE__ */ new Date()).toISOString();
1142
+ const event = {
1143
+ type: "sync-completed",
1144
+ sessionId,
1145
+ nodeId: session.initiatorId,
1146
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1147
+ data: { status: updates.status, itemsSynced: session.itemsSynced }
1148
+ };
1149
+ this.syncEvents.push(event);
1150
+ this.emit("sync-completed", session);
1151
+ }
1152
+ logger.debug("[SyncCoordinator] Sync session updated", {
1153
+ sessionId,
1154
+ status: session.status,
1155
+ itemsSynced: session.itemsSynced
1156
+ });
1157
+ }
1158
+ /**
1159
+ * Record a conflict during sync
1160
+ */
1161
+ recordConflict(sessionId, nodeId, conflictData) {
1162
+ const session = this.sessions.get(sessionId);
1163
+ if (session) {
1164
+ session.conflictsDetected++;
1165
+ const event = {
1166
+ type: "conflict-detected",
1167
+ sessionId,
1168
+ nodeId,
1169
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1170
+ data: conflictData
1171
+ };
1172
+ this.syncEvents.push(event);
1173
+ this.emit("conflict-detected", { session, nodeId, conflictData });
1174
+ logger.debug("[SyncCoordinator] Conflict recorded", {
1175
+ sessionId,
1176
+ nodeId,
1177
+ totalConflicts: session.conflictsDetected
1178
+ });
1179
+ }
1180
+ }
1181
+ /**
1182
+ * Update node status
1183
+ */
1184
+ updateNodeStatus(nodeId, status) {
1185
+ const node = this.nodes.get(nodeId);
1186
+ if (!node) {
1187
+ throw new Error(`Node ${nodeId} not found`);
1188
+ }
1189
+ node.status = status;
1190
+ this.nodeHeartbeats.set(nodeId, Date.now());
1191
+ logger.debug("[SyncCoordinator] Node status updated", {
1192
+ nodeId,
1193
+ status
1194
+ });
1195
+ }
1196
+ /**
1197
+ * Record heartbeat from node
1198
+ */
1199
+ recordHeartbeat(nodeId) {
1200
+ const node = this.nodes.get(nodeId);
1201
+ if (!node) {
1202
+ return;
1203
+ }
1204
+ node.lastHeartbeat = (/* @__PURE__ */ new Date()).toISOString();
1205
+ this.nodeHeartbeats.set(nodeId, Date.now());
1206
+ }
1207
+ /**
1208
+ * Get all nodes
1209
+ */
1210
+ getNodes() {
1211
+ return Array.from(this.nodes.values());
1212
+ }
1213
+ /**
1214
+ * Get node by ID
1215
+ */
1216
+ getNode(nodeId) {
1217
+ return this.nodes.get(nodeId);
1218
+ }
1219
+ /**
1220
+ * Get online nodes
1221
+ */
1222
+ getOnlineNodes() {
1223
+ return Array.from(this.nodes.values()).filter((n) => n.status === "online");
1224
+ }
1225
+ /**
1226
+ * Get nodes by capability
1227
+ */
1228
+ getNodesByCapability(capability) {
1229
+ return Array.from(this.nodes.values()).filter(
1230
+ (n) => n.capabilities.includes(capability)
1231
+ );
1232
+ }
1233
+ /**
1234
+ * Get sync session
1235
+ */
1236
+ getSyncSession(sessionId) {
1237
+ return this.sessions.get(sessionId);
1238
+ }
1239
+ /**
1240
+ * Get all sync sessions
1241
+ */
1242
+ getAllSyncSessions() {
1243
+ return Array.from(this.sessions.values());
1244
+ }
1245
+ /**
1246
+ * Get active sync sessions
1247
+ */
1248
+ getActiveSyncSessions() {
1249
+ return Array.from(this.sessions.values()).filter((s) => s.status === "active");
1250
+ }
1251
+ /**
1252
+ * Get sessions for a node
1253
+ */
1254
+ getSessionsForNode(nodeId) {
1255
+ return Array.from(this.sessions.values()).filter(
1256
+ (s) => s.initiatorId === nodeId || s.participantIds.includes(nodeId)
1257
+ );
1258
+ }
1259
+ /**
1260
+ * Get sync statistics
1261
+ */
1262
+ getStatistics() {
1263
+ const sessions = Array.from(this.sessions.values());
1264
+ const completed = sessions.filter((s) => s.status === "completed").length;
1265
+ const failed = sessions.filter((s) => s.status === "failed").length;
1266
+ const active = sessions.filter((s) => s.status === "active").length;
1267
+ const totalItemsSynced = sessions.reduce((sum, s) => sum + s.itemsSynced, 0);
1268
+ const totalConflicts = sessions.reduce((sum, s) => sum + s.conflictsDetected, 0);
1269
+ return {
1270
+ totalNodes: this.nodes.size,
1271
+ onlineNodes: this.getOnlineNodes().length,
1272
+ offlineNodes: this.nodes.size - this.getOnlineNodes().length,
1273
+ totalSessions: sessions.length,
1274
+ activeSessions: active,
1275
+ completedSessions: completed,
1276
+ failedSessions: failed,
1277
+ successRate: sessions.length > 0 ? completed / sessions.length * 100 : 0,
1278
+ totalItemsSynced,
1279
+ totalConflicts,
1280
+ averageConflictsPerSession: sessions.length > 0 ? totalConflicts / sessions.length : 0
1281
+ };
1282
+ }
1283
+ /**
1284
+ * Get sync events
1285
+ */
1286
+ getSyncEvents(limit) {
1287
+ const events = [...this.syncEvents];
1288
+ if (limit) {
1289
+ return events.slice(-limit);
1290
+ }
1291
+ return events;
1292
+ }
1293
+ /**
1294
+ * Get sync events for session
1295
+ */
1296
+ getSessionEvents(sessionId) {
1297
+ return this.syncEvents.filter((e) => e.sessionId === sessionId);
1298
+ }
1299
+ /**
1300
+ * Check node health
1301
+ */
1302
+ getNodeHealth() {
1303
+ const health = {};
1304
+ for (const [nodeId, lastHeartbeat] of this.nodeHeartbeats) {
1305
+ const now = Date.now();
1306
+ const downtime = now - lastHeartbeat;
1307
+ const isHealthy = downtime < 3e4;
1308
+ health[nodeId] = {
1309
+ isHealthy,
1310
+ downtime
1311
+ };
1312
+ }
1313
+ return health;
1314
+ }
1315
+ /**
1316
+ * Start heartbeat monitoring
1317
+ */
1318
+ startHeartbeatMonitoring(interval = 5e3) {
1319
+ if (this.heartbeatInterval) {
1320
+ return;
1321
+ }
1322
+ this.heartbeatInterval = setInterval(() => {
1323
+ const health = this.getNodeHealth();
1324
+ for (const [nodeId, { isHealthy }] of Object.entries(health)) {
1325
+ const node = this.nodes.get(nodeId);
1326
+ if (!node) {
1327
+ continue;
1328
+ }
1329
+ const newStatus = isHealthy ? "online" : "offline";
1330
+ if (node.status !== newStatus) {
1331
+ this.updateNodeStatus(nodeId, newStatus);
1332
+ }
1333
+ }
1334
+ }, interval);
1335
+ logger.debug("[SyncCoordinator] Heartbeat monitoring started", { interval });
1336
+ }
1337
+ /**
1338
+ * Stop heartbeat monitoring
1339
+ */
1340
+ stopHeartbeatMonitoring() {
1341
+ if (this.heartbeatInterval) {
1342
+ clearInterval(this.heartbeatInterval);
1343
+ this.heartbeatInterval = null;
1344
+ logger.debug("[SyncCoordinator] Heartbeat monitoring stopped");
1345
+ }
1346
+ }
1347
+ /**
1348
+ * Clear all state (for testing)
1349
+ */
1350
+ clear() {
1351
+ this.nodes.clear();
1352
+ this.sessions.clear();
1353
+ this.syncEvents = [];
1354
+ this.nodeHeartbeats.clear();
1355
+ this.nodesByDID.clear();
1356
+ this.cryptoProvider = null;
1357
+ this.stopHeartbeatMonitoring();
1358
+ }
1359
+ /**
1360
+ * Get the crypto provider (for advanced usage)
1361
+ */
1362
+ getCryptoProvider() {
1363
+ return this.cryptoProvider;
1364
+ }
1365
+ };
1366
+
1367
+ // src/distributed/ReplicationManager.ts
1368
+ var ReplicationManager = class {
1369
+ replicas = /* @__PURE__ */ new Map();
1370
+ policies = /* @__PURE__ */ new Map();
1371
+ replicationEvents = [];
1372
+ syncStatus = /* @__PURE__ */ new Map();
1373
+ // Crypto support
1374
+ cryptoProvider = null;
1375
+ replicasByDID = /* @__PURE__ */ new Map();
1376
+ // DID -> replicaId
1377
+ /**
1378
+ * Configure cryptographic provider for encrypted replication
1379
+ */
1380
+ configureCrypto(provider) {
1381
+ this.cryptoProvider = provider;
1382
+ logger.debug("[ReplicationManager] Crypto configured", {
1383
+ initialized: provider.isInitialized()
1384
+ });
1385
+ }
1386
+ /**
1387
+ * Check if crypto is configured
1388
+ */
1389
+ isCryptoEnabled() {
1390
+ return this.cryptoProvider !== null && this.cryptoProvider.isInitialized();
1391
+ }
1392
+ /**
1393
+ * Register an authenticated replica with DID
1394
+ */
1395
+ async registerAuthenticatedReplica(replica, encrypted = false) {
1396
+ const authenticatedReplica = {
1397
+ ...replica,
1398
+ encrypted
1399
+ };
1400
+ this.replicas.set(replica.id, authenticatedReplica);
1401
+ this.replicasByDID.set(replica.did, replica.id);
1402
+ if (!this.syncStatus.has(replica.nodeId)) {
1403
+ this.syncStatus.set(replica.nodeId, { synced: 0, failed: 0 });
1404
+ }
1405
+ if (this.cryptoProvider && replica.publicSigningKey) {
1406
+ await this.cryptoProvider.registerRemoteNode({
1407
+ id: replica.nodeId,
1408
+ did: replica.did,
1409
+ publicSigningKey: replica.publicSigningKey,
1410
+ publicEncryptionKey: replica.publicEncryptionKey
1411
+ });
1412
+ }
1413
+ const event = {
1414
+ type: "replica-added",
1415
+ replicaId: replica.id,
1416
+ nodeId: replica.nodeId,
1417
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1418
+ details: { did: replica.did, encrypted, authenticated: true }
1419
+ };
1420
+ this.replicationEvents.push(event);
1421
+ logger.debug("[ReplicationManager] Authenticated replica registered", {
1422
+ replicaId: replica.id,
1423
+ did: replica.did,
1424
+ encrypted
1425
+ });
1426
+ return authenticatedReplica;
1427
+ }
1428
+ /**
1429
+ * Get replica by DID
1430
+ */
1431
+ getReplicaByDID(did) {
1432
+ const replicaId = this.replicasByDID.get(did);
1433
+ if (!replicaId) return void 0;
1434
+ return this.replicas.get(replicaId);
1435
+ }
1436
+ /**
1437
+ * Get all encrypted replicas
1438
+ */
1439
+ getEncryptedReplicas() {
1440
+ return Array.from(this.replicas.values()).filter((r) => r.encrypted);
1441
+ }
1442
+ /**
1443
+ * Encrypt data for replication to a specific replica
1444
+ */
1445
+ async encryptForReplica(data, targetReplicaDID) {
1446
+ if (!this.cryptoProvider || !this.cryptoProvider.isInitialized()) {
1447
+ throw new Error("Crypto provider not initialized");
1448
+ }
1449
+ const dataBytes = new TextEncoder().encode(JSON.stringify(data));
1450
+ const encrypted = await this.cryptoProvider.encrypt(dataBytes, targetReplicaDID);
1451
+ const localDID = this.cryptoProvider.getLocalDID();
1452
+ return {
1453
+ ct: encrypted.ct,
1454
+ iv: encrypted.iv,
1455
+ tag: encrypted.tag,
1456
+ epk: encrypted.epk,
1457
+ senderDID: localDID || void 0,
1458
+ targetDID: targetReplicaDID,
1459
+ encryptedAt: encrypted.encryptedAt
1460
+ };
1461
+ }
1462
+ /**
1463
+ * Decrypt data received from replication
1464
+ */
1465
+ async decryptReplicationData(encrypted) {
1466
+ if (!this.cryptoProvider || !this.cryptoProvider.isInitialized()) {
1467
+ throw new Error("Crypto provider not initialized");
1468
+ }
1469
+ const decrypted = await this.cryptoProvider.decrypt(
1470
+ {
1471
+ alg: "ECIES-P256",
1472
+ ct: encrypted.ct,
1473
+ iv: encrypted.iv,
1474
+ tag: encrypted.tag,
1475
+ epk: encrypted.epk
1476
+ },
1477
+ encrypted.senderDID
1478
+ );
1479
+ return JSON.parse(new TextDecoder().decode(decrypted));
1480
+ }
1481
+ /**
1482
+ * Create an encrypted replication policy
1483
+ */
1484
+ createEncryptedPolicy(name, replicationFactor, consistencyLevel, encryptionMode, options) {
1485
+ const policy = {
1486
+ id: `policy-${Date.now()}-${Math.random().toString(36).slice(2)}`,
1487
+ name,
1488
+ replicationFactor,
1489
+ consistencyLevel,
1490
+ syncInterval: options?.syncInterval || 1e3,
1491
+ maxReplicationLag: options?.maxReplicationLag || 1e4,
1492
+ encryptionMode,
1493
+ requiredCapabilities: options?.requiredCapabilities
1494
+ };
1495
+ this.policies.set(policy.id, policy);
1496
+ logger.debug("[ReplicationManager] Encrypted policy created", {
1497
+ policyId: policy.id,
1498
+ name,
1499
+ replicationFactor,
1500
+ encryptionMode
1501
+ });
1502
+ return policy;
1503
+ }
1504
+ /**
1505
+ * Verify a replica's capabilities via UCAN
1506
+ */
1507
+ async verifyReplicaCapabilities(replicaDID, token, policyId) {
1508
+ if (!this.cryptoProvider) {
1509
+ return { authorized: true };
1510
+ }
1511
+ const policy = policyId ? this.policies.get(policyId) : void 0;
1512
+ const result = await this.cryptoProvider.verifyUCAN(token, {
1513
+ requiredCapabilities: policy?.requiredCapabilities?.map((cap) => ({
1514
+ can: cap,
1515
+ with: "*"
1516
+ }))
1517
+ });
1518
+ if (!result.authorized) {
1519
+ logger.warn("[ReplicationManager] Replica capability verification failed", {
1520
+ replicaDID,
1521
+ error: result.error
1522
+ });
1523
+ }
1524
+ return result;
1525
+ }
1526
+ /**
1527
+ * Register a replica
1528
+ */
1529
+ registerReplica(replica) {
1530
+ this.replicas.set(replica.id, replica);
1531
+ if (!this.syncStatus.has(replica.nodeId)) {
1532
+ this.syncStatus.set(replica.nodeId, { synced: 0, failed: 0 });
1533
+ }
1534
+ const event = {
1535
+ type: "replica-added",
1536
+ replicaId: replica.id,
1537
+ nodeId: replica.nodeId,
1538
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1539
+ };
1540
+ this.replicationEvents.push(event);
1541
+ logger.debug("[ReplicationManager] Replica registered", {
1542
+ replicaId: replica.id,
1543
+ nodeId: replica.nodeId,
1544
+ status: replica.status
1545
+ });
1546
+ }
1547
+ /**
1548
+ * Remove a replica
1549
+ */
1550
+ removeReplica(replicaId) {
1551
+ const replica = this.replicas.get(replicaId);
1552
+ if (!replica) {
1553
+ throw new Error(`Replica ${replicaId} not found`);
1554
+ }
1555
+ this.replicas.delete(replicaId);
1556
+ const event = {
1557
+ type: "replica-removed",
1558
+ replicaId,
1559
+ nodeId: replica.nodeId,
1560
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1561
+ };
1562
+ this.replicationEvents.push(event);
1563
+ logger.debug("[ReplicationManager] Replica removed", { replicaId });
1564
+ }
1565
+ /**
1566
+ * Create a replication policy
1567
+ */
1568
+ createPolicy(name, replicationFactor, consistencyLevel, syncInterval = 1e3, maxReplicationLag = 1e4) {
1569
+ const policy = {
1570
+ id: `policy-${Date.now()}-${Math.random().toString(36).slice(2)}`,
1571
+ name,
1572
+ replicationFactor,
1573
+ consistencyLevel,
1574
+ syncInterval,
1575
+ maxReplicationLag
1576
+ };
1577
+ this.policies.set(policy.id, policy);
1578
+ logger.debug("[ReplicationManager] Policy created", {
1579
+ policyId: policy.id,
1580
+ name,
1581
+ replicationFactor,
1582
+ consistencyLevel
1583
+ });
1584
+ return policy;
1585
+ }
1586
+ /**
1587
+ * Update replica status
1588
+ */
1589
+ updateReplicaStatus(replicaId, status, lagBytes = 0, lagMillis = 0) {
1590
+ const replica = this.replicas.get(replicaId);
1591
+ if (!replica) {
1592
+ throw new Error(`Replica ${replicaId} not found`);
1593
+ }
1594
+ replica.status = status;
1595
+ replica.lagBytes = lagBytes;
1596
+ replica.lagMillis = lagMillis;
1597
+ replica.lastSyncTime = (/* @__PURE__ */ new Date()).toISOString();
1598
+ const event = {
1599
+ type: status === "syncing" ? "replica-synced" : "sync-failed",
1600
+ replicaId,
1601
+ nodeId: replica.nodeId,
1602
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1603
+ details: { status, lagBytes, lagMillis }
1604
+ };
1605
+ this.replicationEvents.push(event);
1606
+ const syncStatus = this.syncStatus.get(replica.nodeId);
1607
+ if (syncStatus) {
1608
+ if (status === "syncing" || status === "secondary") {
1609
+ syncStatus.synced++;
1610
+ } else if (status === "failed") {
1611
+ syncStatus.failed++;
1612
+ }
1613
+ }
1614
+ logger.debug("[ReplicationManager] Replica status updated", {
1615
+ replicaId,
1616
+ status,
1617
+ lagBytes,
1618
+ lagMillis
1619
+ });
1620
+ }
1621
+ /**
1622
+ * Get replicas for node
1623
+ */
1624
+ getReplicasForNode(nodeId) {
1625
+ return Array.from(this.replicas.values()).filter((r) => r.nodeId === nodeId);
1626
+ }
1627
+ /**
1628
+ * Get healthy replicas
1629
+ */
1630
+ getHealthyReplicas() {
1631
+ return Array.from(this.replicas.values()).filter(
1632
+ (r) => r.status === "secondary" || r.status === "primary"
1633
+ );
1634
+ }
1635
+ /**
1636
+ * Get syncing replicas
1637
+ */
1638
+ getSyncingReplicas() {
1639
+ return Array.from(this.replicas.values()).filter((r) => r.status === "syncing");
1640
+ }
1641
+ /**
1642
+ * Get failed replicas
1643
+ */
1644
+ getFailedReplicas() {
1645
+ return Array.from(this.replicas.values()).filter((r) => r.status === "failed");
1646
+ }
1647
+ /**
1648
+ * Check replication health for policy
1649
+ */
1650
+ checkReplicationHealth(policyId) {
1651
+ const policy = this.policies.get(policyId);
1652
+ if (!policy) {
1653
+ throw new Error(`Policy ${policyId} not found`);
1654
+ }
1655
+ const healthy = this.getHealthyReplicas();
1656
+ const maxLag = Math.max(0, ...healthy.map((r) => r.lagMillis));
1657
+ return {
1658
+ healthy: healthy.length >= policy.replicationFactor && maxLag <= policy.maxReplicationLag,
1659
+ replicasInPolicy: policy.replicationFactor,
1660
+ healthyReplicas: healthy.length,
1661
+ replicationLag: maxLag
1662
+ };
1663
+ }
1664
+ /**
1665
+ * Get consistency level
1666
+ */
1667
+ getConsistencyLevel(policyId) {
1668
+ const policy = this.policies.get(policyId);
1669
+ if (!policy) {
1670
+ return "eventual";
1671
+ }
1672
+ return policy.consistencyLevel;
1673
+ }
1674
+ /**
1675
+ * Get replica
1676
+ */
1677
+ getReplica(replicaId) {
1678
+ return this.replicas.get(replicaId);
1679
+ }
1680
+ /**
1681
+ * Get all replicas
1682
+ */
1683
+ getAllReplicas() {
1684
+ return Array.from(this.replicas.values());
1685
+ }
1686
+ /**
1687
+ * Get policy
1688
+ */
1689
+ getPolicy(policyId) {
1690
+ return this.policies.get(policyId);
1691
+ }
1692
+ /**
1693
+ * Get all policies
1694
+ */
1695
+ getAllPolicies() {
1696
+ return Array.from(this.policies.values());
1697
+ }
1698
+ /**
1699
+ * Get replication statistics
1700
+ */
1701
+ getStatistics() {
1702
+ const healthy = this.getHealthyReplicas().length;
1703
+ const syncing = this.getSyncingReplicas().length;
1704
+ const failed = this.getFailedReplicas().length;
1705
+ const total = this.replicas.size;
1706
+ const replicationLags = Array.from(this.replicas.values()).map((r) => r.lagMillis);
1707
+ const avgLag = replicationLags.length > 0 ? replicationLags.reduce((a, b) => a + b) / replicationLags.length : 0;
1708
+ const maxLag = replicationLags.length > 0 ? Math.max(...replicationLags) : 0;
1709
+ return {
1710
+ totalReplicas: total,
1711
+ healthyReplicas: healthy,
1712
+ syncingReplicas: syncing,
1713
+ failedReplicas: failed,
1714
+ healthiness: total > 0 ? healthy / total * 100 : 0,
1715
+ averageReplicationLagMs: avgLag,
1716
+ maxReplicationLagMs: maxLag,
1717
+ totalPolicies: this.policies.size
1718
+ };
1719
+ }
1720
+ /**
1721
+ * Get replication events
1722
+ */
1723
+ getReplicationEvents(limit) {
1724
+ const events = [...this.replicationEvents];
1725
+ if (limit) {
1726
+ return events.slice(-limit);
1727
+ }
1728
+ return events;
1729
+ }
1730
+ /**
1731
+ * Get sync status for node
1732
+ */
1733
+ getSyncStatus(nodeId) {
1734
+ return this.syncStatus.get(nodeId) || { synced: 0, failed: 0 };
1735
+ }
1736
+ /**
1737
+ * Get replication lag distribution
1738
+ */
1739
+ getReplicationLagDistribution() {
1740
+ const distribution = {
1741
+ "0-100ms": 0,
1742
+ "100-500ms": 0,
1743
+ "500-1000ms": 0,
1744
+ "1000+ms": 0
1745
+ };
1746
+ for (const replica of this.replicas.values()) {
1747
+ if (replica.lagMillis <= 100) {
1748
+ distribution["0-100ms"]++;
1749
+ } else if (replica.lagMillis <= 500) {
1750
+ distribution["100-500ms"]++;
1751
+ } else if (replica.lagMillis <= 1e3) {
1752
+ distribution["500-1000ms"]++;
1753
+ } else {
1754
+ distribution["1000+ms"]++;
1755
+ }
1756
+ }
1757
+ return distribution;
1758
+ }
1759
+ /**
1760
+ * Check if can satisfy consistency level
1761
+ */
1762
+ canSatisfyConsistency(policyId, _requiredAcks) {
1763
+ const policy = this.policies.get(policyId);
1764
+ if (!policy) {
1765
+ return false;
1766
+ }
1767
+ const healthyCount = this.getHealthyReplicas().length;
1768
+ switch (policy.consistencyLevel) {
1769
+ case "eventual":
1770
+ return true;
1771
+ // Always achievable
1772
+ case "read-after-write":
1773
+ return healthyCount >= 1;
1774
+ case "strong":
1775
+ return healthyCount >= policy.replicationFactor;
1776
+ default:
1777
+ return false;
1778
+ }
1779
+ }
1780
+ /**
1781
+ * Clear all state (for testing)
1782
+ */
1783
+ clear() {
1784
+ this.replicas.clear();
1785
+ this.policies.clear();
1786
+ this.replicationEvents = [];
1787
+ this.syncStatus.clear();
1788
+ this.replicasByDID.clear();
1789
+ this.cryptoProvider = null;
1790
+ }
1791
+ /**
1792
+ * Get the crypto provider (for advanced usage)
1793
+ */
1794
+ getCryptoProvider() {
1795
+ return this.cryptoProvider;
1796
+ }
1797
+ };
1798
+
1799
+ // src/distributed/SyncProtocol.ts
1800
+ var SyncProtocol = class {
1801
+ version = "1.0.0";
1802
+ messageQueue = [];
1803
+ messageMap = /* @__PURE__ */ new Map();
1804
+ handshakes = /* @__PURE__ */ new Map();
1805
+ protocolErrors = [];
1806
+ messageCounter = 0;
1807
+ // Crypto support
1808
+ cryptoProvider = null;
1809
+ cryptoConfig = null;
1810
+ /**
1811
+ * Configure cryptographic provider for authenticated/encrypted messages
1812
+ */
1813
+ configureCrypto(provider, config) {
1814
+ this.cryptoProvider = provider;
1815
+ this.cryptoConfig = {
1816
+ encryptionMode: config?.encryptionMode ?? "none",
1817
+ requireSignatures: config?.requireSignatures ?? false,
1818
+ requireCapabilities: config?.requireCapabilities ?? false,
1819
+ requiredCapabilities: config?.requiredCapabilities
1820
+ };
1821
+ logger.debug("[SyncProtocol] Crypto configured", {
1822
+ encryptionMode: this.cryptoConfig.encryptionMode,
1823
+ requireSignatures: this.cryptoConfig.requireSignatures,
1824
+ requireCapabilities: this.cryptoConfig.requireCapabilities
1825
+ });
1826
+ }
1827
+ /**
1828
+ * Check if crypto is configured
1829
+ */
1830
+ isCryptoEnabled() {
1831
+ return this.cryptoProvider !== null && this.cryptoProvider.isInitialized();
1832
+ }
1833
+ /**
1834
+ * Get crypto configuration
1835
+ */
1836
+ getCryptoConfig() {
1837
+ return this.cryptoConfig ? { ...this.cryptoConfig } : null;
1838
+ }
1839
+ /**
1840
+ * Get protocol version
1841
+ */
1842
+ getVersion() {
1843
+ return this.version;
1844
+ }
1845
+ /**
1846
+ * Create authenticated handshake message with DID and keys
1847
+ */
1848
+ async createAuthenticatedHandshake(capabilities, targetDID) {
1849
+ if (!this.cryptoProvider || !this.cryptoProvider.isInitialized()) {
1850
+ throw new Error("Crypto provider not initialized");
1851
+ }
1852
+ const localDID = this.cryptoProvider.getLocalDID();
1853
+ if (!localDID) {
1854
+ throw new Error("Local DID not available");
1855
+ }
1856
+ const publicInfo = await this.cryptoProvider.exportPublicIdentity();
1857
+ if (!publicInfo) {
1858
+ throw new Error("Cannot export public identity");
1859
+ }
1860
+ let ucan;
1861
+ if (targetDID && this.cryptoConfig?.requireCapabilities) {
1862
+ const caps = this.cryptoConfig.requiredCapabilities || [
1863
+ { can: "aeon:sync:read", with: "*" },
1864
+ { can: "aeon:sync:write", with: "*" }
1865
+ ];
1866
+ ucan = await this.cryptoProvider.createUCAN(targetDID, caps);
1867
+ }
1868
+ const handshakePayload = {
1869
+ protocolVersion: this.version,
1870
+ nodeId: localDID,
1871
+ capabilities,
1872
+ state: "initiating",
1873
+ did: localDID,
1874
+ publicSigningKey: publicInfo.publicSigningKey,
1875
+ publicEncryptionKey: publicInfo.publicEncryptionKey,
1876
+ ucan
1877
+ };
1878
+ const message = {
1879
+ type: "handshake",
1880
+ version: this.version,
1881
+ sender: localDID,
1882
+ receiver: targetDID || "",
1883
+ messageId: this.generateMessageId(),
1884
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1885
+ payload: handshakePayload
1886
+ };
1887
+ if (this.cryptoConfig?.requireSignatures) {
1888
+ const signed = await this.cryptoProvider.signData(handshakePayload);
1889
+ message.auth = {
1890
+ senderDID: localDID,
1891
+ receiverDID: targetDID,
1892
+ signature: signed.signature
1893
+ };
1894
+ }
1895
+ this.messageMap.set(message.messageId, message);
1896
+ this.messageQueue.push(message);
1897
+ logger.debug("[SyncProtocol] Authenticated handshake created", {
1898
+ messageId: message.messageId,
1899
+ did: localDID,
1900
+ capabilities: capabilities.length,
1901
+ hasUCAN: !!ucan
1902
+ });
1903
+ return message;
1904
+ }
1905
+ /**
1906
+ * Verify and process an authenticated handshake
1907
+ */
1908
+ async verifyAuthenticatedHandshake(message) {
1909
+ if (message.type !== "handshake") {
1910
+ return { valid: false, error: "Message is not a handshake" };
1911
+ }
1912
+ const handshake = message.payload;
1913
+ if (!this.cryptoProvider || !this.cryptoConfig) {
1914
+ this.handshakes.set(message.sender, handshake);
1915
+ return { valid: true, handshake };
1916
+ }
1917
+ if (handshake.did && handshake.publicSigningKey) {
1918
+ await this.cryptoProvider.registerRemoteNode({
1919
+ id: handshake.nodeId,
1920
+ did: handshake.did,
1921
+ publicSigningKey: handshake.publicSigningKey,
1922
+ publicEncryptionKey: handshake.publicEncryptionKey
1923
+ });
1924
+ }
1925
+ if (this.cryptoConfig.requireSignatures && message.auth?.signature) {
1926
+ const signed = {
1927
+ payload: handshake,
1928
+ signature: message.auth.signature,
1929
+ signer: message.auth.senderDID || message.sender,
1930
+ algorithm: "ES256",
1931
+ signedAt: Date.now()
1932
+ };
1933
+ const isValid = await this.cryptoProvider.verifySignedData(signed);
1934
+ if (!isValid) {
1935
+ logger.warn("[SyncProtocol] Handshake signature verification failed", {
1936
+ messageId: message.messageId,
1937
+ sender: message.sender
1938
+ });
1939
+ return { valid: false, error: "Invalid signature" };
1940
+ }
1941
+ }
1942
+ if (this.cryptoConfig.requireCapabilities && handshake.ucan) {
1943
+ const localDID = this.cryptoProvider.getLocalDID();
1944
+ const result = await this.cryptoProvider.verifyUCAN(handshake.ucan, {
1945
+ expectedAudience: localDID || void 0,
1946
+ requiredCapabilities: this.cryptoConfig.requiredCapabilities
1947
+ });
1948
+ if (!result.authorized) {
1949
+ logger.warn("[SyncProtocol] Handshake UCAN verification failed", {
1950
+ messageId: message.messageId,
1951
+ error: result.error
1952
+ });
1953
+ return { valid: false, error: result.error || "Unauthorized" };
1954
+ }
1955
+ }
1956
+ this.handshakes.set(message.sender, handshake);
1957
+ logger.debug("[SyncProtocol] Authenticated handshake verified", {
1958
+ messageId: message.messageId,
1959
+ did: handshake.did
1960
+ });
1961
+ return { valid: true, handshake };
1962
+ }
1963
+ /**
1964
+ * Sign and optionally encrypt a message payload
1965
+ */
1966
+ async signMessage(message, payload, encrypt = false) {
1967
+ if (!this.cryptoProvider || !this.cryptoProvider.isInitialized()) {
1968
+ throw new Error("Crypto provider not initialized");
1969
+ }
1970
+ const localDID = this.cryptoProvider.getLocalDID();
1971
+ const signed = await this.cryptoProvider.signData(payload);
1972
+ message.auth = {
1973
+ senderDID: localDID || void 0,
1974
+ receiverDID: message.receiver || void 0,
1975
+ signature: signed.signature,
1976
+ encrypted: false
1977
+ };
1978
+ if (encrypt && message.receiver && this.cryptoConfig?.encryptionMode !== "none") {
1979
+ const payloadBytes = new TextEncoder().encode(JSON.stringify(payload));
1980
+ const encrypted = await this.cryptoProvider.encrypt(payloadBytes, message.receiver);
1981
+ message.payload = encrypted;
1982
+ message.auth.encrypted = true;
1983
+ logger.debug("[SyncProtocol] Message encrypted", {
1984
+ messageId: message.messageId,
1985
+ recipient: message.receiver
1986
+ });
1987
+ } else {
1988
+ message.payload = payload;
1989
+ }
1990
+ return message;
1991
+ }
1992
+ /**
1993
+ * Verify signature and optionally decrypt a message
1994
+ */
1995
+ async verifyMessage(message) {
1996
+ if (!this.cryptoProvider || !message.auth) {
1997
+ return { valid: true, payload: message.payload };
1998
+ }
1999
+ let payload = message.payload;
2000
+ if (message.auth.encrypted && message.payload) {
2001
+ try {
2002
+ const encrypted = message.payload;
2003
+ const decrypted = await this.cryptoProvider.decrypt(
2004
+ encrypted,
2005
+ message.auth.senderDID
2006
+ );
2007
+ payload = JSON.parse(new TextDecoder().decode(decrypted));
2008
+ logger.debug("[SyncProtocol] Message decrypted", {
2009
+ messageId: message.messageId
2010
+ });
2011
+ } catch (error) {
2012
+ return {
2013
+ valid: false,
2014
+ error: `Decryption failed: ${error instanceof Error ? error.message : String(error)}`
2015
+ };
2016
+ }
2017
+ }
2018
+ if (message.auth.signature && message.auth.senderDID) {
2019
+ const signed = {
2020
+ payload,
2021
+ signature: message.auth.signature,
2022
+ signer: message.auth.senderDID,
2023
+ algorithm: "ES256",
2024
+ signedAt: Date.now()
2025
+ };
2026
+ const isValid = await this.cryptoProvider.verifySignedData(signed);
2027
+ if (!isValid) {
2028
+ return { valid: false, error: "Invalid signature" };
2029
+ }
2030
+ }
2031
+ return { valid: true, payload };
2032
+ }
2033
+ /**
2034
+ * Create handshake message
2035
+ */
2036
+ createHandshakeMessage(nodeId, capabilities) {
2037
+ const message = {
2038
+ type: "handshake",
2039
+ version: this.version,
2040
+ sender: nodeId,
2041
+ receiver: "",
2042
+ messageId: this.generateMessageId(),
2043
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2044
+ payload: {
2045
+ protocolVersion: this.version,
2046
+ nodeId,
2047
+ capabilities,
2048
+ state: "initiating"
2049
+ }
2050
+ };
2051
+ this.messageMap.set(message.messageId, message);
2052
+ this.messageQueue.push(message);
2053
+ logger.debug("[SyncProtocol] Handshake message created", {
2054
+ messageId: message.messageId,
2055
+ nodeId,
2056
+ capabilities: capabilities.length
2057
+ });
2058
+ return message;
2059
+ }
2060
+ /**
2061
+ * Create sync request message
2062
+ */
2063
+ createSyncRequestMessage(sender, receiver, sessionId, fromVersion, toVersion, filter) {
2064
+ const message = {
2065
+ type: "sync-request",
2066
+ version: this.version,
2067
+ sender,
2068
+ receiver,
2069
+ messageId: this.generateMessageId(),
2070
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2071
+ payload: {
2072
+ sessionId,
2073
+ fromVersion,
2074
+ toVersion,
2075
+ filter
2076
+ }
2077
+ };
2078
+ this.messageMap.set(message.messageId, message);
2079
+ this.messageQueue.push(message);
2080
+ logger.debug("[SyncProtocol] Sync request created", {
2081
+ messageId: message.messageId,
2082
+ sessionId,
2083
+ fromVersion,
2084
+ toVersion
2085
+ });
2086
+ return message;
2087
+ }
2088
+ /**
2089
+ * Create sync response message
2090
+ */
2091
+ createSyncResponseMessage(sender, receiver, sessionId, fromVersion, toVersion, data, hasMore = false, offset = 0) {
2092
+ const message = {
2093
+ type: "sync-response",
2094
+ version: this.version,
2095
+ sender,
2096
+ receiver,
2097
+ messageId: this.generateMessageId(),
2098
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2099
+ payload: {
2100
+ sessionId,
2101
+ fromVersion,
2102
+ toVersion,
2103
+ data,
2104
+ hasMore,
2105
+ offset
2106
+ }
2107
+ };
2108
+ this.messageMap.set(message.messageId, message);
2109
+ this.messageQueue.push(message);
2110
+ logger.debug("[SyncProtocol] Sync response created", {
2111
+ messageId: message.messageId,
2112
+ sessionId,
2113
+ itemCount: data.length,
2114
+ hasMore
2115
+ });
2116
+ return message;
2117
+ }
2118
+ /**
2119
+ * Create acknowledgement message
2120
+ */
2121
+ createAckMessage(sender, receiver, messageId) {
2122
+ const message = {
2123
+ type: "ack",
2124
+ version: this.version,
2125
+ sender,
2126
+ receiver,
2127
+ messageId: this.generateMessageId(),
2128
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2129
+ payload: { acknowledgedMessageId: messageId }
2130
+ };
2131
+ this.messageMap.set(message.messageId, message);
2132
+ this.messageQueue.push(message);
2133
+ return message;
2134
+ }
2135
+ /**
2136
+ * Create error message
2137
+ */
2138
+ createErrorMessage(sender, receiver, error, relatedMessageId) {
2139
+ const message = {
2140
+ type: "error",
2141
+ version: this.version,
2142
+ sender,
2143
+ receiver,
2144
+ messageId: this.generateMessageId(),
2145
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2146
+ payload: {
2147
+ error,
2148
+ relatedMessageId
2149
+ }
2150
+ };
2151
+ this.messageMap.set(message.messageId, message);
2152
+ this.messageQueue.push(message);
2153
+ this.protocolErrors.push({
2154
+ error,
2155
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2156
+ });
2157
+ logger.error("[SyncProtocol] Error message created", {
2158
+ messageId: message.messageId,
2159
+ errorCode: error.code,
2160
+ recoverable: error.recoverable
2161
+ });
2162
+ return message;
2163
+ }
2164
+ /**
2165
+ * Validate message
2166
+ */
2167
+ validateMessage(message) {
2168
+ const errors = [];
2169
+ if (!message.type) {
2170
+ errors.push("Message type is required");
2171
+ }
2172
+ if (!message.sender) {
2173
+ errors.push("Sender is required");
2174
+ }
2175
+ if (!message.messageId) {
2176
+ errors.push("Message ID is required");
2177
+ }
2178
+ if (!message.timestamp) {
2179
+ errors.push("Timestamp is required");
2180
+ }
2181
+ try {
2182
+ new Date(message.timestamp);
2183
+ } catch {
2184
+ errors.push("Invalid timestamp format");
2185
+ }
2186
+ return {
2187
+ valid: errors.length === 0,
2188
+ errors
2189
+ };
2190
+ }
2191
+ /**
2192
+ * Serialize message
2193
+ */
2194
+ serializeMessage(message) {
2195
+ try {
2196
+ return JSON.stringify(message);
2197
+ } catch (error) {
2198
+ logger.error("[SyncProtocol] Message serialization failed", {
2199
+ messageId: message.messageId,
2200
+ error: error instanceof Error ? error.message : String(error)
2201
+ });
2202
+ throw new Error(`Failed to serialize message: ${error instanceof Error ? error.message : String(error)}`);
2203
+ }
2204
+ }
2205
+ /**
2206
+ * Deserialize message
2207
+ */
2208
+ deserializeMessage(data) {
2209
+ try {
2210
+ const message = JSON.parse(data);
2211
+ const validation = this.validateMessage(message);
2212
+ if (!validation.valid) {
2213
+ throw new Error(`Invalid message: ${validation.errors.join(", ")}`);
2214
+ }
2215
+ return message;
2216
+ } catch (error) {
2217
+ logger.error("[SyncProtocol] Message deserialization failed", {
2218
+ error: error instanceof Error ? error.message : String(error)
2219
+ });
2220
+ throw new Error(`Failed to deserialize message: ${error instanceof Error ? error.message : String(error)}`);
2221
+ }
2222
+ }
2223
+ /**
2224
+ * Process handshake
2225
+ */
2226
+ processHandshake(message) {
2227
+ if (message.type !== "handshake") {
2228
+ throw new Error("Message is not a handshake");
2229
+ }
2230
+ const handshake = message.payload;
2231
+ const nodeId = message.sender;
2232
+ this.handshakes.set(nodeId, handshake);
2233
+ logger.debug("[SyncProtocol] Handshake processed", {
2234
+ nodeId,
2235
+ protocolVersion: handshake.protocolVersion,
2236
+ capabilities: handshake.capabilities.length
2237
+ });
2238
+ return handshake;
2239
+ }
2240
+ /**
2241
+ * Get message
2242
+ */
2243
+ getMessage(messageId) {
2244
+ return this.messageMap.get(messageId);
2245
+ }
2246
+ /**
2247
+ * Get all messages
2248
+ */
2249
+ getAllMessages() {
2250
+ return [...this.messageQueue];
2251
+ }
2252
+ /**
2253
+ * Get messages by type
2254
+ */
2255
+ getMessagesByType(type) {
2256
+ return this.messageQueue.filter((m) => m.type === type);
2257
+ }
2258
+ /**
2259
+ * Get messages from sender
2260
+ */
2261
+ getMessagesFromSender(sender) {
2262
+ return this.messageQueue.filter((m) => m.sender === sender);
2263
+ }
2264
+ /**
2265
+ * Get pending messages
2266
+ */
2267
+ getPendingMessages(receiver) {
2268
+ return this.messageQueue.filter((m) => m.receiver === receiver);
2269
+ }
2270
+ /**
2271
+ * Get handshakes
2272
+ */
2273
+ getHandshakes() {
2274
+ return new Map(this.handshakes);
2275
+ }
2276
+ /**
2277
+ * Get protocol statistics
2278
+ */
2279
+ getStatistics() {
2280
+ const messagesByType = {};
2281
+ for (const message of this.messageQueue) {
2282
+ messagesByType[message.type] = (messagesByType[message.type] || 0) + 1;
2283
+ }
2284
+ const errorCount = this.protocolErrors.length;
2285
+ const recoverableErrors = this.protocolErrors.filter((e) => e.error.recoverable).length;
2286
+ return {
2287
+ totalMessages: this.messageQueue.length,
2288
+ messagesByType,
2289
+ totalHandshakes: this.handshakes.size,
2290
+ totalErrors: errorCount,
2291
+ recoverableErrors,
2292
+ unrecoverableErrors: errorCount - recoverableErrors
2293
+ };
2294
+ }
2295
+ /**
2296
+ * Get protocol errors
2297
+ */
2298
+ getErrors() {
2299
+ return [...this.protocolErrors];
2300
+ }
2301
+ /**
2302
+ * Generate message ID
2303
+ */
2304
+ generateMessageId() {
2305
+ this.messageCounter++;
2306
+ return `msg-${Date.now()}-${this.messageCounter}`;
2307
+ }
2308
+ /**
2309
+ * Clear all state (for testing)
2310
+ */
2311
+ clear() {
2312
+ this.messageQueue = [];
2313
+ this.messageMap.clear();
2314
+ this.handshakes.clear();
2315
+ this.protocolErrors = [];
2316
+ this.messageCounter = 0;
2317
+ this.cryptoProvider = null;
2318
+ this.cryptoConfig = null;
2319
+ }
2320
+ /**
2321
+ * Get the crypto provider (for advanced usage)
2322
+ */
2323
+ getCryptoProvider() {
2324
+ return this.cryptoProvider;
2325
+ }
2326
+ };
2327
+
2328
+ // src/distributed/StateReconciler.ts
2329
+ var StateReconciler = class {
2330
+ stateVersions = /* @__PURE__ */ new Map();
2331
+ reconciliationHistory = [];
2332
+ cryptoProvider = null;
2333
+ requireSignedVersions = false;
2334
+ /**
2335
+ * Configure cryptographic provider for signed state versions
2336
+ */
2337
+ configureCrypto(provider, requireSigned = false) {
2338
+ this.cryptoProvider = provider;
2339
+ this.requireSignedVersions = requireSigned;
2340
+ logger.debug("[StateReconciler] Crypto configured", {
2341
+ initialized: provider.isInitialized(),
2342
+ requireSigned
2343
+ });
2344
+ }
2345
+ /**
2346
+ * Check if crypto is configured
2347
+ */
2348
+ isCryptoEnabled() {
2349
+ return this.cryptoProvider !== null && this.cryptoProvider.isInitialized();
2350
+ }
2351
+ /**
2352
+ * Record a signed state version with cryptographic verification
2353
+ */
2354
+ async recordSignedStateVersion(key, version, data) {
2355
+ if (!this.cryptoProvider || !this.cryptoProvider.isInitialized()) {
2356
+ throw new Error("Crypto provider not initialized");
2357
+ }
2358
+ const localDID = this.cryptoProvider.getLocalDID();
2359
+ if (!localDID) {
2360
+ throw new Error("Local DID not available");
2361
+ }
2362
+ const dataBytes = new TextEncoder().encode(JSON.stringify(data));
2363
+ const hashBytes = await this.cryptoProvider.hash(dataBytes);
2364
+ const hash = Array.from(hashBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2365
+ const versionData = { version, data, hash };
2366
+ const signed = await this.cryptoProvider.signData(versionData);
2367
+ const stateVersion = {
2368
+ version,
2369
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2370
+ nodeId: localDID,
2371
+ hash,
2372
+ data,
2373
+ signerDID: localDID,
2374
+ signature: signed.signature,
2375
+ signedAt: signed.signedAt
2376
+ };
2377
+ if (!this.stateVersions.has(key)) {
2378
+ this.stateVersions.set(key, []);
2379
+ }
2380
+ this.stateVersions.get(key).push(stateVersion);
2381
+ logger.debug("[StateReconciler] Signed state version recorded", {
2382
+ key,
2383
+ version,
2384
+ signerDID: localDID,
2385
+ hash: hash.slice(0, 16) + "..."
2386
+ });
2387
+ return stateVersion;
2388
+ }
2389
+ /**
2390
+ * Verify a state version's signature
2391
+ */
2392
+ async verifyStateVersion(version) {
2393
+ if (!version.signature || !version.signerDID) {
2394
+ if (this.requireSignedVersions) {
2395
+ return { valid: false, error: "Signature required but not present" };
2396
+ }
2397
+ const dataBytes = new TextEncoder().encode(JSON.stringify(version.data));
2398
+ if (this.cryptoProvider) {
2399
+ const hashBytes = await this.cryptoProvider.hash(dataBytes);
2400
+ const computedHash = Array.from(hashBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
2401
+ if (computedHash !== version.hash) {
2402
+ return { valid: false, error: "Hash mismatch" };
2403
+ }
2404
+ }
2405
+ return { valid: true };
2406
+ }
2407
+ if (!this.cryptoProvider) {
2408
+ return { valid: false, error: "Crypto provider not configured" };
2409
+ }
2410
+ const versionData = {
2411
+ version: version.version,
2412
+ data: version.data,
2413
+ hash: version.hash
2414
+ };
2415
+ const signed = {
2416
+ payload: versionData,
2417
+ signature: version.signature,
2418
+ signer: version.signerDID,
2419
+ algorithm: "ES256",
2420
+ signedAt: version.signedAt || Date.now()
2421
+ };
2422
+ const isValid = await this.cryptoProvider.verifySignedData(signed);
2423
+ if (!isValid) {
2424
+ return { valid: false, error: "Invalid signature" };
2425
+ }
2426
+ return { valid: true };
2427
+ }
2428
+ /**
2429
+ * Reconcile with verification - only accept verified versions
2430
+ */
2431
+ async reconcileWithVerification(key, strategy = "last-write-wins") {
2432
+ const versions = this.stateVersions.get(key) || [];
2433
+ const verifiedVersions = [];
2434
+ const verificationErrors = [];
2435
+ for (const version of versions) {
2436
+ const result2 = await this.verifyStateVersion(version);
2437
+ if (result2.valid) {
2438
+ verifiedVersions.push(version);
2439
+ } else {
2440
+ verificationErrors.push(
2441
+ `Version ${version.version} from ${version.nodeId}: ${result2.error}`
2442
+ );
2443
+ logger.warn("[StateReconciler] Version verification failed", {
2444
+ version: version.version,
2445
+ nodeId: version.nodeId,
2446
+ error: result2.error
2447
+ });
2448
+ }
2449
+ }
2450
+ if (verifiedVersions.length === 0) {
2451
+ return {
2452
+ success: false,
2453
+ mergedState: null,
2454
+ conflictsResolved: 0,
2455
+ strategy,
2456
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2457
+ verificationErrors
2458
+ };
2459
+ }
2460
+ let result;
2461
+ switch (strategy) {
2462
+ case "last-write-wins":
2463
+ result = this.reconcileLastWriteWins(verifiedVersions);
2464
+ break;
2465
+ case "vector-clock":
2466
+ result = this.reconcileVectorClock(verifiedVersions);
2467
+ break;
2468
+ case "majority-vote":
2469
+ result = this.reconcileMajorityVote(verifiedVersions);
2470
+ break;
2471
+ default:
2472
+ result = this.reconcileLastWriteWins(verifiedVersions);
2473
+ }
2474
+ return { ...result, verificationErrors };
2475
+ }
2476
+ /**
2477
+ * Record a state version
2478
+ */
2479
+ recordStateVersion(key, version, timestamp, nodeId, hash, data) {
2480
+ if (!this.stateVersions.has(key)) {
2481
+ this.stateVersions.set(key, []);
2482
+ }
2483
+ const versions = this.stateVersions.get(key);
2484
+ versions.push({
2485
+ version,
2486
+ timestamp,
2487
+ nodeId,
2488
+ hash,
2489
+ data
2490
+ });
2491
+ logger.debug("[StateReconciler] State version recorded", {
2492
+ key,
2493
+ version,
2494
+ nodeId,
2495
+ hash
2496
+ });
2497
+ }
2498
+ /**
2499
+ * Detect conflicts in state versions
2500
+ */
2501
+ detectConflicts(key) {
2502
+ const versions = this.stateVersions.get(key);
2503
+ if (!versions || versions.length <= 1) {
2504
+ return false;
2505
+ }
2506
+ const hashes = new Set(versions.map((v) => v.hash));
2507
+ return hashes.size > 1;
2508
+ }
2509
+ /**
2510
+ * Compare two states and generate diff
2511
+ */
2512
+ compareStates(state1, state2) {
2513
+ const diff = {
2514
+ added: {},
2515
+ modified: {},
2516
+ removed: [],
2517
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2518
+ };
2519
+ for (const [key, value] of Object.entries(state2)) {
2520
+ if (!(key in state1)) {
2521
+ diff.added[key] = value;
2522
+ } else if (JSON.stringify(state1[key]) !== JSON.stringify(value)) {
2523
+ diff.modified[key] = { old: state1[key], new: value };
2524
+ }
2525
+ }
2526
+ for (const key of Object.keys(state1)) {
2527
+ if (!(key in state2)) {
2528
+ diff.removed.push(key);
2529
+ }
2530
+ }
2531
+ return diff;
2532
+ }
2533
+ /**
2534
+ * Reconcile states using last-write-wins strategy
2535
+ */
2536
+ reconcileLastWriteWins(versions) {
2537
+ if (versions.length === 0) {
2538
+ throw new Error("No versions to reconcile");
2539
+ }
2540
+ const sorted = [...versions].sort(
2541
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
2542
+ );
2543
+ const latest = sorted[0];
2544
+ const conflictsResolved = versions.length - 1;
2545
+ const result = {
2546
+ success: true,
2547
+ mergedState: latest.data,
2548
+ conflictsResolved,
2549
+ strategy: "last-write-wins",
2550
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2551
+ };
2552
+ this.reconciliationHistory.push(result);
2553
+ logger.debug("[StateReconciler] State reconciled (last-write-wins)", {
2554
+ winnerNode: latest.nodeId,
2555
+ conflictsResolved
2556
+ });
2557
+ return result;
2558
+ }
2559
+ /**
2560
+ * Reconcile states using vector clock strategy
2561
+ */
2562
+ reconcileVectorClock(versions) {
2563
+ if (versions.length === 0) {
2564
+ throw new Error("No versions to reconcile");
2565
+ }
2566
+ const sorted = [...versions].sort(
2567
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
2568
+ );
2569
+ const latest = sorted[0];
2570
+ let conflictsResolved = 0;
2571
+ for (const v of versions) {
2572
+ const timeDiff = Math.abs(
2573
+ new Date(v.timestamp).getTime() - new Date(latest.timestamp).getTime()
2574
+ );
2575
+ if (timeDiff > 100) {
2576
+ conflictsResolved++;
2577
+ }
2578
+ }
2579
+ const result = {
2580
+ success: true,
2581
+ mergedState: latest.data,
2582
+ conflictsResolved,
2583
+ strategy: "vector-clock",
2584
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2585
+ };
2586
+ this.reconciliationHistory.push(result);
2587
+ logger.debug("[StateReconciler] State reconciled (vector-clock)", {
2588
+ winnerVersion: latest.version,
2589
+ conflictsResolved
2590
+ });
2591
+ return result;
2592
+ }
2593
+ /**
2594
+ * Reconcile states using majority vote strategy
2595
+ */
2596
+ reconcileMajorityVote(versions) {
2597
+ if (versions.length === 0) {
2598
+ throw new Error("No versions to reconcile");
2599
+ }
2600
+ const hashGroups = /* @__PURE__ */ new Map();
2601
+ for (const version of versions) {
2602
+ if (!hashGroups.has(version.hash)) {
2603
+ hashGroups.set(version.hash, []);
2604
+ }
2605
+ hashGroups.get(version.hash).push(version);
2606
+ }
2607
+ let majorityVersion = null;
2608
+ let maxCount = 0;
2609
+ for (const [, versionGroup] of hashGroups) {
2610
+ if (versionGroup.length > maxCount) {
2611
+ maxCount = versionGroup.length;
2612
+ majorityVersion = versionGroup[0];
2613
+ }
2614
+ }
2615
+ if (!majorityVersion) {
2616
+ majorityVersion = versions[0];
2617
+ }
2618
+ const conflictsResolved = versions.length - maxCount;
2619
+ const result = {
2620
+ success: true,
2621
+ mergedState: majorityVersion.data,
2622
+ conflictsResolved,
2623
+ strategy: "majority-vote",
2624
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2625
+ };
2626
+ this.reconciliationHistory.push(result);
2627
+ logger.debug("[StateReconciler] State reconciled (majority-vote)", {
2628
+ majorityCount: maxCount,
2629
+ conflictsResolved
2630
+ });
2631
+ return result;
2632
+ }
2633
+ /**
2634
+ * Merge multiple states
2635
+ */
2636
+ mergeStates(states) {
2637
+ if (states.length === 0) {
2638
+ return {};
2639
+ }
2640
+ if (states.length === 1) {
2641
+ return states[0];
2642
+ }
2643
+ const merged = {};
2644
+ for (const state of states) {
2645
+ if (typeof state === "object" && state !== null) {
2646
+ Object.assign(merged, state);
2647
+ }
2648
+ }
2649
+ return merged;
2650
+ }
2651
+ /**
2652
+ * Validate state after reconciliation
2653
+ */
2654
+ validateState(state) {
2655
+ const errors = [];
2656
+ if (state === null) {
2657
+ errors.push("State is null");
2658
+ } else if (state === void 0) {
2659
+ errors.push("State is undefined");
2660
+ } else if (typeof state !== "object") {
2661
+ errors.push("State is not an object");
2662
+ }
2663
+ return {
2664
+ valid: errors.length === 0,
2665
+ errors
2666
+ };
2667
+ }
2668
+ /**
2669
+ * Get state versions for a key
2670
+ */
2671
+ getStateVersions(key) {
2672
+ return this.stateVersions.get(key) || [];
2673
+ }
2674
+ /**
2675
+ * Get all state versions
2676
+ */
2677
+ getAllStateVersions() {
2678
+ const result = {};
2679
+ for (const [key, versions] of this.stateVersions) {
2680
+ result[key] = [...versions];
2681
+ }
2682
+ return result;
2683
+ }
2684
+ /**
2685
+ * Get reconciliation history
2686
+ */
2687
+ getReconciliationHistory() {
2688
+ return [...this.reconciliationHistory];
2689
+ }
2690
+ /**
2691
+ * Get reconciliation statistics
2692
+ */
2693
+ getStatistics() {
2694
+ const resolvedConflicts = this.reconciliationHistory.reduce(
2695
+ (sum, r) => sum + r.conflictsResolved,
2696
+ 0
2697
+ );
2698
+ const strategyUsage = {};
2699
+ for (const result of this.reconciliationHistory) {
2700
+ strategyUsage[result.strategy] = (strategyUsage[result.strategy] || 0) + 1;
2701
+ }
2702
+ return {
2703
+ totalReconciliations: this.reconciliationHistory.length,
2704
+ successfulReconciliations: this.reconciliationHistory.filter((r) => r.success).length,
2705
+ totalConflictsResolved: resolvedConflicts,
2706
+ averageConflictsPerReconciliation: this.reconciliationHistory.length > 0 ? resolvedConflicts / this.reconciliationHistory.length : 0,
2707
+ strategyUsage,
2708
+ trackedKeys: this.stateVersions.size
2709
+ };
2710
+ }
2711
+ /**
2712
+ * Clear all state (for testing)
2713
+ */
2714
+ clear() {
2715
+ this.stateVersions.clear();
2716
+ this.reconciliationHistory = [];
2717
+ this.cryptoProvider = null;
2718
+ this.requireSignedVersions = false;
2719
+ }
2720
+ /**
2721
+ * Get the crypto provider (for advanced usage)
2722
+ */
2723
+ getCryptoProvider() {
2724
+ return this.cryptoProvider;
2725
+ }
2726
+ };
2727
+ var logger2 = getLogger();
2728
+ var OfflineOperationQueue = class extends EventEmitter {
2729
+ queue = /* @__PURE__ */ new Map();
2730
+ syncingIds = /* @__PURE__ */ new Set();
2731
+ maxQueueSize = 1e3;
2732
+ defaultMaxRetries = 3;
2733
+ constructor(maxQueueSize = 1e3, defaultMaxRetries = 3) {
2734
+ super();
2735
+ this.maxQueueSize = maxQueueSize;
2736
+ this.defaultMaxRetries = defaultMaxRetries;
2737
+ logger2.debug("[OfflineOperationQueue] Initialized", {
2738
+ maxQueueSize,
2739
+ defaultMaxRetries
2740
+ });
2741
+ }
2742
+ /**
2743
+ * Add operation to the queue
2744
+ */
2745
+ enqueue(type, data, sessionId, priority = "normal", maxRetries) {
2746
+ if (this.queue.size >= this.maxQueueSize) {
2747
+ const oldest = this.findOldestLowPriority();
2748
+ if (oldest) {
2749
+ this.queue.delete(oldest.id);
2750
+ logger2.warn("[OfflineOperationQueue] Queue full, removed oldest", {
2751
+ removedId: oldest.id
2752
+ });
2753
+ }
2754
+ }
2755
+ const operation = {
2756
+ id: `op-${Date.now()}-${Math.random().toString(36).slice(2)}`,
2757
+ type,
2758
+ data,
2759
+ sessionId,
2760
+ priority,
2761
+ createdAt: Date.now(),
2762
+ retryCount: 0,
2763
+ maxRetries: maxRetries ?? this.defaultMaxRetries,
2764
+ status: "pending"
2765
+ };
2766
+ this.queue.set(operation.id, operation);
2767
+ this.emit("operation-added", operation);
2768
+ logger2.debug("[OfflineOperationQueue] Operation enqueued", {
2769
+ id: operation.id,
2770
+ type,
2771
+ priority,
2772
+ queueSize: this.queue.size
2773
+ });
2774
+ return operation;
2775
+ }
2776
+ /**
2777
+ * Get next operations to sync (by priority)
2778
+ */
2779
+ getNextBatch(batchSize = 10) {
2780
+ const pending = Array.from(this.queue.values()).filter((op) => op.status === "pending" && !this.syncingIds.has(op.id)).sort((a, b) => {
2781
+ const priorityOrder = { high: 0, normal: 1, low: 2 };
2782
+ const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
2783
+ if (priorityDiff !== 0) return priorityDiff;
2784
+ return a.createdAt - b.createdAt;
2785
+ });
2786
+ return pending.slice(0, batchSize);
2787
+ }
2788
+ /**
2789
+ * Mark operations as syncing
2790
+ */
2791
+ markSyncing(operationIds) {
2792
+ for (const id of operationIds) {
2793
+ const op = this.queue.get(id);
2794
+ if (op) {
2795
+ op.status = "syncing";
2796
+ this.syncingIds.add(id);
2797
+ }
2798
+ }
2799
+ }
2800
+ /**
2801
+ * Mark operation as synced
2802
+ */
2803
+ markSynced(operationId) {
2804
+ const op = this.queue.get(operationId);
2805
+ if (op) {
2806
+ op.status = "synced";
2807
+ this.syncingIds.delete(operationId);
2808
+ this.emit("operation-synced", op);
2809
+ setTimeout(() => {
2810
+ this.queue.delete(operationId);
2811
+ if (this.getPendingCount() === 0) {
2812
+ this.emit("queue-empty");
2813
+ }
2814
+ }, 1e3);
2815
+ }
2816
+ }
2817
+ /**
2818
+ * Mark operation as failed
2819
+ */
2820
+ markFailed(operationId, error) {
2821
+ const op = this.queue.get(operationId);
2822
+ if (op) {
2823
+ op.retryCount++;
2824
+ op.lastError = error.message;
2825
+ this.syncingIds.delete(operationId);
2826
+ if (op.retryCount >= op.maxRetries) {
2827
+ op.status = "failed";
2828
+ this.emit("operation-failed", op, error);
2829
+ logger2.error("[OfflineOperationQueue] Operation permanently failed", {
2830
+ id: operationId,
2831
+ retries: op.retryCount,
2832
+ error: error.message
2833
+ });
2834
+ } else {
2835
+ op.status = "pending";
2836
+ logger2.warn("[OfflineOperationQueue] Operation failed, will retry", {
2837
+ id: operationId,
2838
+ retryCount: op.retryCount,
2839
+ maxRetries: op.maxRetries
2840
+ });
2841
+ }
2842
+ }
2843
+ }
2844
+ /**
2845
+ * Get operation by ID
2846
+ */
2847
+ getOperation(operationId) {
2848
+ return this.queue.get(operationId);
2849
+ }
2850
+ /**
2851
+ * Get all pending operations
2852
+ */
2853
+ getPendingOperations() {
2854
+ return Array.from(this.queue.values()).filter(
2855
+ (op) => op.status === "pending"
2856
+ );
2857
+ }
2858
+ /**
2859
+ * Get pending count
2860
+ */
2861
+ getPendingCount() {
2862
+ return Array.from(this.queue.values()).filter(
2863
+ (op) => op.status === "pending"
2864
+ ).length;
2865
+ }
2866
+ /**
2867
+ * Get queue statistics
2868
+ */
2869
+ getStats() {
2870
+ const operations = Array.from(this.queue.values());
2871
+ const pending = operations.filter((op) => op.status === "pending").length;
2872
+ const syncing = operations.filter((op) => op.status === "syncing").length;
2873
+ const failed = operations.filter((op) => op.status === "failed").length;
2874
+ const synced = operations.filter((op) => op.status === "synced").length;
2875
+ const pendingOps = operations.filter((op) => op.status === "pending");
2876
+ const oldestPendingMs = pendingOps.length > 0 ? Date.now() - Math.min(...pendingOps.map((op) => op.createdAt)) : 0;
2877
+ const averageRetries = operations.length > 0 ? operations.reduce((sum, op) => sum + op.retryCount, 0) / operations.length : 0;
2878
+ return {
2879
+ pending,
2880
+ syncing,
2881
+ failed,
2882
+ synced,
2883
+ totalOperations: operations.length,
2884
+ oldestPendingMs,
2885
+ averageRetries
2886
+ };
2887
+ }
2888
+ /**
2889
+ * Clear all operations
2890
+ */
2891
+ clear() {
2892
+ this.queue.clear();
2893
+ this.syncingIds.clear();
2894
+ logger2.debug("[OfflineOperationQueue] Queue cleared");
2895
+ }
2896
+ /**
2897
+ * Clear failed operations
2898
+ */
2899
+ clearFailed() {
2900
+ for (const [id, op] of this.queue.entries()) {
2901
+ if (op.status === "failed") {
2902
+ this.queue.delete(id);
2903
+ }
2904
+ }
2905
+ }
2906
+ /**
2907
+ * Retry failed operations
2908
+ */
2909
+ retryFailed() {
2910
+ for (const op of this.queue.values()) {
2911
+ if (op.status === "failed") {
2912
+ op.status = "pending";
2913
+ op.retryCount = 0;
2914
+ }
2915
+ }
2916
+ }
2917
+ /**
2918
+ * Find oldest low-priority operation
2919
+ */
2920
+ findOldestLowPriority() {
2921
+ const lowPriority = Array.from(this.queue.values()).filter((op) => op.priority === "low" && op.status === "pending").sort((a, b) => a.createdAt - b.createdAt);
2922
+ return lowPriority[0] ?? null;
2923
+ }
2924
+ /**
2925
+ * Export queue for persistence
2926
+ */
2927
+ export() {
2928
+ return Array.from(this.queue.values());
2929
+ }
2930
+ /**
2931
+ * Import queue from persistence
2932
+ */
2933
+ import(operations) {
2934
+ for (const op of operations) {
2935
+ this.queue.set(op.id, op);
2936
+ }
2937
+ logger2.debug("[OfflineOperationQueue] Imported operations", {
2938
+ count: operations.length
2939
+ });
2940
+ }
2941
+ };
2942
+ var offlineQueueInstance = null;
2943
+ function getOfflineOperationQueue() {
2944
+ if (!offlineQueueInstance) {
2945
+ offlineQueueInstance = new OfflineOperationQueue();
2946
+ }
2947
+ return offlineQueueInstance;
2948
+ }
2949
+ function resetOfflineOperationQueue() {
2950
+ offlineQueueInstance = null;
2951
+ }
2952
+
2953
+ // src/compression/CompressionEngine.ts
2954
+ var logger3 = getLogger();
2955
+ var CompressionEngine = class {
2956
+ stats = {
2957
+ totalCompressed: 0,
2958
+ totalDecompressed: 0,
2959
+ totalOriginalBytes: 0,
2960
+ totalCompressedBytes: 0,
2961
+ averageCompressionRatio: 0,
2962
+ compressionTimeMs: 0,
2963
+ decompressionTimeMs: 0
2964
+ };
2965
+ preferredAlgorithm = "gzip";
2966
+ constructor(preferredAlgorithm = "gzip") {
2967
+ this.preferredAlgorithm = preferredAlgorithm;
2968
+ logger3.debug("[CompressionEngine] Initialized", {
2969
+ algorithm: preferredAlgorithm,
2970
+ supportsNative: this.supportsNativeCompression()
2971
+ });
2972
+ }
2973
+ /**
2974
+ * Check if native compression is available
2975
+ */
2976
+ supportsNativeCompression() {
2977
+ return typeof CompressionStream !== "undefined" && typeof DecompressionStream !== "undefined";
2978
+ }
2979
+ /**
2980
+ * Compress data
2981
+ */
2982
+ async compress(data) {
2983
+ const startTime = performance.now();
2984
+ const inputData = typeof data === "string" ? new TextEncoder().encode(data) : data;
2985
+ const originalSize = inputData.byteLength;
2986
+ let compressed;
2987
+ let algorithm = this.preferredAlgorithm;
2988
+ if (this.supportsNativeCompression()) {
2989
+ try {
2990
+ compressed = await this.compressNative(inputData, this.preferredAlgorithm);
2991
+ } catch (error) {
2992
+ logger3.warn("[CompressionEngine] Native compression failed, using fallback", error);
2993
+ compressed = inputData;
2994
+ algorithm = "none";
2995
+ }
2996
+ } else {
2997
+ compressed = inputData;
2998
+ algorithm = "none";
2999
+ }
3000
+ const compressionRatio = originalSize > 0 ? 1 - compressed.byteLength / originalSize : 0;
3001
+ const batch = {
3002
+ id: `batch-${Date.now()}-${Math.random().toString(36).slice(2)}`,
3003
+ compressed,
3004
+ originalSize,
3005
+ compressedSize: compressed.byteLength,
3006
+ compressionRatio,
3007
+ algorithm,
3008
+ timestamp: Date.now()
3009
+ };
3010
+ const elapsed = performance.now() - startTime;
3011
+ this.stats.totalCompressed++;
3012
+ this.stats.totalOriginalBytes += originalSize;
3013
+ this.stats.totalCompressedBytes += compressed.byteLength;
3014
+ this.stats.compressionTimeMs += elapsed;
3015
+ this.updateAverageRatio();
3016
+ logger3.debug("[CompressionEngine] Compressed", {
3017
+ original: originalSize,
3018
+ compressed: compressed.byteLength,
3019
+ ratio: (compressionRatio * 100).toFixed(1) + "%",
3020
+ algorithm,
3021
+ timeMs: elapsed.toFixed(2)
3022
+ });
3023
+ return batch;
3024
+ }
3025
+ /**
3026
+ * Decompress data
3027
+ */
3028
+ async decompress(batch) {
3029
+ const startTime = performance.now();
3030
+ let decompressed;
3031
+ if (batch.algorithm === "none") {
3032
+ decompressed = batch.compressed;
3033
+ } else if (this.supportsNativeCompression()) {
3034
+ try {
3035
+ decompressed = await this.decompressNative(
3036
+ batch.compressed,
3037
+ batch.algorithm
3038
+ );
3039
+ } catch (error) {
3040
+ logger3.warn("[CompressionEngine] Native decompression failed", error);
3041
+ throw error;
3042
+ }
3043
+ } else {
3044
+ throw new Error("Native decompression not available");
3045
+ }
3046
+ const elapsed = performance.now() - startTime;
3047
+ this.stats.totalDecompressed++;
3048
+ this.stats.decompressionTimeMs += elapsed;
3049
+ logger3.debug("[CompressionEngine] Decompressed", {
3050
+ compressed: batch.compressedSize,
3051
+ decompressed: decompressed.byteLength,
3052
+ algorithm: batch.algorithm,
3053
+ timeMs: elapsed.toFixed(2)
3054
+ });
3055
+ return decompressed;
3056
+ }
3057
+ /**
3058
+ * Compress using native CompressionStream
3059
+ */
3060
+ async compressNative(data, algorithm) {
3061
+ const stream = new CompressionStream(algorithm);
3062
+ const writer = stream.writable.getWriter();
3063
+ const reader = stream.readable.getReader();
3064
+ writer.write(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
3065
+ writer.close();
3066
+ const chunks = [];
3067
+ let done = false;
3068
+ while (!done) {
3069
+ const result = await reader.read();
3070
+ done = result.done;
3071
+ if (result.value) {
3072
+ chunks.push(result.value);
3073
+ }
3074
+ }
3075
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
3076
+ const combined = new Uint8Array(totalLength);
3077
+ let offset = 0;
3078
+ for (const chunk of chunks) {
3079
+ combined.set(chunk, offset);
3080
+ offset += chunk.length;
3081
+ }
3082
+ return combined;
3083
+ }
3084
+ /**
3085
+ * Decompress using native DecompressionStream
3086
+ */
3087
+ async decompressNative(data, algorithm) {
3088
+ const stream = new DecompressionStream(algorithm);
3089
+ const writer = stream.writable.getWriter();
3090
+ const reader = stream.readable.getReader();
3091
+ writer.write(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
3092
+ writer.close();
3093
+ const chunks = [];
3094
+ let done = false;
3095
+ while (!done) {
3096
+ const result = await reader.read();
3097
+ done = result.done;
3098
+ if (result.value) {
3099
+ chunks.push(result.value);
3100
+ }
3101
+ }
3102
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
3103
+ const combined = new Uint8Array(totalLength);
3104
+ let offset = 0;
3105
+ for (const chunk of chunks) {
3106
+ combined.set(chunk, offset);
3107
+ offset += chunk.length;
3108
+ }
3109
+ return combined;
3110
+ }
3111
+ /**
3112
+ * Split compressed batch into chunks for transmission
3113
+ */
3114
+ splitIntoChunks(batch, chunkSize = 64 * 1024) {
3115
+ const chunks = [];
3116
+ const data = batch.compressed;
3117
+ const total = Math.ceil(data.byteLength / chunkSize);
3118
+ for (let i = 0; i < total; i++) {
3119
+ const start = i * chunkSize;
3120
+ const end = Math.min(start + chunkSize, data.byteLength);
3121
+ const chunkData = data.slice(start, end);
3122
+ chunks.push({
3123
+ chunkId: `${batch.id}-chunk-${i}`,
3124
+ batchId: batch.id,
3125
+ data: chunkData,
3126
+ index: i,
3127
+ total,
3128
+ checksum: this.simpleChecksum(chunkData)
3129
+ });
3130
+ }
3131
+ return chunks;
3132
+ }
3133
+ /**
3134
+ * Reassemble chunks into compressed batch
3135
+ */
3136
+ reassembleChunks(chunks) {
3137
+ const sorted = [...chunks].sort((a, b) => a.index - b.index);
3138
+ const total = sorted[0]?.total ?? 0;
3139
+ if (sorted.length !== total) {
3140
+ throw new Error(`Missing chunks: got ${sorted.length}, expected ${total}`);
3141
+ }
3142
+ const totalLength = sorted.reduce((sum, chunk) => sum + chunk.data.length, 0);
3143
+ const combined = new Uint8Array(totalLength);
3144
+ let offset = 0;
3145
+ for (const chunk of sorted) {
3146
+ combined.set(chunk.data, offset);
3147
+ offset += chunk.data.length;
3148
+ }
3149
+ return combined;
3150
+ }
3151
+ /**
3152
+ * Simple checksum for chunk verification
3153
+ */
3154
+ simpleChecksum(data) {
3155
+ let hash = 0;
3156
+ for (let i = 0; i < data.length; i++) {
3157
+ hash = (hash << 5) - hash + data[i] | 0;
3158
+ }
3159
+ return hash.toString(16);
3160
+ }
3161
+ /**
3162
+ * Update average compression ratio
3163
+ */
3164
+ updateAverageRatio() {
3165
+ if (this.stats.totalOriginalBytes > 0) {
3166
+ this.stats.averageCompressionRatio = 1 - this.stats.totalCompressedBytes / this.stats.totalOriginalBytes;
3167
+ }
3168
+ }
3169
+ /**
3170
+ * Get statistics
3171
+ */
3172
+ getStats() {
3173
+ return { ...this.stats };
3174
+ }
3175
+ /**
3176
+ * Reset statistics
3177
+ */
3178
+ resetStats() {
3179
+ this.stats = {
3180
+ totalCompressed: 0,
3181
+ totalDecompressed: 0,
3182
+ totalOriginalBytes: 0,
3183
+ totalCompressedBytes: 0,
3184
+ averageCompressionRatio: 0,
3185
+ compressionTimeMs: 0,
3186
+ decompressionTimeMs: 0
3187
+ };
3188
+ }
3189
+ };
3190
+ var compressionEngineInstance = null;
3191
+ function getCompressionEngine() {
3192
+ if (!compressionEngineInstance) {
3193
+ compressionEngineInstance = new CompressionEngine();
3194
+ }
3195
+ return compressionEngineInstance;
3196
+ }
3197
+ function resetCompressionEngine() {
3198
+ compressionEngineInstance = null;
3199
+ }
3200
+
3201
+ // src/compression/DeltaSyncOptimizer.ts
3202
+ var logger4 = getLogger();
3203
+ var DeltaSyncOptimizer = class {
3204
+ operationHistory = /* @__PURE__ */ new Map();
3205
+ stats = {
3206
+ totalOperations: 0,
3207
+ totalFull: 0,
3208
+ totalDelta: 0,
3209
+ totalOriginalSize: 0,
3210
+ totalDeltaSize: 0,
3211
+ averageReductionPercent: 0,
3212
+ lastSyncTime: 0,
3213
+ fullOperationThreshold: 1e3
3214
+ // Force full if delta > 1KB
3215
+ };
3216
+ constructor(fullOperationThreshold = 1e3) {
3217
+ this.stats.fullOperationThreshold = fullOperationThreshold;
3218
+ logger4.debug("[DeltaSyncOptimizer] Initialized", {
3219
+ threshold: fullOperationThreshold
3220
+ });
3221
+ }
3222
+ /**
3223
+ * Compute delta for single operation
3224
+ */
3225
+ computeDelta(operation) {
3226
+ const operationJson = JSON.stringify(operation);
3227
+ const originalSize = new TextEncoder().encode(operationJson).byteLength;
3228
+ const previous = this.operationHistory.get(operation.id);
3229
+ if (!previous) {
3230
+ const delta = {
3231
+ id: `delta-${Date.now()}-${Math.random().toString(36).slice(2)}`,
3232
+ type: "full",
3233
+ operationId: operation.id,
3234
+ operationType: operation.type,
3235
+ sessionId: operation.sessionId,
3236
+ timestamp: Date.now(),
3237
+ fullData: operation.data,
3238
+ priority: operation.priority
3239
+ };
3240
+ this.stats.totalOperations++;
3241
+ this.stats.totalFull++;
3242
+ this.stats.totalOriginalSize += originalSize;
3243
+ const deltaSize2 = new TextEncoder().encode(
3244
+ JSON.stringify(delta)
3245
+ ).byteLength;
3246
+ this.stats.totalDeltaSize += deltaSize2;
3247
+ this.operationHistory.set(operation.id, operation);
3248
+ return delta;
3249
+ }
3250
+ const changes = {};
3251
+ const changeMask = [];
3252
+ let hasMeaningfulChanges = false;
3253
+ for (const [key, value] of Object.entries(operation.data)) {
3254
+ const oldValue = previous.data[key];
3255
+ if (!this.deepEqual(value, oldValue)) {
3256
+ changes[key] = value;
3257
+ changeMask.push(key);
3258
+ hasMeaningfulChanges = true;
3259
+ }
3260
+ }
3261
+ for (const key of Object.keys(previous.data)) {
3262
+ if (!(key in operation.data)) {
3263
+ changes[key] = null;
3264
+ changeMask.push(`${key}:deleted`);
3265
+ hasMeaningfulChanges = true;
3266
+ }
3267
+ }
3268
+ const deltaData = {
3269
+ id: `delta-${Date.now()}-${Math.random().toString(36).slice(2)}`,
3270
+ type: "delta",
3271
+ operationId: operation.id,
3272
+ operationType: operation.type,
3273
+ sessionId: operation.sessionId,
3274
+ timestamp: Date.now(),
3275
+ changes: hasMeaningfulChanges ? changes : void 0,
3276
+ changeMask: hasMeaningfulChanges ? changeMask : void 0,
3277
+ priority: operation.priority
3278
+ };
3279
+ const deltaSize = new TextEncoder().encode(
3280
+ JSON.stringify(deltaData)
3281
+ ).byteLength;
3282
+ const finalDelta = deltaSize > this.stats.fullOperationThreshold ? {
3283
+ ...deltaData,
3284
+ type: "full",
3285
+ fullData: operation.data,
3286
+ changes: void 0,
3287
+ changeMask: void 0
3288
+ } : deltaData;
3289
+ this.stats.totalOperations++;
3290
+ if (finalDelta.type === "full") {
3291
+ this.stats.totalFull++;
3292
+ } else {
3293
+ this.stats.totalDelta++;
3294
+ }
3295
+ this.stats.totalOriginalSize += originalSize;
3296
+ this.stats.totalDeltaSize += deltaSize;
3297
+ this.operationHistory.set(operation.id, operation);
3298
+ return finalDelta;
3299
+ }
3300
+ /**
3301
+ * Compute deltas for batch of operations
3302
+ */
3303
+ computeBatchDeltas(operations) {
3304
+ const deltas = operations.map((op) => this.computeDelta(op));
3305
+ const totalOriginalSize = operations.reduce(
3306
+ (sum, op) => sum + new TextEncoder().encode(JSON.stringify(op)).byteLength,
3307
+ 0
3308
+ );
3309
+ const totalDeltaSize = deltas.reduce(
3310
+ (sum, delta) => sum + new TextEncoder().encode(JSON.stringify(delta)).byteLength,
3311
+ 0
3312
+ );
3313
+ const reductionPercent = totalOriginalSize > 0 ? Math.round(
3314
+ (totalOriginalSize - totalDeltaSize) / totalOriginalSize * 100
3315
+ ) : 0;
3316
+ const batch = {
3317
+ batchId: `batch-${Date.now()}-${Math.random().toString(36).slice(2)}`,
3318
+ operations: deltas,
3319
+ timestamp: Date.now(),
3320
+ totalOriginalSize,
3321
+ totalDeltaSize,
3322
+ reductionPercent
3323
+ };
3324
+ logger4.debug("[DeltaSyncOptimizer] Batch computed", {
3325
+ operations: operations.length,
3326
+ reduction: reductionPercent,
3327
+ size: totalDeltaSize
3328
+ });
3329
+ return batch;
3330
+ }
3331
+ /**
3332
+ * Decompress delta operation back to full operation
3333
+ */
3334
+ decompressDelta(delta) {
3335
+ if (delta.type === "full") {
3336
+ return {
3337
+ id: delta.operationId,
3338
+ type: delta.operationType,
3339
+ sessionId: delta.sessionId,
3340
+ data: delta.fullData || {},
3341
+ status: "pending",
3342
+ createdAt: delta.timestamp
3343
+ };
3344
+ }
3345
+ const previous = this.operationHistory.get(delta.operationId);
3346
+ if (!previous) {
3347
+ logger4.warn("[DeltaSyncOptimizer] Cannot decompress - no history", {
3348
+ operationId: delta.operationId
3349
+ });
3350
+ return {
3351
+ id: delta.operationId,
3352
+ type: delta.operationType,
3353
+ sessionId: delta.sessionId,
3354
+ data: delta.changes || {},
3355
+ status: "pending",
3356
+ createdAt: delta.timestamp
3357
+ };
3358
+ }
3359
+ const reconstructed = {
3360
+ ...previous,
3361
+ data: {
3362
+ ...previous.data,
3363
+ ...delta.changes || {}
3364
+ }
3365
+ };
3366
+ if (delta.changes) {
3367
+ for (const [key, value] of Object.entries(delta.changes)) {
3368
+ if (value === null) {
3369
+ delete reconstructed.data[key];
3370
+ }
3371
+ }
3372
+ }
3373
+ return reconstructed;
3374
+ }
3375
+ /**
3376
+ * Update history after successful sync
3377
+ */
3378
+ updateHistory(operations) {
3379
+ for (const op of operations) {
3380
+ this.operationHistory.set(op.id, op);
3381
+ }
3382
+ logger4.debug("[DeltaSyncOptimizer] History updated", {
3383
+ count: operations.length,
3384
+ totalHistorySize: this.operationHistory.size
3385
+ });
3386
+ }
3387
+ /**
3388
+ * Clear history for specific operations
3389
+ */
3390
+ clearHistory(operationIds) {
3391
+ for (const id of operationIds) {
3392
+ this.operationHistory.delete(id);
3393
+ }
3394
+ logger4.debug("[DeltaSyncOptimizer] History cleared", {
3395
+ cleared: operationIds.length,
3396
+ remaining: this.operationHistory.size
3397
+ });
3398
+ }
3399
+ /**
3400
+ * Get current performance statistics
3401
+ */
3402
+ getStats() {
3403
+ if (this.stats.totalOperations > 0) {
3404
+ this.stats.averageReductionPercent = Math.round(
3405
+ (this.stats.totalOriginalSize - this.stats.totalDeltaSize) / this.stats.totalOriginalSize * 100
3406
+ );
3407
+ }
3408
+ return { ...this.stats };
3409
+ }
3410
+ /**
3411
+ * Reset statistics
3412
+ */
3413
+ resetStats() {
3414
+ this.stats = {
3415
+ totalOperations: 0,
3416
+ totalFull: 0,
3417
+ totalDelta: 0,
3418
+ totalOriginalSize: 0,
3419
+ totalDeltaSize: 0,
3420
+ averageReductionPercent: 0,
3421
+ lastSyncTime: 0,
3422
+ fullOperationThreshold: this.stats.fullOperationThreshold
3423
+ };
3424
+ logger4.debug("[DeltaSyncOptimizer] Stats reset");
3425
+ }
3426
+ /**
3427
+ * Set the full operation threshold
3428
+ */
3429
+ setFullOperationThreshold(bytes) {
3430
+ this.stats.fullOperationThreshold = bytes;
3431
+ logger4.debug("[DeltaSyncOptimizer] Threshold updated", { bytes });
3432
+ }
3433
+ /**
3434
+ * Get history size for memory monitoring
3435
+ */
3436
+ getHistorySize() {
3437
+ return this.operationHistory.size;
3438
+ }
3439
+ /**
3440
+ * Get memory footprint estimate
3441
+ */
3442
+ getMemoryEstimate() {
3443
+ let totalBytes = 0;
3444
+ for (const op of this.operationHistory.values()) {
3445
+ totalBytes += new TextEncoder().encode(JSON.stringify(op)).byteLength;
3446
+ }
3447
+ return totalBytes;
3448
+ }
3449
+ /**
3450
+ * Deep equality check for nested objects
3451
+ */
3452
+ deepEqual(a, b) {
3453
+ if (a === b) return true;
3454
+ if (a == null || b == null) return false;
3455
+ if (typeof a !== "object" || typeof b !== "object") return false;
3456
+ const aObj = a;
3457
+ const bObj = b;
3458
+ const aKeys = Object.keys(aObj);
3459
+ const bKeys = Object.keys(bObj);
3460
+ if (aKeys.length !== bKeys.length) return false;
3461
+ for (const key of aKeys) {
3462
+ if (!this.deepEqual(aObj[key], bObj[key])) {
3463
+ return false;
3464
+ }
3465
+ }
3466
+ return true;
3467
+ }
3468
+ };
3469
+ var deltaSyncInstance = null;
3470
+ function getDeltaSyncOptimizer(threshold) {
3471
+ if (!deltaSyncInstance) {
3472
+ deltaSyncInstance = new DeltaSyncOptimizer(threshold);
3473
+ }
3474
+ return deltaSyncInstance;
3475
+ }
3476
+ function resetDeltaSyncOptimizer() {
3477
+ deltaSyncInstance = null;
3478
+ }
3479
+
3480
+ // src/optimization/PrefetchingEngine.ts
3481
+ var logger5 = getLogger();
3482
+ var PrefetchingEngine = class {
3483
+ operationHistory = [];
3484
+ patterns = /* @__PURE__ */ new Map();
3485
+ prefetchCache = /* @__PURE__ */ new Map();
3486
+ maxHistoryEntries = 1e3;
3487
+ maxCachePerType = 5;
3488
+ prefetchTTL = 5 * 60 * 1e3;
3489
+ // 5 minutes
3490
+ predictionThreshold = 0.3;
3491
+ stats = {
3492
+ totalPrefetched: 0,
3493
+ totalHits: 0,
3494
+ totalMisses: 0,
3495
+ totalOverwrites: 0,
3496
+ hitRatio: 0,
3497
+ bandwidthSaved: 0,
3498
+ patternsDetected: 0,
3499
+ predictionAccuracy: 0
3500
+ };
3501
+ lastPredictionTime = 0;
3502
+ predictionInterval = 30 * 1e3;
3503
+ constructor() {
3504
+ logger5.debug("[PrefetchingEngine] Initialized", {
3505
+ ttl: this.prefetchTTL,
3506
+ threshold: this.predictionThreshold
3507
+ });
3508
+ }
3509
+ /**
3510
+ * Record operation for pattern analysis
3511
+ */
3512
+ recordOperation(operationType, size) {
3513
+ const now = Date.now();
3514
+ this.operationHistory.push({
3515
+ type: operationType,
3516
+ timestamp: now,
3517
+ size
3518
+ });
3519
+ if (this.operationHistory.length > this.maxHistoryEntries) {
3520
+ this.operationHistory.shift();
3521
+ }
3522
+ if (Math.random() < 0.1) {
3523
+ this.cleanExpiredPrefetches();
3524
+ }
3525
+ logger5.debug("[PrefetchingEngine] Operation recorded", {
3526
+ type: operationType,
3527
+ size,
3528
+ historySize: this.operationHistory.length
3529
+ });
3530
+ }
3531
+ /**
3532
+ * Analyze patterns in operation history
3533
+ */
3534
+ analyzePatterns() {
3535
+ if (this.operationHistory.length < 5) {
3536
+ return;
3537
+ }
3538
+ const patterns = /* @__PURE__ */ new Map();
3539
+ for (let length = 2; length <= 3; length++) {
3540
+ for (let i = 0; i < this.operationHistory.length - length; i++) {
3541
+ const sequence = this.operationHistory.slice(i, i + length).map((op) => op.type);
3542
+ const key = sequence.join(" \u2192 ");
3543
+ if (!patterns.has(key)) {
3544
+ patterns.set(key, {
3545
+ sequence,
3546
+ frequency: 0,
3547
+ probability: 0,
3548
+ lastOccurred: 0,
3549
+ avgIntervalMs: 0
3550
+ });
3551
+ }
3552
+ const pattern = patterns.get(key);
3553
+ pattern.frequency++;
3554
+ pattern.lastOccurred = Date.now();
3555
+ }
3556
+ }
3557
+ const totalSequences = this.operationHistory.length;
3558
+ for (const [key, pattern] of patterns.entries()) {
3559
+ pattern.probability = Math.min(1, pattern.frequency / totalSequences);
3560
+ }
3561
+ this.patterns = patterns;
3562
+ this.stats.patternsDetected = patterns.size;
3563
+ logger5.debug("[PrefetchingEngine] Patterns analyzed", {
3564
+ patternsFound: patterns.size
3565
+ });
3566
+ }
3567
+ /**
3568
+ * Predict next operations
3569
+ */
3570
+ predictNextOperations(recentOperations) {
3571
+ const now = Date.now();
3572
+ if (now - this.lastPredictionTime > this.predictionInterval) {
3573
+ this.analyzePatterns();
3574
+ this.lastPredictionTime = now;
3575
+ }
3576
+ if (this.patterns.size === 0) {
3577
+ return [];
3578
+ }
3579
+ const predictions = [];
3580
+ const recentTypeSequence = recentOperations.slice(-3).map((op) => op.type).join(" \u2192 ");
3581
+ for (const [key, pattern] of this.patterns.entries()) {
3582
+ if (key.includes(recentTypeSequence)) {
3583
+ const nextType = pattern.sequence[pattern.sequence.length - 1];
3584
+ const prediction = {
3585
+ operationType: nextType,
3586
+ probability: pattern.probability,
3587
+ reason: `Detected pattern: ${key}`,
3588
+ shouldPrefetch: pattern.probability > this.predictionThreshold,
3589
+ estimatedTimeMs: pattern.avgIntervalMs
3590
+ };
3591
+ predictions.push(prediction);
3592
+ }
3593
+ }
3594
+ const deduped = Array.from(
3595
+ new Map(predictions.map((p) => [p.operationType, p])).values()
3596
+ ).sort((a, b) => b.probability - a.probability);
3597
+ logger5.debug("[PrefetchingEngine] Predictions", {
3598
+ predictions: deduped.slice(0, 3).map((p) => ({
3599
+ type: p.operationType,
3600
+ probability: (p.probability * 100).toFixed(1) + "%"
3601
+ }))
3602
+ });
3603
+ return deduped;
3604
+ }
3605
+ /**
3606
+ * Add prefetched batch
3607
+ */
3608
+ addPrefetchedBatch(operationType, compressed, originalSize) {
3609
+ if (!this.prefetchCache.has(operationType)) {
3610
+ this.prefetchCache.set(operationType, []);
3611
+ }
3612
+ const cache = this.prefetchCache.get(operationType);
3613
+ if (cache.length >= this.maxCachePerType) {
3614
+ const oldest = cache.shift();
3615
+ if (oldest.hitCount === 0) {
3616
+ this.stats.totalMisses++;
3617
+ } else {
3618
+ this.stats.totalOverwrites++;
3619
+ }
3620
+ }
3621
+ const batch = {
3622
+ id: `prefetch-${operationType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
3623
+ operationType,
3624
+ compressed,
3625
+ compressedSize: compressed.length,
3626
+ originalSize,
3627
+ compressionRatio: 1 - compressed.length / originalSize,
3628
+ compressed_at: Date.now(),
3629
+ created_at: Date.now(),
3630
+ ttl: this.prefetchTTL,
3631
+ expiresAt: Date.now() + this.prefetchTTL,
3632
+ hitCount: 0,
3633
+ missCount: 0
3634
+ };
3635
+ cache.push(batch);
3636
+ this.stats.totalPrefetched++;
3637
+ this.stats.bandwidthSaved += originalSize - compressed.length;
3638
+ logger5.debug("[PrefetchingEngine] Prefetched batch added", {
3639
+ type: operationType,
3640
+ id: batch.id,
3641
+ ratio: (batch.compressionRatio * 100).toFixed(1) + "%"
3642
+ });
3643
+ return batch;
3644
+ }
3645
+ /**
3646
+ * Try to use prefetched batch
3647
+ */
3648
+ getPrefetchedBatch(operationType) {
3649
+ const cache = this.prefetchCache.get(operationType);
3650
+ if (!cache || cache.length === 0) {
3651
+ return null;
3652
+ }
3653
+ const now = Date.now();
3654
+ for (let i = 0; i < cache.length; i++) {
3655
+ const batch = cache[i];
3656
+ if (batch.expiresAt > now) {
3657
+ batch.hitCount++;
3658
+ this.stats.totalHits++;
3659
+ this.updatePredictionAccuracy(true);
3660
+ logger5.debug("[PrefetchingEngine] Prefetch hit", {
3661
+ type: operationType,
3662
+ id: batch.id
3663
+ });
3664
+ return batch;
3665
+ } else {
3666
+ cache.splice(i, 1);
3667
+ i--;
3668
+ batch.missCount++;
3669
+ this.stats.totalMisses++;
3670
+ this.updatePredictionAccuracy(false);
3671
+ }
3672
+ }
3673
+ return null;
3674
+ }
3675
+ /**
3676
+ * Update prediction accuracy metric
3677
+ */
3678
+ updatePredictionAccuracy(hit) {
3679
+ const total = this.stats.totalHits + this.stats.totalMisses;
3680
+ if (total === 0) return;
3681
+ this.stats.predictionAccuracy = this.stats.totalHits / total;
3682
+ }
3683
+ /**
3684
+ * Clean expired prefetches
3685
+ */
3686
+ cleanExpiredPrefetches() {
3687
+ const now = Date.now();
3688
+ let cleanedCount = 0;
3689
+ for (const [type, cache] of this.prefetchCache.entries()) {
3690
+ for (let i = cache.length - 1; i >= 0; i--) {
3691
+ if (cache[i].expiresAt < now) {
3692
+ const batch = cache.splice(i, 1)[0];
3693
+ if (batch.hitCount === 0) {
3694
+ this.stats.totalMisses++;
3695
+ }
3696
+ cleanedCount++;
3697
+ }
3698
+ }
3699
+ if (cache.length === 0) {
3700
+ this.prefetchCache.delete(type);
3701
+ }
3702
+ }
3703
+ if (cleanedCount > 0) {
3704
+ logger5.debug("[PrefetchingEngine] Cleaned expired prefetches", {
3705
+ count: cleanedCount
3706
+ });
3707
+ }
3708
+ }
3709
+ /**
3710
+ * Get statistics
3711
+ */
3712
+ getStats() {
3713
+ const total = this.stats.totalHits + this.stats.totalMisses;
3714
+ this.stats.hitRatio = total > 0 ? this.stats.totalHits / total : 0;
3715
+ return { ...this.stats };
3716
+ }
3717
+ /**
3718
+ * Clear all caches
3719
+ */
3720
+ clear() {
3721
+ this.operationHistory = [];
3722
+ this.patterns.clear();
3723
+ this.prefetchCache.clear();
3724
+ this.stats = {
3725
+ totalPrefetched: 0,
3726
+ totalHits: 0,
3727
+ totalMisses: 0,
3728
+ totalOverwrites: 0,
3729
+ hitRatio: 0,
3730
+ bandwidthSaved: 0,
3731
+ patternsDetected: 0,
3732
+ predictionAccuracy: 0
3733
+ };
3734
+ logger5.debug("[PrefetchingEngine] Cleared all caches");
3735
+ }
3736
+ };
3737
+ var prefetchingEngineInstance = null;
3738
+ function getPrefetchingEngine() {
3739
+ if (!prefetchingEngineInstance) {
3740
+ prefetchingEngineInstance = new PrefetchingEngine();
3741
+ }
3742
+ return prefetchingEngineInstance;
3743
+ }
3744
+ function resetPrefetchingEngine() {
3745
+ prefetchingEngineInstance = null;
3746
+ }
3747
+
3748
+ // src/optimization/BatchTimingOptimizer.ts
3749
+ var logger6 = getLogger();
3750
+ var BatchTimingOptimizer = class {
3751
+ networkHistory = [];
3752
+ activityHistory = [];
3753
+ stats = {
3754
+ totalBatches: 0,
3755
+ immediateDeliveries: 0,
3756
+ deferredBatches: 0,
3757
+ averageWaitTimeMs: 0,
3758
+ averageDeliveryTimeMs: 0,
3759
+ networkWindowsUsed: 0,
3760
+ congestionAvoided: 0,
3761
+ userFocusedOptimizations: 0
3762
+ };
3763
+ lastActivityTime = Date.now();
3764
+ isUserActive = true;
3765
+ congestionDetectionWindow = 60 * 1e3;
3766
+ optimalBatchSize = 50 * 1024;
3767
+ constructor() {
3768
+ logger6.debug("[BatchTimingOptimizer] Initialized", {
3769
+ congestionWindow: this.congestionDetectionWindow,
3770
+ optimalBatchSize: this.optimalBatchSize
3771
+ });
3772
+ }
3773
+ /**
3774
+ * Record network measurement
3775
+ */
3776
+ recordNetworkMeasurement(latencyMs, bandwidthMbps) {
3777
+ const quality = this.assessNetworkQuality(latencyMs, bandwidthMbps);
3778
+ this.networkHistory.push({
3779
+ latencyMs,
3780
+ bandwidthMbps,
3781
+ timestamp: Date.now(),
3782
+ quality
3783
+ });
3784
+ if (this.networkHistory.length > 100) {
3785
+ this.networkHistory.shift();
3786
+ }
3787
+ this.stats.networkWindowsUsed++;
3788
+ logger6.debug("[BatchTimingOptimizer] Network measured", {
3789
+ latency: latencyMs + "ms",
3790
+ bandwidth: bandwidthMbps.toFixed(1) + " Mbps",
3791
+ quality
3792
+ });
3793
+ }
3794
+ /**
3795
+ * Assess network quality
3796
+ */
3797
+ assessNetworkQuality(latencyMs, bandwidthMbps) {
3798
+ if (latencyMs < 20 && bandwidthMbps > 10) return "excellent";
3799
+ if (latencyMs < 50 && bandwidthMbps > 5) return "good";
3800
+ if (latencyMs < 100 && bandwidthMbps > 2) return "fair";
3801
+ return "poor";
3802
+ }
3803
+ /**
3804
+ * Detect congestion in network
3805
+ */
3806
+ detectCongestion() {
3807
+ const recentMeasurements = this.networkHistory.filter(
3808
+ (m) => Date.now() - m.timestamp < this.congestionDetectionWindow
3809
+ );
3810
+ if (recentMeasurements.length < 3) {
3811
+ return 0;
3812
+ }
3813
+ const poorCount = recentMeasurements.filter(
3814
+ (m) => m.quality === "poor"
3815
+ ).length;
3816
+ return poorCount / recentMeasurements.length;
3817
+ }
3818
+ /**
3819
+ * Find next optimal network window
3820
+ */
3821
+ findOptimalWindow() {
3822
+ const now = Date.now();
3823
+ const recentMeasurements = this.networkHistory.slice(-20);
3824
+ if (recentMeasurements.length === 0) {
3825
+ return {
3826
+ startTime: now,
3827
+ endTime: now + 1e3,
3828
+ expectedDurationMs: 1e3,
3829
+ latencyMs: 50,
3830
+ bandwidthMbps: 5,
3831
+ quality: "good",
3832
+ isStable: true,
3833
+ congestionLevel: 0,
3834
+ recommendedBatchSize: this.optimalBatchSize
3835
+ };
3836
+ }
3837
+ const avgLatency = recentMeasurements.reduce((sum, m) => sum + m.latencyMs, 0) / recentMeasurements.length;
3838
+ const avgBandwidth = recentMeasurements.reduce((sum, m) => sum + m.bandwidthMbps, 0) / recentMeasurements.length;
3839
+ const latencyVariance = Math.sqrt(
3840
+ recentMeasurements.reduce(
3841
+ (sum, m) => sum + Math.pow(m.latencyMs - avgLatency, 2),
3842
+ 0
3843
+ ) / recentMeasurements.length
3844
+ ) / avgLatency;
3845
+ const isStable = latencyVariance < 0.2;
3846
+ const congestionLevel = this.detectCongestion();
3847
+ const quality = this.assessNetworkQuality(avgLatency, avgBandwidth);
3848
+ const recommendedBatchSize = Math.max(
3849
+ 10 * 1024,
3850
+ Math.min(500 * 1024, avgBandwidth * 1024 * 100 / 8)
3851
+ );
3852
+ return {
3853
+ startTime: now,
3854
+ endTime: now + (isStable ? 30 * 1e3 : 10 * 1e3),
3855
+ expectedDurationMs: isStable ? 30 * 1e3 : 10 * 1e3,
3856
+ latencyMs: avgLatency,
3857
+ bandwidthMbps: avgBandwidth,
3858
+ quality,
3859
+ isStable,
3860
+ congestionLevel,
3861
+ recommendedBatchSize
3862
+ };
3863
+ }
3864
+ /**
3865
+ * Get scheduling decision for a batch
3866
+ */
3867
+ getSchedulingDecision(batchSize, batchPriority = "normal", isUserTriggered = false) {
3868
+ const now = Date.now();
3869
+ const currentWindow = this.findOptimalWindow();
3870
+ const congestionLevel = this.detectCongestion();
3871
+ let shouldSendNow = false;
3872
+ let recommendedDelay = 0;
3873
+ let reason = "";
3874
+ let priority = batchPriority;
3875
+ if (priority === "critical") {
3876
+ shouldSendNow = true;
3877
+ reason = "Critical operation (bypass optimization)";
3878
+ } else if (isUserTriggered && this.isUserActive) {
3879
+ shouldSendNow = true;
3880
+ reason = "User-triggered operation";
3881
+ priority = "high";
3882
+ } else if (currentWindow.quality === "excellent" || currentWindow.quality === "good") {
3883
+ if (congestionLevel < 0.3) {
3884
+ shouldSendNow = true;
3885
+ reason = "Good network conditions";
3886
+ } else {
3887
+ shouldSendNow = true;
3888
+ reason = "Good network despite some congestion";
3889
+ recommendedDelay = 1e3 + Math.random() * 2e3;
3890
+ }
3891
+ } else if (currentWindow.quality === "fair") {
3892
+ if (priority === "high") {
3893
+ shouldSendNow = true;
3894
+ reason = "High priority despite fair network";
3895
+ } else {
3896
+ shouldSendNow = false;
3897
+ reason = "Fair network: waiting for better window";
3898
+ recommendedDelay = 30 * 1e3 + Math.random() * 30 * 1e3;
3899
+ }
3900
+ } else {
3901
+ shouldSendNow = false;
3902
+ reason = "Poor network conditions: deferring";
3903
+ if (priority === "high") {
3904
+ recommendedDelay = 60 * 1e3 + Math.random() * 30 * 1e3;
3905
+ } else {
3906
+ recommendedDelay = 120 * 1e3 + Math.random() * 60 * 1e3;
3907
+ }
3908
+ }
3909
+ const estimatedDeliveryMs = batchSize / (currentWindow.bandwidthMbps * 1024 * 1024 / 8) * 1e3 + currentWindow.latencyMs + recommendedDelay;
3910
+ const decision = {
3911
+ shouldSendNow,
3912
+ nextOptimalWindowMs: now + recommendedDelay,
3913
+ recommendedDelay,
3914
+ reason,
3915
+ priority,
3916
+ estimatedDeliveryMs
3917
+ };
3918
+ logger6.debug("[BatchTimingOptimizer] Scheduling decision", {
3919
+ size: (batchSize / 1024).toFixed(1) + " KB",
3920
+ shouldSendNow,
3921
+ delay: recommendedDelay + "ms",
3922
+ reason
3923
+ });
3924
+ return decision;
3925
+ }
3926
+ /**
3927
+ * Apply scheduling and update stats
3928
+ */
3929
+ applyScheduling(batchSize, sendNow, actualDelay) {
3930
+ this.stats.totalBatches++;
3931
+ if (sendNow) {
3932
+ this.stats.immediateDeliveries++;
3933
+ } else {
3934
+ this.stats.deferredBatches++;
3935
+ }
3936
+ const totalWait = this.stats.averageWaitTimeMs * (this.stats.totalBatches - 1) + actualDelay;
3937
+ this.stats.averageWaitTimeMs = totalWait / this.stats.totalBatches;
3938
+ if (this.detectCongestion() > 0.3 && !sendNow) {
3939
+ this.stats.congestionAvoided++;
3940
+ }
3941
+ if (this.isUserActive) {
3942
+ this.stats.userFocusedOptimizations++;
3943
+ }
3944
+ this.stats.networkWindowsUsed++;
3945
+ }
3946
+ /**
3947
+ * Get optimal batch size recommendation
3948
+ */
3949
+ getOptimalBatchSize() {
3950
+ const window = this.findOptimalWindow();
3951
+ return window.recommendedBatchSize;
3952
+ }
3953
+ /**
3954
+ * Get current network window
3955
+ */
3956
+ getCurrentNetworkWindow() {
3957
+ return this.findOptimalWindow();
3958
+ }
3959
+ /**
3960
+ * Set user activity state
3961
+ */
3962
+ setUserActive(active) {
3963
+ this.isUserActive = active;
3964
+ if (active) {
3965
+ this.lastActivityTime = Date.now();
3966
+ }
3967
+ }
3968
+ /**
3969
+ * Get statistics
3970
+ */
3971
+ getStats() {
3972
+ return { ...this.stats };
3973
+ }
3974
+ /**
3975
+ * Clear history
3976
+ */
3977
+ clear() {
3978
+ this.networkHistory = [];
3979
+ this.activityHistory = [];
3980
+ this.stats = {
3981
+ totalBatches: 0,
3982
+ immediateDeliveries: 0,
3983
+ deferredBatches: 0,
3984
+ averageWaitTimeMs: 0,
3985
+ averageDeliveryTimeMs: 0,
3986
+ networkWindowsUsed: 0,
3987
+ congestionAvoided: 0,
3988
+ userFocusedOptimizations: 0
3989
+ };
3990
+ }
3991
+ };
3992
+ var batchTimingOptimizerInstance = null;
3993
+ function getBatchTimingOptimizer() {
3994
+ if (!batchTimingOptimizerInstance) {
3995
+ batchTimingOptimizerInstance = new BatchTimingOptimizer();
3996
+ }
3997
+ return batchTimingOptimizerInstance;
3998
+ }
3999
+ function resetBatchTimingOptimizer() {
4000
+ batchTimingOptimizerInstance = null;
4001
+ }
4002
+
4003
+ // src/optimization/AdaptiveCompressionOptimizer.ts
4004
+ var logger7 = getLogger();
4005
+ var AdaptiveCompressionOptimizer = class {
4006
+ currentLevel = 6;
4007
+ networkProfile = {
4008
+ estimatedSpeedKbps: 5e3,
4009
+ latencyMs: 50,
4010
+ isOnline: true,
4011
+ isWifi: false,
4012
+ isFast: true,
4013
+ isSlow: false,
4014
+ isEmpty: false
4015
+ };
4016
+ deviceProfile = {
4017
+ cpuCores: 4,
4018
+ cpuUtilization: 0.3,
4019
+ memoryAvailableMB: 512,
4020
+ memoryTotalMB: 1024,
4021
+ isConstrained: false,
4022
+ isPremium: false,
4023
+ supportsWebWorkers: true,
4024
+ supportsWebAssembly: true
4025
+ };
4026
+ compressionHistory = [];
4027
+ stats = {
4028
+ currentLevel: 6,
4029
+ averageCompressionMs: 10,
4030
+ averageRatio: 0.85,
4031
+ levelsUsed: /* @__PURE__ */ new Set([6]),
4032
+ adjustmentCount: 0,
4033
+ totalBatches: 0,
4034
+ networkCondition: "normal"
4035
+ };
4036
+ constructor() {
4037
+ logger7.debug("[AdaptiveCompressionOptimizer] Initialized", {
4038
+ level: this.currentLevel
4039
+ });
4040
+ }
4041
+ /**
4042
+ * Update network conditions
4043
+ */
4044
+ updateNetworkConditions(speedKbps, latencyMs, isOnline) {
4045
+ this.networkProfile.estimatedSpeedKbps = speedKbps;
4046
+ if (latencyMs !== void 0) {
4047
+ this.networkProfile.latencyMs = latencyMs;
4048
+ }
4049
+ if (isOnline !== void 0) {
4050
+ this.networkProfile.isOnline = isOnline;
4051
+ }
4052
+ this.networkProfile.isFast = speedKbps > 5e3;
4053
+ this.networkProfile.isSlow = speedKbps < 1e3;
4054
+ this.networkProfile.isEmpty = speedKbps < 100;
4055
+ if (isOnline === false) {
4056
+ this.stats.networkCondition = "offline";
4057
+ } else if (this.networkProfile.isSlow) {
4058
+ this.stats.networkCondition = "slow";
4059
+ } else if (this.networkProfile.isFast) {
4060
+ this.stats.networkCondition = "fast";
4061
+ } else {
4062
+ this.stats.networkCondition = "normal";
4063
+ }
4064
+ logger7.debug("[AdaptiveCompressionOptimizer] Network updated", {
4065
+ speedKbps,
4066
+ condition: this.stats.networkCondition
4067
+ });
4068
+ }
4069
+ /**
4070
+ * Update device resource usage
4071
+ */
4072
+ updateDeviceResources(cpuUtilization, memoryAvailableMB) {
4073
+ this.deviceProfile.cpuUtilization = Math.max(0, Math.min(1, cpuUtilization));
4074
+ this.deviceProfile.memoryAvailableMB = memoryAvailableMB;
4075
+ this.deviceProfile.isConstrained = memoryAvailableMB < 512;
4076
+ this.deviceProfile.isPremium = memoryAvailableMB > 2048;
4077
+ logger7.debug("[AdaptiveCompressionOptimizer] Device resources updated", {
4078
+ cpuUtilization: (cpuUtilization * 100).toFixed(1) + "%",
4079
+ memoryAvailableMB
4080
+ });
4081
+ }
4082
+ /**
4083
+ * Record compression performance
4084
+ */
4085
+ recordCompressionPerformance(level, compressionMs, ratio) {
4086
+ this.compressionHistory.push({
4087
+ level,
4088
+ ratio,
4089
+ timeMs: compressionMs,
4090
+ timestamp: Date.now()
4091
+ });
4092
+ if (this.compressionHistory.length > 100) {
4093
+ this.compressionHistory.shift();
4094
+ }
4095
+ this.stats.totalBatches++;
4096
+ this.stats.averageCompressionMs = this.compressionHistory.reduce((sum, h) => sum + h.timeMs, 0) / this.compressionHistory.length;
4097
+ this.stats.averageRatio = this.compressionHistory.reduce((sum, h) => sum + h.ratio, 0) / this.compressionHistory.length;
4098
+ }
4099
+ /**
4100
+ * Get compression recommendation based on conditions
4101
+ */
4102
+ getRecommendedLevel() {
4103
+ const networkFactor = this.calculateNetworkFactor();
4104
+ const deviceFactor = this.calculateDeviceFactor();
4105
+ const combinedFactor = (networkFactor + deviceFactor) / 2;
4106
+ const recommendedLevel = Math.max(
4107
+ 1,
4108
+ Math.min(9, Math.round(combinedFactor * 9))
4109
+ );
4110
+ const estimatedCompressionMs = this.estimateCompressionTime(recommendedLevel);
4111
+ const estimatedRatio = this.estimateCompressionRatio(recommendedLevel);
4112
+ let reason = "";
4113
+ if (networkFactor < 0.3 && deviceFactor < 0.3) {
4114
+ reason = "Slow network + constrained device: using level 1-2 (fast)";
4115
+ } else if (networkFactor > 0.7 && deviceFactor > 0.7) {
4116
+ reason = "Fast network + premium device: using level 8-9 (best compression)";
4117
+ } else if (networkFactor > 0.7) {
4118
+ reason = "Fast network: prioritizing compression ratio";
4119
+ } else if (deviceFactor < 0.3) {
4120
+ reason = "Constrained device: prioritizing speed";
4121
+ } else {
4122
+ reason = "Normal conditions: balanced compression level";
4123
+ }
4124
+ const recommendation = {
4125
+ recommendedLevel,
4126
+ reason,
4127
+ confidence: this.compressionHistory.length > 10 ? 0.9 : 0.5,
4128
+ estimatedCompressionMs,
4129
+ estimatedRatio,
4130
+ networkFactor,
4131
+ deviceFactor
4132
+ };
4133
+ logger7.debug("[AdaptiveCompressionOptimizer] Recommendation", recommendation);
4134
+ return recommendation;
4135
+ }
4136
+ /**
4137
+ * Calculate network factor (0-1)
4138
+ */
4139
+ calculateNetworkFactor() {
4140
+ if (!this.networkProfile.isOnline) return 0;
4141
+ const speedMbps = this.networkProfile.estimatedSpeedKbps / 1e3;
4142
+ if (speedMbps < 0.1) return 0;
4143
+ if (speedMbps < 1) return 0.1 + speedMbps / 1 * 0.2;
4144
+ if (speedMbps < 5) return 0.3 + (speedMbps - 1) / 4 * 0.3;
4145
+ if (speedMbps < 20) return 0.6 + (speedMbps - 5) / 15 * 0.3;
4146
+ return Math.min(1, 0.9 + (speedMbps - 20) / 200);
4147
+ }
4148
+ /**
4149
+ * Calculate device factor (0-1)
4150
+ */
4151
+ calculateDeviceFactor() {
4152
+ let factor = 0.5;
4153
+ if (this.deviceProfile.isPremium) {
4154
+ factor = 0.8;
4155
+ } else if (this.deviceProfile.isConstrained) {
4156
+ factor = 0.2;
4157
+ }
4158
+ if (this.deviceProfile.cpuUtilization > 0.8) {
4159
+ factor *= 0.7;
4160
+ } else if (this.deviceProfile.cpuUtilization < 0.2) {
4161
+ factor *= 1.1;
4162
+ }
4163
+ if (this.deviceProfile.supportsWebAssembly) {
4164
+ factor = Math.min(1, factor + 0.1);
4165
+ }
4166
+ return Math.max(0, Math.min(1, factor));
4167
+ }
4168
+ /**
4169
+ * Estimate compression time for a level (in ms)
4170
+ */
4171
+ estimateCompressionTime(level) {
4172
+ return Math.max(1, level * 2.5);
4173
+ }
4174
+ /**
4175
+ * Estimate compression ratio for a level
4176
+ */
4177
+ estimateCompressionRatio(level) {
4178
+ return 0.6 + level / 9 * 0.3;
4179
+ }
4180
+ /**
4181
+ * Apply recommendation and get new level
4182
+ */
4183
+ applyRecommendation() {
4184
+ const recommendation = this.getRecommendedLevel();
4185
+ const oldLevel = this.currentLevel;
4186
+ const shouldChange = recommendation.confidence > 0.7 || Math.abs(recommendation.recommendedLevel - oldLevel) > 2;
4187
+ if (shouldChange) {
4188
+ this.currentLevel = recommendation.recommendedLevel;
4189
+ this.stats.levelsUsed.add(this.currentLevel);
4190
+ if (oldLevel !== this.currentLevel) {
4191
+ this.stats.adjustmentCount++;
4192
+ logger7.debug("[AdaptiveCompressionOptimizer] Level adjusted", {
4193
+ from: oldLevel,
4194
+ to: this.currentLevel,
4195
+ reason: recommendation.reason
4196
+ });
4197
+ }
4198
+ }
4199
+ this.stats.currentLevel = this.currentLevel;
4200
+ return this.currentLevel;
4201
+ }
4202
+ /**
4203
+ * Get current level
4204
+ */
4205
+ getCurrentLevel() {
4206
+ return this.currentLevel;
4207
+ }
4208
+ /**
4209
+ * Get statistics
4210
+ */
4211
+ getStats() {
4212
+ return { ...this.stats };
4213
+ }
4214
+ /**
4215
+ * Get detailed analysis
4216
+ */
4217
+ getDetailedAnalysis() {
4218
+ return {
4219
+ stats: this.stats,
4220
+ network: this.networkProfile,
4221
+ device: this.deviceProfile,
4222
+ recommendation: this.getRecommendedLevel(),
4223
+ history: this.compressionHistory.slice(-20)
4224
+ };
4225
+ }
4226
+ };
4227
+ var adaptiveOptimizerInstance = null;
4228
+ function getAdaptiveCompressionOptimizer() {
4229
+ if (!adaptiveOptimizerInstance) {
4230
+ adaptiveOptimizerInstance = new AdaptiveCompressionOptimizer();
4231
+ }
4232
+ return adaptiveOptimizerInstance;
4233
+ }
4234
+ function resetAdaptiveCompressionOptimizer() {
4235
+ adaptiveOptimizerInstance = null;
4236
+ }
4237
+ var logger8 = getLogger();
4238
+ var AgentPresenceManager = class extends EventEmitter {
4239
+ presences = /* @__PURE__ */ new Map();
4240
+ sessionId;
4241
+ heartbeatInterval = null;
4242
+ heartbeatTimeout = 3e4;
4243
+ inactivityThreshold = 6e4;
4244
+ constructor(sessionId) {
4245
+ super();
4246
+ this.sessionId = sessionId;
4247
+ this.startHeartbeatCheck();
4248
+ logger8.debug("[AgentPresenceManager] Initialized", { sessionId });
4249
+ }
4250
+ /**
4251
+ * Add or update agent presence
4252
+ */
4253
+ updatePresence(agentId, presence) {
4254
+ const existing = this.presences.get(agentId);
4255
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4256
+ const updated = {
4257
+ ...existing,
4258
+ ...presence,
4259
+ agentId,
4260
+ joinedAt: existing?.joinedAt ?? now,
4261
+ lastSeen: now
4262
+ };
4263
+ this.presences.set(agentId, updated);
4264
+ this.emit("presence_updated", {
4265
+ agentId,
4266
+ presence: updated
4267
+ });
4268
+ }
4269
+ /**
4270
+ * Agent joined
4271
+ */
4272
+ agentJoined(agentId, name, role = "user", metadata) {
4273
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4274
+ const presence = {
4275
+ agentId,
4276
+ name,
4277
+ role,
4278
+ status: "online",
4279
+ joinedAt: now,
4280
+ lastSeen: now,
4281
+ metadata
4282
+ };
4283
+ this.presences.set(agentId, presence);
4284
+ this.emit("agent_joined", { agentId, presence });
4285
+ logger8.debug("[AgentPresenceManager] Agent joined", { agentId, name, role });
4286
+ }
4287
+ /**
4288
+ * Agent left
4289
+ */
4290
+ agentLeft(agentId) {
4291
+ const presence = this.presences.get(agentId);
4292
+ if (presence) {
4293
+ presence.status = "offline";
4294
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
4295
+ this.presences.set(agentId, presence);
4296
+ this.emit("agent_left", { agentId, presence });
4297
+ logger8.debug("[AgentPresenceManager] Agent left", { agentId });
4298
+ }
4299
+ }
4300
+ /**
4301
+ * Update cursor position
4302
+ */
4303
+ updateCursor(agentId, x, y, path) {
4304
+ const presence = this.presences.get(agentId);
4305
+ if (presence) {
4306
+ presence.cursorPosition = { x, y, path };
4307
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
4308
+ this.presences.set(agentId, presence);
4309
+ this.emit("cursor_updated", {
4310
+ agentId,
4311
+ cursorPosition: presence.cursorPosition
4312
+ });
4313
+ }
4314
+ }
4315
+ /**
4316
+ * Update active section
4317
+ */
4318
+ updateActiveSection(agentId, section) {
4319
+ const presence = this.presences.get(agentId);
4320
+ if (presence) {
4321
+ presence.activeSection = section;
4322
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
4323
+ this.presences.set(agentId, presence);
4324
+ this.emit("section_updated", {
4325
+ agentId,
4326
+ activeSection: section
4327
+ });
4328
+ }
4329
+ }
4330
+ /**
4331
+ * Update status
4332
+ */
4333
+ updateStatus(agentId, status) {
4334
+ const presence = this.presences.get(agentId);
4335
+ if (presence) {
4336
+ presence.status = status;
4337
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
4338
+ this.presences.set(agentId, presence);
4339
+ this.emit("status_updated", { agentId, status });
4340
+ }
4341
+ }
4342
+ /**
4343
+ * Heartbeat from agent (keeps them online)
4344
+ */
4345
+ heartbeat(agentId) {
4346
+ const presence = this.presences.get(agentId);
4347
+ if (presence) {
4348
+ if (presence.status === "reconnecting") {
4349
+ presence.status = "online";
4350
+ this.emit("status_updated", { agentId, status: "online" });
4351
+ }
4352
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
4353
+ this.presences.set(agentId, presence);
4354
+ }
4355
+ }
4356
+ /**
4357
+ * Get presence for agent
4358
+ */
4359
+ getPresence(agentId) {
4360
+ return this.presences.get(agentId);
4361
+ }
4362
+ /**
4363
+ * Get all online agents
4364
+ */
4365
+ getOnlineAgents() {
4366
+ return Array.from(this.presences.values()).filter(
4367
+ (p) => p.status === "online"
4368
+ );
4369
+ }
4370
+ /**
4371
+ * Get all agents
4372
+ */
4373
+ getAllAgents() {
4374
+ return Array.from(this.presences.values());
4375
+ }
4376
+ /**
4377
+ * Get all presences
4378
+ */
4379
+ getAllPresences() {
4380
+ return Array.from(this.presences.values());
4381
+ }
4382
+ /**
4383
+ * Get agent count
4384
+ */
4385
+ getAgentCount() {
4386
+ const counts = {
4387
+ online: 0,
4388
+ away: 0,
4389
+ offline: 0,
4390
+ reconnecting: 0
4391
+ };
4392
+ this.presences.forEach((p) => {
4393
+ counts[p.status]++;
4394
+ });
4395
+ return counts;
4396
+ }
4397
+ /**
4398
+ * Get statistics
4399
+ */
4400
+ getStats() {
4401
+ return {
4402
+ totalAgents: this.presences.size,
4403
+ onlineAgents: Array.from(this.presences.values()).filter(
4404
+ (p) => p.status === "online"
4405
+ ).length,
4406
+ offlineAgents: Array.from(this.presences.values()).filter(
4407
+ (p) => p.status === "offline"
4408
+ ).length,
4409
+ awayAgents: Array.from(this.presences.values()).filter(
4410
+ (p) => p.status === "away"
4411
+ ).length,
4412
+ reconnectingAgents: Array.from(this.presences.values()).filter(
4413
+ (p) => p.status === "reconnecting"
4414
+ ).length
4415
+ };
4416
+ }
4417
+ /**
4418
+ * Clear expired presences
4419
+ */
4420
+ clearExpiredPresences(maxAgeMs) {
4421
+ const now = Date.now();
4422
+ const toRemove = [];
4423
+ this.presences.forEach((presence, agentId) => {
4424
+ const lastSeenTime = new Date(presence.lastSeen).getTime();
4425
+ const ageMs = now - lastSeenTime;
4426
+ if (ageMs > maxAgeMs && presence.status === "offline") {
4427
+ toRemove.push(agentId);
4428
+ }
4429
+ });
4430
+ toRemove.forEach((agentId) => {
4431
+ this.presences.delete(agentId);
4432
+ });
4433
+ if (toRemove.length > 0) {
4434
+ logger8.debug("[AgentPresenceManager] Cleared expired presences", {
4435
+ count: toRemove.length
4436
+ });
4437
+ }
4438
+ }
4439
+ /**
4440
+ * Get agents by role
4441
+ */
4442
+ getByRole(role) {
4443
+ return Array.from(this.presences.values()).filter((p) => p.role === role);
4444
+ }
4445
+ /**
4446
+ * Get agents in active section
4447
+ */
4448
+ getInSection(section) {
4449
+ return Array.from(this.presences.values()).filter(
4450
+ (p) => p.activeSection === section && p.status === "online"
4451
+ );
4452
+ }
4453
+ /**
4454
+ * Get presence timeline
4455
+ */
4456
+ getPresenceStats() {
4457
+ const stats = {
4458
+ total: this.presences.size,
4459
+ online: 0,
4460
+ away: 0,
4461
+ offline: 0,
4462
+ reconnecting: 0,
4463
+ byRole: {}
4464
+ };
4465
+ this.presences.forEach((p) => {
4466
+ stats[p.status]++;
4467
+ stats.byRole[p.role] = (stats.byRole[p.role] ?? 0) + 1;
4468
+ });
4469
+ return stats;
4470
+ }
4471
+ /**
4472
+ * Start heartbeat check (mark inactive agents as away)
4473
+ */
4474
+ startHeartbeatCheck() {
4475
+ this.heartbeatInterval = setInterval(() => {
4476
+ const now = Date.now();
4477
+ this.presences.forEach((presence) => {
4478
+ const lastSeenTime = new Date(presence.lastSeen).getTime();
4479
+ const timeSinceLastSeen = now - lastSeenTime;
4480
+ if (timeSinceLastSeen > this.inactivityThreshold && presence.status === "online") {
4481
+ presence.status = "away";
4482
+ this.emit("status_updated", {
4483
+ agentId: presence.agentId,
4484
+ status: "away"
4485
+ });
4486
+ }
4487
+ if (timeSinceLastSeen > this.heartbeatTimeout && presence.status !== "offline") {
4488
+ presence.status = "reconnecting";
4489
+ this.emit("status_updated", {
4490
+ agentId: presence.agentId,
4491
+ status: "reconnecting"
4492
+ });
4493
+ }
4494
+ });
4495
+ }, 1e4);
4496
+ }
4497
+ /**
4498
+ * Stop heartbeat monitoring
4499
+ */
4500
+ stopHeartbeatMonitoring() {
4501
+ if (this.heartbeatInterval) {
4502
+ clearInterval(this.heartbeatInterval);
4503
+ this.heartbeatInterval = null;
4504
+ }
4505
+ }
4506
+ /**
4507
+ * Clear all presences
4508
+ */
4509
+ clear() {
4510
+ this.presences.clear();
4511
+ }
4512
+ /**
4513
+ * Destroy the manager
4514
+ */
4515
+ destroy() {
4516
+ this.stopHeartbeatMonitoring();
4517
+ this.presences.clear();
4518
+ this.removeAllListeners();
4519
+ logger8.debug("[AgentPresenceManager] Destroyed", { sessionId: this.sessionId });
4520
+ }
4521
+ };
4522
+ var instances = /* @__PURE__ */ new Map();
4523
+ function getAgentPresenceManager(sessionId) {
4524
+ if (!instances.has(sessionId)) {
4525
+ instances.set(sessionId, new AgentPresenceManager(sessionId));
4526
+ }
4527
+ return instances.get(sessionId);
4528
+ }
4529
+ function clearAgentPresenceManager(sessionId) {
4530
+ const instance = instances.get(sessionId);
4531
+ if (instance) {
4532
+ instance.destroy();
4533
+ instances.delete(sessionId);
4534
+ }
4535
+ }
4536
+
4537
+ // src/crypto/types.ts
4538
+ var AEON_CAPABILITIES = {
4539
+ // Basic sync operations
4540
+ SYNC_READ: "aeon:sync:read",
4541
+ SYNC_WRITE: "aeon:sync:write",
4542
+ SYNC_ADMIN: "aeon:sync:admin",
4543
+ // Node operations
4544
+ NODE_REGISTER: "aeon:node:register",
4545
+ NODE_HEARTBEAT: "aeon:node:heartbeat",
4546
+ // Replication operations
4547
+ REPLICATE_READ: "aeon:replicate:read",
4548
+ REPLICATE_WRITE: "aeon:replicate:write",
4549
+ // State operations
4550
+ STATE_READ: "aeon:state:read",
4551
+ STATE_WRITE: "aeon:state:write",
4552
+ STATE_RECONCILE: "aeon:state:reconcile"
4553
+ };
4554
+ var DEFAULT_CRYPTO_CONFIG = {
4555
+ defaultEncryptionMode: "none",
4556
+ requireSignatures: false,
4557
+ requireCapabilities: false,
4558
+ allowedSignatureAlgorithms: ["ES256", "Ed25519"],
4559
+ allowedEncryptionAlgorithms: ["ECIES-P256", "AES-256-GCM"],
4560
+ sessionKeyExpiration: 24 * 60 * 60 * 1e3
4561
+ // 24 hours
4562
+ };
4563
+
4564
+ // src/crypto/CryptoProvider.ts
4565
+ var NullCryptoProvider = class {
4566
+ notConfiguredError() {
4567
+ return new Error("Crypto provider not configured");
4568
+ }
4569
+ async generateIdentity() {
4570
+ throw this.notConfiguredError();
4571
+ }
4572
+ getLocalDID() {
4573
+ return null;
4574
+ }
4575
+ async exportPublicIdentity() {
4576
+ return null;
4577
+ }
4578
+ async registerRemoteNode() {
4579
+ }
4580
+ async getRemotePublicKey() {
4581
+ return null;
4582
+ }
4583
+ async sign() {
4584
+ throw this.notConfiguredError();
4585
+ }
4586
+ async signData(_data) {
4587
+ throw this.notConfiguredError();
4588
+ }
4589
+ async verify() {
4590
+ return true;
4591
+ }
4592
+ async verifySignedData() {
4593
+ return true;
4594
+ }
4595
+ async encrypt() {
4596
+ throw this.notConfiguredError();
4597
+ }
4598
+ async decrypt() {
4599
+ throw this.notConfiguredError();
4600
+ }
4601
+ async getSessionKey() {
4602
+ throw this.notConfiguredError();
4603
+ }
4604
+ async encryptWithSessionKey() {
4605
+ throw this.notConfiguredError();
4606
+ }
4607
+ async decryptWithSessionKey() {
4608
+ throw this.notConfiguredError();
4609
+ }
4610
+ async createUCAN() {
4611
+ throw this.notConfiguredError();
4612
+ }
4613
+ async verifyUCAN() {
4614
+ return { authorized: true };
4615
+ }
4616
+ async delegateCapabilities() {
4617
+ throw this.notConfiguredError();
4618
+ }
4619
+ async hash() {
4620
+ throw this.notConfiguredError();
4621
+ }
4622
+ randomBytes(length) {
4623
+ return crypto.getRandomValues(new Uint8Array(length));
4624
+ }
4625
+ isInitialized() {
4626
+ return false;
4627
+ }
4628
+ };
4629
+
4630
+ export { AEON_CAPABILITIES, AdaptiveCompressionOptimizer, AgentPresenceManager, BatchTimingOptimizer, CompressionEngine, DEFAULT_CRYPTO_CONFIG, DataTransformer, DeltaSyncOptimizer, MigrationEngine, MigrationTracker, NullCryptoProvider, OfflineOperationQueue, PrefetchingEngine, ReplicationManager, SchemaVersionManager, StateReconciler, SyncCoordinator, SyncProtocol, clearAgentPresenceManager, createNamespacedLogger, disableLogging, getAdaptiveCompressionOptimizer, getAgentPresenceManager, getBatchTimingOptimizer, getCompressionEngine, getDeltaSyncOptimizer, getLogger, getOfflineOperationQueue, getPrefetchingEngine, logger, resetAdaptiveCompressionOptimizer, resetBatchTimingOptimizer, resetCompressionEngine, resetDeltaSyncOptimizer, resetLogger, resetOfflineOperationQueue, resetPrefetchingEngine, setLogger };
4631
+ //# sourceMappingURL=index.js.map
4632
+ //# sourceMappingURL=index.js.map