@affectively/aeon 1.0.0 → 1.2.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.
Files changed (62) hide show
  1. package/README.md +10 -0
  2. package/dist/compression/index.cjs +580 -0
  3. package/dist/compression/index.cjs.map +1 -0
  4. package/dist/compression/index.d.cts +189 -0
  5. package/dist/compression/index.d.ts +189 -0
  6. package/dist/compression/index.js +573 -0
  7. package/dist/compression/index.js.map +1 -0
  8. package/dist/core/index.d.cts +70 -5
  9. package/dist/core/index.d.ts +70 -5
  10. package/dist/crypto/index.cjs +100 -0
  11. package/dist/crypto/index.cjs.map +1 -0
  12. package/dist/crypto/index.d.cts +407 -0
  13. package/dist/crypto/index.d.ts +407 -0
  14. package/dist/crypto/index.js +96 -0
  15. package/dist/crypto/index.js.map +1 -0
  16. package/dist/distributed/index.cjs +420 -23
  17. package/dist/distributed/index.cjs.map +1 -1
  18. package/dist/distributed/index.d.cts +901 -2
  19. package/dist/distributed/index.d.ts +901 -2
  20. package/dist/distributed/index.js +420 -23
  21. package/dist/distributed/index.js.map +1 -1
  22. package/dist/index.cjs +1222 -55
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +11 -811
  25. package/dist/index.d.ts +11 -811
  26. package/dist/index.js +1221 -56
  27. package/dist/index.js.map +1 -1
  28. package/dist/offline/index.cjs +419 -0
  29. package/dist/offline/index.cjs.map +1 -0
  30. package/dist/offline/index.d.cts +148 -0
  31. package/dist/offline/index.d.ts +148 -0
  32. package/dist/offline/index.js +415 -0
  33. package/dist/offline/index.js.map +1 -0
  34. package/dist/optimization/index.cjs +797 -0
  35. package/dist/optimization/index.cjs.map +1 -0
  36. package/dist/optimization/index.d.cts +347 -0
  37. package/dist/optimization/index.d.ts +347 -0
  38. package/dist/optimization/index.js +787 -0
  39. package/dist/optimization/index.js.map +1 -0
  40. package/dist/persistence/index.cjs +145 -0
  41. package/dist/persistence/index.cjs.map +1 -0
  42. package/dist/persistence/index.d.cts +63 -0
  43. package/dist/persistence/index.d.ts +63 -0
  44. package/dist/persistence/index.js +142 -0
  45. package/dist/persistence/index.js.map +1 -0
  46. package/dist/presence/index.cjs +489 -0
  47. package/dist/presence/index.cjs.map +1 -0
  48. package/dist/presence/index.d.cts +283 -0
  49. package/dist/presence/index.d.ts +283 -0
  50. package/dist/presence/index.js +485 -0
  51. package/dist/presence/index.js.map +1 -0
  52. package/dist/types-CMxO7QF0.d.cts +33 -0
  53. package/dist/types-CMxO7QF0.d.ts +33 -0
  54. package/dist/versioning/index.cjs +296 -14
  55. package/dist/versioning/index.cjs.map +1 -1
  56. package/dist/versioning/index.d.cts +66 -1
  57. package/dist/versioning/index.d.ts +66 -1
  58. package/dist/versioning/index.js +296 -14
  59. package/dist/versioning/index.js.map +1 -1
  60. package/package.json +51 -1
  61. package/dist/index-C_4CMV5c.d.cts +0 -1207
  62. package/dist/index-C_4CMV5c.d.ts +0 -1207
package/dist/index.cjs CHANGED
@@ -56,6 +56,145 @@ var logger = {
56
56
  error: (...args) => getLogger().error(...args)
57
57
  };
58
58
 
59
+ // src/persistence/DashStorageAdapter.ts
60
+ var DashStorageAdapter = class {
61
+ backend;
62
+ syncClient;
63
+ syncDebounceMs;
64
+ maxPendingChanges;
65
+ onSyncError;
66
+ pendingChanges = /* @__PURE__ */ new Map();
67
+ syncTimer = null;
68
+ syncInFlight = false;
69
+ syncPending = false;
70
+ constructor(backend, options = {}) {
71
+ this.backend = backend;
72
+ this.syncClient = options.syncClient ?? null;
73
+ this.syncDebounceMs = options.syncDebounceMs ?? 50;
74
+ this.maxPendingChanges = options.maxPendingChanges ?? 5e3;
75
+ this.onSyncError = options.onSyncError ?? null;
76
+ }
77
+ async getItem(key) {
78
+ return await this.backend.get(key);
79
+ }
80
+ async setItem(key, value) {
81
+ await this.backend.set(key, value);
82
+ this.trackChange({
83
+ key,
84
+ operation: "set",
85
+ value,
86
+ timestamp: Date.now()
87
+ });
88
+ }
89
+ async removeItem(key) {
90
+ await this.backend.delete(key);
91
+ this.trackChange({
92
+ key,
93
+ operation: "delete",
94
+ timestamp: Date.now()
95
+ });
96
+ }
97
+ getPendingSyncCount() {
98
+ return this.pendingChanges.size;
99
+ }
100
+ async flushSync() {
101
+ if (!this.syncClient || this.pendingChanges.size === 0) {
102
+ return;
103
+ }
104
+ if (this.syncTimer) {
105
+ clearTimeout(this.syncTimer);
106
+ this.syncTimer = null;
107
+ }
108
+ await this.performSync();
109
+ }
110
+ trackChange(change) {
111
+ this.pendingChanges.set(change.key, change);
112
+ this.enforcePendingLimit();
113
+ this.scheduleSync();
114
+ }
115
+ enforcePendingLimit() {
116
+ if (this.pendingChanges.size <= this.maxPendingChanges) {
117
+ return;
118
+ }
119
+ const sorted = Array.from(this.pendingChanges.values()).sort(
120
+ (a, b) => a.timestamp - b.timestamp
121
+ );
122
+ const overflow = this.pendingChanges.size - this.maxPendingChanges;
123
+ for (let i = 0; i < overflow; i++) {
124
+ const toDrop = sorted[i];
125
+ if (toDrop) {
126
+ this.pendingChanges.delete(toDrop.key);
127
+ }
128
+ }
129
+ }
130
+ scheduleSync() {
131
+ if (!this.syncClient) {
132
+ return;
133
+ }
134
+ if (this.syncTimer) {
135
+ clearTimeout(this.syncTimer);
136
+ }
137
+ this.syncTimer = setTimeout(() => {
138
+ void this.performSync();
139
+ }, this.syncDebounceMs);
140
+ }
141
+ async performSync() {
142
+ if (!this.syncClient) {
143
+ return;
144
+ }
145
+ if (this.syncInFlight) {
146
+ this.syncPending = true;
147
+ return;
148
+ }
149
+ const changes = Array.from(this.pendingChanges.values()).sort(
150
+ (a, b) => a.timestamp - b.timestamp
151
+ );
152
+ if (changes.length === 0) {
153
+ return;
154
+ }
155
+ this.pendingChanges.clear();
156
+ this.syncInFlight = true;
157
+ try {
158
+ await this.syncClient.syncChanges(changes);
159
+ } catch (error) {
160
+ for (const change of changes) {
161
+ const current = this.pendingChanges.get(change.key);
162
+ if (!current || change.timestamp > current.timestamp) {
163
+ this.pendingChanges.set(change.key, change);
164
+ }
165
+ }
166
+ if (this.onSyncError) {
167
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
168
+ this.onSyncError(normalizedError, changes);
169
+ }
170
+ } finally {
171
+ this.syncInFlight = false;
172
+ const rerun = this.syncPending || this.pendingChanges.size > 0;
173
+ this.syncPending = false;
174
+ if (rerun) {
175
+ this.scheduleSync();
176
+ }
177
+ }
178
+ }
179
+ };
180
+
181
+ // src/persistence/InMemoryStorageAdapter.ts
182
+ var InMemoryStorageAdapter = class {
183
+ store = /* @__PURE__ */ new Map();
184
+ getItem(key) {
185
+ return this.store.get(key) ?? null;
186
+ }
187
+ setItem(key, value) {
188
+ this.store.set(key, value);
189
+ }
190
+ removeItem(key) {
191
+ this.store.delete(key);
192
+ }
193
+ clear() {
194
+ this.store.clear();
195
+ }
196
+ };
197
+
59
198
  // src/versioning/SchemaVersionManager.ts
