@sovereignbase/convergent-replicated-list 1.1.0 → 1.2.1
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 +53 -24
- package/dist/index.cjs +286 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -44
- package/dist/index.d.ts +58 -44
- package/dist/index.js +285 -223
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -15,18 +15,27 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
// src/.helpers/
|
|
19
|
-
function
|
|
20
|
-
if (!crListReplica.cursor)
|
|
18
|
+
// src/.helpers/rebuildLiveIndex/index.ts
|
|
19
|
+
function rebuildLiveIndex(crListReplica) {
|
|
20
|
+
if (!crListReplica.cursor) {
|
|
21
|
+
crListReplica.index?.clear();
|
|
22
|
+
crListReplica.cursorIndex = void 0;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
21
25
|
let index = crListReplica.size;
|
|
26
|
+
const entries = crListReplica.index ?? /* @__PURE__ */ new Map();
|
|
27
|
+
void entries.clear();
|
|
22
28
|
while (crListReplica.cursor.next)
|
|
23
29
|
crListReplica.cursor = crListReplica.cursor.next;
|
|
24
30
|
while (index >= 1) {
|
|
25
31
|
index--;
|
|
26
32
|
crListReplica.cursor.index = index;
|
|
33
|
+
void entries.set(index, crListReplica.cursor);
|
|
27
34
|
if (crListReplica.cursor.prev === void 0) break;
|
|
28
35
|
crListReplica.cursor = crListReplica.cursor.prev;
|
|
29
36
|
}
|
|
37
|
+
crListReplica.index = entries;
|
|
38
|
+
crListReplica.cursorIndex = 0;
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
// src/.errors/class.ts
|
|
@@ -49,102 +58,115 @@ var CRListError = class extends Error {
|
|
|
49
58
|
}
|
|
50
59
|
};
|
|
51
60
|
|
|
52
|
-
// src/.helpers/
|
|
53
|
-
function
|
|
61
|
+
// src/.helpers/seekCursorToIndex/index.ts
|
|
62
|
+
function seekCursorToIndex(targetIndex, crListReplica) {
|
|
54
63
|
if (targetIndex < 0 || targetIndex >= crListReplica.size)
|
|
55
64
|
throw new CRListError("INDEX_OUT_OF_BOUNDS", "Index out of bounds");
|
|
65
|
+
const indexedEntry = crListReplica.index?.get(targetIndex);
|
|
66
|
+
if (indexedEntry) {
|
|
67
|
+
if (crListReplica.parentMap.get(indexedEntry.uuidv7) === indexedEntry) {
|
|
68
|
+
crListReplica.cursor = indexedEntry;
|
|
69
|
+
crListReplica.cursorIndex = targetIndex;
|
|
70
|
+
return;
|
|
71
|
+
} else {
|
|
72
|
+
void crListReplica.index?.delete(targetIndex);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
56
75
|
if (!crListReplica.cursor)
|
|
57
76
|
throw new CRListError("LIST_EMPTY", "List is empty");
|
|
58
|
-
|
|
59
|
-
|
|
77
|
+
let cursorIndex = crListReplica.cursorIndex ?? crListReplica.cursor.index;
|
|
78
|
+
const direction = cursorIndex > targetIndex ? "prev" : "next";
|
|
79
|
+
while (crListReplica.cursor && cursorIndex !== targetIndex) {
|
|
60
80
|
crListReplica.cursor = crListReplica.cursor[direction];
|
|
81
|
+
cursorIndex += direction === "next" ? 1 : -1;
|
|
82
|
+
}
|
|
83
|
+
if (crListReplica.cursor) {
|
|
84
|
+
crListReplica.cursorIndex = targetIndex;
|
|
85
|
+
void crListReplica.index?.set(targetIndex, crListReplica.cursor);
|
|
61
86
|
}
|
|
62
87
|
}
|
|
63
88
|
|
|
64
|
-
// src/.helpers/
|
|
65
|
-
function
|
|
89
|
+
// src/.helpers/linkEntryBetween/index.ts
|
|
90
|
+
function linkEntryBetween(prev, linkedListEntry, next) {
|
|
66
91
|
linkedListEntry.prev = prev;
|
|
67
92
|
linkedListEntry.next = next;
|
|
68
93
|
if (prev) prev.next = linkedListEntry;
|
|
69
94
|
if (next) next.prev = linkedListEntry;
|
|
70
95
|
}
|
|
71
96
|
|
|
72
|
-
// src/.helpers/
|
|
73
|
-
function
|
|
97
|
+
// src/.helpers/rebuildLiveProjection/index.ts
|
|
98
|
+
function rebuildLiveProjection(crListReplica) {
|
|
74
99
|
crListReplica.cursor = void 0;
|
|
75
|
-
const
|
|
100
|
+
const entries = crListReplica.index ?? /* @__PURE__ */ new Map();
|
|
101
|
+
void entries.clear();
|
|
76
102
|
for (const entry of crListReplica.parentMap.values()) {
|
|
77
103
|
if (!entry) continue;
|
|
78
104
|
entry.prev = void 0;
|
|
79
105
|
entry.next = void 0;
|
|
80
106
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
siblings
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
continue;
|
|
96
|
-
let prev = predecessor ?? crListReplica.cursor;
|
|
97
|
-
const predecessorNext = predecessor?.next;
|
|
98
|
-
if (siblings.length === 1) {
|
|
99
|
-
const sibling = siblings[0];
|
|
100
|
-
insertBetween(prev, sibling, sibling.next);
|
|
101
|
-
prev = sibling;
|
|
102
|
-
if (predecessorNext && predecessorNext !== sibling) {
|
|
103
|
-
prev.next = predecessorNext;
|
|
104
|
-
predecessorNext.prev = prev;
|
|
105
|
-
} else {
|
|
106
|
-
prev.next = void 0;
|
|
107
|
+
let previous = void 0;
|
|
108
|
+
let first = void 0;
|
|
109
|
+
let index = 0;
|
|
110
|
+
const appendChildren = (predecessorIdentifier) => {
|
|
111
|
+
const stack = [{ predecessorIdentifier, siblingIndex: 0 }];
|
|
112
|
+
while (stack.length > 0) {
|
|
113
|
+
const frame = stack[stack.length - 1];
|
|
114
|
+
if (!frame.siblings) {
|
|
115
|
+
frame.siblings = crListReplica.childrenMap.get(
|
|
116
|
+
frame.predecessorIdentifier
|
|
117
|
+
);
|
|
118
|
+
if (!frame.siblings) {
|
|
119
|
+
void stack.pop();
|
|
120
|
+
continue;
|
|
107
121
|
}
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
hasProgress = true;
|
|
111
|
-
continue;
|
|
122
|
+
if (frame.siblings.length > 1)
|
|
123
|
+
void frame.siblings.sort((a, b) => a.uuidv7 > b.uuidv7 ? 1 : -1);
|
|
112
124
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const next = siblings[index + 1];
|
|
117
|
-
insertBetween(prev, sibling, sibling.next);
|
|
118
|
-
prev = sibling;
|
|
119
|
-
if (next) {
|
|
120
|
-
prev.next = next;
|
|
121
|
-
next.prev = prev;
|
|
122
|
-
} else if (predecessorNext && !siblingSet.has(predecessorNext)) {
|
|
123
|
-
prev.next = predecessorNext;
|
|
124
|
-
predecessorNext.prev = prev;
|
|
125
|
-
} else {
|
|
126
|
-
prev.next = void 0;
|
|
127
|
-
}
|
|
125
|
+
if (frame.siblingIndex >= frame.siblings.length) {
|
|
126
|
+
void stack.pop();
|
|
127
|
+
continue;
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
const sibling = frame.siblings[frame.siblingIndex];
|
|
130
|
+
frame.siblingIndex++;
|
|
131
|
+
if (!sibling) continue;
|
|
132
|
+
if (crListReplica.parentMap.get(sibling.uuidv7) !== sibling) continue;
|
|
133
|
+
sibling.index = index;
|
|
134
|
+
index++;
|
|
135
|
+
void linkEntryBetween(previous, sibling, void 0);
|
|
136
|
+
if (!first) first = sibling;
|
|
137
|
+
previous = sibling;
|
|
138
|
+
void stack.push({
|
|
139
|
+
predecessorIdentifier: sibling.uuidv7,
|
|
140
|
+
siblingIndex: 0
|
|
141
|
+
});
|
|
132
142
|
}
|
|
133
|
-
}
|
|
143
|
+
};
|
|
144
|
+
void appendChildren("\0");
|
|
145
|
+
const detachedPredecessors = [];
|
|
146
|
+
for (const predecessorIdentifier of crListReplica.childrenMap.keys()) {
|
|
147
|
+
if (predecessorIdentifier !== "\0" && !crListReplica.parentMap.get(predecessorIdentifier))
|
|
148
|
+
void detachedPredecessors.push(predecessorIdentifier);
|
|
149
|
+
}
|
|
150
|
+
if (detachedPredecessors.length > 1)
|
|
151
|
+
detachedPredecessors.sort((a, b) => a > b ? 1 : -1);
|
|
152
|
+
for (const predecessorIdentifier of detachedPredecessors)
|
|
153
|
+
void appendChildren(predecessorIdentifier);
|
|
154
|
+
crListReplica.cursor = first;
|
|
155
|
+
crListReplica.cursorIndex = first ? 0 : void 0;
|
|
156
|
+
if (first) void entries.set(0, first);
|
|
157
|
+
crListReplica.index = entries;
|
|
134
158
|
crListReplica.size = crListReplica.parentMap.size;
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
// src/.helpers/
|
|
138
|
-
import { isUuidV7
|
|
139
|
-
function
|
|
161
|
+
// src/.helpers/materializeSnapshotEntry/index.ts
|
|
162
|
+
import { isUuidV7 } from "@sovereignbase/utils";
|
|
163
|
+
function materializeSnapshotEntry(valueEntry, crListReplica) {
|
|
140
164
|
if (valueEntry === null || valueEntry === void 0) return void 0;
|
|
141
165
|
if (!isUuidV7(valueEntry.uuidv7) || crListReplica.tombstones.has(valueEntry.uuidv7) || crListReplica.parentMap.has(valueEntry.uuidv7) || !isUuidV7(valueEntry.predecessor) && valueEntry.predecessor !== "\0" && !crListReplica.tombstones.has(valueEntry.predecessor))
|
|
142
166
|
return void 0;
|
|
143
|
-
const [cloned, copiedValue] = safeStructuredClone(valueEntry.value);
|
|
144
|
-
if (!cloned) return void 0;
|
|
145
167
|
return {
|
|
146
168
|
uuidv7: valueEntry.uuidv7,
|
|
147
|
-
value:
|
|
169
|
+
value: valueEntry.value,
|
|
148
170
|
predecessor: valueEntry.predecessor,
|
|
149
171
|
index: 0,
|
|
150
172
|
next: void 0,
|
|
@@ -152,59 +174,65 @@ function transformSnapshotEntryToStateEntry(valueEntry, crListReplica) {
|
|
|
152
174
|
};
|
|
153
175
|
}
|
|
154
176
|
|
|
155
|
-
// src/.helpers/
|
|
156
|
-
function
|
|
157
|
-
crListReplica.parentMap.set(linkedListEntry.uuidv7, linkedListEntry);
|
|
177
|
+
// src/.helpers/attachEntryToIndexes/index.ts
|
|
178
|
+
function attachEntryToIndexes(crListReplica, linkedListEntry, deltaBuf) {
|
|
179
|
+
void crListReplica.parentMap.set(linkedListEntry.uuidv7, linkedListEntry);
|
|
158
180
|
const siblings = crListReplica.childrenMap.get(linkedListEntry.predecessor);
|
|
159
181
|
if (siblings) {
|
|
160
|
-
siblings.push(linkedListEntry);
|
|
182
|
+
void siblings.push(linkedListEntry);
|
|
161
183
|
} else {
|
|
162
|
-
crListReplica.childrenMap.set(linkedListEntry.predecessor, [
|
|
184
|
+
void crListReplica.childrenMap.set(linkedListEntry.predecessor, [
|
|
163
185
|
linkedListEntry
|
|
164
186
|
]);
|
|
165
187
|
}
|
|
166
188
|
if (deltaBuf && !Array.isArray(deltaBuf.values)) deltaBuf.values = [];
|
|
167
189
|
if (deltaBuf?.values)
|
|
168
|
-
deltaBuf.values.push({
|
|
190
|
+
void deltaBuf.values.push({
|
|
169
191
|
uuidv7: linkedListEntry.uuidv7,
|
|
170
192
|
value: linkedListEntry.value,
|
|
171
193
|
predecessor: linkedListEntry.predecessor
|
|
172
194
|
});
|
|
173
195
|
}
|
|
174
196
|
|
|
175
|
-
// src/.helpers/
|
|
176
|
-
function
|
|
177
|
-
crListReplica.parentMap.delete(linkedListEntry.uuidv7);
|
|
197
|
+
// src/.helpers/detachEntryFromIndexes/index.ts
|
|
198
|
+
function detachEntryFromIndexes(crListReplica, linkedListEntry) {
|
|
199
|
+
void crListReplica.parentMap.delete(linkedListEntry.uuidv7);
|
|
178
200
|
const siblings = crListReplica.childrenMap.get(linkedListEntry.predecessor);
|
|
179
201
|
if (!siblings) return;
|
|
180
202
|
const index = siblings.indexOf(linkedListEntry);
|
|
181
|
-
if (index !== -1) siblings.splice(index, 1);
|
|
203
|
+
if (index !== -1) void siblings.splice(index, 1);
|
|
182
204
|
}
|
|
183
205
|
|
|
184
|
-
// src/.helpers/
|
|
185
|
-
function
|
|
206
|
+
// src/.helpers/deleteLiveEntry/index.ts
|
|
207
|
+
function deleteLiveEntry(crListReplica, linkedListEntry, deltaBuf) {
|
|
186
208
|
const prev = linkedListEntry.prev;
|
|
187
209
|
const next = linkedListEntry.next;
|
|
188
|
-
crListReplica.tombstones.add(linkedListEntry.uuidv7);
|
|
210
|
+
void crListReplica.tombstones.add(linkedListEntry.uuidv7);
|
|
189
211
|
if (deltaBuf && !Array.isArray(deltaBuf.tombstones)) deltaBuf.tombstones = [];
|
|
190
|
-
deltaBuf?.tombstones?.push(linkedListEntry.uuidv7);
|
|
212
|
+
void deltaBuf?.tombstones?.push(linkedListEntry.uuidv7);
|
|
191
213
|
if (prev) prev.next = next;
|
|
192
214
|
if (next) {
|
|
193
215
|
next.prev = prev;
|
|
194
216
|
}
|
|
195
|
-
void
|
|
217
|
+
void detachEntryFromIndexes(crListReplica, linkedListEntry);
|
|
196
218
|
if (crListReplica.cursor === linkedListEntry)
|
|
197
219
|
crListReplica.cursor = next ?? prev;
|
|
220
|
+
if (!crListReplica.cursor) crListReplica.cursorIndex = void 0;
|
|
198
221
|
linkedListEntry.prev = void 0;
|
|
199
222
|
linkedListEntry.next = void 0;
|
|
200
223
|
crListReplica.size = crListReplica.parentMap.size;
|
|
201
224
|
}
|
|
202
225
|
|
|
226
|
+
// src/.helpers/dispatchCRListEvent/index.ts
|
|
227
|
+
function dispatchCRListEvent(eventTarget, type, detail) {
|
|
228
|
+
void eventTarget.dispatchEvent(new CustomEvent(type, { detail }));
|
|
229
|
+
}
|
|
230
|
+
|
|
203
231
|
// src/.helpers/moveEntryToPredecessor/index.ts
|
|
204
232
|
function moveEntryToPredecessor(crListReplica, linkedListEntry, predecessor, deltaBuf) {
|
|
205
|
-
void
|
|
233
|
+
void detachEntryFromIndexes(crListReplica, linkedListEntry);
|
|
206
234
|
linkedListEntry.predecessor = predecessor;
|
|
207
|
-
void
|
|
235
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, deltaBuf);
|
|
208
236
|
}
|
|
209
237
|
|
|
210
238
|
// src/.helpers/indexFromPropertyKey/index.ts
|
|
@@ -221,6 +249,8 @@ function __create(snapshot) {
|
|
|
221
249
|
const crListReplica = {
|
|
222
250
|
size: 0,
|
|
223
251
|
cursor: void 0,
|
|
252
|
+
cursorIndex: void 0,
|
|
253
|
+
index: /* @__PURE__ */ new Map(),
|
|
224
254
|
tombstones: /* @__PURE__ */ new Set(),
|
|
225
255
|
parentMap: /* @__PURE__ */ new Map(),
|
|
226
256
|
childrenMap: /* @__PURE__ */ new Map()
|
|
@@ -230,36 +260,50 @@ function __create(snapshot) {
|
|
|
230
260
|
for (const tombstone of snapshot.tombstones) {
|
|
231
261
|
if (crListReplica.tombstones.has(tombstone) || !isUuidV72(tombstone))
|
|
232
262
|
continue;
|
|
233
|
-
crListReplica.tombstones.add(tombstone);
|
|
263
|
+
void crListReplica.tombstones.add(tombstone);
|
|
234
264
|
}
|
|
235
265
|
}
|
|
236
266
|
if (!Object.hasOwn(snapshot, "values") || !Array.isArray(snapshot.values))
|
|
237
267
|
return crListReplica;
|
|
268
|
+
let canUseLinearProjection = true;
|
|
269
|
+
let previous = void 0;
|
|
238
270
|
for (const valueEntry of snapshot.values) {
|
|
239
|
-
const linkedListEntry =
|
|
271
|
+
const linkedListEntry = materializeSnapshotEntry(
|
|
240
272
|
valueEntry,
|
|
241
273
|
crListReplica
|
|
242
274
|
);
|
|
243
275
|
if (!linkedListEntry) continue;
|
|
244
|
-
void
|
|
276
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry);
|
|
277
|
+
if (canUseLinearProjection && linkedListEntry.predecessor === (previous?.uuidv7 ?? "\0")) {
|
|
278
|
+
linkedListEntry.index = crListReplica.parentMap.size - 1;
|
|
279
|
+
void linkEntryBetween(previous, linkedListEntry, void 0);
|
|
280
|
+
previous = linkedListEntry;
|
|
281
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
canUseLinearProjection = false;
|
|
285
|
+
}
|
|
286
|
+
if (canUseLinearProjection) {
|
|
287
|
+
crListReplica.cursor = previous;
|
|
288
|
+
crListReplica.cursorIndex = previous ? crListReplica.parentMap.size - 1 : void 0;
|
|
289
|
+
crListReplica.size = crListReplica.parentMap.size;
|
|
290
|
+
return crListReplica;
|
|
245
291
|
}
|
|
246
|
-
void
|
|
247
|
-
void assertListIndices(crListReplica);
|
|
292
|
+
void rebuildLiveProjection(crListReplica);
|
|
248
293
|
return crListReplica;
|
|
249
294
|
}
|
|
250
295
|
|
|
251
296
|
// src/core/crud/read/index.ts
|
|
252
297
|
function __read(targetIndex, crListReplica) {
|
|
253
298
|
try {
|
|
254
|
-
void
|
|
255
|
-
return
|
|
299
|
+
void seekCursorToIndex(targetIndex, crListReplica);
|
|
300
|
+
return crListReplica.cursor?.value;
|
|
256
301
|
} catch {
|
|
257
302
|
return void 0;
|
|
258
303
|
}
|
|
259
304
|
}
|
|
260
305
|
|
|
261
306
|
// src/core/crud/update/index.ts
|
|
262
|
-
import { safeStructuredClone as safeStructuredClone2 } from "@sovereignbase/utils";
|
|
263
307
|
import { v7 as uuidv7 } from "uuid";
|
|
264
308
|
function __update(listIndex, listValues, crListReplica, mode) {
|
|
265
309
|
if (listIndex < 0 || listIndex > crListReplica.size)
|
|
@@ -272,14 +316,11 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
272
316
|
if (listValues.length === 0) return false;
|
|
273
317
|
const change = {};
|
|
274
318
|
const delta = { values: [], tombstones: [] };
|
|
275
|
-
let shiftCursor;
|
|
276
319
|
for (const listValue of listValues) {
|
|
277
|
-
const [cloned, copiedValue] = safeStructuredClone2(listValue);
|
|
278
|
-
if (!cloned) throw new CRListError("VALUE_NOT_CLONEABLE");
|
|
279
320
|
const v7 = uuidv7();
|
|
280
321
|
const linkedListEntry = {
|
|
281
322
|
uuidv7: v7,
|
|
282
|
-
value:
|
|
323
|
+
value: listValue,
|
|
283
324
|
predecessor: "\0",
|
|
284
325
|
index: 0,
|
|
285
326
|
next: void 0,
|
|
@@ -290,26 +331,35 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
290
331
|
if (listIndex === crListReplica.size) {
|
|
291
332
|
if (crListReplica.size === 0) {
|
|
292
333
|
crListReplica.cursor = linkedListEntry;
|
|
293
|
-
|
|
334
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
335
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
336
|
+
crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
294
337
|
change[linkedListEntry.index] = linkedListEntry.value;
|
|
295
338
|
break;
|
|
296
339
|
}
|
|
297
|
-
void
|
|
340
|
+
void seekCursorToIndex(crListReplica.size - 1, crListReplica);
|
|
298
341
|
if (!crListReplica.cursor) return false;
|
|
299
|
-
linkedListEntry.index = crListReplica.
|
|
342
|
+
linkedListEntry.index = (crListReplica.cursorIndex ?? 0) + 1;
|
|
300
343
|
linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
|
|
301
|
-
|
|
302
|
-
|
|
344
|
+
void linkEntryBetween(
|
|
345
|
+
crListReplica.cursor,
|
|
346
|
+
linkedListEntry,
|
|
347
|
+
void 0
|
|
348
|
+
);
|
|
349
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
303
350
|
crListReplica.cursor = linkedListEntry;
|
|
304
|
-
|
|
351
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
352
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
353
|
+
change[linkedListEntry.index] = linkedListEntry.value;
|
|
305
354
|
break;
|
|
306
355
|
}
|
|
307
|
-
void
|
|
356
|
+
void seekCursorToIndex(listIndex, crListReplica);
|
|
308
357
|
if (!crListReplica.cursor) return false;
|
|
309
358
|
const entryToOverwrite = crListReplica.cursor;
|
|
359
|
+
const actualIndex = crListReplica.cursorIndex ?? listIndex;
|
|
310
360
|
linkedListEntry.predecessor = entryToOverwrite.predecessor;
|
|
311
|
-
linkedListEntry.index =
|
|
312
|
-
|
|
361
|
+
linkedListEntry.index = actualIndex;
|
|
362
|
+
void linkEntryBetween(
|
|
313
363
|
entryToOverwrite.prev,
|
|
314
364
|
linkedListEntry,
|
|
315
365
|
entryToOverwrite.next
|
|
@@ -324,34 +374,38 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
324
374
|
);
|
|
325
375
|
}
|
|
326
376
|
}
|
|
327
|
-
void
|
|
328
|
-
crListReplica.tombstones.add(entryToOverwrite.uuidv7);
|
|
329
|
-
delta.tombstones?.push(entryToOverwrite.uuidv7);
|
|
330
|
-
void
|
|
377
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
378
|
+
void crListReplica.tombstones.add(entryToOverwrite.uuidv7);
|
|
379
|
+
void delta.tombstones?.push(entryToOverwrite.uuidv7);
|
|
380
|
+
void detachEntryFromIndexes(crListReplica, entryToOverwrite);
|
|
331
381
|
entryToOverwrite.next = void 0;
|
|
332
382
|
entryToOverwrite.prev = void 0;
|
|
333
383
|
crListReplica.cursor = linkedListEntry;
|
|
334
|
-
|
|
384
|
+
crListReplica.cursorIndex = actualIndex;
|
|
385
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
386
|
+
change[actualIndex] = linkedListEntry.value;
|
|
335
387
|
break;
|
|
336
388
|
}
|
|
337
389
|
case "after": {
|
|
338
390
|
if (crListReplica.size === 0 && listIndex === 0) {
|
|
339
391
|
crListReplica.cursor = linkedListEntry;
|
|
340
|
-
|
|
341
|
-
|
|
392
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
393
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
394
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
395
|
+
change[linkedListEntry.index] = linkedListEntry.value;
|
|
342
396
|
break;
|
|
343
397
|
}
|
|
344
398
|
if (listIndex === crListReplica.size) {
|
|
345
|
-
void
|
|
399
|
+
void seekCursorToIndex(crListReplica.size - 1, crListReplica);
|
|
346
400
|
} else {
|
|
347
|
-
void
|
|
401
|
+
void seekCursorToIndex(listIndex, crListReplica);
|
|
348
402
|
}
|
|
349
403
|
if (!crListReplica.cursor) return false;
|
|
404
|
+
const actualIndex = crListReplica.cursorIndex ?? listIndex;
|
|
350
405
|
const next = listIndex === crListReplica.size ? void 0 : crListReplica.cursor.next;
|
|
351
|
-
|
|
352
|
-
linkedListEntry.index = crListReplica.cursor.index + 1;
|
|
406
|
+
linkedListEntry.index = actualIndex + 1;
|
|
353
407
|
linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
|
|
354
|
-
|
|
408
|
+
void linkEntryBetween(crListReplica.cursor, linkedListEntry, next);
|
|
355
409
|
if (next) {
|
|
356
410
|
if (next.predecessor === crListReplica.cursor.uuidv7) {
|
|
357
411
|
void moveEntryToPredecessor(
|
|
@@ -362,27 +416,32 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
362
416
|
);
|
|
363
417
|
}
|
|
364
418
|
}
|
|
365
|
-
void
|
|
419
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
366
420
|
crListReplica.cursor = linkedListEntry;
|
|
367
|
-
|
|
421
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
422
|
+
if (next) crListReplica.index = /* @__PURE__ */ new Map();
|
|
423
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
424
|
+
change[linkedListEntry.index] = linkedListEntry.value;
|
|
368
425
|
break;
|
|
369
426
|
}
|
|
370
427
|
case "before": {
|
|
371
428
|
if (crListReplica.size === 0 && listIndex === 0) {
|
|
372
429
|
crListReplica.cursor = linkedListEntry;
|
|
373
|
-
|
|
374
|
-
|
|
430
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
431
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
432
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
433
|
+
change[linkedListEntry.index] = linkedListEntry.value;
|
|
375
434
|
mode = "after";
|
|
376
435
|
listIndex = linkedListEntry.index - 1;
|
|
377
436
|
break;
|
|
378
437
|
}
|
|
379
|
-
void
|
|
438
|
+
void seekCursorToIndex(listIndex, crListReplica);
|
|
380
439
|
if (!crListReplica.cursor) return false;
|
|
440
|
+
const actualIndex = crListReplica.cursorIndex ?? listIndex;
|
|
381
441
|
const prev = crListReplica.cursor.prev;
|
|
382
|
-
|
|
383
|
-
linkedListEntry.index = crListReplica.cursor.index;
|
|
442
|
+
linkedListEntry.index = actualIndex;
|
|
384
443
|
linkedListEntry.predecessor = prev?.uuidv7 ?? "\0";
|
|
385
|
-
|
|
444
|
+
void linkEntryBetween(prev, linkedListEntry, crListReplica.cursor);
|
|
386
445
|
if (crListReplica.cursor.predecessor === linkedListEntry.predecessor) {
|
|
387
446
|
void moveEntryToPredecessor(
|
|
388
447
|
crListReplica,
|
|
@@ -391,9 +450,12 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
391
450
|
delta
|
|
392
451
|
);
|
|
393
452
|
}
|
|
394
|
-
void
|
|
453
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry, delta);
|
|
395
454
|
crListReplica.cursor = linkedListEntry;
|
|
396
|
-
|
|
455
|
+
crListReplica.cursorIndex = actualIndex;
|
|
456
|
+
crListReplica.index = /* @__PURE__ */ new Map();
|
|
457
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
458
|
+
change[actualIndex] = linkedListEntry.value;
|
|
397
459
|
mode = "after";
|
|
398
460
|
listIndex = linkedListEntry.index - 1;
|
|
399
461
|
break;
|
|
@@ -402,11 +464,6 @@ function __update(listIndex, listValues, crListReplica, mode) {
|
|
|
402
464
|
crListReplica.size = crListReplica.parentMap.size;
|
|
403
465
|
listIndex++;
|
|
404
466
|
}
|
|
405
|
-
if (mode !== "overwrite")
|
|
406
|
-
while (shiftCursor) {
|
|
407
|
-
shiftCursor.index += listValues.length;
|
|
408
|
-
shiftCursor = shiftCursor.next;
|
|
409
|
-
}
|
|
410
467
|
return { change, delta };
|
|
411
468
|
}
|
|
412
469
|
|
|
@@ -420,22 +477,29 @@ function __delete(crListReplica, startIndex, endIndex) {
|
|
|
420
477
|
throw new CRListError("INDEX_OUT_OF_BOUNDS");
|
|
421
478
|
const deleteCount = Math.min(targetEndIndex, crListReplica.size) - listIndex;
|
|
422
479
|
if (deleteCount <= 0) return false;
|
|
423
|
-
void
|
|
480
|
+
void seekCursorToIndex(listIndex, crListReplica);
|
|
424
481
|
if (!crListReplica.cursor) return false;
|
|
425
482
|
let current = crListReplica.cursor;
|
|
426
483
|
let deleted = 0;
|
|
484
|
+
let currentIndex = crListReplica.cursorIndex ?? listIndex;
|
|
427
485
|
while (current && deleted < deleteCount) {
|
|
428
486
|
const next = current.next;
|
|
429
|
-
change[
|
|
430
|
-
void
|
|
487
|
+
change[currentIndex] = void 0;
|
|
488
|
+
void crListReplica.index?.delete(currentIndex);
|
|
489
|
+
void deleteLiveEntry(crListReplica, current, delta);
|
|
431
490
|
current = next;
|
|
491
|
+
currentIndex++;
|
|
432
492
|
deleted++;
|
|
433
493
|
}
|
|
434
494
|
crListReplica.size = crListReplica.parentMap.size;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
495
|
+
crListReplica.cursor = current ?? crListReplica.cursor;
|
|
496
|
+
crListReplica.cursorIndex = current ? listIndex : crListReplica.cursor ? Math.max(0, crListReplica.size - 1) : void 0;
|
|
497
|
+
crListReplica.index = /* @__PURE__ */ new Map();
|
|
498
|
+
if (crListReplica.cursor && crListReplica.cursorIndex !== void 0)
|
|
499
|
+
void crListReplica.index.set(
|
|
500
|
+
crListReplica.cursorIndex,
|
|
501
|
+
crListReplica.cursor
|
|
502
|
+
);
|
|
439
503
|
return { change, delta };
|
|
440
504
|
}
|
|
441
505
|
|
|
@@ -447,22 +511,42 @@ function __merge(crListReplica, crListDelta) {
|
|
|
447
511
|
const newTombsIndices = [];
|
|
448
512
|
const change = {};
|
|
449
513
|
let needsRelink = false;
|
|
514
|
+
if (Object.hasOwn(crListDelta, "values") && Array.isArray(crListDelta.values) && crListDelta.values.length === 1 && (!Object.hasOwn(crListDelta, "tombstones") || Array.isArray(crListDelta.tombstones) && crListDelta.tombstones.length === 0)) {
|
|
515
|
+
const linkedListEntry = materializeSnapshotEntry(
|
|
516
|
+
crListDelta.values[0],
|
|
517
|
+
crListReplica
|
|
518
|
+
);
|
|
519
|
+
if (!linkedListEntry) return false;
|
|
520
|
+
const predecessor = linkedListEntry.predecessor === "\0" ? void 0 : crListReplica.parentMap.get(linkedListEntry.predecessor);
|
|
521
|
+
if (linkedListEntry.predecessor === "\0" && crListReplica.size === 0 || predecessor && !predecessor.next) {
|
|
522
|
+
linkedListEntry.prev = predecessor;
|
|
523
|
+
linkedListEntry.index = crListReplica.size;
|
|
524
|
+
if (predecessor) predecessor.next = linkedListEntry;
|
|
525
|
+
crListReplica.cursor = linkedListEntry;
|
|
526
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
527
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry);
|
|
528
|
+
crListReplica.size = crListReplica.parentMap.size;
|
|
529
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
530
|
+
return { [linkedListEntry.index]: linkedListEntry.value };
|
|
531
|
+
}
|
|
532
|
+
}
|
|
450
533
|
if (Object.hasOwn(crListDelta, "tombstones") && Array.isArray(crListDelta.tombstones)) {
|
|
451
534
|
for (const tombstone of crListDelta.tombstones) {
|
|
452
535
|
if (crListReplica.tombstones.has(tombstone) || !isUuidV73(tombstone))
|
|
453
536
|
continue;
|
|
454
|
-
crListReplica.tombstones.add(tombstone);
|
|
537
|
+
void crListReplica.tombstones.add(tombstone);
|
|
455
538
|
const linkedListEntry = crListReplica.parentMap.get(tombstone);
|
|
456
539
|
if (linkedListEntry) {
|
|
457
540
|
void newTombsIndices.push(linkedListEntry.index);
|
|
458
|
-
void
|
|
541
|
+
void crListReplica.index?.delete(linkedListEntry.index);
|
|
542
|
+
void deleteLiveEntry(crListReplica, linkedListEntry);
|
|
459
543
|
needsRelink = true;
|
|
460
544
|
}
|
|
461
545
|
}
|
|
462
546
|
}
|
|
463
547
|
if (!Object.hasOwn(crListDelta, "values") || !Array.isArray(crListDelta.values)) {
|
|
464
548
|
if (newTombsIndices.length === 0) return false;
|
|
465
|
-
void
|
|
549
|
+
void rebuildLiveIndex(crListReplica);
|
|
466
550
|
for (const index of newTombsIndices) {
|
|
467
551
|
change[index] = void 0;
|
|
468
552
|
}
|
|
@@ -472,7 +556,8 @@ function __merge(crListReplica, crListDelta) {
|
|
|
472
556
|
if (valueEntry === null || valueEntry === void 0) continue;
|
|
473
557
|
const existingEntry = crListReplica.parentMap.get(valueEntry.uuidv7);
|
|
474
558
|
if (existingEntry) {
|
|
475
|
-
if (crListReplica.tombstones.has(valueEntry.uuidv7)
|
|
559
|
+
if (crListReplica.tombstones.has(valueEntry.uuidv7)) continue;
|
|
560
|
+
if (valueEntry.predecessor !== "\0" && !isUuidV73(valueEntry.predecessor))
|
|
476
561
|
continue;
|
|
477
562
|
if (existingEntry.predecessor >= valueEntry.predecessor) continue;
|
|
478
563
|
void moveEntryToPredecessor(
|
|
@@ -483,41 +568,44 @@ function __merge(crListReplica, crListDelta) {
|
|
|
483
568
|
needsRelink = true;
|
|
484
569
|
continue;
|
|
485
570
|
}
|
|
486
|
-
const linkedListEntry =
|
|
571
|
+
const linkedListEntry = materializeSnapshotEntry(
|
|
487
572
|
valueEntry,
|
|
488
573
|
crListReplica
|
|
489
574
|
);
|
|
490
575
|
if (!linkedListEntry) continue;
|
|
491
576
|
const predecessor = linkedListEntry.predecessor === "\0" ? void 0 : crListReplica.parentMap.get(linkedListEntry.predecessor);
|
|
492
|
-
void
|
|
577
|
+
void attachEntryToIndexes(crListReplica, linkedListEntry);
|
|
493
578
|
void newVals.push(linkedListEntry);
|
|
494
579
|
if (!needsRelink && linkedListEntry.predecessor === "\0") {
|
|
495
580
|
if (crListReplica.size === 0) {
|
|
496
581
|
crListReplica.cursor = linkedListEntry;
|
|
582
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
497
583
|
crListReplica.size = crListReplica.parentMap.size;
|
|
584
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
498
585
|
} else {
|
|
499
586
|
needsRelink = true;
|
|
500
587
|
}
|
|
501
588
|
} else if (!needsRelink && predecessor && !predecessor.next) {
|
|
502
589
|
linkedListEntry.prev = predecessor;
|
|
503
|
-
linkedListEntry.index =
|
|
590
|
+
linkedListEntry.index = crListReplica.size;
|
|
504
591
|
predecessor.next = linkedListEntry;
|
|
505
592
|
crListReplica.cursor = linkedListEntry;
|
|
593
|
+
crListReplica.cursorIndex = linkedListEntry.index;
|
|
506
594
|
crListReplica.size = crListReplica.parentMap.size;
|
|
595
|
+
void crListReplica.index?.set(linkedListEntry.index, linkedListEntry);
|
|
507
596
|
} else {
|
|
508
597
|
needsRelink = true;
|
|
509
598
|
}
|
|
510
599
|
}
|
|
511
600
|
if (needsRelink) {
|
|
512
|
-
void
|
|
513
|
-
void assertListIndices(crListReplica);
|
|
601
|
+
void rebuildLiveProjection(crListReplica);
|
|
514
602
|
}
|
|
515
603
|
if (newTombsIndices.length === 0 && newVals.length === 0) return false;
|
|
516
604
|
for (const index of newTombsIndices) {
|
|
517
605
|
change[index] = void 0;
|
|
518
606
|
}
|
|
519
607
|
for (const val of newVals) {
|
|
520
|
-
change[val.index] =
|
|
608
|
+
change[val.index] = val.value;
|
|
521
609
|
}
|
|
522
610
|
return change;
|
|
523
611
|
}
|
|
@@ -525,7 +613,7 @@ function __merge(crListReplica, crListDelta) {
|
|
|
525
613
|
// src/core/mags/acknowledge/index.ts
|
|
526
614
|
function __acknowledge(crListReplica) {
|
|
527
615
|
let largest = false;
|
|
528
|
-
crListReplica.tombstones.forEach((tombstone) => {
|
|
616
|
+
void crListReplica.tombstones.forEach((tombstone) => {
|
|
529
617
|
if (largest === false || largest < tombstone) largest = tombstone;
|
|
530
618
|
});
|
|
531
619
|
if (typeof largest === "string") return largest;
|
|
@@ -536,12 +624,12 @@ function __acknowledge(crListReplica) {
|
|
|
536
624
|
import { isUuidV7 as isUuidV74 } from "@sovereignbase/utils";
|
|
537
625
|
function __garbageCollect(frontiers, crListReplica) {
|
|
538
626
|
if (!Array.isArray(frontiers)) return;
|
|
539
|
-
frontiers.sort();
|
|
627
|
+
void frontiers.sort();
|
|
540
628
|
const smallest = frontiers.find((frontier) => isUuidV74(frontier));
|
|
541
629
|
if (typeof smallest !== "string") return;
|
|
542
|
-
crListReplica.tombstones.forEach((tombstone, __, tombstones) => {
|
|
630
|
+
void crListReplica.tombstones.forEach((tombstone, __, tombstones) => {
|
|
543
631
|
if (tombstone <= smallest) {
|
|
544
|
-
tombstones.delete(tombstone);
|
|
632
|
+
void tombstones.delete(tombstone);
|
|
545
633
|
}
|
|
546
634
|
});
|
|
547
635
|
}
|
|
@@ -554,7 +642,7 @@ function __snapshot(crListReplica) {
|
|
|
554
642
|
if (!linkedListEntry) throw new CRListError("LIST_INTEGRITY_VIOLATION");
|
|
555
643
|
return {
|
|
556
644
|
uuidv7: linkedListEntry.uuidv7,
|
|
557
|
-
value:
|
|
645
|
+
value: linkedListEntry.value,
|
|
558
646
|
predecessor: linkedListEntry.predecessor
|
|
559
647
|
};
|
|
560
648
|
}
|
|
@@ -566,12 +654,12 @@ function __snapshot(crListReplica) {
|
|
|
566
654
|
// src/CRList/class.ts
|
|
567
655
|
var CRList = class {
|
|
568
656
|
/**
|
|
569
|
-
* Creates a replicated list from an optional
|
|
657
|
+
* Creates a replicated list from an optional CRList snapshot.
|
|
570
658
|
*
|
|
571
659
|
* @param snapshot - A previously emitted CRList snapshot.
|
|
572
660
|
*/
|
|
573
661
|
constructor(snapshot) {
|
|
574
|
-
Object.defineProperties(this, {
|
|
662
|
+
void Object.defineProperties(this, {
|
|
575
663
|
state: {
|
|
576
664
|
value: __create(snapshot),
|
|
577
665
|
enumerable: false,
|
|
@@ -604,13 +692,9 @@ var CRList = class {
|
|
|
604
692
|
if (!result) return false;
|
|
605
693
|
const { delta, change } = result;
|
|
606
694
|
if (delta)
|
|
607
|
-
void target.eventTarget
|
|
608
|
-
new CustomEvent("delta", { detail: delta })
|
|
609
|
-
);
|
|
695
|
+
void dispatchCRListEvent(target.eventTarget, "delta", delta);
|
|
610
696
|
if (change)
|
|
611
|
-
void target.eventTarget
|
|
612
|
-
new CustomEvent("change", { detail: change })
|
|
613
|
-
);
|
|
697
|
+
void dispatchCRListEvent(target.eventTarget, "change", change);
|
|
614
698
|
return true;
|
|
615
699
|
} catch (error) {
|
|
616
700
|
if (error instanceof CRListError) throw error;
|
|
@@ -624,16 +708,10 @@ var CRList = class {
|
|
|
624
708
|
const result = __delete(target.state, listIndex, listIndex + 1);
|
|
625
709
|
if (!result) return false;
|
|
626
710
|
const { delta, change } = result;
|
|
627
|
-
if (delta)
|
|
628
|
-
void target.eventTarget
|
|
629
|
-
|
|
630
|
-
);
|
|
631
|
-
}
|
|
632
|
-
if (change) {
|
|
633
|
-
void target.eventTarget.dispatchEvent(
|
|
634
|
-
new CustomEvent("change", { detail: change })
|
|
635
|
-
);
|
|
636
|
-
}
|
|
711
|
+
if (delta)
|
|
712
|
+
void dispatchCRListEvent(target.eventTarget, "delta", delta);
|
|
713
|
+
if (change)
|
|
714
|
+
void dispatchCRListEvent(target.eventTarget, "change", change);
|
|
637
715
|
return true;
|
|
638
716
|
} catch (error) {
|
|
639
717
|
if (error instanceof CRListError) throw error;
|
|
@@ -678,14 +756,8 @@ var CRList = class {
|
|
|
678
756
|
const result = __update(beforeIndex ?? 0, [value], this.state, "before");
|
|
679
757
|
if (!result) return;
|
|
680
758
|
const { delta, change } = result;
|
|
681
|
-
if (delta)
|
|
682
|
-
|
|
683
|
-
new CustomEvent("delta", { detail: delta })
|
|
684
|
-
);
|
|
685
|
-
if (change)
|
|
686
|
-
void this.eventTarget.dispatchEvent(
|
|
687
|
-
new CustomEvent("change", { detail: change })
|
|
688
|
-
);
|
|
759
|
+
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
760
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
689
761
|
}
|
|
690
762
|
/**
|
|
691
763
|
* Inserts a value after an index.
|
|
@@ -704,14 +776,8 @@ var CRList = class {
|
|
|
704
776
|
);
|
|
705
777
|
if (!result) return;
|
|
706
778
|
const { delta, change } = result;
|
|
707
|
-
if (delta)
|
|
708
|
-
|
|
709
|
-
new CustomEvent("delta", { detail: delta })
|
|
710
|
-
);
|
|
711
|
-
if (change)
|
|
712
|
-
void this.eventTarget.dispatchEvent(
|
|
713
|
-
new CustomEvent("change", { detail: change })
|
|
714
|
-
);
|
|
779
|
+
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
780
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
715
781
|
}
|
|
716
782
|
/**
|
|
717
783
|
* Removes the entry at an index.
|
|
@@ -722,28 +788,26 @@ var CRList = class {
|
|
|
722
788
|
const result = __delete(this.state, index, index + 1);
|
|
723
789
|
if (!result) return;
|
|
724
790
|
const { delta, change } = result;
|
|
725
|
-
if (delta)
|
|
726
|
-
|
|
727
|
-
new CustomEvent("delta", { detail: delta })
|
|
728
|
-
);
|
|
729
|
-
if (change)
|
|
730
|
-
void this.eventTarget.dispatchEvent(
|
|
731
|
-
new CustomEvent("change", { detail: change })
|
|
732
|
-
);
|
|
791
|
+
if (delta) void dispatchCRListEvent(this.eventTarget, "delta", delta);
|
|
792
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
733
793
|
}
|
|
734
794
|
/**
|
|
735
|
-
* Returns the first live value
|
|
795
|
+
* Returns the first live value matching a predicate in index order.
|
|
736
796
|
*
|
|
737
|
-
* Predicate values are
|
|
738
|
-
* list.
|
|
797
|
+
* Predicate values are live references. Mutating them directly can mutate the
|
|
798
|
+
* list without emitting a delta.
|
|
739
799
|
*
|
|
740
|
-
* @param predicate - Function to test each value
|
|
800
|
+
* @param predicate - Function to test each live value.
|
|
741
801
|
* @param thisArg - Optional `this` value for the predicate.
|
|
742
802
|
*/
|
|
743
803
|
find(predicate, thisArg) {
|
|
804
|
+
let linkedListEntry = this.state.index?.get(0) ?? this.state.cursor;
|
|
805
|
+
while (linkedListEntry?.prev) linkedListEntry = linkedListEntry.prev;
|
|
744
806
|
let index = 0;
|
|
745
|
-
|
|
746
|
-
if (predicate.call(thisArg, value, index, this))
|
|
807
|
+
while (linkedListEntry) {
|
|
808
|
+
if (predicate.call(thisArg, linkedListEntry.value, index, this))
|
|
809
|
+
return linkedListEntry.value;
|
|
810
|
+
linkedListEntry = linkedListEntry.next;
|
|
747
811
|
index++;
|
|
748
812
|
}
|
|
749
813
|
return void 0;
|
|
@@ -757,20 +821,14 @@ var CRList = class {
|
|
|
757
821
|
*/
|
|
758
822
|
merge(delta) {
|
|
759
823
|
const change = __merge(this.state, delta);
|
|
760
|
-
if (change)
|
|
761
|
-
void this.eventTarget.dispatchEvent(
|
|
762
|
-
new CustomEvent("change", { detail: change })
|
|
763
|
-
);
|
|
824
|
+
if (change) void dispatchCRListEvent(this.eventTarget, "change", change);
|
|
764
825
|
}
|
|
765
826
|
/**
|
|
766
827
|
* Emits an acknowledgement frontier for currently retained tombstones.
|
|
767
828
|
*/
|
|
768
829
|
acknowledge() {
|
|
769
830
|
const ack = __acknowledge(this.state);
|
|
770
|
-
if (ack)
|
|
771
|
-
void this.eventTarget.dispatchEvent(
|
|
772
|
-
new CustomEvent("ack", { detail: ack })
|
|
773
|
-
);
|
|
831
|
+
if (ack) void dispatchCRListEvent(this.eventTarget, "ack", ack);
|
|
774
832
|
}
|
|
775
833
|
/**
|
|
776
834
|
* Garbage-collects tombstones that are covered by acknowledgement frontiers.
|
|
@@ -781,14 +839,15 @@ var CRList = class {
|
|
|
781
839
|
void __garbageCollect(frontiers, this.state);
|
|
782
840
|
}
|
|
783
841
|
/**
|
|
784
|
-
* Emits the current
|
|
842
|
+
* Emits the current CRList snapshot.
|
|
843
|
+
*
|
|
844
|
+
* Snapshot value payloads are live references. Mutating them can mutate
|
|
845
|
+
* replica state without emitting a delta.
|
|
785
846
|
*/
|
|
786
847
|
snapshot() {
|
|
787
848
|
const snapshot = __snapshot(this.state);
|
|
788
849
|
if (snapshot)
|
|
789
|
-
void this.eventTarget
|
|
790
|
-
new CustomEvent("snapshot", { detail: snapshot })
|
|
791
|
-
);
|
|
850
|
+
void dispatchCRListEvent(this.eventTarget, "snapshot", snapshot);
|
|
792
851
|
}
|
|
793
852
|
/**
|
|
794
853
|
* Registers an event listener.
|
|
@@ -798,7 +857,7 @@ var CRList = class {
|
|
|
798
857
|
* @param options - Listener registration options.
|
|
799
858
|
*/
|
|
800
859
|
addEventListener(type, listener, options) {
|
|
801
|
-
this.eventTarget.addEventListener(
|
|
860
|
+
void this.eventTarget.addEventListener(
|
|
802
861
|
type,
|
|
803
862
|
listener,
|
|
804
863
|
options
|
|
@@ -812,14 +871,17 @@ var CRList = class {
|
|
|
812
871
|
* @param options - Listener removal options.
|
|
813
872
|
*/
|
|
814
873
|
removeEventListener(type, listener, options) {
|
|
815
|
-
this.eventTarget.removeEventListener(
|
|
874
|
+
void this.eventTarget.removeEventListener(
|
|
816
875
|
type,
|
|
817
876
|
listener,
|
|
818
877
|
options
|
|
819
878
|
);
|
|
820
879
|
}
|
|
821
880
|
/**
|
|
822
|
-
* Returns a
|
|
881
|
+
* Returns a CRList snapshot of this list.
|
|
882
|
+
*
|
|
883
|
+
* Snapshot value payloads are live references. Mutating them can mutate
|
|
884
|
+
* replica state without emitting a delta.
|
|
823
885
|
*
|
|
824
886
|
* Called automatically by `JSON.stringify`.
|
|
825
887
|
*/
|
|
@@ -847,7 +909,7 @@ var CRList = class {
|
|
|
847
909
|
return this.toJSON();
|
|
848
910
|
}
|
|
849
911
|
/**
|
|
850
|
-
* Iterates over
|
|
912
|
+
* Iterates over current live values in index order.
|
|
851
913
|
*/
|
|
852
914
|
*[Symbol.iterator]() {
|
|
853
915
|
for (let index = 0; index < this.size; index++) {
|
|
@@ -856,17 +918,17 @@ var CRList = class {
|
|
|
856
918
|
}
|
|
857
919
|
}
|
|
858
920
|
/**
|
|
859
|
-
* Calls a function once for each live value
|
|
921
|
+
* Calls a function once for each live value in index order.
|
|
860
922
|
*
|
|
861
|
-
* Callback values are
|
|
862
|
-
* list.
|
|
923
|
+
* Callback values are live references. Mutating them directly can mutate the
|
|
924
|
+
* list without emitting a delta.
|
|
863
925
|
*
|
|
864
|
-
* @param callback - Function to call for each value
|
|
926
|
+
* @param callback - Function to call for each live value.
|
|
865
927
|
* @param thisArg - Optional `this` value for the callback.
|
|
866
928
|
*/
|
|
867
929
|
forEach(callback, thisArg) {
|
|
868
930
|
for (let index = 0; index < this.size; index++) {
|
|
869
|
-
callback.call(thisArg, this[index], index, this);
|
|
931
|
+
void callback.call(thisArg, this[index], index, this);
|
|
870
932
|
}
|
|
871
933
|
}
|
|
872
934
|
};
|