@topgunbuild/core 0.1.0 → 0.2.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +405 -2
- package/dist/index.d.ts +405 -2
- package/dist/index.js +465 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +449 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,8 +32,19 @@ __export(index_exports, {
|
|
|
32
32
|
MerkleTree: () => MerkleTree,
|
|
33
33
|
MessageSchema: () => MessageSchema,
|
|
34
34
|
ORMap: () => ORMap,
|
|
35
|
+
ORMapDiffRequestSchema: () => ORMapDiffRequestSchema,
|
|
36
|
+
ORMapDiffResponseSchema: () => ORMapDiffResponseSchema,
|
|
37
|
+
ORMapMerkleReqBucketSchema: () => ORMapMerkleReqBucketSchema,
|
|
38
|
+
ORMapMerkleTree: () => ORMapMerkleTree,
|
|
39
|
+
ORMapPushDiffSchema: () => ORMapPushDiffSchema,
|
|
35
40
|
ORMapRecordSchema: () => ORMapRecordSchema,
|
|
41
|
+
ORMapSyncInitSchema: () => ORMapSyncInitSchema,
|
|
42
|
+
ORMapSyncRespBucketsSchema: () => ORMapSyncRespBucketsSchema,
|
|
43
|
+
ORMapSyncRespLeafSchema: () => ORMapSyncRespLeafSchema,
|
|
44
|
+
ORMapSyncRespRootSchema: () => ORMapSyncRespRootSchema,
|
|
36
45
|
OpBatchMessageSchema: () => OpBatchMessageSchema,
|
|
46
|
+
PingMessageSchema: () => PingMessageSchema,
|
|
47
|
+
PongMessageSchema: () => PongMessageSchema,
|
|
37
48
|
PredicateNodeSchema: () => PredicateNodeSchema,
|
|
38
49
|
PredicateOpSchema: () => PredicateOpSchema,
|
|
39
50
|
Predicates: () => Predicates,
|
|
@@ -50,10 +61,14 @@ __export(index_exports, {
|
|
|
50
61
|
TopicSubSchema: () => TopicSubSchema,
|
|
51
62
|
TopicUnsubSchema: () => TopicUnsubSchema,
|
|
52
63
|
combineHashes: () => combineHashes,
|
|
64
|
+
compareTimestamps: () => compareTimestamps,
|
|
53
65
|
deserialize: () => deserialize,
|
|
54
66
|
evaluatePredicate: () => evaluatePredicate,
|
|
67
|
+
hashORMapEntry: () => hashORMapEntry,
|
|
68
|
+
hashORMapRecord: () => hashORMapRecord,
|
|
55
69
|
hashString: () => hashString,
|
|
56
|
-
serialize: () => serialize
|
|
70
|
+
serialize: () => serialize,
|
|
71
|
+
timestampToString: () => timestampToString
|
|
57
72
|
});
|
|
58
73
|
module.exports = __toCommonJS(index_exports);
|
|
59
74
|
|
|
@@ -433,6 +448,225 @@ var LWWMap = class {
|
|
|
433
448
|
}
|
|
434
449
|
};
|
|
435
450
|
|
|
451
|
+
// src/ORMapMerkle.ts
|
|
452
|
+
function timestampToString(ts) {
|
|
453
|
+
return `${ts.millis}:${ts.counter}:${ts.nodeId}`;
|
|
454
|
+
}
|
|
455
|
+
function stringifyValue(value) {
|
|
456
|
+
if (value === null || value === void 0) {
|
|
457
|
+
return String(value);
|
|
458
|
+
}
|
|
459
|
+
if (typeof value === "object") {
|
|
460
|
+
return JSON.stringify(value, Object.keys(value).sort());
|
|
461
|
+
}
|
|
462
|
+
return String(value);
|
|
463
|
+
}
|
|
464
|
+
function hashORMapEntry(key, records) {
|
|
465
|
+
const sortedTags = Array.from(records.keys()).sort();
|
|
466
|
+
const parts = [`key:${key}`];
|
|
467
|
+
for (const tag of sortedTags) {
|
|
468
|
+
const record = records.get(tag);
|
|
469
|
+
const valuePart = stringifyValue(record.value);
|
|
470
|
+
let recordStr = `${tag}:${valuePart}:${timestampToString(record.timestamp)}`;
|
|
471
|
+
if (record.ttlMs !== void 0) {
|
|
472
|
+
recordStr += `:ttl=${record.ttlMs}`;
|
|
473
|
+
}
|
|
474
|
+
parts.push(recordStr);
|
|
475
|
+
}
|
|
476
|
+
return hashString(parts.join("|"));
|
|
477
|
+
}
|
|
478
|
+
function hashORMapRecord(record) {
|
|
479
|
+
const valuePart = stringifyValue(record.value);
|
|
480
|
+
let str = `${record.tag}:${valuePart}:${timestampToString(record.timestamp)}`;
|
|
481
|
+
if (record.ttlMs !== void 0) {
|
|
482
|
+
str += `:ttl=${record.ttlMs}`;
|
|
483
|
+
}
|
|
484
|
+
return hashString(str);
|
|
485
|
+
}
|
|
486
|
+
function compareTimestamps(a, b) {
|
|
487
|
+
if (a.millis !== b.millis) {
|
|
488
|
+
return a.millis - b.millis;
|
|
489
|
+
}
|
|
490
|
+
if (a.counter !== b.counter) {
|
|
491
|
+
return a.counter - b.counter;
|
|
492
|
+
}
|
|
493
|
+
return a.nodeId.localeCompare(b.nodeId);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/ORMapMerkleTree.ts
|
|
497
|
+
var ORMapMerkleTree = class {
|
|
498
|
+
constructor(depth = 3) {
|
|
499
|
+
this.depth = depth;
|
|
500
|
+
this.root = { hash: 0, children: {} };
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Update tree from ORMap data.
|
|
504
|
+
* Rebuilds hashes for all entries in the map.
|
|
505
|
+
*/
|
|
506
|
+
updateFromORMap(map) {
|
|
507
|
+
this.root = { hash: 0, children: {} };
|
|
508
|
+
const snapshot = map.getSnapshot();
|
|
509
|
+
for (const [key, records] of snapshot.items) {
|
|
510
|
+
if (records.size > 0) {
|
|
511
|
+
const keyStr = String(key);
|
|
512
|
+
const entryHash = hashORMapEntry(keyStr, records);
|
|
513
|
+
const pathHash = hashString(keyStr).toString(16).padStart(8, "0");
|
|
514
|
+
this.updateNode(this.root, keyStr, entryHash, pathHash, 0);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Incrementally update a single key's hash.
|
|
520
|
+
* Call this when records for a key change.
|
|
521
|
+
*/
|
|
522
|
+
update(key, records) {
|
|
523
|
+
const pathHash = hashString(key).toString(16).padStart(8, "0");
|
|
524
|
+
if (records.size === 0) {
|
|
525
|
+
this.removeNode(this.root, key, pathHash, 0);
|
|
526
|
+
} else {
|
|
527
|
+
const entryHash = hashORMapEntry(key, records);
|
|
528
|
+
this.updateNode(this.root, key, entryHash, pathHash, 0);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Remove a key from the tree.
|
|
533
|
+
* Called when all records for a key are removed.
|
|
534
|
+
*/
|
|
535
|
+
remove(key) {
|
|
536
|
+
const pathHash = hashString(key).toString(16).padStart(8, "0");
|
|
537
|
+
this.removeNode(this.root, key, pathHash, 0);
|
|
538
|
+
}
|
|
539
|
+
updateNode(node, key, entryHash, pathHash, level) {
|
|
540
|
+
if (level >= this.depth) {
|
|
541
|
+
if (!node.entries) node.entries = /* @__PURE__ */ new Map();
|
|
542
|
+
node.entries.set(key, entryHash);
|
|
543
|
+
let h2 = 0;
|
|
544
|
+
for (const val of node.entries.values()) {
|
|
545
|
+
h2 = h2 + val | 0;
|
|
546
|
+
}
|
|
547
|
+
node.hash = h2 >>> 0;
|
|
548
|
+
return node.hash;
|
|
549
|
+
}
|
|
550
|
+
const bucketChar = pathHash[level];
|
|
551
|
+
if (!node.children) node.children = {};
|
|
552
|
+
if (!node.children[bucketChar]) {
|
|
553
|
+
node.children[bucketChar] = { hash: 0 };
|
|
554
|
+
}
|
|
555
|
+
this.updateNode(node.children[bucketChar], key, entryHash, pathHash, level + 1);
|
|
556
|
+
let h = 0;
|
|
557
|
+
for (const child of Object.values(node.children)) {
|
|
558
|
+
h = h + child.hash | 0;
|
|
559
|
+
}
|
|
560
|
+
node.hash = h >>> 0;
|
|
561
|
+
return node.hash;
|
|
562
|
+
}
|
|
563
|
+
removeNode(node, key, pathHash, level) {
|
|
564
|
+
if (level >= this.depth) {
|
|
565
|
+
if (node.entries) {
|
|
566
|
+
node.entries.delete(key);
|
|
567
|
+
let h2 = 0;
|
|
568
|
+
for (const val of node.entries.values()) {
|
|
569
|
+
h2 = h2 + val | 0;
|
|
570
|
+
}
|
|
571
|
+
node.hash = h2 >>> 0;
|
|
572
|
+
}
|
|
573
|
+
return node.hash;
|
|
574
|
+
}
|
|
575
|
+
const bucketChar = pathHash[level];
|
|
576
|
+
if (node.children && node.children[bucketChar]) {
|
|
577
|
+
this.removeNode(node.children[bucketChar], key, pathHash, level + 1);
|
|
578
|
+
}
|
|
579
|
+
let h = 0;
|
|
580
|
+
if (node.children) {
|
|
581
|
+
for (const child of Object.values(node.children)) {
|
|
582
|
+
h = h + child.hash | 0;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
node.hash = h >>> 0;
|
|
586
|
+
return node.hash;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Get the root hash for quick comparison.
|
|
590
|
+
*/
|
|
591
|
+
getRootHash() {
|
|
592
|
+
return this.root.hash;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Get node at a specific path.
|
|
596
|
+
*/
|
|
597
|
+
getNode(path) {
|
|
598
|
+
let current = this.root;
|
|
599
|
+
for (const char of path) {
|
|
600
|
+
if (!current.children || !current.children[char]) {
|
|
601
|
+
return void 0;
|
|
602
|
+
}
|
|
603
|
+
current = current.children[char];
|
|
604
|
+
}
|
|
605
|
+
return current;
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Returns the hashes of the children at the given path.
|
|
609
|
+
* Used by the client/server to compare buckets.
|
|
610
|
+
*/
|
|
611
|
+
getBuckets(path) {
|
|
612
|
+
const node = this.getNode(path);
|
|
613
|
+
if (!node || !node.children) return {};
|
|
614
|
+
const result = {};
|
|
615
|
+
for (const [key, child] of Object.entries(node.children)) {
|
|
616
|
+
result[key] = child.hash;
|
|
617
|
+
}
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* For a leaf node (bucket), returns the actual keys it contains.
|
|
622
|
+
* Used to request specific keys when a bucket differs.
|
|
623
|
+
*/
|
|
624
|
+
getKeysInBucket(path) {
|
|
625
|
+
const node = this.getNode(path);
|
|
626
|
+
if (!node || !node.entries) return [];
|
|
627
|
+
return Array.from(node.entries.keys());
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Find keys that differ between this tree and bucket info from remote.
|
|
631
|
+
* Returns keys that:
|
|
632
|
+
* - Exist locally but have different hash on remote
|
|
633
|
+
* - Exist on remote but not locally
|
|
634
|
+
* - Exist locally but not on remote
|
|
635
|
+
*/
|
|
636
|
+
findDiffKeys(path, remoteEntries) {
|
|
637
|
+
const diffKeys = /* @__PURE__ */ new Set();
|
|
638
|
+
const node = this.getNode(path);
|
|
639
|
+
const localEntries = node?.entries || /* @__PURE__ */ new Map();
|
|
640
|
+
for (const [key, hash] of localEntries) {
|
|
641
|
+
const remoteHash = remoteEntries.get(key);
|
|
642
|
+
if (remoteHash === void 0 || remoteHash !== hash) {
|
|
643
|
+
diffKeys.add(key);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
for (const key of remoteEntries.keys()) {
|
|
647
|
+
if (!localEntries.has(key)) {
|
|
648
|
+
diffKeys.add(key);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return diffKeys;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Get all entry hashes at a leaf path.
|
|
655
|
+
* Used when sending bucket details to remote.
|
|
656
|
+
*/
|
|
657
|
+
getEntryHashes(path) {
|
|
658
|
+
const node = this.getNode(path);
|
|
659
|
+
return node?.entries || /* @__PURE__ */ new Map();
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Check if a path leads to a leaf node.
|
|
663
|
+
*/
|
|
664
|
+
isLeaf(path) {
|
|
665
|
+
const node = this.getNode(path);
|
|
666
|
+
return node !== void 0 && node.entries !== void 0 && node.entries.size > 0;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
|
|
436
670
|
// src/ORMap.ts
|
|
437
671
|
var ORMap = class {
|
|
438
672
|
constructor(hlc) {
|
|
@@ -440,6 +674,7 @@ var ORMap = class {
|
|
|
440
674
|
this.hlc = hlc;
|
|
441
675
|
this.items = /* @__PURE__ */ new Map();
|
|
442
676
|
this.tombstones = /* @__PURE__ */ new Set();
|
|
677
|
+
this.merkleTree = new ORMapMerkleTree();
|
|
443
678
|
}
|
|
444
679
|
onChange(callback) {
|
|
445
680
|
this.listeners.push(callback);
|
|
@@ -484,6 +719,7 @@ var ORMap = class {
|
|
|
484
719
|
this.items.set(key, keyMap);
|
|
485
720
|
}
|
|
486
721
|
keyMap.set(tag, record);
|
|
722
|
+
this.updateMerkleTree(key);
|
|
487
723
|
this.notify();
|
|
488
724
|
return record;
|
|
489
725
|
}
|
|
@@ -508,6 +744,7 @@ var ORMap = class {
|
|
|
508
744
|
if (keyMap.size === 0) {
|
|
509
745
|
this.items.delete(key);
|
|
510
746
|
}
|
|
747
|
+
this.updateMerkleTree(key);
|
|
511
748
|
this.notify();
|
|
512
749
|
return tagsToRemove;
|
|
513
750
|
}
|
|
@@ -517,6 +754,7 @@ var ORMap = class {
|
|
|
517
754
|
clear() {
|
|
518
755
|
this.items.clear();
|
|
519
756
|
this.tombstones.clear();
|
|
757
|
+
this.merkleTree = new ORMapMerkleTree();
|
|
520
758
|
this.notify();
|
|
521
759
|
}
|
|
522
760
|
/**
|
|
@@ -566,9 +804,10 @@ var ORMap = class {
|
|
|
566
804
|
}
|
|
567
805
|
/**
|
|
568
806
|
* Applies a record from a remote source (Sync).
|
|
807
|
+
* Returns true if the record was applied (not tombstoned).
|
|
569
808
|
*/
|
|
570
809
|
apply(key, record) {
|
|
571
|
-
if (this.tombstones.has(record.tag)) return;
|
|
810
|
+
if (this.tombstones.has(record.tag)) return false;
|
|
572
811
|
let keyMap = this.items.get(key);
|
|
573
812
|
if (!keyMap) {
|
|
574
813
|
keyMap = /* @__PURE__ */ new Map();
|
|
@@ -576,7 +815,9 @@ var ORMap = class {
|
|
|
576
815
|
}
|
|
577
816
|
keyMap.set(record.tag, record);
|
|
578
817
|
this.hlc.update(record.timestamp);
|
|
818
|
+
this.updateMerkleTree(key);
|
|
579
819
|
this.notify();
|
|
820
|
+
return true;
|
|
580
821
|
}
|
|
581
822
|
/**
|
|
582
823
|
* Applies a tombstone (deletion) from a remote source.
|
|
@@ -587,6 +828,7 @@ var ORMap = class {
|
|
|
587
828
|
if (keyMap.has(tag)) {
|
|
588
829
|
keyMap.delete(tag);
|
|
589
830
|
if (keyMap.size === 0) this.items.delete(key);
|
|
831
|
+
this.updateMerkleTree(key);
|
|
590
832
|
break;
|
|
591
833
|
}
|
|
592
834
|
}
|
|
@@ -599,6 +841,7 @@ var ORMap = class {
|
|
|
599
841
|
* - Updates HLC with observed timestamps.
|
|
600
842
|
*/
|
|
601
843
|
merge(other) {
|
|
844
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
602
845
|
for (const tag of other.tombstones) {
|
|
603
846
|
this.tombstones.add(tag);
|
|
604
847
|
}
|
|
@@ -612,6 +855,7 @@ var ORMap = class {
|
|
|
612
855
|
if (!this.tombstones.has(tag)) {
|
|
613
856
|
if (!localKeyMap.has(tag)) {
|
|
614
857
|
localKeyMap.set(tag, record);
|
|
858
|
+
changedKeys.add(key);
|
|
615
859
|
}
|
|
616
860
|
this.hlc.update(record.timestamp);
|
|
617
861
|
}
|
|
@@ -621,12 +865,16 @@ var ORMap = class {
|
|
|
621
865
|
for (const tag of localKeyMap.keys()) {
|
|
622
866
|
if (this.tombstones.has(tag)) {
|
|
623
867
|
localKeyMap.delete(tag);
|
|
868
|
+
changedKeys.add(key);
|
|
624
869
|
}
|
|
625
870
|
}
|
|
626
871
|
if (localKeyMap.size === 0) {
|
|
627
872
|
this.items.delete(key);
|
|
628
873
|
}
|
|
629
874
|
}
|
|
875
|
+
for (const key of changedKeys) {
|
|
876
|
+
this.updateMerkleTree(key);
|
|
877
|
+
}
|
|
630
878
|
this.notify();
|
|
631
879
|
}
|
|
632
880
|
/**
|
|
@@ -646,6 +894,108 @@ var ORMap = class {
|
|
|
646
894
|
}
|
|
647
895
|
return removedTags;
|
|
648
896
|
}
|
|
897
|
+
// ============ Merkle Sync Methods ============
|
|
898
|
+
/**
|
|
899
|
+
* Get the Merkle Tree for this ORMap.
|
|
900
|
+
* Used for efficient synchronization.
|
|
901
|
+
*/
|
|
902
|
+
getMerkleTree() {
|
|
903
|
+
return this.merkleTree;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Get a snapshot of internal state for Merkle Tree synchronization.
|
|
907
|
+
* Returns references to internal structures - do not modify!
|
|
908
|
+
*/
|
|
909
|
+
getSnapshot() {
|
|
910
|
+
return {
|
|
911
|
+
items: this.items,
|
|
912
|
+
tombstones: this.tombstones
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Get all keys in this ORMap.
|
|
917
|
+
*/
|
|
918
|
+
allKeys() {
|
|
919
|
+
return Array.from(this.items.keys());
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Get the internal records map for a key.
|
|
923
|
+
* Returns Map<tag, record> or undefined if key doesn't exist.
|
|
924
|
+
* Used for Merkle sync.
|
|
925
|
+
*/
|
|
926
|
+
getRecordsMap(key) {
|
|
927
|
+
return this.items.get(key);
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Merge remote records for a specific key into local state.
|
|
931
|
+
* Implements Observed-Remove CRDT semantics.
|
|
932
|
+
* Used during Merkle Tree synchronization.
|
|
933
|
+
*
|
|
934
|
+
* @param key The key to merge
|
|
935
|
+
* @param remoteRecords Array of records from remote
|
|
936
|
+
* @param remoteTombstones Array of tombstone tags from remote
|
|
937
|
+
* @returns Result with count of added and updated records
|
|
938
|
+
*/
|
|
939
|
+
mergeKey(key, remoteRecords, remoteTombstones = []) {
|
|
940
|
+
let added = 0;
|
|
941
|
+
let updated = 0;
|
|
942
|
+
for (const tag of remoteTombstones) {
|
|
943
|
+
if (!this.tombstones.has(tag)) {
|
|
944
|
+
this.tombstones.add(tag);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
let localKeyMap = this.items.get(key);
|
|
948
|
+
if (!localKeyMap) {
|
|
949
|
+
localKeyMap = /* @__PURE__ */ new Map();
|
|
950
|
+
this.items.set(key, localKeyMap);
|
|
951
|
+
}
|
|
952
|
+
for (const tag of localKeyMap.keys()) {
|
|
953
|
+
if (this.tombstones.has(tag)) {
|
|
954
|
+
localKeyMap.delete(tag);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
for (const remoteRecord of remoteRecords) {
|
|
958
|
+
if (this.tombstones.has(remoteRecord.tag)) {
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
const localRecord = localKeyMap.get(remoteRecord.tag);
|
|
962
|
+
if (!localRecord) {
|
|
963
|
+
localKeyMap.set(remoteRecord.tag, remoteRecord);
|
|
964
|
+
added++;
|
|
965
|
+
} else if (compareTimestamps(remoteRecord.timestamp, localRecord.timestamp) > 0) {
|
|
966
|
+
localKeyMap.set(remoteRecord.tag, remoteRecord);
|
|
967
|
+
updated++;
|
|
968
|
+
}
|
|
969
|
+
this.hlc.update(remoteRecord.timestamp);
|
|
970
|
+
}
|
|
971
|
+
if (localKeyMap.size === 0) {
|
|
972
|
+
this.items.delete(key);
|
|
973
|
+
}
|
|
974
|
+
this.updateMerkleTree(key);
|
|
975
|
+
if (added > 0 || updated > 0) {
|
|
976
|
+
this.notify();
|
|
977
|
+
}
|
|
978
|
+
return { added, updated };
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Check if a tag is tombstoned.
|
|
982
|
+
*/
|
|
983
|
+
isTombstoned(tag) {
|
|
984
|
+
return this.tombstones.has(tag);
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Update the Merkle Tree for a specific key.
|
|
988
|
+
* Called internally after any modification.
|
|
989
|
+
*/
|
|
990
|
+
updateMerkleTree(key) {
|
|
991
|
+
const keyStr = String(key);
|
|
992
|
+
const keyMap = this.items.get(key);
|
|
993
|
+
if (!keyMap || keyMap.size === 0) {
|
|
994
|
+
this.merkleTree.remove(keyStr);
|
|
995
|
+
} else {
|
|
996
|
+
this.merkleTree.update(keyStr, keyMap);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
649
999
|
};
|
|
650
1000
|
|
|
651
1001
|
// src/serializer.ts
|
|
@@ -909,6 +1259,91 @@ var TopicMessageEventSchema = import_zod.z.object({
|
|
|
909
1259
|
timestamp: import_zod.z.number()
|
|
910
1260
|
})
|
|
911
1261
|
});
|
|
1262
|
+
var PingMessageSchema = import_zod.z.object({
|
|
1263
|
+
type: import_zod.z.literal("PING"),
|
|
1264
|
+
timestamp: import_zod.z.number()
|
|
1265
|
+
// Client's Date.now()
|
|
1266
|
+
});
|
|
1267
|
+
var PongMessageSchema = import_zod.z.object({
|
|
1268
|
+
type: import_zod.z.literal("PONG"),
|
|
1269
|
+
timestamp: import_zod.z.number(),
|
|
1270
|
+
// Echo back client's timestamp
|
|
1271
|
+
serverTime: import_zod.z.number()
|
|
1272
|
+
// Server's Date.now() (for clock skew detection)
|
|
1273
|
+
});
|
|
1274
|
+
var ORMapSyncInitSchema = import_zod.z.object({
|
|
1275
|
+
type: import_zod.z.literal("ORMAP_SYNC_INIT"),
|
|
1276
|
+
mapName: import_zod.z.string(),
|
|
1277
|
+
rootHash: import_zod.z.number(),
|
|
1278
|
+
bucketHashes: import_zod.z.record(import_zod.z.string(), import_zod.z.number()),
|
|
1279
|
+
// path -> hash
|
|
1280
|
+
lastSyncTimestamp: import_zod.z.number().optional()
|
|
1281
|
+
});
|
|
1282
|
+
var ORMapSyncRespRootSchema = import_zod.z.object({
|
|
1283
|
+
type: import_zod.z.literal("ORMAP_SYNC_RESP_ROOT"),
|
|
1284
|
+
payload: import_zod.z.object({
|
|
1285
|
+
mapName: import_zod.z.string(),
|
|
1286
|
+
rootHash: import_zod.z.number(),
|
|
1287
|
+
timestamp: TimestampSchema
|
|
1288
|
+
})
|
|
1289
|
+
});
|
|
1290
|
+
var ORMapSyncRespBucketsSchema = import_zod.z.object({
|
|
1291
|
+
type: import_zod.z.literal("ORMAP_SYNC_RESP_BUCKETS"),
|
|
1292
|
+
payload: import_zod.z.object({
|
|
1293
|
+
mapName: import_zod.z.string(),
|
|
1294
|
+
path: import_zod.z.string(),
|
|
1295
|
+
buckets: import_zod.z.record(import_zod.z.string(), import_zod.z.number())
|
|
1296
|
+
})
|
|
1297
|
+
});
|
|
1298
|
+
var ORMapMerkleReqBucketSchema = import_zod.z.object({
|
|
1299
|
+
type: import_zod.z.literal("ORMAP_MERKLE_REQ_BUCKET"),
|
|
1300
|
+
payload: import_zod.z.object({
|
|
1301
|
+
mapName: import_zod.z.string(),
|
|
1302
|
+
path: import_zod.z.string()
|
|
1303
|
+
})
|
|
1304
|
+
});
|
|
1305
|
+
var ORMapSyncRespLeafSchema = import_zod.z.object({
|
|
1306
|
+
type: import_zod.z.literal("ORMAP_SYNC_RESP_LEAF"),
|
|
1307
|
+
payload: import_zod.z.object({
|
|
1308
|
+
mapName: import_zod.z.string(),
|
|
1309
|
+
path: import_zod.z.string(),
|
|
1310
|
+
entries: import_zod.z.array(import_zod.z.object({
|
|
1311
|
+
key: import_zod.z.string(),
|
|
1312
|
+
records: import_zod.z.array(ORMapRecordSchema),
|
|
1313
|
+
tombstones: import_zod.z.array(import_zod.z.string())
|
|
1314
|
+
// Tombstone tags for this key's records
|
|
1315
|
+
}))
|
|
1316
|
+
})
|
|
1317
|
+
});
|
|
1318
|
+
var ORMapDiffRequestSchema = import_zod.z.object({
|
|
1319
|
+
type: import_zod.z.literal("ORMAP_DIFF_REQUEST"),
|
|
1320
|
+
payload: import_zod.z.object({
|
|
1321
|
+
mapName: import_zod.z.string(),
|
|
1322
|
+
keys: import_zod.z.array(import_zod.z.string())
|
|
1323
|
+
})
|
|
1324
|
+
});
|
|
1325
|
+
var ORMapDiffResponseSchema = import_zod.z.object({
|
|
1326
|
+
type: import_zod.z.literal("ORMAP_DIFF_RESPONSE"),
|
|
1327
|
+
payload: import_zod.z.object({
|
|
1328
|
+
mapName: import_zod.z.string(),
|
|
1329
|
+
entries: import_zod.z.array(import_zod.z.object({
|
|
1330
|
+
key: import_zod.z.string(),
|
|
1331
|
+
records: import_zod.z.array(ORMapRecordSchema),
|
|
1332
|
+
tombstones: import_zod.z.array(import_zod.z.string())
|
|
1333
|
+
}))
|
|
1334
|
+
})
|
|
1335
|
+
});
|
|
1336
|
+
var ORMapPushDiffSchema = import_zod.z.object({
|
|
1337
|
+
type: import_zod.z.literal("ORMAP_PUSH_DIFF"),
|
|
1338
|
+
payload: import_zod.z.object({
|
|
1339
|
+
mapName: import_zod.z.string(),
|
|
1340
|
+
entries: import_zod.z.array(import_zod.z.object({
|
|
1341
|
+
key: import_zod.z.string(),
|
|
1342
|
+
records: import_zod.z.array(ORMapRecordSchema),
|
|
1343
|
+
tombstones: import_zod.z.array(import_zod.z.string())
|
|
1344
|
+
}))
|
|
1345
|
+
})
|
|
1346
|
+
});
|
|
912
1347
|
var MessageSchema = import_zod.z.discriminatedUnion("type", [
|
|
913
1348
|
AuthMessageSchema,
|
|
914
1349
|
QuerySubMessageSchema,
|
|
@@ -924,7 +1359,18 @@ var MessageSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
924
1359
|
LockReleaseSchema,
|
|
925
1360
|
TopicSubSchema,
|
|
926
1361
|
TopicUnsubSchema,
|
|
927
|
-
TopicPubSchema
|
|
1362
|
+
TopicPubSchema,
|
|
1363
|
+
PingMessageSchema,
|
|
1364
|
+
PongMessageSchema,
|
|
1365
|
+
// ORMap Sync Messages
|
|
1366
|
+
ORMapSyncInitSchema,
|
|
1367
|
+
ORMapSyncRespRootSchema,
|
|
1368
|
+
ORMapSyncRespBucketsSchema,
|
|
1369
|
+
ORMapMerkleReqBucketSchema,
|
|
1370
|
+
ORMapSyncRespLeafSchema,
|
|
1371
|
+
ORMapDiffRequestSchema,
|
|
1372
|
+
ORMapDiffResponseSchema,
|
|
1373
|
+
ORMapPushDiffSchema
|
|
928
1374
|
]);
|
|
929
1375
|
// Annotate the CommonJS export names for ESM import in node:
|
|
930
1376
|
0 && (module.exports = {
|
|
@@ -940,8 +1386,19 @@ var MessageSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
940
1386
|
MerkleTree,
|
|
941
1387
|
MessageSchema,
|
|
942
1388
|
ORMap,
|
|
1389
|
+
ORMapDiffRequestSchema,
|
|
1390
|
+
ORMapDiffResponseSchema,
|
|
1391
|
+
ORMapMerkleReqBucketSchema,
|
|
1392
|
+
ORMapMerkleTree,
|
|
1393
|
+
ORMapPushDiffSchema,
|
|
943
1394
|
ORMapRecordSchema,
|
|
1395
|
+
ORMapSyncInitSchema,
|
|
1396
|
+
ORMapSyncRespBucketsSchema,
|
|
1397
|
+
ORMapSyncRespLeafSchema,
|
|
1398
|
+
ORMapSyncRespRootSchema,
|
|
944
1399
|
OpBatchMessageSchema,
|
|
1400
|
+
PingMessageSchema,
|
|
1401
|
+
PongMessageSchema,
|
|
945
1402
|
PredicateNodeSchema,
|
|
946
1403
|
PredicateOpSchema,
|
|
947
1404
|
Predicates,
|
|
@@ -958,9 +1415,13 @@ var MessageSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
958
1415
|
TopicSubSchema,
|
|
959
1416
|
TopicUnsubSchema,
|
|
960
1417
|
combineHashes,
|
|
1418
|
+
compareTimestamps,
|
|
961
1419
|
deserialize,
|
|
962
1420
|
evaluatePredicate,
|
|
1421
|
+
hashORMapEntry,
|
|
1422
|
+
hashORMapRecord,
|
|
963
1423
|
hashString,
|
|
964
|
-
serialize
|
|
1424
|
+
serialize,
|
|
1425
|
+
timestampToString
|
|
965
1426
|
});
|
|
966
1427
|
//# sourceMappingURL=index.js.map
|