60
199
  var SchemaVersionManager = class {
61
200
  versions = /* @__PURE__ */ new Map();
@@ -107,7 +246,9 @@ var SchemaVersionManager = class {
107
246
  */
108
247
  setCurrentVersion(version) {
109
248
  if (!this.versions.has(this.versionToString(version))) {
110
- throw new Error(`Version ${this.versionToString(version)} not registered`);
249
+ throw new Error(
250
+ `Version ${this.versionToString(version)} not registered`
251
+ );
111
252
  }
112
253
  this.currentVersion = version;
113
254
  logger.debug("[SchemaVersionManager] Current version set", {
@@ -393,7 +534,9 @@ var MigrationEngine = class {
393
534
  id: migrationId,
394
535
  error: result.errors[0]
395
536
  });
396
- throw new Error(`Rollback for ${migrationId} failed: ${result.errors[0]}`);
537
+ throw new Error(
538
+ `Rollback for ${migrationId} failed: ${result.errors[0]}`
539
+ );
397
540
  }
398
541
  }
399
542
  /**
@@ -446,8 +589,14 @@ var MigrationEngine = class {
446
589
  getStatistics() {
447
590
  const successful = this.executedMigrations.filter((m) => m.success).length;
448
591
  const failed = this.executedMigrations.filter((m) => !m.success).length;
449
- const totalDuration = this.executedMigrations.reduce((sum, m) => sum + m.duration, 0);
450
- const totalAffected = this.executedMigrations.reduce((sum, m) => sum + m.itemsAffected, 0);
592
+ const totalDuration = this.executedMigrations.reduce(
593
+ (sum, m) => sum + m.duration,
594
+ 0
595
+ );
596
+ const totalAffected = this.executedMigrations.reduce(
597
+ (sum, m) => sum + m.itemsAffected,
598
+ 0
599
+ );
451
600
  return {
452
601
  totalExecuted: this.executedMigrations.length,
453
602
  successful,
@@ -501,7 +650,9 @@ var DataTransformer = class {
501
650
  return rule.transformer(value);
502
651
  } catch (error) {
503
652
  if (rule.required) {
504
- throw new Error(`Failed to transform required field ${field}: ${error instanceof Error ? error.message : String(error)}`);
653
+ throw new Error(
654
+ `Failed to transform required field ${field}: ${error instanceof Error ? error.message : String(error)}`
655
+ );
505
656
  }
506
657
  return rule.defaultValue !== void 0 ? rule.defaultValue : value;
507
658
  }
@@ -574,7 +725,9 @@ var DataTransformer = class {
574
725
  validateTransformation(original, transformed) {
575
726
  const issues = [];
576
727
  if (original.length !== transformed.length) {
577
- issues.push(`Item count mismatch: ${original.length} -> ${transformed.length}`);
728
+ issues.push(
729
+ `Item count mismatch: ${original.length} -> ${transformed.length}`
730
+ );
578
731
  }
579
732
  for (let i = 0; i < Math.min(original.length, transformed.length); i++) {
580
733
  const orig = original[i];
@@ -665,14 +818,40 @@ var DataTransformer = class {
665
818
  };
666
819
 
667
820
  // src/versioning/MigrationTracker.ts
668
- var MigrationTracker = class {
821
+ var MigrationTracker = class _MigrationTracker {
822
+ static DEFAULT_PERSIST_KEY = "aeon:migration-tracker:v1";
823
+ static INTEGRITY_ROOT = "aeon:migration-integrity-root:v1";
669
824
  migrations = [];
670
825
  snapshots = /* @__PURE__ */ new Map();
826
+ persistence = null;
827
+ persistTimer = null;
828
+ persistInFlight = false;
829
+ persistPending = false;
830
+ constructor(options) {
831
+ if (options?.persistence) {
832
+ this.persistence = {
833
+ ...options.persistence,
834
+ key: options.persistence.key ?? _MigrationTracker.DEFAULT_PERSIST_KEY,
835
+ autoPersist: options.persistence.autoPersist ?? true,
836
+ autoLoad: options.persistence.autoLoad ?? false,
837
+ persistDebounceMs: options.persistence.persistDebounceMs ?? 25
838
+ };
839
+ }
840
+ if (this.persistence?.autoLoad) {
841
+ void this.loadFromPersistence().catch((error) => {
842
+ logger.error("[MigrationTracker] Failed to load persistence", {
843
+ key: this.persistence?.key,
844
+ error: error instanceof Error ? error.message : String(error)
845
+ });
846
+ });
847
+ }
848
+ }
671
849
  /**
672
850
  * Track a new migration
673
851
  */
674
852
  recordMigration(record) {
675
853
  this.migrations.push({ ...record });
854
+ this.schedulePersist();
676
855
  logger.debug("[MigrationTracker] Migration recorded", {
677
856
  id: record.id,
678
857
  migrationId: record.migrationId,
@@ -729,7 +908,9 @@ var MigrationTracker = class {
729
908
  * Check if can rollback
730
909
  */
731
910
  canRollback(fromVersion, toVersion) {
732
- const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
911
+ const fromIndex = this.migrations.findIndex(
912
+ (m) => m.version === fromVersion
913
+ );
733
914
  const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
734
915
  if (fromIndex === -1 || toIndex === -1) {
735
916
  return false;
@@ -753,7 +934,9 @@ var MigrationTracker = class {
753
934
  const affectedVersions = [];
754
935
  let estimatedDuration = 0;
755
936
  if (canRollback) {
756
- const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
937
+ const fromIndex = this.migrations.findIndex(
938
+ (m) => m.version === fromVersion
939
+ );
757
940
  const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
758
941
  for (let i = fromIndex; i > toIndex; i--) {
759
942
  const migration = this.migrations[i];
@@ -809,12 +992,24 @@ var MigrationTracker = class {
809
992
  * Get migration statistics
810
993
  */
811
994
  getStatistics() {
812
- const applied = this.migrations.filter((m) => m.status === "applied").length;
995
+ const applied = this.migrations.filter(
996
+ (m) => m.status === "applied"
997
+ ).length;
813
998
  const failed = this.migrations.filter((m) => m.status === "failed").length;
814
- const pending = this.migrations.filter((m) => m.status === "pending").length;
815
- const rolledBack = this.migrations.filter((m) => m.status === "rolled-back").length;
816
- const totalDuration = this.migrations.reduce((sum, m) => sum + m.duration, 0);
817
- const totalAffected = this.migrations.reduce((sum, m) => sum + m.itemsAffected, 0);
999
+ const pending = this.migrations.filter(
1000
+ (m) => m.status === "pending"
1001
+ ).length;
1002
+ const rolledBack = this.migrations.filter(
1003
+ (m) => m.status === "rolled-back"
1004
+ ).length;
1005
+ const totalDuration = this.migrations.reduce(
1006
+ (sum, m) => sum + m.duration,
1007
+ 0
1008
+ );
1009
+ const totalAffected = this.migrations.reduce(
1010
+ (sum, m) => sum + m.itemsAffected,
1011
+ 0
1012
+ );
818
1013
  return {
819
1014
  total: this.migrations.length,
820
1015
  applied,
@@ -865,7 +1060,147 @@ var MigrationTracker = class {
865
1060
  status,
866
1061
  hasError: !!error
867
1062
  });
1063
+ this.schedulePersist();
1064
+ }
1065
+ }
1066
+ /**
1067
+ * Persist tracker state with integrity chain verification metadata.
1068
+ */
1069
+ async saveToPersistence() {
1070
+ if (!this.persistence) {
1071
+ return;
1072
+ }
1073
+ const normalizedMigrations = this.migrations.map((migration) => ({
1074
+ ...migration,
1075
+ previousHash: void 0,
1076
+ integrityHash: void 0
1077
+ }));
1078
+ const integrityEntries = [];
1079
+ let previousHash = _MigrationTracker.INTEGRITY_ROOT;
1080
+ for (const migration of normalizedMigrations) {
1081
+ const hash = await this.computeDigestHex(
1082
+ `${previousHash}|${this.stableStringify(migration)}`
1083
+ );
1084
+ integrityEntries.push({
1085
+ recordId: migration.id,
1086
+ previousHash,
1087
+ hash
1088
+ });
1089
+ previousHash = hash;
1090
+ }
1091
+ const persistedMigrations = normalizedMigrations.map((migration, index) => ({
1092
+ ...migration,
1093
+ previousHash: integrityEntries[index]?.previousHash,
1094
+ integrityHash: integrityEntries[index]?.hash
1095
+ }));
1096
+ const data = {
1097
+ migrations: persistedMigrations,
1098
+ snapshots: Array.from(this.snapshots.entries()).map(
1099
+ ([recordId, snapshot]) => ({
1100
+ recordId,
1101
+ beforeHash: snapshot.beforeHash,
1102
+ afterHash: snapshot.afterHash,
1103
+ itemCount: snapshot.itemCount
1104
+ })
1105
+ ),
1106
+ integrity: {
1107
+ algorithm: "sha256-chain-v1",
1108
+ entries: integrityEntries,
1109
+ rootHash: previousHash
1110
+ }
1111
+ };
1112
+ const envelope = {
1113
+ version: 1,
1114
+ updatedAt: Date.now(),
1115
+ data
1116
+ };
1117
+ const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
1118
+ await this.persistence.adapter.setItem(this.persistence.key, serialize(envelope));
1119
+ }
1120
+ /**
1121
+ * Load tracker state and verify integrity chain.
1122
+ */
1123
+ async loadFromPersistence() {
1124
+ if (!this.persistence) {
1125
+ return { migrations: 0, snapshots: 0 };
1126
+ }
1127
+ const raw = await this.persistence.adapter.getItem(this.persistence.key);
1128
+ if (!raw) {
1129
+ return { migrations: 0, snapshots: 0 };
1130
+ }
1131
+ const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
1132
+ const envelope = deserialize(raw);
1133
+ if (envelope.version !== 1 || !envelope.data) {
1134
+ throw new Error("Invalid migration tracker persistence payload");
1135
+ }
1136
+ if (!Array.isArray(envelope.data.migrations) || !Array.isArray(envelope.data.snapshots) || !envelope.data.integrity || !Array.isArray(envelope.data.integrity.entries) || typeof envelope.data.integrity.rootHash !== "string") {
1137
+ throw new Error("Invalid migration tracker persistence structure");
1138
+ }
1139
+ if (envelope.data.integrity.algorithm !== "sha256-chain-v1") {
1140
+ throw new Error("Unsupported migration integrity algorithm");
1141
+ }
1142
+ if (envelope.data.integrity.entries.length !== envelope.data.migrations.length) {
1143
+ throw new Error("Migration integrity entry count mismatch");
1144
+ }
1145
+ const validatedMigrations = [];
1146
+ let previousHash = _MigrationTracker.INTEGRITY_ROOT;
1147
+ for (let i = 0; i < envelope.data.migrations.length; i++) {
1148
+ const migration = envelope.data.migrations[i];
1149
+ const integrity = envelope.data.integrity.entries[i];
1150
+ if (!this.isValidMigrationRecord(migration)) {
1151
+ throw new Error("Invalid persisted migration record");
1152
+ }
1153
+ if (!integrity || integrity.recordId !== migration.id || integrity.previousHash !== previousHash) {
1154
+ throw new Error("Migration integrity chain mismatch");
1155
+ }
1156
+ const expectedHash = await this.computeDigestHex(
1157
+ `${previousHash}|${this.stableStringify({
1158
+ ...migration,
1159
+ previousHash: void 0,
1160
+ integrityHash: void 0
1161
+ })}`
1162
+ );
1163
+ if (expectedHash !== integrity.hash) {
1164
+ throw new Error("Migration integrity verification failed");
1165
+ }
1166
+ validatedMigrations.push({
1167
+ ...migration,
1168
+ previousHash: integrity.previousHash,
1169
+ integrityHash: integrity.hash
1170
+ });
1171
+ previousHash = expectedHash;
1172
+ }
1173
+ if (previousHash !== envelope.data.integrity.rootHash) {
1174
+ throw new Error("Migration integrity root hash mismatch");
1175
+ }
1176
+ const validatedSnapshots = /* @__PURE__ */ new Map();
1177
+ for (const snapshot of envelope.data.snapshots) {
1178
+ if (typeof snapshot.recordId !== "string" || typeof snapshot.beforeHash !== "string" || typeof snapshot.afterHash !== "string" || typeof snapshot.itemCount !== "number") {
1179
+ throw new Error("Invalid persisted migration snapshot");
1180
+ }
1181
+ validatedSnapshots.set(snapshot.recordId, {
1182
+ beforeHash: snapshot.beforeHash,
1183
+ afterHash: snapshot.afterHash,
1184
+ itemCount: snapshot.itemCount
1185
+ });
1186
+ }
1187
+ this.migrations = validatedMigrations;
1188
+ this.snapshots = validatedSnapshots;
1189
+ logger.debug("[MigrationTracker] Loaded from persistence", {
1190
+ key: this.persistence.key,
1191
+ migrations: this.migrations.length,
1192
+ snapshots: this.snapshots.size
1193
+ });
1194
+ return { migrations: this.migrations.length, snapshots: this.snapshots.size };
1195
+ }
1196
+ /**
1197
+ * Remove persisted migration tracker state.
1198
+ */
1199
+ async clearPersistence() {
1200
+ if (!this.persistence) {
1201
+ return;
868
1202
  }
1203
+ await this.persistence.adapter.removeItem(this.persistence.key);
869
1204
  }
870
1205
  /**
871
1206
  * Clear history (for testing)
@@ -873,6 +1208,7 @@ var MigrationTracker = class {
873
1208
  clear() {
874
1209
  this.migrations = [];
875
1210
  this.snapshots.clear();
1211
+ this.schedulePersist();
876
1212
  }
877
1213
  /**
878
1214
  * Get total migrations tracked
@@ -891,6 +1227,91 @@ var MigrationTracker = class {
891
1227
  return time >= start && time <= end;
892
1228
  });
893
1229
  }
1230
+ schedulePersist() {
1231
+ if (!this.persistence || this.persistence.autoPersist === false) {
1232
+ return;
1233
+ }
1234
+ if (this.persistTimer) {
1235
+ clearTimeout(this.persistTimer);
1236
+ }
1237
+ this.persistTimer = setTimeout(() => {
1238
+ void this.persistSafely();
1239
+ }, this.persistence.persistDebounceMs ?? 25);
1240
+ }
1241
+ async persistSafely() {
1242
+ if (!this.persistence) {
1243
+ return;
1244
+ }
1245
+ if (this.persistInFlight) {
1246
+ this.persistPending = true;
1247
+ return;
1248
+ }
1249
+ this.persistInFlight = true;
1250
+ try {
1251
+ await this.saveToPersistence();
1252
+ } catch (error) {
1253
+ logger.error("[MigrationTracker] Persistence write failed", {
1254
+ key: this.persistence.key,
1255
+ error: error instanceof Error ? error.message : String(error)
1256
+ });
1257
+ } finally {
1258
+ this.persistInFlight = false;
1259
+ const shouldRunAgain = this.persistPending;
1260
+ this.persistPending = false;
1261
+ if (shouldRunAgain) {
1262
+ void this.persistSafely();
1263
+ }
1264
+ }
1265
+ }
1266
+ isValidMigrationRecord(value) {
1267
+ if (typeof value !== "object" || value === null) {
1268
+ return false;
1269
+ }
1270
+ const record = value;
1271
+ const validDirection = record.direction === "up" || record.direction === "down";
1272
+ const validStatus = record.status === "pending" || record.status === "applied" || record.status === "failed" || record.status === "rolled-back";
1273
+ return typeof record.id === "string" && typeof record.migrationId === "string" && typeof record.timestamp === "string" && typeof record.version === "string" && validDirection && validStatus && typeof record.duration === "number" && typeof record.itemsAffected === "number" && typeof record.appliedBy === "string";
1274
+ }
1275
+ stableStringify(value) {
1276
+ if (value === null || typeof value !== "object") {
1277
+ return JSON.stringify(value);
1278
+ }
1279
+ if (Array.isArray(value)) {
1280
+ return `[${value.map((item) => this.stableStringify(item)).join(",")}]`;
1281
+ }
1282
+ const entries = Object.entries(value).sort(
1283
+ ([a], [b]) => a.localeCompare(b)
1284
+ );
1285
+ return `{${entries.map(
1286
+ ([key, entryValue]) => `${JSON.stringify(key)}:${this.stableStringify(entryValue)}`
1287
+ ).join(",")}}`;
1288
+ }
1289
+ async computeDigestHex(value) {
1290
+ if (globalThis.crypto?.subtle) {
1291
+ const bytes = new TextEncoder().encode(value);
1292
+ const normalized = bytes.buffer.slice(
1293
+ bytes.byteOffset,
1294
+ bytes.byteOffset + bytes.byteLength
1295
+ );
1296
+ const digest = await globalThis.crypto.subtle.digest(
1297
+ "SHA-256",
1298
+ normalized
1299
+ );
1300
+ return this.toHex(new Uint8Array(digest));
1301
+ }
1302
+ return this.fallbackDigestHex(value);
1303
+ }
1304
+ toHex(bytes) {
1305
+ return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
1306
+ }
1307
+ fallbackDigestHex(value) {
1308
+ let hash = 2166136261;
1309
+ for (let i = 0; i < value.length; i++) {
1310
+ hash ^= value.charCodeAt(i);
1311
+ hash = Math.imul(hash, 16777619);
1312
+ }
1313
+ return (hash >>> 0).toString(16).padStart(8, "0");
1314
+ }
894
1315
  };
895
1316
  var SyncCoordinator = class extends eventemitter3.EventEmitter {
896
1317
  nodes = /* @__PURE__ */ new Map();
@@ -1248,7 +1669,9 @@ var SyncCoordinator = class extends eventemitter3.EventEmitter {
1248
1669
  * Get active sync sessions
1249
1670
  */
1250
1671
  getActiveSyncSessions() {
1251
- return Array.from(this.sessions.values()).filter((s) => s.status === "active");
1672
+ return Array.from(this.sessions.values()).filter(
1673
+ (s) => s.status === "active"
1674
+ );
1252
1675
  }
1253
1676
  /**
1254
1677
  * Get sessions for a node
@@ -1266,8 +1689,14 @@ var SyncCoordinator = class extends eventemitter3.EventEmitter {
1266
1689
  const completed = sessions.filter((s) => s.status === "completed").length;
1267
1690
  const failed = sessions.filter((s) => s.status === "failed").length;
1268
1691
  const active = sessions.filter((s) => s.status === "active").length;
1269
- const totalItemsSynced = sessions.reduce((sum, s) => sum + s.itemsSynced, 0);
1270
- const totalConflicts = sessions.reduce((sum, s) => sum + s.conflictsDetected, 0);
1692
+ const totalItemsSynced = sessions.reduce(
1693
+ (sum, s) => sum + s.itemsSynced,
1694
+ 0
1695
+ );
1696
+ const totalConflicts = sessions.reduce(
1697
+ (sum, s) => sum + s.conflictsDetected,
1698
+ 0
1699
+ );
1271
1700
  return {
1272
1701
  totalNodes: this.nodes.size,
1273
1702
  onlineNodes: this.getOnlineNodes().length,
@@ -1334,7 +1763,9 @@ var SyncCoordinator = class extends eventemitter3.EventEmitter {
1334
1763
  }
1335
1764
  }
1336
1765
  }, interval);
1337
- logger.debug("[SyncCoordinator] Heartbeat monitoring started", { interval });
1766
+ logger.debug("[SyncCoordinator] Heartbeat monitoring started", {
1767
+ interval
1768
+ });
1338
1769
  }
1339
1770
  /**
1340
1771
  * Stop heartbeat monitoring
@@ -1367,7 +1798,8 @@ var SyncCoordinator = class extends eventemitter3.EventEmitter {
1367
1798
  };
1368
1799
 
1369
1800
  // src/distributed/ReplicationManager.ts
1370
- var ReplicationManager = class {
1801
+ var ReplicationManager = class _ReplicationManager {
1802
+ static DEFAULT_PERSIST_KEY = "aeon:replication-state:v1";
1371
1803
  replicas = /* @__PURE__ */ new Map();
1372
1804
  policies = /* @__PURE__ */ new Map();
1373
1805
  replicationEvents = [];
@@ -1376,6 +1808,29 @@ var ReplicationManager = class {
1376
1808
  cryptoProvider = null;
1377
1809
  replicasByDID = /* @__PURE__ */ new Map();
1378
1810
  // DID -> replicaId
1811
+ persistence = null;
1812
+ persistTimer = null;
1813
+ persistInFlight = false;
1814
+ persistPending = false;
1815
+ constructor(options) {
1816
+ if (options?.persistence) {
1817
+ this.persistence = {
1818
+ ...options.persistence,
1819
+ key: options.persistence.key ?? _ReplicationManager.DEFAULT_PERSIST_KEY,
1820
+ autoPersist: options.persistence.autoPersist ?? true,
1821
+ autoLoad: options.persistence.autoLoad ?? false,
1822
+ persistDebounceMs: options.persistence.persistDebounceMs ?? 25
1823
+ };
1824
+ }
1825
+ if (this.persistence?.autoLoad) {
1826
+ void this.loadFromPersistence().catch((error) => {
1827
+ logger.error("[ReplicationManager] Failed to load persistence", {
1828
+ key: this.persistence?.key,
1829
+ error: error instanceof Error ? error.message : String(error)
1830
+ });
1831
+ });
1832
+ }
1833
+ }
1379
1834
  /**
1380
1835
  * Configure cryptographic provider for encrypted replication
1381
1836
  */
@@ -1420,6 +1875,7 @@ var ReplicationManager = class {
1420
1875
  details: { did: replica.did, encrypted, authenticated: true }
1421
1876
  };
1422
1877
  this.replicationEvents.push(event);
1878
+ this.schedulePersist();
1423
1879
  logger.debug("[ReplicationManager] Authenticated replica registered", {
1424
1880
  replicaId: replica.id,
1425
1881
  did: replica.did,
@@ -1449,7 +1905,10 @@ var ReplicationManager = class {
1449
1905
  throw new Error("Crypto provider not initialized");
1450
1906
  }
1451
1907
  const dataBytes = new TextEncoder().encode(JSON.stringify(data));
1452
- const encrypted = await this.cryptoProvider.encrypt(dataBytes, targetReplicaDID);
1908
+ const encrypted = await this.cryptoProvider.encrypt(
1909
+ dataBytes,
1910
+ targetReplicaDID
1911
+ );
1453
1912
  const localDID = this.cryptoProvider.getLocalDID();
1454
1913
  return {
1455
1914
  ct: encrypted.ct,
@@ -1518,10 +1977,13 @@ var ReplicationManager = class {
1518
1977
  }))
1519
1978
  });
1520
1979
  if (!result.authorized) {
1521
- logger.warn("[ReplicationManager] Replica capability verification failed", {
1522
- replicaDID,
1523
- error: result.error
1524
- });
1980
+ logger.warn(
1981
+ "[ReplicationManager] Replica capability verification failed",
1982
+ {
1983
+ replicaDID,
1984
+ error: result.error
1985
+ }
1986
+ );
1525
1987
  }
1526
1988
  return result;
1527
1989
  }
@@ -1540,6 +2002,7 @@ var ReplicationManager = class {
1540
2002
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1541
2003
  };
1542
2004
  this.replicationEvents.push(event);
2005
+ this.schedulePersist();
1543
2006
  logger.debug("[ReplicationManager] Replica registered", {
1544
2007
  replicaId: replica.id,
1545
2008
  nodeId: replica.nodeId,
@@ -1562,6 +2025,7 @@ var ReplicationManager = class {
1562
2025
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1563
2026
  };
1564
2027
  this.replicationEvents.push(event);
2028
+ this.schedulePersist();
1565
2029
  logger.debug("[ReplicationManager] Replica removed", { replicaId });
1566
2030
  }
1567
2031
  /**
@@ -1577,6 +2041,7 @@ var ReplicationManager = class {
1577
2041
  maxReplicationLag
1578
2042
  };
1579
2043
  this.policies.set(policy.id, policy);
2044
+ this.schedulePersist();
1580
2045
  logger.debug("[ReplicationManager] Policy created", {
1581
2046
  policyId: policy.id,
1582
2047
  name,
@@ -1619,12 +2084,15 @@ var ReplicationManager = class {
1619
2084
  lagBytes,
1620
2085
  lagMillis
1621
2086
  });
2087
+ this.schedulePersist();
1622
2088
  }
1623
2089
  /**
1624
2090
  * Get replicas for node
1625
2091
  */
1626
2092
  getReplicasForNode(nodeId) {
1627
- return Array.from(this.replicas.values()).filter((r) => r.nodeId === nodeId);
2093
+ return Array.from(this.replicas.values()).filter(
2094
+ (r) => r.nodeId === nodeId
2095
+ );
1628
2096
  }
1629
2097
  /**
1630
2098
  * Get healthy replicas
@@ -1638,13 +2106,17 @@ var ReplicationManager = class {
1638
2106
  * Get syncing replicas
1639
2107
  */
1640
2108
  getSyncingReplicas() {
1641
- return Array.from(this.replicas.values()).filter((r) => r.status === "syncing");
2109
+ return Array.from(this.replicas.values()).filter(
2110
+ (r) => r.status === "syncing"
2111
+ );
1642
2112
  }
1643
2113
  /**
1644
2114
  * Get failed replicas
1645
2115
  */
1646
2116
  getFailedReplicas() {
1647
- return Array.from(this.replicas.values()).filter((r) => r.status === "failed");
2117
+ return Array.from(this.replicas.values()).filter(
2118
+ (r) => r.status === "failed"
2119
+ );
1648
2120
  }
1649
2121
  /**
1650
2122
  * Check replication health for policy
@@ -1705,7 +2177,9 @@ var ReplicationManager = class {
1705
2177
  const syncing = this.getSyncingReplicas().length;
1706
2178
  const failed = this.getFailedReplicas().length;
1707
2179
  const total = this.replicas.size;
1708
- const replicationLags = Array.from(this.replicas.values()).map((r) => r.lagMillis);
2180
+ const replicationLags = Array.from(this.replicas.values()).map(
2181
+ (r) => r.lagMillis
2182
+ );
1709
2183
  const avgLag = replicationLags.length > 0 ? replicationLags.reduce((a, b) => a + b) / replicationLags.length : 0;
1710
2184
  const maxLag = replicationLags.length > 0 ? Math.max(...replicationLags) : 0;
1711
2185
  return {
@@ -1779,6 +2253,155 @@ var ReplicationManager = class {
1779
2253
  return false;
1780
2254
  }
1781
2255
  }
2256
+ /**
2257
+ * Persist current replication state snapshot.
2258
+ */
2259
+ async saveToPersistence() {
2260
+ if (!this.persistence) {
2261
+ return;
2262
+ }
2263
+ const data = {
2264
+ replicas: this.getAllReplicas(),
2265
+ policies: this.getAllPolicies(),
2266
+ syncStatus: Array.from(this.syncStatus.entries()).map(
2267
+ ([nodeId, state]) => ({
2268
+ nodeId,
2269
+ synced: state.synced,
2270
+ failed: state.failed
2271
+ })
2272
+ )
2273
+ };
2274
+ const envelope = {
2275
+ version: 1,
2276
+ updatedAt: Date.now(),
2277
+ data
2278
+ };
2279
+ const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
2280
+ await this.persistence.adapter.setItem(this.persistence.key, serialize(envelope));
2281
+ }
2282
+ /**
2283
+ * Load replication snapshot from persistence.
2284
+ */
2285
+ async loadFromPersistence() {
2286
+ if (!this.persistence) {
2287
+ return { replicas: 0, policies: 0, syncStatus: 0 };
2288
+ }
2289
+ const raw = await this.persistence.adapter.getItem(this.persistence.key);
2290
+ if (!raw) {
2291
+ return { replicas: 0, policies: 0, syncStatus: 0 };
2292
+ }
2293
+ const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
2294
+ const envelope = deserialize(raw);
2295
+ if (envelope.version !== 1 || !envelope.data) {
2296
+ throw new Error("Invalid replication persistence payload");
2297
+ }
2298
+ if (!Array.isArray(envelope.data.replicas) || !Array.isArray(envelope.data.policies) || !Array.isArray(envelope.data.syncStatus)) {
2299
+ throw new Error("Invalid replication persistence structure");
2300
+ }
2301
+ this.replicas.clear();
2302
+ this.policies.clear();
2303
+ this.syncStatus.clear();
2304
+ this.replicasByDID.clear();
2305
+ let importedReplicas = 0;
2306
+ for (const replica of envelope.data.replicas) {
2307
+ if (this.isValidReplica(replica)) {
2308
+ this.replicas.set(replica.id, replica);
2309
+ if (replica.did) {
2310
+ this.replicasByDID.set(replica.did, replica.id);
2311
+ }
2312
+ importedReplicas++;
2313
+ }
2314
+ }
2315
+ let importedPolicies = 0;
2316
+ for (const policy of envelope.data.policies) {
2317
+ if (this.isValidPolicy(policy)) {
2318
+ this.policies.set(policy.id, policy);
2319
+ importedPolicies++;
2320
+ }
2321
+ }
2322
+ let importedSyncStatus = 0;
2323
+ for (const status of envelope.data.syncStatus) {
2324
+ if (typeof status.nodeId === "string" && typeof status.synced === "number" && typeof status.failed === "number") {
2325
+ this.syncStatus.set(status.nodeId, {
2326
+ synced: status.synced,
2327
+ failed: status.failed
2328
+ });
2329
+ importedSyncStatus++;
2330
+ }
2331
+ }
2332
+ logger.debug("[ReplicationManager] Loaded from persistence", {
2333
+ key: this.persistence.key,
2334
+ replicas: importedReplicas,
2335
+ policies: importedPolicies,
2336
+ syncStatus: importedSyncStatus
2337
+ });
2338
+ return {
2339
+ replicas: importedReplicas,
2340
+ policies: importedPolicies,
2341
+ syncStatus: importedSyncStatus
2342
+ };
2343
+ }
2344
+ /**
2345
+ * Remove persisted replication snapshot.
2346
+ */
2347
+ async clearPersistence() {
2348
+ if (!this.persistence) {
2349
+ return;
2350
+ }
2351
+ await this.persistence.adapter.removeItem(this.persistence.key);
2352
+ }
2353
+ schedulePersist() {
2354
+ if (!this.persistence || this.persistence.autoPersist === false) {
2355
+ return;
2356
+ }
2357
+ if (this.persistTimer) {
2358
+ clearTimeout(this.persistTimer);
2359
+ }
2360
+ this.persistTimer = setTimeout(() => {
2361
+ void this.persistSafely();
2362
+ }, this.persistence.persistDebounceMs ?? 25);
2363
+ }
2364
+ async persistSafely() {
2365
+ if (!this.persistence) {
2366
+ return;
2367
+ }
2368
+ if (this.persistInFlight) {
2369
+ this.persistPending = true;
2370
+ return;
2371
+ }
2372
+ this.persistInFlight = true;
2373
+ try {
2374
+ await this.saveToPersistence();
2375
+ } catch (error) {
2376
+ logger.error("[ReplicationManager] Persistence write failed", {
2377
+ key: this.persistence.key,
2378
+ error: error instanceof Error ? error.message : String(error)
2379
+ });
2380
+ } finally {
2381
+ this.persistInFlight = false;
2382
+ const shouldRunAgain = this.persistPending;
2383
+ this.persistPending = false;
2384
+ if (shouldRunAgain) {
2385
+ void this.persistSafely();
2386
+ }
2387
+ }
2388
+ }
2389
+ isValidReplica(value) {
2390
+ if (typeof value !== "object" || value === null) {
2391
+ return false;
2392
+ }
2393
+ const candidate = value;
2394
+ const validStatus = candidate.status === "primary" || candidate.status === "secondary" || candidate.status === "syncing" || candidate.status === "failed";
2395
+ return typeof candidate.id === "string" && typeof candidate.nodeId === "string" && validStatus && typeof candidate.lastSyncTime === "string" && typeof candidate.lagBytes === "number" && typeof candidate.lagMillis === "number";
2396
+ }
2397
+ isValidPolicy(value) {
2398
+ if (typeof value !== "object" || value === null) {
2399
+ return false;
2400
+ }
2401
+ const candidate = value;
2402
+ const validConsistency = candidate.consistencyLevel === "eventual" || candidate.consistencyLevel === "read-after-write" || candidate.consistencyLevel === "strong";
2403
+ return typeof candidate.id === "string" && typeof candidate.name === "string" && typeof candidate.replicationFactor === "number" && validConsistency && typeof candidate.syncInterval === "number" && typeof candidate.maxReplicationLag === "number";
2404
+ }
1782
2405
  /**
1783
2406
  * Clear all state (for testing)
1784
2407
  */
@@ -1789,6 +2412,7 @@ var ReplicationManager = class {
1789
2412
  this.syncStatus.clear();
1790
2413
  this.replicasByDID.clear();
1791
2414
  this.cryptoProvider = null;
2415
+ this.schedulePersist();
1792
2416
  }
1793
2417
  /**
1794
2418
  * Get the crypto provider (for advanced usage)
@@ -1799,7 +2423,8 @@ var ReplicationManager = class {
1799
2423
  };
1800
2424
 
1801
2425
  // src/distributed/SyncProtocol.ts
1802
- var SyncProtocol = class {
2426
+ var SyncProtocol = class _SyncProtocol {
2427
+ static DEFAULT_PERSIST_KEY = "aeon:sync-protocol:v1";
1803
2428
  version = "1.0.0";
1804
2429
  messageQueue = [];
1805
2430
  messageMap = /* @__PURE__ */ new Map();
@@ -1809,6 +2434,29 @@ var SyncProtocol = class {
1809
2434
  // Crypto support
1810
2435
  cryptoProvider = null;
1811
2436
  cryptoConfig = null;
2437
+ persistence = null;
2438
+ persistTimer = null;
2439
+ persistInFlight = false;
2440
+ persistPending = false;
2441
+ constructor(options) {
2442
+ if (options?.persistence) {
2443
+ this.persistence = {
2444
+ ...options.persistence,
2445
+ key: options.persistence.key ?? _SyncProtocol.DEFAULT_PERSIST_KEY,
2446
+ autoPersist: options.persistence.autoPersist ?? true,
2447
+ autoLoad: options.persistence.autoLoad ?? false,
2448
+ persistDebounceMs: options.persistence.persistDebounceMs ?? 25
2449
+ };
2450
+ }
2451
+ if (this.persistence?.autoLoad) {
2452
+ void this.loadFromPersistence().catch((error) => {
2453
+ logger.error("[SyncProtocol] Failed to load persistence", {
2454
+ key: this.persistence?.key,
2455
+ error: error instanceof Error ? error.message : String(error)
2456
+ });
2457
+ });
2458
+ }
2459
+ }
1812
2460
  /**
1813
2461
  * Configure cryptographic provider for authenticated/encrypted messages
1814
2462
  */
@@ -1896,6 +2544,7 @@ var SyncProtocol = class {
1896
2544
  }
1897
2545
  this.messageMap.set(message.messageId, message);
1898
2546
  this.messageQueue.push(message);
2547
+ this.schedulePersist();
1899
2548
  logger.debug("[SyncProtocol] Authenticated handshake created", {
1900
2549
  messageId: message.messageId,
1901
2550
  did: localDID,
@@ -1914,6 +2563,7 @@ var SyncProtocol = class {
1914
2563
  const handshake = message.payload;
1915
2564
  if (!this.cryptoProvider || !this.cryptoConfig) {
1916
2565
  this.handshakes.set(message.sender, handshake);
2566
+ this.schedulePersist();
1917
2567
  return { valid: true, handshake };
1918
2568
  }
1919
2569
  if (handshake.did && handshake.publicSigningKey) {
@@ -1956,6 +2606,7 @@ var SyncProtocol = class {
1956
2606
  }
1957
2607
  }
1958
2608
  this.handshakes.set(message.sender, handshake);
2609
+ this.schedulePersist();
1959
2610
  logger.debug("[SyncProtocol] Authenticated handshake verified", {
1960
2611
  messageId: message.messageId,
1961
2612
  did: handshake.did
@@ -1979,7 +2630,10 @@ var SyncProtocol = class {
1979
2630
  };
1980
2631
  if (encrypt && message.receiver && this.cryptoConfig?.encryptionMode !== "none") {
1981
2632
  const payloadBytes = new TextEncoder().encode(JSON.stringify(payload));
1982
- const encrypted = await this.cryptoProvider.encrypt(payloadBytes, message.receiver);
2633
+ const encrypted = await this.cryptoProvider.encrypt(
2634
+ payloadBytes,
2635
+ message.receiver
2636
+ );
1983
2637
  message.payload = encrypted;
1984
2638
  message.auth.encrypted = true;
1985
2639
  logger.debug("[SyncProtocol] Message encrypted", {
@@ -2052,6 +2706,7 @@ var SyncProtocol = class {
2052
2706
  };
2053
2707
  this.messageMap.set(message.messageId, message);
2054
2708
  this.messageQueue.push(message);
2709
+ this.schedulePersist();
2055
2710
  logger.debug("[SyncProtocol] Handshake message created", {
2056
2711
  messageId: message.messageId,
2057
2712
  nodeId,
@@ -2079,6 +2734,7 @@ var SyncProtocol = class {
2079
2734
  };
2080
2735
  this.messageMap.set(message.messageId, message);
2081
2736
  this.messageQueue.push(message);
2737
+ this.schedulePersist();
2082
2738
  logger.debug("[SyncProtocol] Sync request created", {
2083
2739
  messageId: message.messageId,
2084
2740
  sessionId,
@@ -2109,6 +2765,7 @@ var SyncProtocol = class {
2109
2765
  };
2110
2766
  this.messageMap.set(message.messageId, message);
2111
2767
  this.messageQueue.push(message);
2768
+ this.schedulePersist();
2112
2769
  logger.debug("[SyncProtocol] Sync response created", {
2113
2770
  messageId: message.messageId,
2114
2771
  sessionId,
@@ -2132,6 +2789,7 @@ var SyncProtocol = class {
2132
2789
  };
2133
2790
  this.messageMap.set(message.messageId, message);
2134
2791
  this.messageQueue.push(message);
2792
+ this.schedulePersist();
2135
2793
  return message;
2136
2794
  }
2137
2795
  /**
@@ -2156,6 +2814,7 @@ var SyncProtocol = class {
2156
2814
  error,
2157
2815
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
2158
2816
  });
2817
+ this.schedulePersist();
2159
2818
  logger.error("[SyncProtocol] Error message created", {
2160
2819
  messageId: message.messageId,
2161
2820
  errorCode: error.code,
@@ -2180,9 +2839,8 @@ var SyncProtocol = class {
2180
2839
  if (!message.timestamp) {
2181
2840
  errors.push("Timestamp is required");
2182
2841
  }
2183
- try {
2184
- new Date(message.timestamp);
2185
- } catch {
2842
+ const timestampValue = new Date(message.timestamp);
2843
+ if (Number.isNaN(timestampValue.getTime())) {
2186
2844
  errors.push("Invalid timestamp format");
2187
2845
  }
2188
2846
  return {
@@ -2201,7 +2859,9 @@ var SyncProtocol = class {
2201
2859
  messageId: message.messageId,
2202
2860
  error: error instanceof Error ? error.message : String(error)
2203
2861
  });
2204
- throw new Error(`Failed to serialize message: ${error instanceof Error ? error.message : String(error)}`);
2862
+ throw new Error(
2863
+ `Failed to serialize message: ${error instanceof Error ? error.message : String(error)}`
2864
+ );
2205
2865
  }
2206
2866
  }
2207
2867
  /**
@@ -2219,7 +2879,9 @@ var SyncProtocol = class {
2219
2879
  logger.error("[SyncProtocol] Message deserialization failed", {
2220
2880
  error: error instanceof Error ? error.message : String(error)
2221
2881
  });
2222
- throw new Error(`Failed to deserialize message: ${error instanceof Error ? error.message : String(error)}`);
2882
+ throw new Error(
2883
+ `Failed to deserialize message: ${error instanceof Error ? error.message : String(error)}`
2884
+ );
2223
2885
  }
2224
2886
  }
2225
2887
  /**
@@ -2232,6 +2894,7 @@ var SyncProtocol = class {
2232
2894
  const handshake = message.payload;
2233
2895
  const nodeId = message.sender;
2234
2896
  this.handshakes.set(nodeId, handshake);
2897
+ this.schedulePersist();
2235
2898
  logger.debug("[SyncProtocol] Handshake processed", {
2236
2899
  nodeId,
2237
2900
  protocolVersion: handshake.protocolVersion,
@@ -2284,7 +2947,9 @@ var SyncProtocol = class {
2284
2947
  messagesByType[message.type] = (messagesByType[message.type] || 0) + 1;
2285
2948
  }
2286
2949
  const errorCount = this.protocolErrors.length;
2287
- const recoverableErrors = this.protocolErrors.filter((e) => e.error.recoverable).length;
2950
+ const recoverableErrors = this.protocolErrors.filter(
2951
+ (e) => e.error.recoverable
2952
+ ).length;
2288
2953
  return {
2289
2954
  totalMessages: this.messageQueue.length,
2290
2955
  messagesByType,
@@ -2300,6 +2965,156 @@ var SyncProtocol = class {
2300
2965
  getErrors() {
2301
2966
  return [...this.protocolErrors];
2302
2967
  }
2968
+ /**
2969
+ * Persist protocol state for reconnect/replay.
2970
+ */
2971
+ async saveToPersistence() {
2972
+ if (!this.persistence) {
2973
+ return;
2974
+ }
2975
+ const data = {
2976
+ protocolVersion: this.version,
2977
+ messageCounter: this.messageCounter,
2978
+ messageQueue: this.getAllMessages(),
2979
+ handshakes: Array.from(this.handshakes.entries()).map(
2980
+ ([nodeId, handshake]) => ({
2981
+ nodeId,
2982
+ handshake
2983
+ })
2984
+ ),
2985
+ protocolErrors: this.getErrors()
2986
+ };
2987
+ const envelope = {
2988
+ version: 1,
2989
+ updatedAt: Date.now(),
2990
+ data
2991
+ };
2992
+ const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
2993
+ await this.persistence.adapter.setItem(this.persistence.key, serialize(envelope));
2994
+ }
2995
+ /**
2996
+ * Load protocol state from persistence.
2997
+ */
2998
+ async loadFromPersistence() {
2999
+ if (!this.persistence) {
3000
+ return { messages: 0, handshakes: 0, errors: 0 };
3001
+ }
3002
+ const raw = await this.persistence.adapter.getItem(this.persistence.key);
3003
+ if (!raw) {
3004
+ return { messages: 0, handshakes: 0, errors: 0 };
3005
+ }
3006
+ const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
3007
+ const envelope = deserialize(raw);
3008
+ if (envelope.version !== 1 || !envelope.data) {
3009
+ throw new Error("Invalid sync protocol persistence payload");
3010
+ }
3011
+ if (!Array.isArray(envelope.data.messageQueue) || !Array.isArray(envelope.data.handshakes) || !Array.isArray(envelope.data.protocolErrors)) {
3012
+ throw new Error("Invalid sync protocol persistence structure");
3013
+ }
3014
+ const nextMessages = [];
3015
+ for (const message of envelope.data.messageQueue) {
3016
+ const validation = this.validateMessage(message);
3017
+ if (!validation.valid) {
3018
+ throw new Error(
3019
+ `Invalid persisted message ${message?.messageId ?? "unknown"}: ${validation.errors.join(", ")}`
3020
+ );
3021
+ }
3022
+ nextMessages.push(message);
3023
+ }
3024
+ const nextHandshakes = /* @__PURE__ */ new Map();
3025
+ for (const entry of envelope.data.handshakes) {
3026
+ if (typeof entry.nodeId !== "string" || !this.isValidHandshake(entry.handshake)) {
3027
+ throw new Error("Invalid persisted handshake payload");
3028
+ }
3029
+ nextHandshakes.set(entry.nodeId, entry.handshake);
3030
+ }
3031
+ const nextErrors = [];
3032
+ for (const entry of envelope.data.protocolErrors) {
3033
+ if (!this.isValidProtocolErrorEntry(entry)) {
3034
+ throw new Error("Invalid persisted protocol error payload");
3035
+ }
3036
+ nextErrors.push(entry);
3037
+ }
3038
+ this.messageQueue = nextMessages;
3039
+ this.messageMap = new Map(nextMessages.map((m) => [m.messageId, m]));
3040
+ this.handshakes = nextHandshakes;
3041
+ this.protocolErrors = nextErrors;
3042
+ this.messageCounter = Math.max(
3043
+ envelope.data.messageCounter || 0,
3044
+ this.messageQueue.length
3045
+ );
3046
+ logger.debug("[SyncProtocol] Loaded from persistence", {
3047
+ key: this.persistence.key,
3048
+ messages: this.messageQueue.length,
3049
+ handshakes: this.handshakes.size,
3050
+ errors: this.protocolErrors.length
3051
+ });
3052
+ return {
3053
+ messages: this.messageQueue.length,
3054
+ handshakes: this.handshakes.size,
3055
+ errors: this.protocolErrors.length
3056
+ };
3057
+ }
3058
+ /**
3059
+ * Clear persisted protocol checkpoint.
3060
+ */
3061
+ async clearPersistence() {
3062
+ if (!this.persistence) {
3063
+ return;
3064
+ }
3065
+ await this.persistence.adapter.removeItem(this.persistence.key);
3066
+ }
3067
+ schedulePersist() {
3068
+ if (!this.persistence || this.persistence.autoPersist === false) {
3069
+ return;
3070
+ }
3071
+ if (this.persistTimer) {
3072
+ clearTimeout(this.persistTimer);
3073
+ }
3074
+ this.persistTimer = setTimeout(() => {
3075
+ void this.persistSafely();
3076
+ }, this.persistence.persistDebounceMs ?? 25);
3077
+ }
3078
+ async persistSafely() {
3079
+ if (!this.persistence) {
3080
+ return;
3081
+ }
3082
+ if (this.persistInFlight) {
3083
+ this.persistPending = true;
3084
+ return;
3085
+ }
3086
+ this.persistInFlight = true;
3087
+ try {
3088
+ await this.saveToPersistence();
3089
+ } catch (error) {
3090
+ logger.error("[SyncProtocol] Persistence write failed", {
3091
+ key: this.persistence.key,
3092
+ error: error instanceof Error ? error.message : String(error)
3093
+ });
3094
+ } finally {
3095
+ this.persistInFlight = false;
3096
+ const shouldRunAgain = this.persistPending;
3097
+ this.persistPending = false;
3098
+ if (shouldRunAgain) {
3099
+ void this.persistSafely();
3100
+ }
3101
+ }
3102
+ }
3103
+ isValidHandshake(value) {
3104
+ if (typeof value !== "object" || value === null) {
3105
+ return false;
3106
+ }
3107
+ const handshake = value;
3108
+ const validState = handshake.state === "initiating" || handshake.state === "responding" || handshake.state === "completed";
3109
+ return typeof handshake.protocolVersion === "string" && typeof handshake.nodeId === "string" && Array.isArray(handshake.capabilities) && handshake.capabilities.every((cap) => typeof cap === "string") && validState;
3110
+ }
3111
+ isValidProtocolErrorEntry(entry) {
3112
+ if (typeof entry !== "object" || entry === null) {
3113
+ return false;
3114
+ }
3115
+ const candidate = entry;
3116
+ return typeof candidate.timestamp === "string" && typeof candidate.error?.code === "string" && typeof candidate.error.message === "string" && typeof candidate.error.recoverable === "boolean";
3117
+ }
2303
3118
  /**
2304
3119
  * Generate message ID
2305
3120
  */
@@ -2318,6 +3133,7 @@ var SyncProtocol = class {
2318
3133
  this.messageCounter = 0;
2319
3134
  this.cryptoProvider = null;
2320
3135
  this.cryptoConfig = null;
3136
+ this.schedulePersist();
2321
3137
  }
2322
3138
  /**
2323
3139
  * Get the crypto provider (for advanced usage)
@@ -2703,7 +3519,9 @@ var StateReconciler = class {
2703
3519
  }
2704
3520
  return {
2705
3521
  totalReconciliations: this.reconciliationHistory.length,
2706
- successfulReconciliations: this.reconciliationHistory.filter((r) => r.success).length,
3522
+ successfulReconciliations: this.reconciliationHistory.filter(
3523
+ (r) => r.success
3524
+ ).length,
2707
3525
  totalConflictsResolved: resolvedConflicts,
2708
3526
  averageConflictsPerReconciliation: this.reconciliationHistory.length > 0 ? resolvedConflicts / this.reconciliationHistory.length : 0,
2709
3527
  strategyUsage,
@@ -2727,18 +3545,46 @@ var StateReconciler = class {
2727
3545
  }
2728
3546
  };
2729
3547
  var logger2 = getLogger();
2730
- var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
3548
+ var OfflineOperationQueue = class _OfflineOperationQueue extends eventemitter3.EventEmitter {
3549
+ static DEFAULT_PERSIST_KEY = "aeon:offline-queue:v1";
2731
3550
  queue = /* @__PURE__ */ new Map();
2732
3551
  syncingIds = /* @__PURE__ */ new Set();
2733
3552
  maxQueueSize = 1e3;
2734
3553
  defaultMaxRetries = 3;
2735
- constructor(maxQueueSize = 1e3, defaultMaxRetries = 3) {
3554
+ persistence = null;
3555
+ persistTimer = null;
3556
+ persistInFlight = false;
3557
+ persistPending = false;
3558
+ constructor(maxQueueSizeOrOptions = 1e3, defaultMaxRetries = 3) {
2736
3559
  super();
2737
- this.maxQueueSize = maxQueueSize;
2738
- this.defaultMaxRetries = defaultMaxRetries;
3560
+ if (typeof maxQueueSizeOrOptions === "number") {
3561
+ this.maxQueueSize = maxQueueSizeOrOptions;
3562
+ this.defaultMaxRetries = defaultMaxRetries;
3563
+ } else {
3564
+ this.maxQueueSize = maxQueueSizeOrOptions.maxQueueSize ?? 1e3;
3565
+ this.defaultMaxRetries = maxQueueSizeOrOptions.defaultMaxRetries ?? 3;
3566
+ if (maxQueueSizeOrOptions.persistence) {
3567
+ this.persistence = {
3568
+ ...maxQueueSizeOrOptions.persistence,
3569
+ key: maxQueueSizeOrOptions.persistence.key ?? _OfflineOperationQueue.DEFAULT_PERSIST_KEY,
3570
+ autoPersist: maxQueueSizeOrOptions.persistence.autoPersist ?? true,
3571
+ autoLoad: maxQueueSizeOrOptions.persistence.autoLoad ?? false,
3572
+ persistDebounceMs: maxQueueSizeOrOptions.persistence.persistDebounceMs ?? 25
3573
+ };
3574
+ if (this.persistence.autoLoad) {
3575
+ void this.loadFromPersistence().catch((error) => {
3576
+ logger2.error("[OfflineOperationQueue] Failed to load persistence", {
3577
+ key: this.persistence?.key,
3578
+ error: error instanceof Error ? error.message : String(error)
3579
+ });
3580
+ });
3581
+ }
3582
+ }
3583
+ }
2739
3584
  logger2.debug("[OfflineOperationQueue] Initialized", {
2740
- maxQueueSize,
2741
- defaultMaxRetries
3585
+ maxQueueSize: this.maxQueueSize,
3586
+ defaultMaxRetries: this.defaultMaxRetries,
3587
+ persistenceEnabled: this.persistence !== null
2742
3588
  });
2743
3589
  }
2744
3590
  /**
@@ -2767,6 +3613,7 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2767
3613
  };
2768
3614
  this.queue.set(operation.id, operation);
2769
3615
  this.emit("operation-added", operation);
3616
+ this.schedulePersist();
2770
3617
  logger2.debug("[OfflineOperationQueue] Operation enqueued", {
2771
3618
  id: operation.id,
2772
3619
  type,
@@ -2791,13 +3638,18 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2791
3638
  * Mark operations as syncing
2792
3639
  */
2793
3640
  markSyncing(operationIds) {
3641
+ let changed = false;
2794
3642
  for (const id of operationIds) {
2795
3643
  const op = this.queue.get(id);
2796
3644
  if (op) {
2797
3645
  op.status = "syncing";
2798
3646
  this.syncingIds.add(id);
3647
+ changed = true;
2799
3648
  }
2800
3649
  }
3650
+ if (changed) {
3651
+ this.schedulePersist();
3652
+ }
2801
3653
  }
2802
3654
  /**
2803
3655
  * Mark operation as synced
@@ -2808,8 +3660,10 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2808
3660
  op.status = "synced";
2809
3661
  this.syncingIds.delete(operationId);
2810
3662
  this.emit("operation-synced", op);
3663
+ this.schedulePersist();
2811
3664
  setTimeout(() => {
2812
3665
  this.queue.delete(operationId);
3666
+ this.schedulePersist();
2813
3667
  if (this.getPendingCount() === 0) {
2814
3668
  this.emit("queue-empty");
2815
3669
  }
@@ -2841,6 +3695,7 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2841
3695
  maxRetries: op.maxRetries
2842
3696
  });
2843
3697
  }
3698
+ this.schedulePersist();
2844
3699
  }
2845
3700
  }
2846
3701
  /**
@@ -2893,28 +3748,39 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2893
3748
  clear() {
2894
3749
  this.queue.clear();
2895
3750
  this.syncingIds.clear();
3751
+ this.schedulePersist();
2896
3752
  logger2.debug("[OfflineOperationQueue] Queue cleared");
2897
3753
  }
2898
3754
  /**
2899
3755
  * Clear failed operations
2900
3756
  */
2901
3757
  clearFailed() {
3758
+ let changed = false;
2902
3759
  for (const [id, op] of this.queue.entries()) {
2903
3760
  if (op.status === "failed") {
2904
3761
  this.queue.delete(id);
3762
+ changed = true;
2905
3763
  }
2906
3764
  }
3765
+ if (changed) {
3766
+ this.schedulePersist();
3767
+ }
2907
3768
  }
2908
3769
  /**
2909
3770
  * Retry failed operations
2910
3771
  */
2911
3772
  retryFailed() {
3773
+ let changed = false;
2912
3774
  for (const op of this.queue.values()) {
2913
3775
  if (op.status === "failed") {
2914
3776
  op.status = "pending";
2915
3777
  op.retryCount = 0;
3778
+ changed = true;
2916
3779
  }
2917
3780
  }
3781
+ if (changed) {
3782
+ this.schedulePersist();
3783
+ }
2918
3784
  }
2919
3785
  /**
2920
3786
  * Find oldest low-priority operation
@@ -2933,12 +3799,125 @@ var OfflineOperationQueue = class extends eventemitter3.EventEmitter {
2933
3799
  * Import queue from persistence
2934
3800
  */
2935
3801
  import(operations) {
3802
+ this.queue.clear();
3803
+ this.syncingIds.clear();
2936
3804
  for (const op of operations) {
2937
- this.queue.set(op.id, op);
3805
+ if (this.isValidOfflineOperation(op)) {
3806
+ this.queue.set(op.id, {
3807
+ ...op,
3808
+ status: op.status === "syncing" ? "pending" : op.status
3809
+ });
3810
+ }
2938
3811
  }
3812
+ this.schedulePersist();
2939
3813
  logger2.debug("[OfflineOperationQueue] Imported operations", {
2940
- count: operations.length
3814
+ count: this.queue.size
3815
+ });
3816
+ }
3817
+ /**
3818
+ * Persist current queue snapshot.
3819
+ */
3820
+ async saveToPersistence() {
3821
+ if (!this.persistence) {
3822
+ return;
3823
+ }
3824
+ const envelope = {
3825
+ version: 1,
3826
+ updatedAt: Date.now(),
3827
+ data: this.export()
3828
+ };
3829
+ const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
3830
+ const raw = serialize(envelope);
3831
+ await this.persistence.adapter.setItem(this.persistence.key, raw);
3832
+ }
3833
+ /**
3834
+ * Load queue snapshot from persistence.
3835
+ */
3836
+ async loadFromPersistence() {
3837
+ if (!this.persistence) {
3838
+ return 0;
3839
+ }
3840
+ const raw = await this.persistence.adapter.getItem(this.persistence.key);
3841
+ if (!raw) {
3842
+ return 0;
3843
+ }
3844
+ const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
3845
+ const envelope = deserialize(raw);
3846
+ if (envelope.version !== 1 || !Array.isArray(envelope.data)) {
3847
+ throw new Error("Invalid offline queue persistence payload");
3848
+ }
3849
+ this.queue.clear();
3850
+ this.syncingIds.clear();
3851
+ let imported = 0;
3852
+ for (const operation of envelope.data) {
3853
+ if (this.isValidOfflineOperation(operation)) {
3854
+ this.queue.set(operation.id, {
3855
+ ...operation,
3856
+ status: operation.status === "syncing" ? "pending" : operation.status
3857
+ });
3858
+ imported++;
3859
+ }
3860
+ }
3861
+ logger2.debug("[OfflineOperationQueue] Loaded from persistence", {
3862
+ key: this.persistence.key,
3863
+ imported
2941
3864
  });
3865
+ return imported;
3866
+ }
3867
+ /**
3868
+ * Remove persisted queue snapshot.
3869
+ */
3870
+ async clearPersistence() {
3871
+ if (!this.persistence) {
3872
+ return;
3873
+ }
3874
+ await this.persistence.adapter.removeItem(this.persistence.key);
3875
+ }
3876
+ schedulePersist() {
3877
+ if (!this.persistence || this.persistence.autoPersist === false) {
3878
+ return;
3879
+ }
3880
+ if (this.persistTimer) {
3881
+ clearTimeout(this.persistTimer);
3882
+ }
3883
+ this.persistTimer = setTimeout(() => {
3884
+ void this.persistSafely();
3885
+ }, this.persistence.persistDebounceMs ?? 25);
3886
+ }
3887
+ async persistSafely() {
3888
+ if (!this.persistence) {
3889
+ return;
3890
+ }
3891
+ if (this.persistInFlight) {
3892
+ this.persistPending = true;
3893
+ return;
3894
+ }
3895
+ this.persistInFlight = true;
3896
+ try {
3897
+ await this.saveToPersistence();
3898
+ } catch (error) {
3899
+ logger2.error("[OfflineOperationQueue] Persistence write failed", {
3900
+ key: this.persistence.key,
3901
+ error: error instanceof Error ? error.message : String(error)
3902
+ });
3903
+ } finally {
3904
+ this.persistInFlight = false;
3905
+ const shouldRunAgain = this.persistPending;
3906
+ this.persistPending = false;
3907
+ if (shouldRunAgain) {
3908
+ void this.persistSafely();
3909
+ }
3910
+ }
3911
+ }
3912
+ isValidOfflineOperation(value) {
3913
+ if (typeof value !== "object" || value === null) {
3914
+ return false;
3915
+ }
3916
+ const candidate = value;
3917
+ const validType = candidate.type === "create" || candidate.type === "update" || candidate.type === "delete" || candidate.type === "sync" || candidate.type === "batch";
3918
+ const validPriority = candidate.priority === "high" || candidate.priority === "normal" || candidate.priority === "low";
3919
+ const validStatus = candidate.status === "pending" || candidate.status === "syncing" || candidate.status === "failed" || candidate.status === "synced";
3920
+ return typeof candidate.id === "string" && validType && typeof candidate.data === "object" && candidate.data !== null && !Array.isArray(candidate.data) && typeof candidate.sessionId === "string" && validPriority && typeof candidate.createdAt === "number" && typeof candidate.retryCount === "number" && typeof candidate.maxRetries === "number" && validStatus;
2942
3921
  }
2943
3922
  };
2944
3923
  var offlineQueueInstance = null;
@@ -2989,9 +3968,15 @@ var CompressionEngine = class {
2989
3968
  let algorithm = this.preferredAlgorithm;
2990
3969
  if (this.supportsNativeCompression()) {
2991
3970
  try {
2992
- compressed = await this.compressNative(inputData, this.preferredAlgorithm);
3971
+ compressed = await this.compressNative(
3972
+ inputData,
3973
+ this.preferredAlgorithm
3974
+ );
2993
3975
  } catch (error) {
2994
- logger3.warn("[CompressionEngine] Native compression failed, using fallback", error);
3976
+ logger3.warn(
3977
+ "[CompressionEngine] Native compression failed, using fallback",
3978
+ error
3979
+ );
2995
3980
  compressed = inputData;
2996
3981
  algorithm = "none";
2997
3982
  }
@@ -3063,7 +4048,13 @@ var CompressionEngine = class {
3063
4048
  const stream = new CompressionStream(algorithm);
3064
4049
  const writer = stream.writable.getWriter();
3065
4050
  const reader = stream.readable.getReader();
3066
- writer.write(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
4051
+ writer.write(
4052
+ new Uint8Array(
4053
+ data.buffer,
4054
+ data.byteOffset,
4055
+ data.byteLength
4056
+ )
4057
+ );
3067
4058
  writer.close();
3068
4059
  const chunks = [];
3069
4060
  let done = false;
@@ -3090,7 +4081,13 @@ var CompressionEngine = class {
3090
4081
  const stream = new DecompressionStream(algorithm);
3091
4082
  const writer = stream.writable.getWriter();
3092
4083
  const reader = stream.readable.getReader();
3093
- writer.write(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
4084
+ writer.write(
4085
+ new Uint8Array(
4086
+ data.buffer,
4087
+ data.byteOffset,
4088
+ data.byteLength
4089
+ )
4090
+ );
3094
4091
  writer.close();
3095
4092
  const chunks = [];
3096
4093
  let done = false;
@@ -3139,9 +4136,14 @@ var CompressionEngine = class {
3139
4136
  const sorted = [...chunks].sort((a, b) => a.index - b.index);
3140
4137
  const total = sorted[0]?.total ?? 0;
3141
4138
  if (sorted.length !== total) {
3142
- throw new Error(`Missing chunks: got ${sorted.length}, expected ${total}`);
4139
+ throw new Error(
4140
+ `Missing chunks: got ${sorted.length}, expected ${total}`
4141
+ );
3143
4142
  }
3144
- const totalLength = sorted.reduce((sum, chunk) => sum + chunk.data.length, 0);
4143
+ const totalLength = sorted.reduce(
4144
+ (sum, chunk) => sum + chunk.data.length,
4145
+ 0
4146
+ );
3145
4147
  const combined = new Uint8Array(totalLength);
3146
4148
  let offset = 0;
3147
4149
  for (const chunk of sorted) {
@@ -4072,7 +5074,10 @@ var AdaptiveCompressionOptimizer = class {
4072
5074
  * Update device resource usage
4073
5075
  */
4074
5076
  updateDeviceResources(cpuUtilization, memoryAvailableMB) {
4075
- this.deviceProfile.cpuUtilization = Math.max(0, Math.min(1, cpuUtilization));
5077
+ this.deviceProfile.cpuUtilization = Math.max(
5078
+ 0,
5079
+ Math.min(1, cpuUtilization)
5080
+ );
4076
5081
  this.deviceProfile.memoryAvailableMB = memoryAvailableMB;
4077
5082
  this.deviceProfile.isConstrained = memoryAvailableMB < 512;
4078
5083
  this.deviceProfile.isPremium = memoryAvailableMB > 2048;
@@ -4132,7 +5137,10 @@ var AdaptiveCompressionOptimizer = class {
4132
5137
  networkFactor,
4133
5138
  deviceFactor
4134
5139
  };
4135
- logger7.debug("[AdaptiveCompressionOptimizer] Recommendation", recommendation);
5140
+ logger7.debug(
5141
+ "[AdaptiveCompressionOptimizer] Recommendation",
5142
+ recommendation
5143
+ );
4136
5144
  return recommendation;
4137
5145
  }
4138
5146
  /**
@@ -4284,7 +5292,11 @@ var AgentPresenceManager = class extends eventemitter3.EventEmitter {
4284
5292
  };
4285
5293
  this.presences.set(agentId, presence);
4286
5294
  this.emit("agent_joined", { agentId, presence });
4287
- logger8.debug("[AgentPresenceManager] Agent joined", { agentId, name, role });
5295
+ logger8.debug("[AgentPresenceManager] Agent joined", {
5296
+ agentId,
5297
+ name,
5298
+ role
5299
+ });
4288
5300
  }
4289
5301
  /**
4290
5302
  * Agent left
@@ -4329,6 +5341,157 @@ var AgentPresenceManager = class extends eventemitter3.EventEmitter {
4329
5341
  });
4330
5342
  }
4331
5343
  }
5344
+ /**
5345
+ * Update focused node path
5346
+ */
5347
+ updateFocusNode(agentId, nodePath) {
5348
+ const presence = this.presences.get(agentId);
5349
+ if (presence) {
5350
+ presence.focusNode = nodePath;
5351
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5352
+ this.presences.set(agentId, presence);
5353
+ this.emit("focus_updated", {
5354
+ agentId,
5355
+ focusNode: nodePath
5356
+ });
5357
+ }
5358
+ }
5359
+ /**
5360
+ * Update text selection range
5361
+ */
5362
+ updateSelection(agentId, selectionRange) {
5363
+ const presence = this.presences.get(agentId);
5364
+ if (presence) {
5365
+ presence.selectionRange = selectionRange;
5366
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5367
+ this.presences.set(agentId, presence);
5368
+ this.emit("selection_updated", {
5369
+ agentId,
5370
+ selectionRange
5371
+ });
5372
+ }
5373
+ }
5374
+ /**
5375
+ * Update typing state
5376
+ */
5377
+ updateTyping(agentId, isTyping, field, isComposing = false) {
5378
+ const presence = this.presences.get(agentId);
5379
+ if (presence) {
5380
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5381
+ const previous = presence.typingState;
5382
+ const typingState = {
5383
+ isTyping,
5384
+ field,
5385
+ isComposing,
5386
+ startedAt: isTyping && !previous?.isTyping ? now : isTyping ? previous?.startedAt : void 0,
5387
+ stoppedAt: isTyping ? void 0 : now
5388
+ };
5389
+ presence.typingState = typingState;
5390
+ presence.lastSeen = now;
5391
+ this.presences.set(agentId, presence);
5392
+ this.emit("typing_updated", {
5393
+ agentId,
5394
+ typingState
5395
+ });
5396
+ }
5397
+ }
5398
+ /**
5399
+ * Update scroll state
5400
+ */
5401
+ updateScroll(agentId, scrollState) {
5402
+ const presence = this.presences.get(agentId);
5403
+ if (presence) {
5404
+ presence.scrollState = {
5405
+ ...scrollState,
5406
+ depth: Math.max(0, Math.min(1, scrollState.depth))
5407
+ };
5408
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5409
+ this.presences.set(agentId, presence);
5410
+ this.emit("scroll_updated", {
5411
+ agentId,
5412
+ scrollState: presence.scrollState
5413
+ });
5414
+ }
5415
+ }
5416
+ /**
5417
+ * Update viewport size
5418
+ */
5419
+ updateViewport(agentId, width, height) {
5420
+ const presence = this.presences.get(agentId);
5421
+ if (presence) {
5422
+ presence.viewport = { width, height };
5423
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5424
+ this.presences.set(agentId, presence);
5425
+ this.emit("viewport_updated", {
5426
+ agentId,
5427
+ viewport: presence.viewport
5428
+ });
5429
+ }
5430
+ }
5431
+ /**
5432
+ * Update input state
5433
+ */
5434
+ updateInputState(agentId, inputState) {
5435
+ const presence = this.presences.get(agentId);
5436
+ if (presence) {
5437
+ presence.inputState = inputState;
5438
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5439
+ this.presences.set(agentId, presence);
5440
+ this.emit("input_state_updated", {
5441
+ agentId,
5442
+ inputState
5443
+ });
5444
+ }
5445
+ }
5446
+ /**
5447
+ * Clear input state
5448
+ */
5449
+ clearInputState(agentId) {
5450
+ const presence = this.presences.get(agentId);
5451
+ if (presence) {
5452
+ presence.inputState = void 0;
5453
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5454
+ this.presences.set(agentId, presence);
5455
+ this.emit("input_state_updated", {
5456
+ agentId,
5457
+ inputState: void 0
5458
+ });
5459
+ }
5460
+ }
5461
+ /**
5462
+ * Update emotional state
5463
+ */
5464
+ updateEmotionState(agentId, emotionState) {
5465
+ const presence = this.presences.get(agentId);
5466
+ if (presence) {
5467
+ const enrichedState = {
5468
+ ...emotionState,
5469
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5470
+ };
5471
+ presence.emotionState = enrichedState;
5472
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5473
+ this.presences.set(agentId, presence);
5474
+ this.emit("emotion_updated", {
5475
+ agentId,
5476
+ emotionState: enrichedState
5477
+ });
5478
+ }
5479
+ }
5480
+ /**
5481
+ * Clear emotional state
5482
+ */
5483
+ clearEmotionState(agentId) {
5484
+ const presence = this.presences.get(agentId);
5485
+ if (presence) {
5486
+ presence.emotionState = void 0;
5487
+ presence.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
5488
+ this.presences.set(agentId, presence);
5489
+ this.emit("emotion_updated", {
5490
+ agentId,
5491
+ emotionState: void 0
5492
+ });
5493
+ }
5494
+ }
4332
5495
  /**
4333
5496
  * Update status
4334
5497
  */
@@ -4518,7 +5681,9 @@ var AgentPresenceManager = class extends eventemitter3.EventEmitter {
4518
5681
  this.stopHeartbeatMonitoring();
4519
5682
  this.presences.clear();
4520
5683
  this.removeAllListeners();
4521
- logger8.debug("[AgentPresenceManager] Destroyed", { sessionId: this.sessionId });
5684
+ logger8.debug("[AgentPresenceManager] Destroyed", {
5685
+ sessionId: this.sessionId
5686
+ });
4522
5687
  }
4523
5688
  };
4524
5689
  var instances = /* @__PURE__ */ new Map();
@@ -4635,8 +5800,10 @@ exports.AgentPresenceManager = AgentPresenceManager;
4635
5800
  exports.BatchTimingOptimizer = BatchTimingOptimizer;
4636
5801
  exports.CompressionEngine = CompressionEngine;
4637
5802
  exports.DEFAULT_CRYPTO_CONFIG = DEFAULT_CRYPTO_CONFIG;
5803
+ exports.DashStorageAdapter = DashStorageAdapter;
4638
5804
  exports.DataTransformer = DataTransformer;
4639
5805
  exports.DeltaSyncOptimizer = DeltaSyncOptimizer;
5806
+ exports.InMemoryStorageAdapter = InMemoryStorageAdapter;
4640
5807
  exports.MigrationEngine = MigrationEngine;
4641
5808
  exports.MigrationTracker = MigrationTracker;
4642
5809
  exports.NullCryptoProvider = NullCryptoProvider;