@sovereignbase/sequencer 1.0.1 → 1.1.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/INTERNALS.md CHANGED
@@ -744,10 +744,18 @@ The reported point is a **frontier**.
744
744
 
745
745
  A single frontier summarizes a received prefix of a Session rather than acknowledging every reducing Insertion separately.
746
746
 
747
+ Every active Actor, including an offline Actor, must be registered before removals. An Actor-only acknowledgement such as `[3]` establishes that membership. Constructing another Projection does not register its Actor in the other replicas.
748
+
749
+ The application must exchange pending history before treating an acknowledgement as a complete Session frontier. The library reports receipt of reducing Insertions; it does not prove that missing earlier operations have arrived.
750
+
747
751
  ## Compaction
748
752
 
749
753
  When all active Actors agree on the same frontier for a reducing Session, the acknowledged part can be removed from future retained Sequences.
750
754
 
755
+ This is whole-Session eligibility: every active Actor must report the same complete Session frontier. A missing claim or a different endpoint blocks that Session.
756
+
757
+ Eligible masks must disappear from the exported Sequence. Wholly removed positive Insertions and deleted Footage disappear as well. Acknowledgments of compacted Sessions are dropped, Actor membership is retained.
758
+
751
759
  Suppose history contains:
752
760
 
753
761
  ```text
@@ -784,6 +792,10 @@ Anchors and remaining removals that referred to the old coordinates are adjusted
784
792
 
785
793
  The running Projection does not need to be rewritten when this happens. Compaction produces another retained description of the same history.
786
794
 
795
+ The exported Sequence is a retained checkpoint. Its shorter Insertions and translated anchors can use different coordinates from the live graph before export. Continued editors must use compatible retained state; a compacted checkpoint does not preserve a permanent mapping to discarded history.
796
+
797
+ An offline Actor's unacknowledged history blocks compaction only if that Actor was registered.
798
+
787
799
  ## Collapsed historical points
788
800
 
789
801
  Compaction can make two old logical points collapse onto the same retained point.
package/README.md CHANGED
@@ -27,10 +27,14 @@ console.log(projection.value(0)) // undefined
27
27
  projection.destroy()
28
28
  ```
29
29
 
