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