@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.
@@ -0,0 +1,871 @@
1
+ 'use strict';
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 currentLogger = consoleLogger;
19
+ function getLogger() {
20
+ return currentLogger;
21
+ }
22
+ var logger = {
23
+ debug: (...args) => getLogger().debug(...args),
24
+ info: (...args) => getLogger().info(...args),
25
+ warn: (...args) => getLogger().warn(...args),
26
+ error: (...args) => getLogger().error(...args)
27
+ };
28
+
29
+ // src/versioning/SchemaVersionManager.ts
30
+ var SchemaVersionManager = class {
31
+ versions = /* @__PURE__ */ new Map();
32
+ versionHistory = [];
33
+ compatibilityMatrix = /* @__PURE__ */ new Map();
34
+ currentVersion = null;
35
+ constructor() {
36
+ this.initializeDefaultVersions();
37
+ }
38
+ /**
39
+ * Initialize default versions
40
+ */
41
+ initializeDefaultVersions() {
42
+ const v1_0_0 = {
43
+ major: 1,
44
+ minor: 0,
45
+ patch: 0,
46
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
47
+ description: "Initial schema version",
48
+ breaking: false
49
+ };
50
+ this.registerVersion(v1_0_0);
51
+ this.currentVersion = v1_0_0;
52
+ }
53
+ /**
54
+ * Register a new schema version
55
+ */
56
+ registerVersion(version) {
57
+ const versionString = this.versionToString(version);
58
+ this.versions.set(versionString, version);
59
+ this.versionHistory.push(version);
60
+ logger.debug("[SchemaVersionManager] Version registered", {
61
+ version: versionString,
62
+ breaking: version.breaking,
63
+ description: version.description
64
+ });
65
+ }
66
+ /**
67
+ * Get current version
68
+ */
69
+ getCurrentVersion() {
70
+ if (!this.currentVersion) {
71
+ throw new Error("No current version set");
72
+ }
73
+ return this.currentVersion;
74
+ }
75
+ /**
76
+ * Set current version
77
+ */
78
+ setCurrentVersion(version) {
79
+ if (!this.versions.has(this.versionToString(version))) {
80
+ throw new Error(`Version ${this.versionToString(version)} not registered`);
81
+ }
82
+ this.currentVersion = version;
83
+ logger.debug("[SchemaVersionManager] Current version set", {
84
+ version: this.versionToString(version)
85
+ });
86
+ }
87
+ /**
88
+ * Get version history
89
+ */
90
+ getVersionHistory() {
91
+ return [...this.versionHistory];
92
+ }
93
+ /**
94
+ * Check if version exists
95
+ */
96
+ hasVersion(version) {
97
+ return this.versions.has(this.versionToString(version));
98
+ }
99
+ /**
100
+ * Get version by string (e.g., "1.2.3")
101
+ */
102
+ getVersion(versionString) {
103
+ return this.versions.get(versionString);
104
+ }
105
+ /**
106
+ * Register compatibility rule
107
+ */
108
+ registerCompatibility(rule) {
109
+ if (!this.compatibilityMatrix.has(rule.from)) {
110
+ this.compatibilityMatrix.set(rule.from, []);
111
+ }
112
+ const rules = this.compatibilityMatrix.get(rule.from);
113
+ if (rules) {
114
+ rules.push(rule);
115
+ }
116
+ logger.debug("[SchemaVersionManager] Compatibility rule registered", {
117
+ from: rule.from,
118
+ to: rule.to,
119
+ compatible: rule.compatible,
120
+ requiresMigration: rule.requiresMigration
121
+ });
122
+ }
123
+ /**
124
+ * Check if migration path exists
125
+ */
126
+ canMigrate(fromVersion, toVersion) {
127
+ const fromStr = typeof fromVersion === "string" ? fromVersion : this.versionToString(fromVersion);
128
+ const toStr = typeof toVersion === "string" ? toVersion : this.versionToString(toVersion);
129
+ const rules = this.compatibilityMatrix.get(fromStr) || [];
130
+ return rules.some((r) => r.to === toStr && r.requiresMigration);
131
+ }
132
+ /**
133
+ * Get migration path
134
+ */
135
+ getMigrationPath(fromVersion, toVersion) {
136
+ const path = [];
137
+ let current = fromVersion;
138
+ const maxSteps = 100;
139
+ let steps = 0;
140
+ while (this.compareVersions(current, toVersion) !== 0 && steps < maxSteps) {
141
+ const fromStr = this.versionToString(current);
142
+ const rules = this.compatibilityMatrix.get(fromStr) || [];
143
+ let found = false;
144
+ for (const rule of rules) {
145
+ const nextVersion = this.getVersion(rule.to);
146
+ if (nextVersion) {
147
+ if (this.compareVersions(nextVersion, toVersion) <= 0 || this.compareVersions(current, nextVersion) < this.compareVersions(current, toVersion)) {
148
+ current = nextVersion;
149
+ path.push(current);
150
+ found = true;
151
+ break;
152
+ }
153
+ }
154
+ }
155
+ if (!found) {
156
+ break;
157
+ }
158
+ steps++;
159
+ }
160
+ return path;
161
+ }
162
+ /**
163
+ * Compare two versions
164
+ * Returns: -1 if v1 < v2, 0 if equal, 1 if v1 > v2
165
+ */
166
+ compareVersions(v1, v2) {
167
+ const ver1 = typeof v1 === "string" ? this.parseVersion(v1) : v1;
168
+ const ver2 = typeof v2 === "string" ? this.parseVersion(v2) : v2;
169
+ if (ver1.major !== ver2.major) {
170
+ return ver1.major < ver2.major ? -1 : 1;
171
+ }
172
+ if (ver1.minor !== ver2.minor) {
173
+ return ver1.minor < ver2.minor ? -1 : 1;
174
+ }
175
+ if (ver1.patch !== ver2.patch) {
176
+ return ver1.patch < ver2.patch ? -1 : 1;
177
+ }
178
+ return 0;
179
+ }
180
+ /**
181
+ * Parse version string to SchemaVersion
182
+ */
183
+ parseVersion(versionString) {
184
+ const parts = versionString.split(".").map(Number);
185
+ return {
186
+ major: parts[0] || 0,
187
+ minor: parts[1] || 0,
188
+ patch: parts[2] || 0,
189
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
190
+ description: "",
191
+ breaking: false
192
+ };
193
+ }
194
+ /**
195
+ * Create new version
196
+ */
197
+ createVersion(major, minor, patch, description, breaking = false) {
198
+ return {
199
+ major,
200
+ minor,
201
+ patch,
202
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
203
+ description,
204
+ breaking
205
+ };
206
+ }
207
+ /**
208
+ * Convert version to string
209
+ */
210
+ versionToString(version) {
211
+ return `${version.major}.${version.minor}.${version.patch}`;
212
+ }
213
+ /**
214
+ * Get version metadata
215
+ */
216
+ getVersionMetadata(version) {
217
+ const history = this.versionHistory;
218
+ const currentIndex = history.findIndex(
219
+ (v) => this.versionToString(v) === this.versionToString(version)
220
+ );
221
+ return {
222
+ version,
223
+ previousVersion: currentIndex > 0 ? history[currentIndex - 1] : void 0,
224
+ changes: [version.description],
225
+ migrationsRequired: this.canMigrate(
226
+ this.currentVersion || version,
227
+ version
228
+ ) ? [this.versionToString(version)] : [],
229
+ rollbackPossible: currentIndex > 0
230
+ };
231
+ }
232
+ /**
233
+ * Get all registered versions
234
+ */
235
+ getAllVersions() {
236
+ return Array.from(this.versions.values()).sort(
237
+ (a, b) => this.compareVersions(a, b)
238
+ );
239
+ }
240
+ /**
241
+ * Clear all versions (for testing)
242
+ */
243
+ clear() {
244
+ this.versions.clear();
245
+ this.versionHistory = [];
246
+ this.compatibilityMatrix.clear();
247
+ this.currentVersion = null;
248
+ }
249
+ };
250
+
251
+ // src/versioning/MigrationEngine.ts
252
+ var MigrationEngine = class {
253
+ migrations = /* @__PURE__ */ new Map();
254
+ executedMigrations = [];
255
+ state = {
256
+ currentVersion: "1.0.0",
257
+ appliedMigrations: [],
258
+ failedMigrations: [],
259
+ lastMigrationTime: (/* @__PURE__ */ new Date()).toISOString(),
260
+ totalMigrationsRun: 0
261
+ };
262
+ /**
263
+ * Register a migration
264
+ */
265
+ registerMigration(migration) {
266
+ this.migrations.set(migration.id, migration);
267
+ logger.debug("[MigrationEngine] Migration registered", {
268
+ id: migration.id,
269
+ version: migration.version,
270
+ name: migration.name
271
+ });
272
+ }
273
+ /**
274
+ * Execute a migration
275
+ */
276
+ async executeMigration(migrationId, data) {
277
+ const migration = this.migrations.get(migrationId);
278
+ if (!migration) {
279
+ throw new Error(`Migration ${migrationId} not found`);
280
+ }
281
+ const startTime = Date.now();
282
+ const result = {
283
+ migrationId,
284
+ success: false,
285
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
286
+ duration: 0,
287
+ itemsAffected: 0,
288
+ errors: []
289
+ };
290
+ try {
291
+ logger.debug("[MigrationEngine] Executing migration", {
292
+ id: migrationId,
293
+ version: migration.version
294
+ });
295
+ migration.up(data);
296
+ result.success = true;
297
+ result.itemsAffected = Array.isArray(data) ? data.length : 1;
298
+ result.duration = Date.now() - startTime;
299
+ this.state.appliedMigrations.push(migrationId);
300
+ this.state.currentVersion = migration.version;
301
+ this.state.totalMigrationsRun++;
302
+ this.state.lastMigrationTime = result.timestamp;
303
+ this.executedMigrations.push(result);
304
+ logger.debug("[MigrationEngine] Migration executed successfully", {
305
+ id: migrationId,
306
+ duration: result.duration,
307
+ itemsAffected: result.itemsAffected
308
+ });
309
+ return result;
310
+ } catch (error) {
311
+ result.errors = [error instanceof Error ? error.message : String(error)];
312
+ this.state.failedMigrations.push(migrationId);
313
+ this.executedMigrations.push(result);
314
+ logger.error("[MigrationEngine] Migration failed", {
315
+ id: migrationId,
316
+ error: result.errors[0]
317
+ });
318
+ throw new Error(`Migration ${migrationId} failed: ${result.errors[0]}`);
319
+ }
320
+ }
321
+ /**
322
+ * Rollback a migration
323
+ */
324
+ async rollbackMigration(migrationId, data) {
325
+ const migration = this.migrations.get(migrationId);
326
+ if (!migration) {
327
+ throw new Error(`Migration ${migrationId} not found`);
328
+ }
329
+ if (!migration.down) {
330
+ throw new Error(`Migration ${migrationId} does not support rollback`);
331
+ }
332
+ const startTime = Date.now();
333
+ const result = {
334
+ migrationId,
335
+ success: false,
336
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
337
+ duration: 0,
338
+ itemsAffected: 0,
339
+ errors: []
340
+ };
341
+ try {
342
+ logger.debug("[MigrationEngine] Rolling back migration", {
343
+ id: migrationId,
344
+ version: migration.version
345
+ });
346
+ migration.down(data);
347
+ result.success = true;
348
+ result.itemsAffected = Array.isArray(data) ? data.length : 1;
349
+ result.duration = Date.now() - startTime;
350
+ this.state.appliedMigrations = this.state.appliedMigrations.filter(
351
+ (id) => id !== migrationId
352
+ );
353
+ this.executedMigrations.push(result);
354
+ logger.debug("[MigrationEngine] Migration rolled back", {
355
+ id: migrationId,
356
+ duration: result.duration
357
+ });
358
+ return result;
359
+ } catch (error) {
360
+ result.errors = [error instanceof Error ? error.message : String(error)];
361
+ this.executedMigrations.push(result);
362
+ logger.error("[MigrationEngine] Rollback failed", {
363
+ id: migrationId,
364
+ error: result.errors[0]
365
+ });
366
+ throw new Error(`Rollback for ${migrationId} failed: ${result.errors[0]}`);
367
+ }
368
+ }
369
+ /**
370
+ * Get migration state
371
+ */
372
+ getState() {
373
+ return { ...this.state };
374
+ }
375
+ /**
376
+ * Get migration execution history
377
+ */
378
+ getExecutionHistory() {
379
+ return [...this.executedMigrations];
380
+ }
381
+ /**
382
+ * Get migration by ID
383
+ */
384
+ getMigration(migrationId) {
385
+ return this.migrations.get(migrationId);
386
+ }
387
+ /**
388
+ * Get all registered migrations
389
+ */
390
+ getAllMigrations() {
391
+ return Array.from(this.migrations.values());
392
+ }
393
+ /**
394
+ * Get applied migrations
395
+ */
396
+ getAppliedMigrations() {
397
+ return [...this.state.appliedMigrations];
398
+ }
399
+ /**
400
+ * Get failed migrations
401
+ */
402
+ getFailedMigrations() {
403
+ return [...this.state.failedMigrations];
404
+ }
405
+ /**
406
+ * Get pending migrations
407
+ */
408
+ getPendingMigrations() {
409
+ return this.getAllMigrations().filter(
410
+ (m) => !this.state.appliedMigrations.includes(m.id)
411
+ );
412
+ }
413
+ /**
414
+ * Get migration statistics
415
+ */
416
+ getStatistics() {
417
+ const successful = this.executedMigrations.filter((m) => m.success).length;
418
+ const failed = this.executedMigrations.filter((m) => !m.success).length;
419
+ const totalDuration = this.executedMigrations.reduce((sum, m) => sum + m.duration, 0);
420
+ const totalAffected = this.executedMigrations.reduce((sum, m) => sum + m.itemsAffected, 0);
421
+ return {
422
+ totalExecuted: this.executedMigrations.length,
423
+ successful,
424
+ failed,
425
+ successRate: this.executedMigrations.length > 0 ? successful / this.executedMigrations.length * 100 : 0,
426
+ totalDurationMs: totalDuration,
427
+ averageDurationMs: this.executedMigrations.length > 0 ? totalDuration / this.executedMigrations.length : 0,
428
+ totalAffected
429
+ };
430
+ }
431
+ /**
432
+ * Clear history (for testing)
433
+ */
434
+ clear() {
435
+ this.migrations.clear();
436
+ this.executedMigrations = [];
437
+ this.state = {
438
+ currentVersion: "1.0.0",
439
+ appliedMigrations: [],
440
+ failedMigrations: [],
441
+ lastMigrationTime: (/* @__PURE__ */ new Date()).toISOString(),
442
+ totalMigrationsRun: 0
443
+ };
444
+ }
445
+ };
446
+
447
+ // src/versioning/DataTransformer.ts
448
+ var DataTransformer = class {
449
+ rules = /* @__PURE__ */ new Map();
450
+ transformationHistory = [];
451
+ /**
452
+ * Register a transformation rule
453
+ */
454
+ registerRule(rule) {
455
+ this.rules.set(rule.field, rule);
456
+ logger.debug("[DataTransformer] Rule registered", {
457
+ field: rule.field,
458
+ required: rule.required,
459
+ hasDefault: rule.defaultValue !== void 0
460
+ });
461
+ }
462
+ /**
463
+ * Transform a single field value
464
+ */
465
+ transformField(field, value) {
466
+ const rule = this.rules.get(field);
467
+ if (!rule) {
468
+ return value;
469
+ }
470
+ try {
471
+ return rule.transformer(value);
472
+ } catch (error) {
473
+ if (rule.required) {
474
+ throw new Error(`Failed to transform required field ${field}: ${error instanceof Error ? error.message : String(error)}`);
475
+ }
476
+ return rule.defaultValue !== void 0 ? rule.defaultValue : value;
477
+ }
478
+ }
479
+ /**
480
+ * Transform a single object
481
+ */
482
+ transformObject(data) {
483
+ const transformed = {};
484
+ for (const [key, value] of Object.entries(data)) {
485
+ try {
486
+ transformed[key] = this.transformField(key, value);
487
+ } catch (error) {
488
+ logger.warn("[DataTransformer] Field transformation failed", {
489
+ field: key,
490
+ error: error instanceof Error ? error.message : String(error)
491
+ });
492
+ const rule = this.rules.get(key);
493
+ if (!rule || !rule.required) {
494
+ transformed[key] = value;
495
+ }
496
+ }
497
+ }
498
+ return transformed;
499
+ }
500
+ /**
501
+ * Transform a collection of items
502
+ */
503
+ transformCollection(items) {
504
+ const startTime = Date.now();
505
+ const result = {
506
+ success: true,
507
+ itemsTransformed: 0,
508
+ itemsFailed: 0,
509
+ errors: [],
510
+ warnings: [],
511
+ duration: 0
512
+ };
513
+ for (let i = 0; i < items.length; i++) {
514
+ const item = items[i];
515
+ try {
516
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
517
+ this.transformObject(item);
518
+ result.itemsTransformed++;
519
+ } else {
520
+ result.warnings.push(`Item ${i} is not a transformable object`);
521
+ }
522
+ } catch (error) {
523
+ result.errors.push({
524
+ item,
525
+ error: error instanceof Error ? error.message : String(error)
526
+ });
527
+ result.itemsFailed++;
528
+ }
529
+ }
530
+ result.duration = Date.now() - startTime;
531
+ result.success = result.itemsFailed === 0;
532
+ this.transformationHistory.push(result);
533
+ logger.debug("[DataTransformer] Collection transformed", {
534
+ total: items.length,
535
+ transformed: result.itemsTransformed,
536
+ failed: result.itemsFailed,
537
+ duration: result.duration
538
+ });
539
+ return result;
540
+ }
541
+ /**
542
+ * Validate transformed data
543
+ */
544
+ validateTransformation(original, transformed) {
545
+ const issues = [];
546
+ if (original.length !== transformed.length) {
547
+ issues.push(`Item count mismatch: ${original.length} -> ${transformed.length}`);
548
+ }
549
+ for (let i = 0; i < Math.min(original.length, transformed.length); i++) {
550
+ const orig = original[i];
551
+ const trans = transformed[i];
552
+ if (!this.validateItem(orig, trans)) {
553
+ issues.push(`Item ${i} validation failed`);
554
+ }
555
+ }
556
+ return {
557
+ valid: issues.length === 0,
558
+ issues
559
+ };
560
+ }
561
+ /**
562
+ * Validate a single item transformation
563
+ */
564
+ validateItem(original, transformed) {
565
+ if (original === null || original === void 0) {
566
+ return true;
567
+ }
568
+ if (typeof original === "object" && typeof transformed !== "object") {
569
+ return false;
570
+ }
571
+ return true;
572
+ }
573
+ /**
574
+ * Get transformation history
575
+ */
576
+ getTransformationHistory() {
577
+ return [...this.transformationHistory];
578
+ }
579
+ /**
580
+ * Get transformation statistics
581
+ */
582
+ getStatistics() {
583
+ const totalTransformed = this.transformationHistory.reduce(
584
+ (sum, r) => sum + r.itemsTransformed,
585
+ 0
586
+ );
587
+ const totalFailed = this.transformationHistory.reduce(
588
+ (sum, r) => sum + r.itemsFailed,
589
+ 0
590
+ );
591
+ const totalDuration = this.transformationHistory.reduce(
592
+ (sum, r) => sum + r.duration,
593
+ 0
594
+ );
595
+ return {
596
+ totalBatches: this.transformationHistory.length,
597
+ totalTransformed,
598
+ totalFailed,
599
+ successRate: totalTransformed + totalFailed > 0 ? totalTransformed / (totalTransformed + totalFailed) * 100 : 0,
600
+ totalDurationMs: totalDuration,
601
+ averageBatchDurationMs: this.transformationHistory.length > 0 ? totalDuration / this.transformationHistory.length : 0
602
+ };
603
+ }
604
+ /**
605
+ * Get registered rules
606
+ */
607
+ getRules() {
608
+ return Array.from(this.rules.values());
609
+ }
610
+ /**
611
+ * Get rule for field
612
+ */
613
+ getRule(field) {
614
+ return this.rules.get(field);
615
+ }
616
+ /**
617
+ * Clear all rules (for testing)
618
+ */
619
+ clearRules() {
620
+ this.rules.clear();
621
+ }
622
+ /**
623
+ * Clear history (for testing)
624
+ */
625
+ clearHistory() {
626
+ this.transformationHistory = [];
627
+ }
628
+ /**
629
+ * Clear all state (for testing)
630
+ */
631
+ clear() {
632
+ this.clearRules();
633
+ this.clearHistory();
634
+ }
635
+ };
636
+
637
+ // src/versioning/MigrationTracker.ts
638
+ var MigrationTracker = class {
639
+ migrations = [];
640
+ snapshots = /* @__PURE__ */ new Map();
641
+ /**
642
+ * Track a new migration
643
+ */
644
+ recordMigration(record) {
645
+ this.migrations.push({ ...record });
646
+ logger.debug("[MigrationTracker] Migration recorded", {
647
+ id: record.id,
648
+ migrationId: record.migrationId,
649
+ version: record.version,
650
+ status: record.status
651
+ });
652
+ }
653
+ /**
654
+ * Track migration with snapshot
655
+ */
656
+ trackMigration(migrationId, version, beforeHash, afterHash, itemCount, duration, itemsAffected, appliedBy = "system") {
657
+ const record = {
658
+ id: `${migrationId}-${Date.now()}`,
659
+ migrationId,
660
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
661
+ version,
662
+ direction: "up",
663
+ status: "applied",
664
+ duration,
665
+ itemsAffected,
666
+ dataSnapshot: {
667
+ beforeHash,
668
+ afterHash,
669
+ itemCount
670
+ },
671
+ appliedBy
672
+ };
673
+ this.recordMigration(record);
674
+ this.snapshots.set(record.id, {
675
+ beforeHash,
676
+ afterHash,
677
+ itemCount
678
+ });
679
+ }
680
+ /**
681
+ * Get all migration records
682
+ */
683
+ getMigrations() {
684
+ return this.migrations.map((m) => ({ ...m }));
685
+ }
686
+ /**
687
+ * Get migrations for a specific version
688
+ */
689
+ getMigrationsForVersion(version) {
690
+ return this.migrations.filter((m) => m.version === version);
691
+ }
692
+ /**
693
+ * Get migration by ID
694
+ */
695
+ getMigration(id) {
696
+ return this.migrations.find((m) => m.id === id);
697
+ }
698
+ /**
699
+ * Check if can rollback
700
+ */
701
+ canRollback(fromVersion, toVersion) {
702
+ const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
703
+ const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
704
+ if (fromIndex === -1 || toIndex === -1) {
705
+ return false;
706
+ }
707
+ if (toIndex >= fromIndex) {
708
+ return false;
709
+ }
710
+ for (let i = fromIndex; i > toIndex; i--) {
711
+ if (!this.migrations[i]?.dataSnapshot) {
712
+ return false;
713
+ }
714
+ }
715
+ return true;
716
+ }
717
+ /**
718
+ * Get rollback path
719
+ */
720
+ getRollbackPath(fromVersion, toVersion) {
721
+ const canRollback = this.canRollback(fromVersion, toVersion);
722
+ const path = [];
723
+ const affectedVersions = [];
724
+ let estimatedDuration = 0;
725
+ if (canRollback) {
726
+ const fromIndex = this.migrations.findIndex((m) => m.version === fromVersion);
727
+ const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
728
+ for (let i = fromIndex; i > toIndex; i--) {
729
+ const migration = this.migrations[i];
730
+ if (migration) {
731
+ path.push(migration.migrationId);
732
+ affectedVersions.push(migration.version);
733
+ estimatedDuration += migration.duration;
734
+ }
735
+ }
736
+ }
737
+ return {
738
+ path,
739
+ canRollback,
740
+ affectedVersions,
741
+ estimatedDuration
742
+ };
743
+ }
744
+ /**
745
+ * Get applied migrations
746
+ */
747
+ getAppliedMigrations() {
748
+ return this.migrations.filter((m) => m.status === "applied");
749
+ }
750
+ /**
751
+ * Get failed migrations
752
+ */
753
+ getFailedMigrations() {
754
+ return this.migrations.filter((m) => m.status === "failed");
755
+ }
756
+ /**
757
+ * Get pending migrations
758
+ */
759
+ getPendingMigrations() {
760
+ return this.migrations.filter((m) => m.status === "pending");
761
+ }
762
+ /**
763
+ * Get latest migration
764
+ */
765
+ getLatestMigration() {
766
+ return this.migrations[this.migrations.length - 1];
767
+ }
768
+ /**
769
+ * Get migration timeline
770
+ */
771
+ getTimeline() {
772
+ return this.migrations.map((m) => ({
773
+ timestamp: m.timestamp,
774
+ version: m.version,
775
+ status: m.status
776
+ }));
777
+ }
778
+ /**
779
+ * Get migration statistics
780
+ */
781
+ getStatistics() {
782
+ const applied = this.migrations.filter((m) => m.status === "applied").length;
783
+ const failed = this.migrations.filter((m) => m.status === "failed").length;
784
+ const pending = this.migrations.filter((m) => m.status === "pending").length;
785
+ const rolledBack = this.migrations.filter((m) => m.status === "rolled-back").length;
786
+ const totalDuration = this.migrations.reduce((sum, m) => sum + m.duration, 0);
787
+ const totalAffected = this.migrations.reduce((sum, m) => sum + m.itemsAffected, 0);
788
+ return {
789
+ total: this.migrations.length,
790
+ applied,
791
+ failed,
792
+ pending,
793
+ rolledBack,
794
+ successRate: this.migrations.length > 0 ? applied / this.migrations.length * 100 : 0,
795
+ totalDurationMs: totalDuration,
796
+ averageDurationMs: this.migrations.length > 0 ? totalDuration / this.migrations.length : 0,
797
+ totalItemsAffected: totalAffected
798
+ };
799
+ }
800
+ /**
801
+ * Get audit trail
802
+ */
803
+ getAuditTrail(migrationId) {
804
+ const filtered = migrationId ? this.migrations.filter((m) => m.migrationId === migrationId) : this.migrations;
805
+ return filtered.map((m) => ({
806
+ id: m.id,
807
+ timestamp: m.timestamp,
808
+ migrationId: m.migrationId,
809
+ version: m.version,
810
+ status: m.status,
811
+ appliedBy: m.appliedBy,
812
+ duration: m.duration,
813
+ itemsAffected: m.itemsAffected,
814
+ error: m.errorMessage
815
+ }));
816
+ }
817
+ /**
818
+ * Get data snapshot for recovery
819
+ */
820
+ getSnapshot(recordId) {
821
+ return this.snapshots.get(recordId);
822
+ }
823
+ /**
824
+ * Update migration status
825
+ */
826
+ updateMigrationStatus(recordId, status, error) {
827
+ const migration = this.migrations.find((m) => m.id === recordId);
828
+ if (migration) {
829
+ migration.status = status;
830
+ if (error) {
831
+ migration.errorMessage = error;
832
+ }
833
+ logger.debug("[MigrationTracker] Migration status updated", {
834
+ recordId,
835
+ status,
836
+ hasError: !!error
837
+ });
838
+ }
839
+ }
840
+ /**
841
+ * Clear history (for testing)
842
+ */
843
+ clear() {
844
+ this.migrations = [];
845
+ this.snapshots.clear();
846
+ }
847
+ /**
848
+ * Get total migrations tracked
849
+ */
850
+ getTotalMigrations() {
851
+ return this.migrations.length;
852
+ }
853
+ /**
854
+ * Find migrations by time range
855
+ */
856
+ getMigrationsByTimeRange(startTime, endTime) {
857
+ const start = new Date(startTime).getTime();
858
+ const end = new Date(endTime).getTime();
859
+ return this.migrations.filter((m) => {
860
+ const time = new Date(m.timestamp).getTime();
861
+ return time >= start && time <= end;
862
+ });
863
+ }
864
+ };
865
+
866
+ exports.DataTransformer = DataTransformer;
867
+ exports.MigrationEngine = MigrationEngine;
868
+ exports.MigrationTracker = MigrationTracker;
869
+ exports.SchemaVersionManager = SchemaVersionManager;
870
+ //# sourceMappingURL=index.cjs.map
871
+ //# sourceMappingURL=index.cjs.map