@sovereignbase/convergent-replicated-list 1.0.9 → 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 +65 -32
- package/dist/index.cjs +281 -220
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -41
- package/dist/index.d.ts +65 -41
- package/dist/index.js +280 -219
- package/dist/index.js.map +1 -1
- package/package.json +12 -8
package/README.md
CHANGED
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
Convergent Replicated List (CR-List), a delta CRDT for an ordered sequence of entries.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- https://sovereignbase.dev/convergent-replicated-list
|
|
10
|
+
- [Check the docs](https://sovereignbase.dev/convergent-replicated-list/docs/)
|
|
11
|
+
- [Read the specification](https://sovereignbase.dev/convergent-replicated-list/)
|
|
13
12
|
|
|
14
13
|
## Compatibility
|
|
15
14
|
|
|
@@ -146,6 +145,11 @@ list.forEach((value, index, target) => {
|
|
|
146
145
|
console.log(index, value, target.size)
|
|
147
146
|
})
|
|
148
147
|
|
|
148
|
+
const found = list.find((value, index, target) => {
|
|
149
|
+
return index === 1 && target.size === 3 && value === 'up'
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
console.log(found) // 'up'
|
|
149
153
|
console.log([...restored]) // ['What is', 'up', 'dude!']
|
|
150
154
|
```
|
|
151
155
|
|
|
@@ -154,9 +158,9 @@ This example assumes your list values are JSON-compatible. For general
|
|
|
154
158
|
snapshots with a structured-clone-capable store or an application-level codec
|
|
155
159
|
instead of plain `JSON.stringify` / `JSON.parse`.
|
|
156
160
|
|
|
157
|
-
Numeric reads, `for...of`, and `forEach()` return detached copies of
|
|
158
|
-
values. Mutating those returned values does not mutate the underlying
|
|
159
|
-
state.
|
|
161
|
+
Numeric reads, `for...of`, `find()`, and `forEach()` return detached copies of
|
|
162
|
+
visible values. Mutating those returned values does not mutate the underlying
|
|
163
|
+
replica state.
|
|
160
164
|
|
|
161
165
|
### Acknowledgements and garbage collection
|
|
162
166
|
|
|
@@ -260,8 +264,8 @@ Ingress stays tolerant:
|
|
|
260
264
|
- `toJSON()` returns a detached structured-clone snapshot.
|
|
261
265
|
- `JSON.stringify()` and `toString()` are only reliable when list values are
|
|
262
266
|
JSON-compatible.
|
|
263
|
-
- Numeric reads, `for...of`, and `forEach()` expose detached copies of visible values rather than mutable references into replica state.
|
|
264
|
-
- `for...of`, `forEach()`, numeric indexing, `append()`, `prepend()`, `remove()`, `merge()`, `snapshot()`, `acknowledge()`, and `garbageCollect()` all operate on the live list projection.
|
|
267
|
+
- Numeric reads, `for...of`, `find()`, and `forEach()` expose detached copies of visible values rather than mutable references into replica state.
|
|
268
|
+
- `for...of`, `find()`, `forEach()`, numeric indexing, `append()`, `prepend()`, `remove()`, `merge()`, `snapshot()`, `acknowledge()`, and `garbageCollect()` all operate on the live list projection.
|
|
265
269
|
|
|
266
270
|
### Convergence and compaction
|
|
267
271
|
|
|
@@ -279,7 +283,7 @@ npm run test
|
|
|
279
283
|
What the current test suite covers:
|
|
280
284
|
|
|
281
285
|
- Coverage on built `dist/**/*.js`: `100%` statements, `100%` branches, `100%` functions, and `100%` lines, together with focused source-coverage tests for helper edge paths.
|
|
282
|
-
- Public `CRList` surface: indexing, iteration, `forEach`, proxy traps, events, JSON/inspect behavior.
|
|
286
|
+
- Public `CRList` surface: indexing, iteration, `find`, `forEach`, proxy traps, events, JSON/inspect behavior.
|
|
283
287
|
- Core edge paths and malicious ingress handling for `__create`, `__read`, `__update`, `__delete`, `__merge`, `__snapshot`, `__acknowledge`, and `__garbageCollect`.
|
|
284
288
|
- Internal defensive branches under intentionally corrupt in-memory replica state.
|
|
285
289
|
- Integration convergence stress for:
|
|
@@ -309,29 +313,58 @@ npm run bench
|
|
|
309
313
|
|
|
310
314
|
Last measured on Node `v22.14.0` (`win32 x64`):
|
|
311
315
|
|
|
312
|
-
| group
|
|
313
|
-
|
|
314
|
-
|
|
|
315
|
-
|
|
|
316
|
-
|
|
|
317
|
-
|
|
|
318
|
-
|
|
|
319
|
-
|
|
|
320
|
-
|
|
|
321
|
-
|
|
|
322
|
-
|
|
|
323
|
-
|
|
|
324
|
-
|
|
|
325
|
-
|
|
|
326
|
-
|
|
|
327
|
-
|
|
|
328
|
-
|
|
|
329
|
-
|
|
|
330
|
-
|
|
|
331
|
-
|
|
|
332
|
-
|
|
|
333
|
-
|
|
|
334
|
-
|
|
|
316
|
+
| group | scenario | n | ops | crlist ms | crlist ms/op | crlist ops/sec | yjs ms/op | yjs ops/sec | json-joy ms/op | json-joy ops/sec | automerge ms/op | automerge ops/sec | winner |
|
|
317
|
+
|---|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---|
|
|
318
|
+
| crud | create / hydrate snapshot | 5,000 | 250 | 2,096.39 | 8.39 | 119.25 | 15.07 | 66.34 | 19.3 | 51.82 | 232.99 | 4.29 | crlist |
|
|
319
|
+
| crud | read / random indexed reads | 5,000 | 250 | 0.35 | 0 | 712,047.85 | 0 | 213,949.51 | 0.01 | 72,573.15 | 0 | 1,487,209.99 | automerge |
|
|
320
|
+
| crud | update / append after tail | 5,000 | 250 | 3.75 | 0.01 | 66,712.92 | 0.04 | 26,447.75 | 0.03 | 34,200.66 | 2.79 | 358 | crlist |
|
|
321
|
+
| crud | update / insert before middle | 5,000 | 250 | 3.97 | 0.02 | 62,962.78 | 0.02 | 47,542.98 | 0.02 | 59,963.54 | 2.77 | 360.61 | crlist |
|
|
322
|
+
| crud | update / insert at head | 5,000 | 250 | 1.53 | 0.01 | 163,302.63 | 0.01 | 77,939.89 | 0.02 | 51,651.83 | 2.58 | 387.17 | crlist |
|
|
323
|
+
| crud | update / overwrite random | 5,000 | 250 | 3.77 | 0.02 | 66,267.3 | 0.07 | 14,168.64 | 0.05 | 19,413.25 | 2.91 | 343.26 | crlist |
|
|
324
|
+
| crud | delete / single deletes from middle | 5,000 | 250 | 1.94 | 0.01 | 129,098.89 | 0.03 | 31,265.24 | 0.13 | 7,665.23 | 0.42 | 2,369.86 | crlist |
|
|
325
|
+
| crud | delete / range deletes | 5,000 | 250 | 5.19 | 0.02 | 48,199.28 | 0.04 | 24,172.81 | 0.25 | 3,945.2 | 0.77 | 1,295.13 | crlist |
|
|
326
|
+
| mags | snapshot | 5,000 | 250 | 65.59 | 0.26 | 3,811.53 | 8.41 | 118.88 | 14.09 | 70.97 | 19.99 | 50.02 | crlist |
|
|
327
|
+
| mags | acknowledge | 5,000 | 250 | 76.25 | 0.31 | 3,278.61 | n/a | n/a | n/a | n/a | n/a | n/a | n/a |
|
|
328
|
+
| mags | garbage collect | 5,000 | 250 | 164.23 | 0.66 | 1,522.22 | n/a | n/a | n/a | n/a | n/a | n/a | n/a |
|
|
329
|
+
| mags | merge ordered deltas | 5,000 | 250 | 4.13 | 0.02 | 60,460.95 | 0.06 | 17,959 | 0.02 | 58,147.65 | 4.68 | 213.68 | crlist |
|
|
330
|
+
| mags | merge shuffled gossip | 5,000 | 250 | 478.37 | 1.91 | 522.61 | 0.64 | 1,555.98 | 0.09 | 11,595.98 | 0.41 | 2,456.81 | json-joy |
|
|
331
|
+
| class | constructor / hydrate snapshot | 5,000 | 250 | 1,886.2 | 7.54 | 132.54 | 12.85 | 77.8 | 18.34 | 54.51 | 211.32 | 4.73 | crlist |
|
|
332
|
+
| class | append after tail | 5,000 | 250 | 3.09 | 0.01 | 80,992.65 | 0.02 | 52,369.18 | 0.02 | 53,936.27 | 2.09 | 479.59 | crlist |
|
|
333
|
+
| class | prepend before middle | 5,000 | 250 | 7.79 | 0.03 | 32,077.6 | 0.01 | 81,163.56 | 0.01 | 80,744.14 | 2.68 | 372.46 | yjs |
|
|
334
|
+
| class | remove from middle | 5,000 | 250 | 1.82 | 0.01 | 137,287.2 | 0.03 | 37,143.24 | 0.03 | 35,865.43 | 0.57 | 1,761.16 | crlist |
|
|
335
|
+
| class | find near tail | 5,000 | 250 | 33.64 | 0.13 | 7,431.54 | 0.44 | 2,276.89 | 5.13 | 195.02 | 0.03 | 38,407.18 | automerge |
|
|
336
|
+
| class | snapshot | 5,000 | 250 | 83.09 | 0.33 | 3,008.93 | 7.99 | 125.19 | 14.86 | 67.28 | 19.63 | 50.93 | crlist |
|
|
337
|
+
| class | acknowledge | 5,000 | 250 | 46.72 | 0.19 | 5,351.54 | n/a | n/a | n/a | n/a | n/a | n/a | n/a |
|
|
338
|
+
| class | garbage collect | 5,000 | 250 | 156.68 | 0.63 | 1,595.56 | n/a | n/a | n/a | n/a | n/a | n/a | n/a |
|
|
339
|
+
| class | merge ordered deltas | 5,000 | 250 | 2.43 | 0.01 | 102,720.03 | 0.04 | 24,436.26 | 0.01 | 79,953.95 | 4.08 | 244.99 | crlist |
|
|
340
|
+
| class | merge shuffled gossip | 5,000 | 250 | 265.96 | 1.06 | 940 | 0.72 | 1,384.5 | 0.01 | 73,120.8 | 0.38 | 2,648.01 | json-joy |
|
|
341
|
+
|
|
|
342
|
+
|
|
343
|
+
These benchmarks compare the work a JavaScript consumer asks each library to do:
|
|
344
|
+
hydrate state, read indexed values, mutate list position, emit or apply deltas,
|
|
345
|
+
and materialize snapshots. CRList is strongest where its live linked projection
|
|
346
|
+
and index cache can be updated incrementally, especially local CRUD, snapshot
|
|
347
|
+
hydration, snapshots, and ordered append deltas.
|
|
348
|
+
|
|
349
|
+
The shuffled-gossip costs more than
|
|
350
|
+
json-joy because CRList immediately maintains a JS live projection and returns
|
|
351
|
+
index-keyed change patches from every merge.
|
|
352
|
+
|
|
353
|
+
json-joy's benchmark path applies compact JSON CRDT patches directly to its
|
|
354
|
+
model, so shuffled patch application is extremely cheap in this scenario. That
|
|
355
|
+
does not prove a weaker convergence model by itself, but it is a different
|
|
356
|
+
tradeoff from CRList's immediate event/change surface.
|
|
357
|
+
|
|
358
|
+
Yjs integrates updates
|
|
359
|
+
into a mature struct store with pending update/delete-set handling, which keeps
|
|
360
|
+
out-of-order gossip relatively cheap.
|
|
361
|
+
|
|
362
|
+
Automerge delegates change application and
|
|
363
|
+
indexed reads to its WASM-backed document store and lazy proxies, explaining its
|
|
364
|
+
very fast random reads and `find` path; its local writes are slower here because
|
|
365
|
+
each write goes through immutable document changes and change generation.
|
|
366
|
+
|
|
367
|
+
Analysis by ChatGPT-5.5.
|
|
335
368
|
|
|
336
369
|
## License
|
|
337
370
|
|