@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.
- package/README.md +10 -0
- package/dist/compression/index.cjs +580 -0
- package/dist/compression/index.cjs.map +1 -0
- package/dist/compression/index.d.cts +189 -0
- package/dist/compression/index.d.ts +189 -0
- package/dist/compression/index.js +573 -0
- package/dist/compression/index.js.map +1 -0
- package/dist/core/index.d.cts +70 -5
- package/dist/core/index.d.ts +70 -5
- package/dist/crypto/index.cjs +100 -0
- package/dist/crypto/index.cjs.map +1 -0
- package/dist/crypto/index.d.cts +407 -0
- package/dist/crypto/index.d.ts +407 -0
- package/dist/crypto/index.js +96 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/distributed/index.cjs +420 -23
- package/dist/distributed/index.cjs.map +1 -1
- package/dist/distributed/index.d.cts +901 -2
- package/dist/distributed/index.d.ts +901 -2
- package/dist/distributed/index.js +420 -23
- package/dist/distributed/index.js.map +1 -1
- package/dist/index.cjs +1222 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -811
- package/dist/index.d.ts +11 -811
- package/dist/index.js +1221 -56
- package/dist/index.js.map +1 -1
- package/dist/offline/index.cjs +419 -0
- package/dist/offline/index.cjs.map +1 -0
- package/dist/offline/index.d.cts +148 -0
- package/dist/offline/index.d.ts +148 -0
- package/dist/offline/index.js +415 -0
- package/dist/offline/index.js.map +1 -0
- package/dist/optimization/index.cjs +797 -0
- package/dist/optimization/index.cjs.map +1 -0
- package/dist/optimization/index.d.cts +347 -0
- package/dist/optimization/index.d.ts +347 -0
- package/dist/optimization/index.js +787 -0
- package/dist/optimization/index.js.map +1 -0
- package/dist/persistence/index.cjs +145 -0
- package/dist/persistence/index.cjs.map +1 -0
- package/dist/persistence/index.d.cts +63 -0
- package/dist/persistence/index.d.ts +63 -0
- package/dist/persistence/index.js +142 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/presence/index.cjs +489 -0
- package/dist/presence/index.cjs.map +1 -0
- package/dist/presence/index.d.cts +283 -0
- package/dist/presence/index.d.ts +283 -0
- package/dist/presence/index.js +485 -0
- package/dist/presence/index.js.map +1 -0
- package/dist/types-CMxO7QF0.d.cts +33 -0
- package/dist/types-CMxO7QF0.d.ts +33 -0
- package/dist/versioning/index.cjs +296 -14
- package/dist/versioning/index.cjs.map +1 -1
- package/dist/versioning/index.d.cts +66 -1
- package/dist/versioning/index.d.ts +66 -1
- package/dist/versioning/index.js +296 -14
- package/dist/versioning/index.js.map +1 -1
- package/package.json +51 -1
- package/dist/index-C_4CMV5c.d.cts +0 -1207
- package/dist/index-C_4CMV5c.d.ts +0 -1207
|
@@ -77,7 +77,9 @@ var SchemaVersionManager = class {
|
|
|
77
77
|
*/
|
|
78
78
|
setCurrentVersion(version) {
|
|
79
79
|
if (!this.versions.has(this.versionToString(version))) {
|
|
80
|
-
throw new Error(
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Version ${this.versionToString(version)} not registered`
|
|
82
|
+
);
|
|
81
83
|
}
|
|
82
84
|
this.currentVersion = version;
|
|
83
85
|
logger.debug("[SchemaVersionManager] Current version set", {
|
|
@@ -363,7 +365,9 @@ var MigrationEngine = class {
|
|
|
363
365
|
id: migrationId,
|
|
364
366
|
error: result.errors[0]
|
|
365
367
|
});
|
|
366
|
-
throw new Error(
|
|
368
|
+
throw new Error(
|
|
369
|
+
`Rollback for ${migrationId} failed: ${result.errors[0]}`
|
|
370
|
+
);
|
|
367
371
|
}
|
|
368
372
|
}
|
|
369
373
|
/**
|
|
@@ -416,8 +420,14 @@ var MigrationEngine = class {
|
|
|
416
420
|
getStatistics() {
|
|
417
421
|
const successful = this.executedMigrations.filter((m) => m.success).length;
|
|
418
422
|
const failed = this.executedMigrations.filter((m) => !m.success).length;
|
|
419
|
-
const totalDuration = this.executedMigrations.reduce(
|
|
420
|
-
|
|
423
|
+
const totalDuration = this.executedMigrations.reduce(
|
|
424
|
+
(sum, m) => sum + m.duration,
|
|
425
|
+
0
|
|
426
|
+
);
|
|
427
|
+
const totalAffected = this.executedMigrations.reduce(
|
|
428
|
+
(sum, m) => sum + m.itemsAffected,
|
|
429
|
+
0
|
|
430
|
+
);
|
|
421
431
|
return {
|
|
422
432
|
totalExecuted: this.executedMigrations.length,
|
|
423
433
|
successful,
|
|
@@ -471,7 +481,9 @@ var DataTransformer = class {
|
|
|
471
481
|
return rule.transformer(value);
|
|
472
482
|
} catch (error) {
|
|
473
483
|
if (rule.required) {
|
|
474
|
-
throw new Error(
|
|
484
|
+
throw new Error(
|
|
485
|
+
`Failed to transform required field ${field}: ${error instanceof Error ? error.message : String(error)}`
|
|
486
|
+
);
|
|
475
487
|
}
|
|
476
488
|
return rule.defaultValue !== void 0 ? rule.defaultValue : value;
|
|
477
489
|
}
|
|
@@ -544,7 +556,9 @@ var DataTransformer = class {
|
|
|
544
556
|
validateTransformation(original, transformed) {
|
|
545
557
|
const issues = [];
|
|
546
558
|
if (original.length !== transformed.length) {
|
|
547
|
-
issues.push(
|
|
559
|
+
issues.push(
|
|
560
|
+
`Item count mismatch: ${original.length} -> ${transformed.length}`
|
|
561
|
+
);
|
|
548
562
|
}
|
|
549
563
|
for (let i = 0; i < Math.min(original.length, transformed.length); i++) {
|
|
550
564
|
const orig = original[i];
|
|
@@ -635,14 +649,40 @@ var DataTransformer = class {
|
|
|
635
649
|
};
|
|
636
650
|
|
|
637
651
|
// src/versioning/MigrationTracker.ts
|
|
638
|
-
var MigrationTracker = class {
|
|
652
|
+
var MigrationTracker = class _MigrationTracker {
|
|
653
|
+
static DEFAULT_PERSIST_KEY = "aeon:migration-tracker:v1";
|
|
654
|
+
static INTEGRITY_ROOT = "aeon:migration-integrity-root:v1";
|
|
639
655
|
migrations = [];
|
|
640
656
|
snapshots = /* @__PURE__ */ new Map();
|
|
657
|
+
persistence = null;
|
|
658
|
+
persistTimer = null;
|
|
659
|
+
persistInFlight = false;
|
|
660
|
+
persistPending = false;
|
|
661
|
+
constructor(options) {
|
|
662
|
+
if (options?.persistence) {
|
|
663
|
+
this.persistence = {
|
|
664
|
+
...options.persistence,
|
|
665
|
+
key: options.persistence.key ?? _MigrationTracker.DEFAULT_PERSIST_KEY,
|
|
666
|
+
autoPersist: options.persistence.autoPersist ?? true,
|
|
667
|
+
autoLoad: options.persistence.autoLoad ?? false,
|
|
668
|
+
persistDebounceMs: options.persistence.persistDebounceMs ?? 25
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
if (this.persistence?.autoLoad) {
|
|
672
|
+
void this.loadFromPersistence().catch((error) => {
|
|
673
|
+
logger.error("[MigrationTracker] Failed to load persistence", {
|
|
674
|
+
key: this.persistence?.key,
|
|
675
|
+
error: error instanceof Error ? error.message : String(error)
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
641
680
|
/**
|
|
642
681
|
* Track a new migration
|
|
643
682
|
*/
|
|
644
683
|
recordMigration(record) {
|
|
645
684
|
this.migrations.push({ ...record });
|
|
685
|
+
this.schedulePersist();
|
|
646
686
|
logger.debug("[MigrationTracker] Migration recorded", {
|
|
647
687
|
id: record.id,
|
|
648
688
|
migrationId: record.migrationId,
|
|
@@ -699,7 +739,9 @@ var MigrationTracker = class {
|
|
|
699
739
|
* Check if can rollback
|
|
700
740
|
*/
|
|
701
741
|
canRollback(fromVersion, toVersion) {
|
|
702
|
-
const fromIndex = this.migrations.findIndex(
|
|
742
|
+
const fromIndex = this.migrations.findIndex(
|
|
743
|
+
(m) => m.version === fromVersion
|
|
744
|
+
);
|
|
703
745
|
const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
|
|
704
746
|
if (fromIndex === -1 || toIndex === -1) {
|
|
705
747
|
return false;
|
|
@@ -723,7 +765,9 @@ var MigrationTracker = class {
|
|
|
723
765
|
const affectedVersions = [];
|
|
724
766
|
let estimatedDuration = 0;
|
|
725
767
|
if (canRollback) {
|
|
726
|
-
const fromIndex = this.migrations.findIndex(
|
|
768
|
+
const fromIndex = this.migrations.findIndex(
|
|
769
|
+
(m) => m.version === fromVersion
|
|
770
|
+
);
|
|
727
771
|
const toIndex = this.migrations.findIndex((m) => m.version === toVersion);
|
|
728
772
|
for (let i = fromIndex; i > toIndex; i--) {
|
|
729
773
|
const migration = this.migrations[i];
|
|
@@ -779,12 +823,24 @@ var MigrationTracker = class {
|
|
|
779
823
|
* Get migration statistics
|
|
780
824
|
*/
|
|
781
825
|
getStatistics() {
|
|
782
|
-
const applied = this.migrations.filter(
|
|
826
|
+
const applied = this.migrations.filter(
|
|
827
|
+
(m) => m.status === "applied"
|
|
828
|
+
).length;
|
|
783
829
|
const failed = this.migrations.filter((m) => m.status === "failed").length;
|
|
784
|
-
const pending = this.migrations.filter(
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const
|
|
830
|
+
const pending = this.migrations.filter(
|
|
831
|
+
(m) => m.status === "pending"
|
|
832
|
+
).length;
|
|
833
|
+
const rolledBack = this.migrations.filter(
|
|
834
|
+
(m) => m.status === "rolled-back"
|
|
835
|
+
).length;
|
|
836
|
+
const totalDuration = this.migrations.reduce(
|
|
837
|
+
(sum, m) => sum + m.duration,
|
|
838
|
+
0
|
|
839
|
+
);
|
|
840
|
+
const totalAffected = this.migrations.reduce(
|
|
841
|
+
(sum, m) => sum + m.itemsAffected,
|
|
842
|
+
0
|
|
843
|
+
);
|
|
788
844
|
return {
|
|
789
845
|
total: this.migrations.length,
|
|
790
846
|
applied,
|
|
@@ -835,7 +891,147 @@ var MigrationTracker = class {
|
|
|
835
891
|
status,
|
|
836
892
|
hasError: !!error
|
|
837
893
|
});
|
|
894
|
+
this.schedulePersist();
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Persist tracker state with integrity chain verification metadata.
|
|
899
|
+
*/
|
|
900
|
+
async saveToPersistence() {
|
|
901
|
+
if (!this.persistence) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
const normalizedMigrations = this.migrations.map((migration) => ({
|
|
905
|
+
...migration,
|
|
906
|
+
previousHash: void 0,
|
|
907
|
+
integrityHash: void 0
|
|
908
|
+
}));
|
|
909
|
+
const integrityEntries = [];
|
|
910
|
+
let previousHash = _MigrationTracker.INTEGRITY_ROOT;
|
|
911
|
+
for (const migration of normalizedMigrations) {
|
|
912
|
+
const hash = await this.computeDigestHex(
|
|
913
|
+
`${previousHash}|${this.stableStringify(migration)}`
|
|
914
|
+
);
|
|
915
|
+
integrityEntries.push({
|
|
916
|
+
recordId: migration.id,
|
|
917
|
+
previousHash,
|
|
918
|
+
hash
|
|
919
|
+
});
|
|
920
|
+
previousHash = hash;
|
|
921
|
+
}
|
|
922
|
+
const persistedMigrations = normalizedMigrations.map((migration, index) => ({
|
|
923
|
+
...migration,
|
|
924
|
+
previousHash: integrityEntries[index]?.previousHash,
|
|
925
|
+
integrityHash: integrityEntries[index]?.hash
|
|
926
|
+
}));
|
|
927
|
+
const data = {
|
|
928
|
+
migrations: persistedMigrations,
|
|
929
|
+
snapshots: Array.from(this.snapshots.entries()).map(
|
|
930
|
+
([recordId, snapshot]) => ({
|
|
931
|
+
recordId,
|
|
932
|
+
beforeHash: snapshot.beforeHash,
|
|
933
|
+
afterHash: snapshot.afterHash,
|
|
934
|
+
itemCount: snapshot.itemCount
|
|
935
|
+
})
|
|
936
|
+
),
|
|
937
|
+
integrity: {
|
|
938
|
+
algorithm: "sha256-chain-v1",
|
|
939
|
+
entries: integrityEntries,
|
|
940
|
+
rootHash: previousHash
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
const envelope = {
|
|
944
|
+
version: 1,
|
|
945
|
+
updatedAt: Date.now(),
|
|
946
|
+
data
|
|
947
|
+
};
|
|
948
|
+
const serialize = this.persistence.serializer ?? ((value) => JSON.stringify(value));
|
|
949
|
+
await this.persistence.adapter.setItem(this.persistence.key, serialize(envelope));
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Load tracker state and verify integrity chain.
|
|
953
|
+
*/
|
|
954
|
+
async loadFromPersistence() {
|
|
955
|
+
if (!this.persistence) {
|
|
956
|
+
return { migrations: 0, snapshots: 0 };
|
|
957
|
+
}
|
|
958
|
+
const raw = await this.persistence.adapter.getItem(this.persistence.key);
|
|
959
|
+
if (!raw) {
|
|
960
|
+
return { migrations: 0, snapshots: 0 };
|
|
961
|
+
}
|
|
962
|
+
const deserialize = this.persistence.deserializer ?? ((value) => JSON.parse(value));
|
|
963
|
+
const envelope = deserialize(raw);
|
|
964
|
+
if (envelope.version !== 1 || !envelope.data) {
|
|
965
|
+
throw new Error("Invalid migration tracker persistence payload");
|
|
966
|
+
}
|
|
967
|
+
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") {
|
|
968
|
+
throw new Error("Invalid migration tracker persistence structure");
|
|
969
|
+
}
|
|
970
|
+
if (envelope.data.integrity.algorithm !== "sha256-chain-v1") {
|
|
971
|
+
throw new Error("Unsupported migration integrity algorithm");
|
|
972
|
+
}
|
|
973
|
+
if (envelope.data.integrity.entries.length !== envelope.data.migrations.length) {
|
|
974
|
+
throw new Error("Migration integrity entry count mismatch");
|
|
975
|
+
}
|
|
976
|
+
const validatedMigrations = [];
|
|
977
|
+
let previousHash = _MigrationTracker.INTEGRITY_ROOT;
|
|
978
|
+
for (let i = 0; i < envelope.data.migrations.length; i++) {
|
|
979
|
+
const migration = envelope.data.migrations[i];
|
|
980
|
+
const integrity = envelope.data.integrity.entries[i];
|
|
981
|
+
if (!this.isValidMigrationRecord(migration)) {
|
|
982
|
+
throw new Error("Invalid persisted migration record");
|
|
983
|
+
}
|
|
984
|
+
if (!integrity || integrity.recordId !== migration.id || integrity.previousHash !== previousHash) {
|
|
985
|
+
throw new Error("Migration integrity chain mismatch");
|
|
986
|
+
}
|
|
987
|
+
const expectedHash = await this.computeDigestHex(
|
|
988
|
+
`${previousHash}|${this.stableStringify({
|
|
989
|
+
...migration,
|
|
990
|
+
previousHash: void 0,
|
|
991
|
+
integrityHash: void 0
|
|
992
|
+
})}`
|
|
993
|
+
);
|
|
994
|
+
if (expectedHash !== integrity.hash) {
|
|
995
|
+
throw new Error("Migration integrity verification failed");
|
|
996
|
+
}
|
|
997
|
+
validatedMigrations.push({
|
|
998
|
+
...migration,
|
|
999
|
+
previousHash: integrity.previousHash,
|
|
1000
|
+
integrityHash: integrity.hash
|
|
1001
|
+
});
|
|
1002
|
+
previousHash = expectedHash;
|
|
1003
|
+
}
|
|
1004
|
+
if (previousHash !== envelope.data.integrity.rootHash) {
|
|
1005
|
+
throw new Error("Migration integrity root hash mismatch");
|
|
1006
|
+
}
|
|
1007
|
+
const validatedSnapshots = /* @__PURE__ */ new Map();
|
|
1008
|
+
for (const snapshot of envelope.data.snapshots) {
|
|
1009
|
+
if (typeof snapshot.recordId !== "string" || typeof snapshot.beforeHash !== "string" || typeof snapshot.afterHash !== "string" || typeof snapshot.itemCount !== "number") {
|
|
1010
|
+
throw new Error("Invalid persisted migration snapshot");
|
|
1011
|
+
}
|
|
1012
|
+
validatedSnapshots.set(snapshot.recordId, {
|
|
1013
|
+
beforeHash: snapshot.beforeHash,
|
|
1014
|
+
afterHash: snapshot.afterHash,
|
|
1015
|
+
itemCount: snapshot.itemCount
|
|
1016
|
+
});
|
|
838
1017
|
}
|
|
1018
|
+
this.migrations = validatedMigrations;
|
|
1019
|
+
this.snapshots = validatedSnapshots;
|
|
1020
|
+
logger.debug("[MigrationTracker] Loaded from persistence", {
|
|
1021
|
+
key: this.persistence.key,
|
|
1022
|
+
migrations: this.migrations.length,
|
|
1023
|
+
snapshots: this.snapshots.size
|
|
1024
|
+
});
|
|
1025
|
+
return { migrations: this.migrations.length, snapshots: this.snapshots.size };
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Remove persisted migration tracker state.
|
|
1029
|
+
*/
|
|
1030
|
+
async clearPersistence() {
|
|
1031
|
+
if (!this.persistence) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
await this.persistence.adapter.removeItem(this.persistence.key);
|
|
839
1035
|
}
|
|
840
1036
|
/**
|
|
841
1037
|
* Clear history (for testing)
|
|
@@ -843,6 +1039,7 @@ var MigrationTracker = class {
|
|
|
843
1039
|
clear() {
|
|
844
1040
|
this.migrations = [];
|
|
845
1041
|
this.snapshots.clear();
|
|
1042
|
+
this.schedulePersist();
|
|
846
1043
|
}
|
|
847
1044
|
/**
|
|
848
1045
|
* Get total migrations tracked
|
|
@@ -861,6 +1058,91 @@ var MigrationTracker = class {
|
|
|
861
1058
|
return time >= start && time <= end;
|
|
862
1059
|
});
|
|
863
1060
|
}
|
|
1061
|
+
schedulePersist() {
|
|
1062
|
+
if (!this.persistence || this.persistence.autoPersist === false) {
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
if (this.persistTimer) {
|
|
1066
|
+
clearTimeout(this.persistTimer);
|
|
1067
|
+
}
|
|
1068
|
+
this.persistTimer = setTimeout(() => {
|
|
1069
|
+
void this.persistSafely();
|
|
1070
|
+
}, this.persistence.persistDebounceMs ?? 25);
|
|
1071
|
+
}
|
|
1072
|
+
async persistSafely() {
|
|
1073
|
+
if (!this.persistence) {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
if (this.persistInFlight) {
|
|
1077
|
+
this.persistPending = true;
|
|
1078
|
+
return;
|
|
1079
|
+
}
|
|
1080
|
+
this.persistInFlight = true;
|
|
1081
|
+
try {
|
|
1082
|
+
await this.saveToPersistence();
|
|
1083
|
+
} catch (error) {
|
|
1084
|
+
logger.error("[MigrationTracker] Persistence write failed", {
|
|
1085
|
+
key: this.persistence.key,
|
|
1086
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1087
|
+
});
|
|
1088
|
+
} finally {
|
|
1089
|
+
this.persistInFlight = false;
|
|
1090
|
+
const shouldRunAgain = this.persistPending;
|
|
1091
|
+
this.persistPending = false;
|
|
1092
|
+
if (shouldRunAgain) {
|
|
1093
|
+
void this.persistSafely();
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
isValidMigrationRecord(value) {
|
|
1098
|
+
if (typeof value !== "object" || value === null) {
|
|
1099
|
+
return false;
|
|
1100
|
+
}
|
|
1101
|
+
const record = value;
|
|
1102
|
+
const validDirection = record.direction === "up" || record.direction === "down";
|
|
1103
|
+
const validStatus = record.status === "pending" || record.status === "applied" || record.status === "failed" || record.status === "rolled-back";
|
|
1104
|
+
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";
|
|
1105
|
+
}
|
|
1106
|
+
stableStringify(value) {
|
|
1107
|
+
if (value === null || typeof value !== "object") {
|
|
1108
|
+
return JSON.stringify(value);
|
|
1109
|
+
}
|
|
1110
|
+
if (Array.isArray(value)) {
|
|
1111
|
+
return `[${value.map((item) => this.stableStringify(item)).join(",")}]`;
|
|
1112
|
+
}
|
|
1113
|
+
const entries = Object.entries(value).sort(
|
|
1114
|
+
([a], [b]) => a.localeCompare(b)
|
|
1115
|
+
);
|
|
1116
|
+
return `{${entries.map(
|
|
1117
|
+
([key, entryValue]) => `${JSON.stringify(key)}:${this.stableStringify(entryValue)}`
|
|
1118
|
+
).join(",")}}`;
|
|
1119
|
+
}
|
|
1120
|
+
async computeDigestHex(value) {
|
|
1121
|
+
if (globalThis.crypto?.subtle) {
|
|
1122
|
+
const bytes = new TextEncoder().encode(value);
|
|
1123
|
+
const normalized = bytes.buffer.slice(
|
|
1124
|
+
bytes.byteOffset,
|
|
1125
|
+
bytes.byteOffset + bytes.byteLength
|
|
1126
|
+
);
|
|
1127
|
+
const digest = await globalThis.crypto.subtle.digest(
|
|
1128
|
+
"SHA-256",
|
|
1129
|
+
normalized
|
|
1130
|
+
);
|
|
1131
|
+
return this.toHex(new Uint8Array(digest));
|
|
1132
|
+
}
|
|
1133
|
+
return this.fallbackDigestHex(value);
|
|
1134
|
+
}
|
|
1135
|
+
toHex(bytes) {
|
|
1136
|
+
return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1137
|
+
}
|
|
1138
|
+
fallbackDigestHex(value) {
|
|
1139
|
+
let hash = 2166136261;
|
|
1140
|
+
for (let i = 0; i < value.length; i++) {
|
|
1141
|
+
hash ^= value.charCodeAt(i);
|
|
1142
|
+
hash = Math.imul(hash, 16777619);
|
|
1143
|
+
}
|
|
1144
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
1145
|
+
}
|
|
864
1146
|
};
|
|
865
1147
|
|
|
866
1148
|
exports.DataTransformer = DataTransformer;
|