@sovereignbase/convergent-replicated-list 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,859 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/*
2
+ * Copyright 2026 Sovereignbase
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+
18
+ // src/core/crud/create/index.ts
19
+ var _utils = require('@sovereignbase/utils');
20
+
21
+ // src/.helpers/assertListIndices/index.ts
22
+ function assertListIndices(crListReplica) {
23
+ if (!crListReplica.cursor) return;
24
+ let index = crListReplica.size;
25
+ while (crListReplica.cursor.next)
26
+ crListReplica.cursor = crListReplica.cursor.next;
27
+ while (index >= 1) {
28
+ index--;
29
+ crListReplica.cursor.index = index;
30
+ if (crListReplica.cursor.prev === void 0) break;
31
+ crListReplica.cursor = crListReplica.cursor.prev;
32
+ }
33
+ }
34
+
35
+ // src/.errors/class.ts
36
+ var CRListError = class extends Error {
37
+ /**
38
+ * The semantic error code for the failure.
39
+ */
40
+
41
+ /**
42
+ * Creates a typed CRList error.
43
+ *
44
+ * @param code - The semantic error code.
45
+ * @param message - An optional human-readable detail message.
46
+ */
47
+ constructor(code, message) {
48
+ const detail = _nullishCoalesce(message, () => ( code));
49
+ super(`{@sovereignbase/convergent-replicated-list} ${detail}`);
50
+ this.code = code;
51
+ this.name = "CRListError";
52
+ }
53
+ };
54
+
55
+ // src/.helpers/walkToIndex/index.ts
56
+ function walkToIndex(targetIndex, crListReplica) {
57
+ if (targetIndex < 0 || targetIndex >= crListReplica.size)
58
+ throw new CRListError("INDEX_OUT_OF_BOUNDS", "Index out of bounds");
59
+ if (!crListReplica.cursor)
60
+ throw new CRListError("LIST_EMPTY", "List is empty");
61
+ const direction = crListReplica.cursor.index > targetIndex ? "prev" : "next";
62
+ while (crListReplica.cursor && crListReplica.cursor.index !== targetIndex) {
63
+ crListReplica.cursor = crListReplica.cursor[direction];
64
+ }
65
+ }
66
+
67
+ // src/.helpers/insertBetween/index.ts
68
+ function insertBetween(prev, linkedListEntry, next) {
69
+ linkedListEntry.prev = prev;
70
+ linkedListEntry.next = next;
71
+ if (prev) prev.next = linkedListEntry;
72
+ if (next) next.prev = linkedListEntry;
73
+ }
74
+
75
+ // src/.helpers/flattenAndLinkTrustedState/index.ts
76
+ function flattenAndLinkTrustedState(crListReplica) {
77
+ crListReplica.cursor = void 0;
78
+ const resolvedSiblingPredecessors = /* @__PURE__ */ new Set();
79
+ for (const entry of crListReplica.parentMap.values()) {
80
+ if (!entry) continue;
81
+ entry.prev = void 0;
82
+ entry.next = void 0;
83
+ }
84
+ const keys = [...crListReplica.childrenMap.keys()].sort(
85
+ (a, b) => a > b ? 1 : -1
86
+ );
87
+ let hasProgress = true;
88
+ while (hasProgress) {
89
+ hasProgress = false;
90
+ for (const predecessorIdentifier of keys) {
91
+ if (resolvedSiblingPredecessors.has(predecessorIdentifier)) continue;
92
+ const siblings = crListReplica.childrenMap.get(predecessorIdentifier);
93
+ if (!siblings) continue;
94
+ if (siblings.length > 1)
95
+ siblings.sort((a, b) => a.uuidv7 > b.uuidv7 ? 1 : -1);
96
+ const predecessor = predecessorIdentifier === "\0" ? void 0 : crListReplica.parentMap.get(predecessorIdentifier);
97
+ if (predecessor && !predecessor.prev && !predecessor.next && crListReplica.cursor !== predecessor)
98
+ continue;
99
+ let prev = _nullishCoalesce(predecessor, () => ( crListReplica.cursor));
100
+ const predecessorNext = _optionalChain([predecessor, 'optionalAccess', _2 => _2.next]);
101
+ if (siblings.length === 1) {
102
+ const sibling = siblings[0];
103
+ insertBetween(prev, sibling, sibling.next);
104
+ prev = sibling;
105
+ if (predecessorNext && predecessorNext !== sibling) {
106
+ prev.next = predecessorNext;
107
+ predecessorNext.prev = prev;
108
+ } else {
109
+ prev.next = void 0;
110
+ }
111
+ if (!predecessorNext) crListReplica.cursor = prev;
112
+ resolvedSiblingPredecessors.add(predecessorIdentifier);
113
+ hasProgress = true;
114
+ continue;
115
+ }
116
+ const siblingSet = new Set(siblings);
117
+ for (let index = 0; index < siblings.length; index++) {
118
+ const sibling = siblings[index];
119
+ const next = siblings[index + 1];
120
+ insertBetween(prev, sibling, sibling.next);
121
+ prev = sibling;
122
+ if (next) {
123
+ prev.next = next;
124
+ next.prev = prev;
125
+ } else if (predecessorNext && !siblingSet.has(predecessorNext)) {
126
+ prev.next = predecessorNext;
127
+ predecessorNext.prev = prev;
128
+ } else {
129
+ prev.next = void 0;
130
+ }
131
+ }
132
+ if (!predecessorNext) crListReplica.cursor = prev;
133
+ resolvedSiblingPredecessors.add(predecessorIdentifier);
134
+ hasProgress = true;
135
+ }
136
+ }
137
+ crListReplica.size = crListReplica.parentMap.size;
138
+ }
139
+
140
+ // src/.helpers/snapshotValueToLinkedListValue/index.ts
141
+
142
+ function snapshotValueToLinkedListValue(valueEntry, crListReplica) {
143
+ if (!_utils.isUuidV7.call(void 0, valueEntry.uuidv7) || crListReplica.tombstones.has(valueEntry.uuidv7) || crListReplica.parentMap.has(valueEntry.uuidv7) || !_utils.isUuidV7.call(void 0, valueEntry.predecessor) && valueEntry.predecessor !== "\0" && !crListReplica.tombstones.has(valueEntry.predecessor))
144
+ return void 0;
145
+ const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, valueEntry.value);
146
+ if (!cloned) return void 0;
147
+ return {
148
+ uuidv7: valueEntry.uuidv7,
149
+ value: copiedValue,
150
+ predecessor: valueEntry.predecessor,
151
+ index: 0,
152
+ next: void 0,
153
+ prev: void 0
154
+ };
155
+ }
156
+
157
+ // src/.helpers/updateEntryToMaps/index.ts
158
+ function updateEntryToMaps(crListReplica, linkedListEntry, deltaBuf) {
159
+ crListReplica.parentMap.set(linkedListEntry.uuidv7, linkedListEntry);
160
+ const siblings = crListReplica.childrenMap.get(linkedListEntry.predecessor);
161
+ if (siblings) {
162
+ siblings.push(linkedListEntry);
163
+ } else {
164
+ crListReplica.childrenMap.set(linkedListEntry.predecessor, [
165
+ linkedListEntry
166
+ ]);
167
+ }
168
+ if (deltaBuf && !Array.isArray(deltaBuf.values)) deltaBuf.values = [];
169
+ if (_optionalChain([deltaBuf, 'optionalAccess', _3 => _3.values]))
170
+ deltaBuf.values.push({
171
+ uuidv7: linkedListEntry.uuidv7,
172
+ value: linkedListEntry.value,
173
+ predecessor: linkedListEntry.predecessor
174
+ });
175
+ }
176
+
177
+ // src/.helpers/deleteEntryFromMaps/index.ts
178
+ function deleteEntryFromMaps(crListReplica, linkedListEntry) {
179
+ crListReplica.parentMap.delete(linkedListEntry.uuidv7);
180
+ const siblings = crListReplica.childrenMap.get(linkedListEntry.predecessor);
181
+ if (!siblings) return;
182
+ const index = siblings.indexOf(linkedListEntry);
183
+ if (index !== -1) siblings.splice(index, 1);
184
+ }
185
+
186
+ // src/.helpers/deleteLinkedEntry/index.ts
187
+ function deleteLinkedEntry(crListReplica, linkedListEntry, deltaBuf) {
188
+ const prev = linkedListEntry.prev;
189
+ const next = linkedListEntry.next;
190
+ crListReplica.tombstones.add(linkedListEntry.uuidv7);
191
+ if (deltaBuf && !Array.isArray(deltaBuf.tombstones)) deltaBuf.tombstones = [];
192
+ _optionalChain([deltaBuf, 'optionalAccess', _4 => _4.tombstones, 'optionalAccess', _5 => _5.push, 'call', _6 => _6(linkedListEntry.uuidv7)]);
193
+ if (prev) prev.next = next;
194
+ if (next) {
195
+ next.prev = prev;
196
+ }
197
+ void deleteEntryFromMaps(crListReplica, linkedListEntry);
198
+ if (crListReplica.cursor === linkedListEntry)
199
+ crListReplica.cursor = _nullishCoalesce(next, () => ( prev));
200
+ linkedListEntry.prev = void 0;
201
+ linkedListEntry.next = void 0;
202
+ crListReplica.size = crListReplica.parentMap.size;
203
+ }
204
+
205
+ // src/.helpers/moveEntryToPredecessor/index.ts
206
+ function moveEntryToPredecessor(crListReplica, linkedListEntry, predecessor, deltaBuf) {
207
+ void deleteEntryFromMaps(crListReplica, linkedListEntry);
208
+ linkedListEntry.predecessor = predecessor;
209
+ void updateEntryToMaps(crListReplica, linkedListEntry, deltaBuf);
210
+ }
211
+
212
+ // src/.helpers/indexFromPropertyKey/index.ts
213
+ function indexFromPropertyKey(index) {
214
+ if (typeof index !== "string" || !/^(0|[1-9]\d*)$/.test(index))
215
+ return void 0;
216
+ const listIndex = Number(index);
217
+ return Number.isSafeInteger(listIndex) ? listIndex : void 0;
218
+ }
219
+
220
+ // src/core/crud/create/index.ts
221
+ function __create(snapshot) {
222
+ const crListReplica = {
223
+ size: 0,
224
+ cursor: void 0,
225
+ tombstones: /* @__PURE__ */ new Set(),
226
+ parentMap: /* @__PURE__ */ new Map(),
227
+ childrenMap: /* @__PURE__ */ new Map()
228
+ };
229
+ if (!snapshot || _utils.prototype.call(void 0, snapshot) !== "record") return crListReplica;
230
+ if (Object.hasOwn(snapshot, "tombstones") && Array.isArray(snapshot.tombstones)) {
231
+ for (const tombstone of snapshot.tombstones) {
232
+ if (crListReplica.tombstones.has(tombstone) || !_utils.isUuidV7.call(void 0, tombstone))
233
+ continue;
234
+ crListReplica.tombstones.add(tombstone);
235
+ }
236
+ }
237
+ if (!Object.hasOwn(snapshot, "values") || !Array.isArray(snapshot.values))
238
+ return crListReplica;
239
+ for (const valueEntry of snapshot.values) {
240
+ const linkedListEntry = snapshotValueToLinkedListValue(
241
+ valueEntry,
242
+ crListReplica
243
+ );
244
+ if (!linkedListEntry) continue;
245
+ void updateEntryToMaps(crListReplica, linkedListEntry);
246
+ }
247
+ void flattenAndLinkTrustedState(crListReplica);
248
+ void assertListIndices(crListReplica);
249
+ return crListReplica;
250
+ }
251
+
252
+ // src/core/crud/read/index.ts
253
+ function __read(targetIndex, crListReplica) {
254
+ try {
255
+ void walkToIndex(targetIndex, crListReplica);
256
+ return _optionalChain([crListReplica, 'optionalAccess', _7 => _7.cursor, 'optionalAccess', _8 => _8.value]);
257
+ } catch (e) {
258
+ return void 0;
259
+ }
260
+ }
261
+
262
+ // src/core/crud/update/index.ts
263
+
264
+ var _uuid = require('uuid');
265
+ function __update(listIndex, listValues, crListReplica, mode) {
266
+ if (listIndex < 0 || listIndex > crListReplica.size)
267
+ throw new CRListError("INDEX_OUT_OF_BOUNDS");
268
+ if (!Array.isArray(listValues))
269
+ throw new CRListError(
270
+ "UPDATE_EXPECTED_AN_ARRAY",
271
+ "`listValues` must be an Array"
272
+ );
273
+ if (listValues.length === 0) return false;
274
+ const change = {};
275
+ const delta = { values: [], tombstones: [] };
276
+ let shiftCursor;
277
+ for (const listValue of listValues) {
278
+ const [cloned, copiedValue] = _utils.safeStructuredClone.call(void 0, listValue);
279
+ if (!cloned) throw new CRListError("VALUE_NOT_CLONEABLE");
280
+ const v7 = _uuid.v7.call(void 0, );
281
+ const linkedListEntry = {
282
+ uuidv7: v7,
283
+ value: copiedValue,
284
+ predecessor: "\0",
285
+ index: 0,
286
+ next: void 0,
287
+ prev: void 0
288
+ };
289
+ switch (mode) {
290
+ case "overwrite": {
291
+ if (listIndex === crListReplica.size) {
292
+ if (crListReplica.size === 0) {
293
+ crListReplica.cursor = linkedListEntry;
294
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
295
+ change[linkedListEntry.index] = linkedListEntry.value;
296
+ break;
297
+ }
298
+ void walkToIndex(crListReplica.size - 1, crListReplica);
299
+ if (!crListReplica.cursor) return false;
300
+ linkedListEntry.index = crListReplica.cursor.index + 1;
301
+ linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
302
+ insertBetween(crListReplica.cursor, linkedListEntry, void 0);
303
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
304
+ crListReplica.cursor = linkedListEntry;
305
+ change[linkedListEntry.index] = linkedListEntry.value;
306
+ break;
307
+ }
308
+ void walkToIndex(listIndex, crListReplica);
309
+ if (!crListReplica.cursor) return false;
310
+ const entryToOverwrite = crListReplica.cursor;
311
+ linkedListEntry.predecessor = entryToOverwrite.predecessor;
312
+ linkedListEntry.index = entryToOverwrite.index;
313
+ insertBetween(
314
+ entryToOverwrite.prev,
315
+ linkedListEntry,
316
+ entryToOverwrite.next
317
+ );
318
+ if (entryToOverwrite.next) {
319
+ if (entryToOverwrite.next.predecessor === entryToOverwrite.uuidv7) {
320
+ void moveEntryToPredecessor(
321
+ crListReplica,
322
+ entryToOverwrite.next,
323
+ linkedListEntry.uuidv7,
324
+ delta
325
+ );
326
+ }
327
+ }
328
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
329
+ crListReplica.tombstones.add(entryToOverwrite.uuidv7);
330
+ _optionalChain([delta, 'access', _9 => _9.tombstones, 'optionalAccess', _10 => _10.push, 'call', _11 => _11(entryToOverwrite.uuidv7)]);
331
+ void deleteEntryFromMaps(crListReplica, entryToOverwrite);
332
+ entryToOverwrite.next = void 0;
333
+ entryToOverwrite.prev = void 0;
334
+ crListReplica.cursor = linkedListEntry;
335
+ change[linkedListEntry.index] = linkedListEntry.value;
336
+ break;
337
+ }
338
+ case "after": {
339
+ if (crListReplica.size === 0 && listIndex === 0) {
340
+ crListReplica.cursor = linkedListEntry;
341
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
342
+ change[linkedListEntry.index] = linkedListEntry.value;
343
+ break;
344
+ }
345
+ if (listIndex === crListReplica.size) {
346
+ void walkToIndex(crListReplica.size - 1, crListReplica);
347
+ } else {
348
+ void walkToIndex(listIndex, crListReplica);
349
+ }
350
+ if (!crListReplica.cursor) return false;
351
+ const next = listIndex === crListReplica.size ? void 0 : crListReplica.cursor.next;
352
+ shiftCursor = next;
353
+ linkedListEntry.index = crListReplica.cursor.index + 1;
354
+ linkedListEntry.predecessor = crListReplica.cursor.uuidv7;
355
+ insertBetween(crListReplica.cursor, linkedListEntry, next);
356
+ if (next) {
357
+ if (next.predecessor === crListReplica.cursor.uuidv7) {
358
+ void moveEntryToPredecessor(
359
+ crListReplica,
360
+ next,
361
+ linkedListEntry.uuidv7,
362
+ delta
363
+ );
364
+ }
365
+ }
366
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
367
+ crListReplica.cursor = linkedListEntry;
368
+ change[linkedListEntry.index] = linkedListEntry.value;
369
+ break;
370
+ }
371
+ case "before": {
372
+ if (crListReplica.size === 0 && listIndex === 0) {
373
+ crListReplica.cursor = linkedListEntry;
374
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
375
+ change[linkedListEntry.index] = linkedListEntry.value;
376
+ mode = "after";
377
+ listIndex = linkedListEntry.index - 1;
378
+ break;
379
+ }
380
+ void walkToIndex(listIndex, crListReplica);
381
+ if (!crListReplica.cursor) return false;
382
+ const prev = crListReplica.cursor.prev;
383
+ shiftCursor = crListReplica.cursor;
384
+ linkedListEntry.index = crListReplica.cursor.index;
385
+ linkedListEntry.predecessor = _nullishCoalesce(_optionalChain([prev, 'optionalAccess', _12 => _12.uuidv7]), () => ( "\0"));
386
+ insertBetween(prev, linkedListEntry, crListReplica.cursor);
387
+ if (crListReplica.cursor.predecessor === linkedListEntry.predecessor) {
388
+ void moveEntryToPredecessor(
389
+ crListReplica,
390
+ crListReplica.cursor,
391
+ linkedListEntry.uuidv7,
392
+ delta
393
+ );
394
+ }
395
+ void updateEntryToMaps(crListReplica, linkedListEntry, delta);
396
+ crListReplica.cursor = linkedListEntry;
397
+ change[linkedListEntry.index] = linkedListEntry.value;
398
+ mode = "after";
399
+ listIndex = linkedListEntry.index - 1;
400
+ break;
401
+ }
402
+ }
403
+ crListReplica.size = crListReplica.parentMap.size;
404
+ listIndex++;
405
+ }
406
+ if (mode !== "overwrite")
407
+ while (shiftCursor) {
408
+ shiftCursor.index += listValues.length;
409
+ shiftCursor = shiftCursor.next;
410
+ }
411
+ return { change, delta };
412
+ }
413
+
414
+ // src/core/crud/delete/index.ts
415
+ function __delete(crListReplica, startIndex, endIndex) {
416
+ const change = {};
417
+ const delta = { values: [], tombstones: [] };
418
+ const listIndex = _nullishCoalesce(startIndex, () => ( 0));
419
+ const targetEndIndex = _nullishCoalesce(endIndex, () => ( crListReplica.size));
420
+ if (listIndex < 0 || targetEndIndex < listIndex || listIndex > crListReplica.size)
421
+ throw new CRListError("INDEX_OUT_OF_BOUNDS");
422
+ const deleteCount = Math.min(targetEndIndex, crListReplica.size) - listIndex;
423
+ if (deleteCount <= 0) return false;
424
+ void walkToIndex(listIndex, crListReplica);
425
+ if (!crListReplica.cursor) return false;
426
+ let current = crListReplica.cursor;
427
+ let deleted = 0;
428
+ while (current && deleted < deleteCount) {
429
+ const next = current.next;
430
+ change[current.index] = void 0;
431
+ void deleteLinkedEntry(crListReplica, current, delta);
432
+ current = next;
433
+ deleted++;
434
+ }
435
+ crListReplica.size = crListReplica.parentMap.size;
436
+ while (current) {
437
+ current.index -= deleted;
438
+ current = current.next;
439
+ }
440
+ return { change, delta };
441
+ }
442
+
443
+ // src/core/mags/merge/index.ts
444
+
445
+ function __merge(crListReplica, crListDelta) {
446
+ if (!crListDelta || _utils.prototype.call(void 0, crListDelta) !== "record") return false;
447
+ const newVals = [];
448
+ const newTombsIndices = [];
449
+ const change = {};
450
+ let needsRelink = false;
451
+ if (Object.hasOwn(crListDelta, "tombstones") && Array.isArray(crListDelta.tombstones)) {
452
+ for (const tombstone of crListDelta.tombstones) {
453
+ if (crListReplica.tombstones.has(tombstone) || !_utils.isUuidV7.call(void 0, tombstone))
454
+ continue;
455
+ crListReplica.tombstones.add(tombstone);
456
+ const linkedListEntry = crListReplica.parentMap.get(tombstone);
457
+ if (linkedListEntry) {
458
+ void newTombsIndices.push(linkedListEntry.index);
459
+ void deleteLinkedEntry(crListReplica, linkedListEntry);
460
+ needsRelink = true;
461
+ }
462
+ }
463
+ }
464
+ if (!Object.hasOwn(crListDelta, "values") || !Array.isArray(crListDelta.values)) {
465
+ if (newTombsIndices.length === 0) return false;
466
+ void assertListIndices(crListReplica);
467
+ for (const index of newTombsIndices) {
468
+ change[index] = void 0;
469
+ }
470
+ return change;
471
+ }
472
+ for (const valueEntry of crListDelta.values) {
473
+ const existingEntry = crListReplica.parentMap.get(valueEntry.uuidv7);
474
+ if (existingEntry) {
475
+ if (crListReplica.tombstones.has(valueEntry.uuidv7) || !_utils.isUuidV7.call(void 0, valueEntry.predecessor) && valueEntry.predecessor !== "\0")
476
+ continue;
477
+ if (existingEntry.predecessor >= valueEntry.predecessor) continue;
478
+ void moveEntryToPredecessor(
479
+ crListReplica,
480
+ existingEntry,
481
+ valueEntry.predecessor
482
+ );
483
+ needsRelink = true;
484
+ void newVals.push(existingEntry);
485
+ continue;
486
+ }
487
+ const linkedListEntry = snapshotValueToLinkedListValue(
488
+ valueEntry,
489
+ crListReplica
490
+ );
491
+ if (!linkedListEntry) continue;
492
+ const predecessor = linkedListEntry.predecessor === "\0" ? void 0 : crListReplica.parentMap.get(linkedListEntry.predecessor);
493
+ void updateEntryToMaps(crListReplica, linkedListEntry);
494
+ void newVals.push(linkedListEntry);
495
+ if (!needsRelink && linkedListEntry.predecessor === "\0") {
496
+ if (crListReplica.size === 0) {
497
+ crListReplica.cursor = linkedListEntry;
498
+ crListReplica.size = crListReplica.parentMap.size;
499
+ } else {
500
+ needsRelink = true;
501
+ }
502
+ } else if (!needsRelink && predecessor && !predecessor.next) {
503
+ linkedListEntry.prev = predecessor;
504
+ linkedListEntry.index = predecessor.index + 1;
505
+ predecessor.next = linkedListEntry;
506
+ crListReplica.cursor = linkedListEntry;
507
+ crListReplica.size = crListReplica.parentMap.size;
508
+ } else {
509
+ needsRelink = true;
510
+ }
511
+ }
512
+ if (needsRelink) {
513
+ void flattenAndLinkTrustedState(crListReplica);
514
+ void assertListIndices(crListReplica);
515
+ }
516
+ if (newTombsIndices.length === 0 && newVals.length === 0) return false;
517
+ for (const index of newTombsIndices) {
518
+ change[index] = void 0;
519
+ }
520
+ for (const val of newVals) {
521
+ change[val.index] = val.value;
522
+ }
523
+ return change;
524
+ }
525
+
526
+ // src/core/mags/acknowledge/index.ts
527
+ function __acknowledge(crListReplica) {
528
+ let frontier = false;
529
+ crListReplica.tombstones.forEach((tombstone) => {
530
+ if (frontier === false || frontier < tombstone) frontier = tombstone;
531
+ });
532
+ if (typeof frontier === "string") return frontier;
533
+ return false;
534
+ }
535
+
536
+ // src/core/mags/garbageCollect/index.ts
537
+ function __garbageCollect(frontiers, crListReplica) {
538
+ if (!Array.isArray(frontiers)) return;
539
+ const frontier = frontiers.sort().shift();
540
+ if (typeof frontier !== "string") return;
541
+ crListReplica.tombstones.forEach((tombstone, __, tombstones) => {
542
+ if (tombstone <= frontier) {
543
+ tombstones.delete(tombstone);
544
+ }
545
+ });
546
+ }
547
+
548
+ // src/core/mags/snapshot/index.ts
549
+ function __snapshot(crListReplica) {
550
+ return {
551
+ values: Array.from(crListReplica.parentMap.values()).map(
552
+ (linkedListEntry) => {
553
+ if (!linkedListEntry) throw new CRListError("LIST_INTEGRITY_VIOLATION");
554
+ return {
555
+ uuidv7: linkedListEntry.uuidv7,
556
+ value: structuredClone(linkedListEntry.value),
557
+ predecessor: linkedListEntry.predecessor
558
+ };
559
+ }
560
+ ),
561
+ tombstones: Array.from(crListReplica.tombstones)
562
+ };
563
+ }
564
+
565
+ // src/CRList/class.ts
566
+ var CRList = class {
567
+ /**
568
+ * Creates a replicated list from an optional serializable snapshot.
569
+ *
570
+ * @param snapshot - A previously emitted CRList snapshot.
571
+ */
572
+ constructor(snapshot) {
573
+ Object.defineProperties(this, {
574
+ state: {
575
+ value: __create(snapshot),
576
+ enumerable: false,
577
+ configurable: false,
578
+ writable: false
579
+ },
580
+ eventTarget: {
581
+ value: new EventTarget(),
582
+ enumerable: false,
583
+ configurable: false,
584
+ writable: false
585
+ }
586
+ });
587
+ return new Proxy(this, {
588
+ get(target, index, receiver) {
589
+ const listIndex = indexFromPropertyKey(index);
590
+ if (listIndex === void 0) return Reflect.get(target, index, receiver);
591
+ return __read(listIndex, target.state);
592
+ },
593
+ has(target, index) {
594
+ const listIndex = indexFromPropertyKey(index);
595
+ if (listIndex === void 0) return Reflect.has(target, index);
596
+ return listIndex >= 0 && listIndex < target.state.size;
597
+ },
598
+ set(target, index, value) {
599
+ const listIndex = indexFromPropertyKey(index);
600
+ if (listIndex === void 0) return false;
601
+ try {
602
+ const result = __update(listIndex, [value], target.state, "overwrite");
603
+ if (!result) return false;
604
+ const { delta, change } = result;
605
+ if (delta)
606
+ void target.eventTarget.dispatchEvent(
607
+ new CustomEvent("delta", { detail: delta })
608
+ );
609
+ if (change)
610
+ void target.eventTarget.dispatchEvent(
611
+ new CustomEvent("change", { detail: change })
612
+ );
613
+ return true;
614
+ } catch (e2) {
615
+ return false;
616
+ }
617
+ },
618
+ deleteProperty(target, index) {
619
+ const listIndex = indexFromPropertyKey(index);
620
+ if (listIndex === void 0) return false;
621
+ try {
622
+ const result = __delete(target.state, listIndex, listIndex + 1);
623
+ if (!result) return false;
624
+ const { delta, change } = result;
625
+ if (delta) {
626
+ void target.eventTarget.dispatchEvent(
627
+ new CustomEvent("delta", { detail: delta })
628
+ );
629
+ }
630
+ if (change) {
631
+ void target.eventTarget.dispatchEvent(
632
+ new CustomEvent("change", { detail: change })
633
+ );
634
+ }
635
+ return true;
636
+ } catch (e3) {
637
+ return false;
638
+ }
639
+ },
640
+ ownKeys(target) {
641
+ return [
642
+ ...Reflect.ownKeys(target),
643
+ ...Array.from({ length: target.size }, (_, index) => String(index))
644
+ ];
645
+ },
646
+ getOwnPropertyDescriptor(target, index) {
647
+ const listIndex = indexFromPropertyKey(index);
648
+ if (listIndex !== void 0 && listIndex < target.size) {
649
+ return {
650
+ value: __read(listIndex, target.state),
651
+ writable: true,
652
+ enumerable: true,
653
+ configurable: true
654
+ };
655
+ }
656
+ return Reflect.getOwnPropertyDescriptor(target, index);
657
+ }
658
+ });
659
+ }
660
+ /**
661
+ * The current number of live entries.
662
+ */
663
+ get size() {
664
+ return this.state.size;
665
+ }
666
+ /**
667
+ * Inserts a value before an index.
668
+ *
669
+ * If `beforeIndex` is omitted, the value is inserted at the start of the list.
670
+ *
671
+ * @param value - The value to insert.
672
+ * @param beforeIndex - The index to insert before.
673
+ */
674
+ prepend(value, beforeIndex) {
675
+ const result = __update(_nullishCoalesce(beforeIndex, () => ( 0)), [value], this.state, "before");
676
+ if (!result) return;
677
+ const { delta, change } = result;
678
+ if (delta)
679
+ void this.eventTarget.dispatchEvent(
680
+ new CustomEvent("delta", { detail: delta })
681
+ );
682
+ if (change)
683
+ void this.eventTarget.dispatchEvent(
684
+ new CustomEvent("change", { detail: change })
685
+ );
686
+ }
687
+ /**
688
+ * Inserts a value after an index.
689
+ *
690
+ * If `afterIndex` is omitted, the value is appended at the end of the list.
691
+ *
692
+ * @param value - The value to insert.
693
+ * @param afterIndex - The index to insert after.
694
+ */
695
+ append(value, afterIndex) {
696
+ const result = __update(
697
+ _nullishCoalesce(afterIndex, () => ( this.state.size)),
698
+ [value],
699
+ this.state,
700
+ "after"
701
+ );
702
+ if (!result) return;
703
+ const { delta, change } = result;
704
+ if (delta)
705
+ void this.eventTarget.dispatchEvent(
706
+ new CustomEvent("delta", { detail: delta })
707
+ );
708
+ if (change)
709
+ void this.eventTarget.dispatchEvent(
710
+ new CustomEvent("change", { detail: change })
711
+ );
712
+ }
713
+ /**
714
+ * Removes the entry at an index.
715
+ *
716
+ * @param index - The index to remove.
717
+ */
718
+ remove(index) {
719
+ const result = __delete(this.state, index, index + 1);
720
+ if (!result) return;
721
+ const { delta, change } = result;
722
+ if (delta)
723
+ void this.eventTarget.dispatchEvent(
724
+ new CustomEvent("delta", { detail: delta })
725
+ );
726
+ if (change)
727
+ void this.eventTarget.dispatchEvent(
728
+ new CustomEvent("change", { detail: change })
729
+ );
730
+ }
731
+ /**
732
+ * Applies a remote gossip delta to this list.
733
+ *
734
+ * Emits a `change` event when the merge changes the live projection.
735
+ *
736
+ * @param delta - The remote CRList delta to merge.
737
+ */
738
+ merge(delta) {
739
+ const change = __merge(this.state, delta);
740
+ if (change)
741
+ void this.eventTarget.dispatchEvent(
742
+ new CustomEvent("change", { detail: change })
743
+ );
744
+ }
745
+ /**
746
+ * Emits an acknowledgement frontier for currently retained tombstones.
747
+ */
748
+ acknowledge() {
749
+ const ack = __acknowledge(this.state);
750
+ if (ack)
751
+ void this.eventTarget.dispatchEvent(
752
+ new CustomEvent("ack", { detail: ack })
753
+ );
754
+ }
755
+ /**
756
+ * Garbage-collects tombstones that are covered by acknowledgement frontiers.
757
+ *
758
+ * @param frontiers - Replica acknowledgement frontiers.
759
+ */
760
+ garbageCollect(frontiers) {
761
+ void __garbageCollect(frontiers, this.state);
762
+ }
763
+ /**
764
+ * Emits the current serializable list snapshot.
765
+ */
766
+ snapshot() {
767
+ const snapshot = __snapshot(this.state);
768
+ if (snapshot)
769
+ void this.eventTarget.dispatchEvent(
770
+ new CustomEvent("snapshot", { detail: snapshot })
771
+ );
772
+ }
773
+ /**
774
+ * Registers an event listener.
775
+ *
776
+ * @param type - The event type to listen for.
777
+ * @param listener - The listener to register.
778
+ * @param options - Listener registration options.
779
+ */
780
+ addEventListener(type, listener, options) {
781
+ this.eventTarget.addEventListener(
782
+ type,
783
+ listener,
784
+ options
785
+ );
786
+ }
787
+ /**
788
+ * Removes an event listener.
789
+ *
790
+ * @param type - The event type to stop listening for.
791
+ * @param listener - The listener to remove.
792
+ * @param options - Listener removal options.
793
+ */
794
+ removeEventListener(type, listener, options) {
795
+ this.eventTarget.removeEventListener(
796
+ type,
797
+ listener,
798
+ options
799
+ );
800
+ }
801
+ /**
802
+ * Returns a serializable snapshot representation of this list.
803
+ *
804
+ * Called automatically by `JSON.stringify`.
805
+ */
806
+ toJSON() {
807
+ return __snapshot(this.state);
808
+ }
809
+ /**
810
+ * Returns this list as a JSON string.
811
+ */
812
+ toString() {
813
+ return JSON.stringify(this);
814
+ }
815
+ /**
816
+ * Returns the Node.js console inspection representation.
817
+ */
818
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
819
+ return this.toJSON();
820
+ }
821
+ /**
822
+ * Returns the Deno console inspection representation.
823
+ */
824
+ [/* @__PURE__ */ Symbol.for("Deno.customInspect")]() {
825
+ return this.toJSON();
826
+ }
827
+ /**
828
+ * Iterates over the current live values in index order.
829
+ */
830
+ *[Symbol.iterator]() {
831
+ for (let index = 0; index < this.size; index++) {
832
+ const value = this[index];
833
+ yield value;
834
+ }
835
+ }
836
+ /**
837
+ * Calls a function once for each live value in index order.
838
+ *
839
+ * @param callback - Function to call for each value.
840
+ * @param thisArg - Optional `this` value for the callback.
841
+ */
842
+ forEach(callback, thisArg) {
843
+ for (let index = 0; index < this.size; index++) {
844
+ callback.call(thisArg, this[index], index, this);
845
+ }
846
+ }
847
+ };
848
+
849
+
850
+
851
+
852
+
853
+
854
+
855
+
856
+
857
+
858
+ exports.CRList = CRList; exports.__acknowledge = __acknowledge; exports.__create = __create; exports.__delete = __delete; exports.__garbageCollect = __garbageCollect; exports.__merge = __merge; exports.__read = __read; exports.__snapshot = __snapshot; exports.__update = __update;
859
+ //# sourceMappingURL=index.cjs.map