@topgunbuild/core 0.1.0 → 0.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/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