@sovereignbase/convergent-replicated-list 1.3.5 → 1.3.7
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 +209 -206
- package/dist/index.cjs +196 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -8
- package/dist/index.d.ts +31 -8
- package/dist/index.js +159 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -112,9 +112,19 @@ function rebuildLiveProjection(crListReplica) {
|
|
|
112
112
|
while (stack.length > 0) {
|
|
113
113
|
const frame = stack[stack.length - 1];
|
|
114
114
|
if (!frame.siblings) {
|
|
115
|
-
|
|
115
|
+
const childrenMapSibs = crListReplica.childrenMap.get(
|
|
116
116
|
frame.predecessorIdentifier
|
|
117
117
|
);
|
|
118
|
+
const runNextEntry = crListReplica.runNext?.get(
|
|
119
|
+
frame.predecessorIdentifier
|
|
120
|
+
);
|
|
121
|
+
if (childrenMapSibs && runNextEntry) {
|
|
122
|
+
frame.siblings = [...childrenMapSibs, runNextEntry];
|
|
123
|
+
} else if (runNextEntry) {
|
|
124
|
+
frame.siblings = [runNextEntry];
|
|
125
|
+
} else {
|
|
126
|
+
frame.siblings = childrenMapSibs;
|
|
127
|
+
}
|
|
118
128
|
if (!frame.siblings) {
|
|
119
129
|
void stack.pop();
|
|
120
130
|
continue;
|
|
@@ -198,9 +208,21 @@ function attachEntryToIndexes(crListReplica, linkedListEntry, deltaBuf) {
|
|
|
198
208
|
function detachEntryFromIndexes(crListReplica, linkedListEntry) {
|
|
199
209
|
void crListReplica.parentMap.delete(linkedListEntry.uuidv7);
|
|
200
210
|
const siblings = crListReplica.childrenMap.get(linkedListEntry.predecessor);
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
if (siblings) {
|
|
212
|
+
const index = siblings.indexOf(linkedListEntry);
|
|
213
|
+
if (index !== -1) void siblings.splice(index, 1);
|
|
214
|
+
}
|
|
215
|
+
if (crListReplica.runNext) {
|
|
216
|
+
if (crListReplica.runNext.get(linkedListEntry.predecessor) === linkedListEntry)
|
|
217
|
+
crListReplica.runNext.delete(linkedListEntry.predecessor);
|
|
218
|
+
const runSuccessor = crListReplica.runNext.get(linkedListEntry.uuidv7);
|
|
219
|
+
if (runSuccessor) {
|
|
220
|
+
crListReplica.runNext.delete(linkedListEntry.uuidv7);
|
|
221
|
+
const sibs = crListReplica.childrenMap.get(linkedListEntry.uuidv7);
|
|
222
|
+
if (sibs) sibs.push(runSuccessor);
|
|
223
|
+
else crListReplica.childrenMap.set(linkedListEntry.uuidv7, [runSuccessor]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
204
226
|
}
|
|
205
227
|
|
|
206
228
|
// src/.helpers/deleteLiveEntry/index.ts
|
|
@@ -363,6 +385,13 @@ function trySpliceSiblingInsert(crListReplica, insertedEntries, reparentedEntrie
|
|
|
363
385
|
return true;
|
|
364
386
|
}
|
|
365
387
|
|
|
388
|
+
// src/.helpers/deriveRunUuid/index.ts
|
|
389
|
+
function deriveRunUuid(startUuid, offset) {
|
|
390
|
+
const randA = parseInt(startUuid.slice(15, 18), 16);
|
|
391
|
+
const newRandA = randA + offset & 4095;
|
|
392
|
+
return startUuid.slice(0, 15) + newRandA.toString(16).padStart(3, "0") + startUuid.slice(18);
|
|
393
|
+
}
|
|
394
|
+
|
|
366
395
|
// src/core/crud/create/index.ts
|
|
367
396
|
import { isUuidV7 as isUuidV72, prototype } from "@sovereignbase/utils";
|
|
368
397
|
function __create(snapshot) {
|
|
@@ -436,6 +465,8 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
436
465
|
if (listValues.length === 0) return false;
|
|
437
466
|
const change = {};
|
|
438
467
|
const delta = { values: [], tombstones: [] };
|
|
468
|
+
let displacedEntry;
|
|
469
|
+
const batchEntries = [];
|
|
439
470
|
for (const listValue of listValues) {
|
|
440
471
|
const v7 = uuidv7();
|
|
441
472
|
const linkedListEntry = {
|
|
@@ -484,15 +515,27 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
484
515
|
linkedListEntry,
|
|
485
516
|
entryToOverwrite.next
|
|
486
517
|
);
|
|
487
|
-
if (entryToOverwrite.next) {
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
);
|
|
518
|
+
if (entryToOverwrite.next?.predecessor === entryToOverwrite.uuidv7) {
|
|
519
|
+
const overwriteNext = entryToOverwrite.next;
|
|
520
|
+
const owSibs = crListReplica.childrenMap.get(
|
|
521
|
+
overwriteNext.predecessor
|
|
522
|
+
);
|
|
523
|
+
if (owSibs) {
|
|
524
|
+
const i = owSibs.indexOf(overwriteNext);
|
|
525
|
+
if (i !== -1) owSibs.splice(i, 1);
|
|
495
526
|
}
|
|
527
|
+
overwriteNext.predecessor = linkedListEntry.uuidv7;
|
|
528
|
+
const newSibs = crListReplica.childrenMap.get(linkedListEntry.uuidv7);
|
|
529
|
+
if (newSibs) newSibs.push(overwriteNext);
|
|
530
|
+
else
|
|
531
|
+
crListReplica.childrenMap.set(linkedListEntry.uuidv7, [
|
|
532
|
+
overwriteNext
|
|
533
|
+
]);
|
|
534
|
+
delta.values?.push({
|
|
535
|
+
uuidv7: overwriteNext.uuidv7,
|
|
536
|
+
value: overwriteNext.value,
|
|
537
|
+
predecessor: overwriteNext.predecessor
|
|
538
|
+
});
|
|
496
539
|
}
|
|
497
540
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
498
541
|
void crListReplica.tombstones.add(entryToOverwrite.uuidv7);
|
|
@@ -526,20 +569,24 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
526
569
|
linkedListEntry.index = actualIndex + 1;
|
|
527
570
|
linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
|
|
528
571
|
void linkEntryBetween(crListReplica.cursor, linkedListEntry, next);
|
|
529
|
-
if (next) {
|
|
530
|
-
if (
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
572
|
+
if (next && next.predecessor === crListReplica.cursor.uuidv7) {
|
|
573
|
+
if (!displacedEntry) {
|
|
574
|
+
displacedEntry = next;
|
|
575
|
+
const sibs = crListReplica.childrenMap.get(next.predecessor);
|
|
576
|
+
if (sibs) {
|
|
577
|
+
const i = sibs.indexOf(next);
|
|
578
|
+
if (i !== -1) sibs.splice(i, 1);
|
|
579
|
+
}
|
|
537
580
|
}
|
|
581
|
+
displacedEntry.predecessor = linkedListEntry.uuidv7;
|
|
538
582
|
}
|
|
539
583
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
540
584
|
crListReplica.cursor = linkedListEntry;
|
|
541
585
|
crListReplica.cursorIndex = linkedListEntry.index;
|
|
542
|
-
if (next)
|
|
586
|
+
if (next) {
|
|
587
|
+
if (crListReplica.index) crListReplica.index.clear();
|
|
588
|
+
else crListReplica.index = /* @__PURE__ */ new Map();
|
|
589
|
+
}
|
|
543
590
|
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
544
591
|
change[linkedListEntry.index] = linkedListEntry.value;
|
|
545
592
|
break;
|
|
@@ -563,17 +610,23 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
563
610
|
linkedListEntry.predecessor = prev?.uuidv7 ?? "\0";
|
|
564
611
|
void linkEntryBetween(prev, linkedListEntry, crListReplica.cursor);
|
|
565
612
|
if (crListReplica.cursor.predecessor === linkedListEntry.predecessor) {
|
|
566
|
-
|
|
567
|
-
crListReplica
|
|
568
|
-
crListReplica.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
613
|
+
if (!displacedEntry) {
|
|
614
|
+
displacedEntry = crListReplica.cursor;
|
|
615
|
+
const sibs = crListReplica.childrenMap.get(
|
|
616
|
+
crListReplica.cursor.predecessor
|
|
617
|
+
);
|
|
618
|
+
if (sibs) {
|
|
619
|
+
const i = sibs.indexOf(crListReplica.cursor);
|
|
620
|
+
if (i !== -1) sibs.splice(i, 1);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
displacedEntry.predecessor = linkedListEntry.uuidv7;
|
|
572
624
|
}
|
|
573
625
|
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
574
626
|
crListReplica.cursor = linkedListEntry;
|
|
575
627
|
crListReplica.cursorIndex = actualIndex;
|
|
576
|
-
crListReplica.index
|
|
628
|
+
if (crListReplica.index) crListReplica.index.clear();
|
|
629
|
+
else crListReplica.index = /* @__PURE__ */ new Map();
|
|
577
630
|
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
578
631
|
change[actualIndex] = linkedListEntry.value;
|
|
579
632
|
mode = "after";
|
|
@@ -581,9 +634,49 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
581
634
|
break;
|
|
582
635
|
}
|
|
583
636
|
}
|
|
637
|
+
batchEntries.push(linkedListEntry);
|
|
584
638
|
crListReplica.size = crListReplica.parentMap.size;
|
|
585
639
|
listIndex++;
|
|
586
640
|
}
|
|
641
|
+
if (batchEntries.length > 1) {
|
|
642
|
+
for (let k = 0; k + 1 < batchEntries.length; k++) {
|
|
643
|
+
const curr = batchEntries[k];
|
|
644
|
+
const next = batchEntries[k + 1];
|
|
645
|
+
if (next.predecessor !== curr.uuidv7) continue;
|
|
646
|
+
crListReplica.childrenMap.delete(curr.uuidv7);
|
|
647
|
+
if (!crListReplica.runNext) crListReplica.runNext = /* @__PURE__ */ new Map();
|
|
648
|
+
crListReplica.runNext.set(curr.uuidv7, next);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (batchEntries.length > 1 && delta.values && delta.values.length >= batchEntries.length) {
|
|
652
|
+
const first = batchEntries[0];
|
|
653
|
+
const last = batchEntries[batchEntries.length - 1];
|
|
654
|
+
if (deriveRunUuid(first.uuidv7, batchEntries.length - 1) === last.uuidv7) {
|
|
655
|
+
delta.values.splice(
|
|
656
|
+
delta.values.length - batchEntries.length,
|
|
657
|
+
batchEntries.length,
|
|
658
|
+
{
|
|
659
|
+
uuidv7: first.uuidv7,
|
|
660
|
+
value: first.value,
|
|
661
|
+
predecessor: first.predecessor,
|
|
662
|
+
tail: batchEntries.slice(1).map((e) => e.value)
|
|
663
|
+
}
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
if (displacedEntry) {
|
|
668
|
+
const sibs = crListReplica.childrenMap.get(displacedEntry.predecessor);
|
|
669
|
+
if (sibs) sibs.push(displacedEntry);
|
|
670
|
+
else
|
|
671
|
+
crListReplica.childrenMap.set(displacedEntry.predecessor, [
|
|
672
|
+
displacedEntry
|
|
673
|
+
]);
|
|
674
|
+
delta.values?.push({
|
|
675
|
+
uuidv7: displacedEntry.uuidv7,
|
|
676
|
+
value: displacedEntry.value,
|
|
677
|
+
predecessor: displacedEntry.predecessor
|
|
678
|
+
});
|
|
679
|
+
}
|
|
587
680
|
return { change, delta };
|
|
588
681
|
}
|
|
589
682
|
|
|
@@ -660,9 +753,20 @@ function __merge(crListReplica, crListDelta) {
|
|
|
660
753
|
const change = {};
|
|
661
754
|
let tailTombstoneMovedCursor = false;
|
|
662
755
|
let needsRelink = false;
|
|
663
|
-
|
|
756
|
+
const expandedValues = Object.hasOwn(crListDelta, "values") && Array.isArray(crListDelta.values) ? crListDelta.values.flatMap((entry) => {
|
|
757
|
+
if (!entry || !entry.tail || entry.tail.length === 0) return [entry];
|
|
758
|
+
return [
|
|
759
|
+
entry,
|
|
760
|
+
...entry.tail.map((value, i) => ({
|
|
761
|
+
uuidv7: deriveRunUuid(entry.uuidv7, i + 1),
|
|
762
|
+
value,
|
|
763
|
+
predecessor: deriveRunUuid(entry.uuidv7, i)
|
|
764
|
+
}))
|
|
765
|
+
];
|
|
766
|
+
}) : void 0;
|
|
767
|
+
if (expandedValues?.length === 1 && (!Object.hasOwn(crListDelta, "tombstones") || Array.isArray(crListDelta.tombstones) && crListDelta.tombstones.length === 0)) {
|
|
664
768
|
const linkedListEntry = materializeSnapshotEntry(
|
|
665
|
-
|
|
769
|
+
expandedValues[0],
|
|
666
770
|
crListReplica
|
|
667
771
|
);
|
|
668
772
|
if (!linkedListEntry) return false;
|
|
@@ -696,7 +800,7 @@ function __merge(crListReplica, crListDelta) {
|
|
|
696
800
|
}
|
|
697
801
|
}
|
|
698
802
|
}
|
|
699
|
-
if (!
|
|
803
|
+
if (!expandedValues || expandedValues.length === 0 && tailTombstoneMovedCursor) {
|
|
700
804
|
if (newTombsIndices.length === 0) return false;
|
|
701
805
|
if (newTombsIndices.length === 1 && tailTombstoneMovedCursor) {
|
|
702
806
|
if (crListReplica.cursor) {
|
|
@@ -717,7 +821,7 @@ function __merge(crListReplica, crListDelta) {
|
|
|
717
821
|
}
|
|
718
822
|
return change;
|
|
719
823
|
}
|
|
720
|
-
for (const valueEntry of
|
|
824
|
+
for (const valueEntry of expandedValues) {
|
|
721
825
|
if (valueEntry === null || valueEntry === void 0) continue;
|
|
722
826
|
const existingEntry = crListReplica.parentMap.get(valueEntry.uuidv7);
|
|
723
827
|
if (existingEntry) {
|
|
@@ -924,32 +1028,32 @@ var CRList = class {
|
|
|
924
1028
|
return this.state.size;
|
|
925
1029
|
}
|
|
926
1030
|
/**
|
|
927
|
-
* Inserts
|
|
1031
|
+
* Inserts values before an index.
|
|
928
1032
|
*
|
|
929
|
-
* If `beforeIndex` is omitted,
|
|
1033
|
+
* If `beforeIndex` is omitted, values are inserted at the start of the list.
|
|
930
1034
|
*
|
|
931
|
-
* @param
|
|
1035
|
+
* @param values - Values to insert.
|
|
932
1036
|
* @param beforeIndex - The index to insert before.
|
|
933
1037
|
*/
|
|
934
|
-
prepend(
|
|
935
|
-
const result = __update(beforeIndex ?? 0,
|
|
1038
|
+
prepend(values, beforeIndex) {
|
|
1039
|
+
const result = __update(beforeIndex ?? 0, values, this.state, "before");
|
|
936
1040
|
if (!result) return;
|
|
937
1041
|
const { delta, change } = result;
|
|
938
1042
|
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
939
1043
|
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
940
1044
|
}
|
|
941
1045
|
/**
|
|
942
|
-
* Inserts
|
|
1046
|
+
* Inserts values after an index.
|
|
943
1047
|
*
|
|
944
|
-
* If `afterIndex` is omitted,
|
|
1048
|
+
* If `afterIndex` is omitted, values are appended at the end of the list.
|
|
945
1049
|
*
|
|
946
|
-
* @param
|
|
1050
|
+
* @param values - Values to insert.
|
|
947
1051
|
* @param afterIndex - The index to insert after.
|
|
948
1052
|
*/
|
|
949
|
-
append(
|
|
1053
|
+
append(values, afterIndex) {
|
|
950
1054
|
const result = __update(
|
|
951
1055
|
afterIndex ?? this.state.size,
|
|
952
|
-
|
|
1056
|
+
values,
|
|
953
1057
|
this.state,
|
|
954
1058
|
"after"
|
|
955
1059
|
);
|
|
@@ -958,6 +1062,19 @@ var CRList = class {
|
|
|
958
1062
|
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
959
1063
|
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
960
1064
|
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Overwrites entries starting at an index.
|
|
1067
|
+
*
|
|
1068
|
+
* @param index - The index to start overwriting at.
|
|
1069
|
+
* @param values - Values to write.
|
|
1070
|
+
*/
|
|
1071
|
+
update(index, values) {
|
|
1072
|
+
const result = __update(index, values, this.state, "overwrite");
|
|
1073
|
+
if (!result) return;
|
|
1074
|
+
const { delta, change } = result;
|
|
1075
|
+
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
1076
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
1077
|
+
}
|
|
961
1078
|
/**
|
|
962
1079
|
* Removes one or more entries starting at an index.
|
|
963
1080
|
*
|