30
+ For text stored as UTF-16 code units, `projection.sequence(true)` returns string
31
+ Footage. Construction and merge accept either form; `sequence()` keeps array
32
+ Footage. See [Projection.sequence](https://sovereignbase.dev/sequencer/classes/Projection.html#sequence).
33
+
30
34
  ### See documentation
31
35
 
32
36
  - [How sequencer works?](INTERNALS.md)
33
- - [Typescript](https://sovereignbase.dev/sequencer/)
37
+ - [Typescript](https://sovereignbase.dev/sequencer/classes/Projection.html)
34
38
  - [C++](https://sovereignbase.dev/sequencer/c++)
35
39
 
36
40
  ### Errors
@@ -39,10 +43,11 @@ Library-reported failures throw `SequencerError`, with a stable `SequencerErrorC
39
43
  and a message prefixed with `{@sovereignbase/sequencer}`. Both are exported from
40
44
  the package. The constructor accepts standard `ErrorOptions`, including `cause`.
41
45
 
42
- | Code | Meaning |
43
- | ------------------------- | ------------------------------------------------------------------- |
44
- | `PROJECTION_DESTROYED` | An operation was called after the Projection was destroyed. |
45
- | `NATIVE_OPERATION_FAILED` | The native runtime reported an initialization or operation failure. |
46
+ | Code | Meaning |
47
+ | ------------------------- | ---------------------------------------------------------------------------- |
48
+ | `PROJECTION_DESTROYED` | An operation was called after the Projection was destroyed. |
49
+ | `NATIVE_OPERATION_FAILED` | The native runtime reported an initialization or operation failure. |
50
+ | `STRING_ENCODING_FAILED` | Snapshot Footage concatenation failed; `cause` preserves the original error. |
46
51
 
47
52
  Invalid Gossip or Sequence input to `apply()` or `merge()` returns `undefined`.
48
53
  Platform errors retain their original types.
@@ -53,8 +58,8 @@ Platform errors retain their original types.
53
58
 
54
59
  | Format | Raw (KiB) | Minified (KiB) | Minified + gzip (KiB) |
55
60
  | -------- | --------: | -------------: | --------------------: |
56
- | ESM | 125.98 | 100.80 | 36.45 |
57
- | CommonJS | 126.12 | 101.49 | 36.53 |
61
+ | ESM | 136.19 | 109.61 | 39.20 |
62
+ | CommonJS | 136.33 | 110.32 | 39.27 |
58
63
 
59
64
  Both bundles include WASM. Terser uses three compression passes; gzip uses level 9.
60
65
 
@@ -67,37 +72,37 @@ Strips contain 1–100 Frames (visible entries). Headers show Strip counts and m
67
72
 
68
73
  | Method / case | 1,000 Strips<br>50,871 Frames | 5,000 Strips<br>252,214 Frames | 10,000 Strips<br>504,871 Frames | 15,000 Strips<br>758,280 Frames | 20,000 Strips<br>1,010,749 Frames | 25,000 Strips<br>1,264,003 Frames |
69
74
  | -------------- | ----------------------------: | -----------------------------: | ------------------------------: | ------------------------------: | --------------------------------: | --------------------------------: |
70
- | apply.random | 146,512 | 50,162 | 35,425 | 25,372 | 17,992 | 13,401 |
71
- | insert.head | 1,103,240 | 627,952 | 723,841 | 741,193 | 692,500 | 629,581 |
72
- | insert.random | 423,106 | 138,442 | 91,906 | 64,213 | 44,063 | 33,092 |
73
- | insert.tail | 1,247,342 | 779,594 | 895,027 | 892,070 | 830,660 | 765,706 |
75
+ | apply.random | 168,473 | 87,171 | 60,658 | 46,603 | 38,343 | 32,658 |
76
+ | insert.head | 1,271,814 | 999,755 | 1,074,002 | 1,093,264 | 1,106,172 | 1,105,184 |
77
+ | insert.random | 475,390 | 255,768 | 161,979 | 124,466 | 100,709 | 85,015 |
78
+ | insert.tail | 1,470,843 | 1,177,272 | 1,266,352 | 1,276,470 | 1,281,022 | 1,280,911 |
74
79
  | remove.head | — | — | — | — | — | — |
75
- | remove.random | 258,681 | 95,210 | 65,861 | 46,668 | 31,655 | 23,556 |
80
+ | remove.random | 358,067 | 180,092 | 117,059 | 86,936 | 69,330 | 57,290 |
76
81
  | remove.tail | — | — | — | — | — | — |
77
- | replace.head | 380,869 | 309,212 | 303,788 | 291,544 | 270,032 | 245,792 |
78
- | replace.random | 253,774 | 94,640 | 63,352 | 45,272 | 31,633 | 23,736 |
79
- | replace.tail | 392,296 | 315,718 | 313,645 | 310,052 | 268,791 | 247,351 |
80
- | value.head | 2,283,059 | 2,095,440 | 1,999,974 | 2,016,602 | 1,907,994 | 1,721,581 |
81
- | value.random | 569,971 | 133,693 | 78,867 | 51,725 | 34,540 | 25,316 |
82
- | value.tail | 4,749,438 | 3,636,984 | 3,461,656 | 3,227,876 | 2,914,996 | 2,408,625 |
82
+ | replace.head | 453,369 | 416,649 | 429,360 | 394,513 | 395,389 | 403,713 |
83
+ | replace.random | 298,112 | 160,606 | 108,525 | 80,892 | 65,452 | 54,680 |
84
+ | replace.tail | 401,284 | 449,608 | 412,634 | 430,354 | 408,033 | 387,953 |
85
+ | value.head | 2,827,881 | 3,525,681 | 3,620,595 | 3,723,069 | 3,810,856 | 3,811,845 |
86
+ | value.random | 731,172 | 255,071 | 143,482 | 100,113 | 78,156 | 63,980 |
87
+ | value.tail | 5,453,695 | 5,310,238 | 5,096,734 | 5,044,621 | 5,054,127 | 4,915,815 |
83
88
 
84
89
  **↓ Scale down (25,000 → 0 Strips)**
85
90
 
86
91
  | Method / case | 20,000 Strips<br>1,012,742 Frames | 15,000 Strips<br>755,860 Frames | 10,000 Strips<br>504,103 Frames | 5,000 Strips<br>251,203 Frames | 1,000 Strips<br>51,057 Frames | 0 Strips<br>0 Frames |
87
92
  | -------------- | --------------------------------: | ------------------------------: | ------------------------------: | -----------------------------: | ----------------------------: | -------------------: |
88
- | apply.random | 7,268 | 7,592 | 8,263 | 8,783 | 9,083 | 9,219 |
93
+ | apply.random | 21,832 | 22,291 | 22,406 | 22,966 | 23,864 | 24,211 |
89
94
  | insert.head | — | — | — | — | — | — |
90
- | insert.random | 17,296 | 18,458 | 20,290 | 21,279 | 22,052 | 22,459 |
95
+ | insert.random | 53,637 | 55,767 | 57,227 | 57,796 | 60,536 | 60,616 |
91
96
  | insert.tail | — | — | — | — | — | — |
92
- | remove.head | 157,981 | 165,917 | 180,514 | 178,894 | 181,826 | 183,709 |
93
- | remove.random | 13,036 | 13,992 | 15,527 | 16,535 | 17,163 | 17,459 |
94
- | remove.tail | 192,199 | 192,220 | 203,528 | 209,615 | 209,694 | 210,394 |
95
- | replace.head | 176,953 | 178,240 | 186,921 | 185,389 | 181,259 | 161,071 |
96
- | replace.random | 13,038 | 14,084 | 15,647 | 16,708 | 17,397 | 17,697 |
97
- | replace.tail | 190,938 | 184,284 | 193,773 | 187,715 | 182,304 | 182,496 |
98
- | value.head | 794,128 | 838,606 | 885,880 | 922,502 | 940,112 | 948,944 |
99
- | value.random | 13,677 | 14,768 | 16,600 | 18,037 | 18,894 | 19,271 |
100
- | value.tail | 1,070,897 | 1,038,948 | 1,093,604 | 1,140,368 | 1,178,006 | 1,192,164 |
97
+ | remove.head | 493,654 | 493,034 | 492,611 | 492,704 | 494,704 | 497,520 |
98
+ | remove.random | 37,466 | 39,462 | 41,048 | 43,073 | 45,209 | 45,778 |
99
+ | remove.tail | 491,829 | 472,405 | 399,771 | 416,614 | 426,344 | 383,461 |
100
+ | replace.head | 380,504 | 371,861 | 365,935 | 312,468 | 315,039 | 271,629 |
101
+ | replace.random | 35,794 | 37,986 | 39,619 | 41,464 | 43,674 | 43,633 |
102
+ | replace.tail | 198,219 | 176,520 | 166,748 | 150,292 | 149,123 | 140,224 |
103
+ | value.head | 1,820,081 | 1,813,320 | 1,792,267 | 1,804,349 | 1,844,976 | 1,872,844 |
104
+ | value.random | 41,888 | 43,912 | 45,754 | 48,224 | 51,108 | 52,192 |
105
+ | value.tail | 2,154,911 | 2,130,711 | 2,112,616 | 2,133,349 | 2,207,459 | 2,246,004 |
101
106
 
102
107
  ### API throughput at checkpoint
103
108
 
@@ -107,17 +112,17 @@ Checkpoint calls, in ops/s, averaged across runs.
107
112
 
108
113
  | Method | 1,000 Strips<br>50,871 Frames | 5,000 Strips<br>252,214 Frames | 10,000 Strips<br>504,871 Frames | 15,000 Strips<br>758,280 Frames | 20,000 Strips<br>1,010,749 Frames | 25,000 Strips<br>1,264,003 Frames |
109
114
  | --------------------------------- | ----------------------------: | -----------------------------: | ------------------------------: | ------------------------------: | --------------------------------: | --------------------------------: |
110
- | new Projection(actorID, sequence) | 2,513 | 795 | 408 | 215 | 154 | 107 |
111
- | sequence() | 375 | 66 | 33 | 18 | 11 | 6 |
112
- | values() | 480 | 163 | 108 | 70 | 49 | 32 |
115
+ | new Projection(actorID, sequence) | 4,665 | 968 | 614 | 420 | 291 | 244 |
116
+ | sequence() | 611 | 102 | 50 | 31 | 21 | 15 |
117
+ | values() | 669 | 251 | 84 | 50 | 50 | 31 |
113
118
 
114
119
  **↓ Scale down (25,000 → 0 Strips)**
115
120
 
116
121
  | Method | 20,000 Strips<br>1,012,742 Frames | 15,000 Strips<br>755,860 Frames | 10,000 Strips<br>504,103 Frames | 5,000 Strips<br>251,203 Frames | 1,000 Strips<br>51,057 Frames | 0 Strips<br>0 Frames |
117
122
  | --------------------------------- | --------------------------------: | ------------------------------: | ------------------------------: | -----------------------------: | ----------------------------: | -------------------: |
118
- | new Projection(actorID, sequence) | 116 | 212 | 273 | 586 | 1,881 | 16,098 |
119
- | sequence() | 7 | 6 | 5 | 4 | 4 | 38,383 |
120
- | values() | 44 | 51 | 58 | 62 | 199 | 68,912 |
123
+ | new Projection(actorID, sequence) | 276 | 420 | 499 | 1,294 | 5,450 | 23,249 |
124
+ | sequence() | 15 | 14 | 10 | 12 | 11 | 10 |
125
+ | values() | 46 | 45 | 68 | 96 | 258 | 150,052 |
121
126
 
122
127
  ### Sequence disk size at checkpoint
123
128
 
@@ -127,8 +132,8 @@ Complete exported Sequences, including Footage and acknowledgements. Sizes are i
127
132
 
128
133
  | Encoding | 1,000 Strips<br>50,871 Frames | 5,000 Strips<br>252,214 Frames | 10,000 Strips<br>504,871 Frames | 15,000 Strips<br>758,280 Frames | 20,000 Strips<br>1,010,749 Frames | 25,000 Strips<br>1,264,003 Frames |
129
134
  | ------------------ | ----------------------------: | -----------------------------: | ------------------------------: | ------------------------------: | --------------------------------: | --------------------------------: |
130
- | JSON | 277.17 | 1,621.65 | 3,261.72 | 4,901.02 | 7,041.25 | 9,162.75 |
131
- | JSON + gzip | 14.59 | 73.84 | 150.38 | 226.94 | 311.22 | 391.69 |
135
+ | JSON | 277.29 | 1,622.20 | 3,262.86 | 4,902.77 | 7,043.50 | 9,165.60 |
136
+ | JSON + gzip | 14.60 | 73.83 | 150.38 | 226.92 | 311.16 | 391.60 |
132
137
  | MessagePack | 164.81 | 818.88 | 1,639.69 | 3,529.41 | 5,081.04 | 6,483.22 |
133
138
  | MessagePack + gzip | 12.38 | 61.62 | 124.91 | 198.59 | 263.54 | 332.77 |
134
139
 
@@ -136,8 +141,8 @@ Complete exported Sequences, including Footage and acknowledgements. Sizes are i
136
141
 
137
142
  | Encoding | 20,000 Strips<br>1,012,742 Frames | 15,000 Strips<br>755,860 Frames | 10,000 Strips<br>504,103 Frames | 5,000 Strips<br>251,203 Frames | 1,000 Strips<br>51,057 Frames | 0 Strips<br>0 Frames |
138
143
  | ------------------ | --------------------------------: | ------------------------------: | ------------------------------: | -----------------------------: | ----------------------------: | -------------------: |
139
- | JSON | 7,446.44 | 5,617.36 | 3,769.76 | 1,885.51 | 383.23 | 0.02 |
140
- | JSON + gzip | 323.23 | 244.45 | 163.91 | 80.61 | 16.33 | 0.03 |
144
+ | JSON | 7,449.19 | 5,619.45 | 3,771.17 | 1,886.19 | 383.37 | 0.02 |
145
+ | JSON + gzip | 323.17 | 244.42 | 163.89 | 80.61 | 16.33 | 0.03 |
141
146
  | MessagePack | 5,237.17 | 3,930.33 | 2,628.38 | 1,312.43 | 266.67 | 0.01 |
142
147
  | MessagePack + gzip | 274.96 | 207.78 | 137.38 | 67.41 | 13.67 | 0.03 |
143
148
 
@@ -157,8 +162,8 @@ One instance: WASM memory plus retained JS array slots, in KiB (1,024 bytes).
157
162
  | ---------------------- | --------------------------------: | ------------------------------: | ------------------------------: | -----------------------------: | ----------------------------: | -------------------: |
158
163
  | Estimated memory (KiB) | 163,746.93 | 174,034.00 | 202,660.72 | 293,941.85 | 302,158.29 | 304,203.30 |
159
164
 
160
- Measured on Node 24.16.0, V8 13.6.233.17-node.49,
161
- win32 x64, Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz.
165
+ Measured on Node 24.22.0, V8 13.6.233.17-node.57,
166
+ linux x64, AMD EPYC 7763 64-Core Processor.
162
167
  Peer synchronization, encoding and JS process garbage collection are outside API timings.
163
168
  [Full lifecycle results](benchmark/.results/lifecycle.md) · [Throughput results](benchmark/.results/throughput.md).
164
169
 
@@ -166,7 +171,7 @@ Peer synchronization, encoding and JS process garbage collection are outside API
166
171
 
167
172
  ### Behaviour guaranteed by excessive tests
168
173
 
169
- The latest verification passed 184 Vitest tests and 96 compatibility checks (1 failed).
174
+ The latest verification passed 221 Vitest tests and 117 compatibility checks.
170
175
  The configured 100% coverage threshold is met (100% statements, 100% branches, 100% functions, 100% lines).
171
176
  See the [test suites](test/README.md) and
172
177
  [automated test report](https://sovereignbase.dev/sequencer/tests/).
@@ -182,7 +187,7 @@ Runtimes covered by the latest compatibility verification:
182
187
  - Edge Runtime: passed
183
188
  - Cloudflare Workers through workerd: passed
184
189
  - Chromium browser windows: passed
185
- - Firefox browser windows: failed (matching Playwright browser binary unavailable)
190
+ - Firefox browser windows: passed
186
191
  - WebKit browser windows: passed
187
192
 
188
193
  ### Tested realtime and offline text editing behaviour examples