@dxos/merkle-search-tree 0.8.3 → 0.8.4-main.3f58842

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.
@@ -1,994 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var node_exports = {};
20
- __export(node_exports, {
21
- Forest: () => Forest,
22
- LWWTree: () => LWWTree,
23
- MirrorMultiMap: () => MirrorMultiMap,
24
- TreeMut: () => TreeMut,
25
- createValue: () => createValue,
26
- digestEquals: () => digestEquals,
27
- formatDigest: () => formatDigest,
28
- getLevel: () => getLevel,
29
- getLevelHex: () => getLevelHex,
30
- initLWWTreeSyncState: () => initLWWTreeSyncState,
31
- makeItem: () => makeItem,
32
- randomKey: () => randomKey,
33
- randomSample: () => randomSample
34
- });
35
- module.exports = __toCommonJS(node_exports);
36
- var import_util = require("@dxos/util");
37
- var import_invariant = require("@dxos/invariant");
38
- var import_util2 = require("@dxos/util");
39
- var import_util3 = require("@dxos/util");
40
- var makeItem = async (key, value) => {
41
- const keyBytes = textEncoder.encode(key);
42
- const data = new Uint8Array(keyBytes.length + value.length);
43
- data.set(keyBytes, 0);
44
- data.set(value, keyBytes.length);
45
- const digest = await crypto.subtle.digest({
46
- name: "SHA-256"
47
- }, data);
48
- return {
49
- key,
50
- value,
51
- digest: new Uint8Array(digest)
52
- };
53
- };
54
- var getLevel = (digest) => {
55
- let level = 0;
56
- for (let i = 0; i < digest.length; i++) {
57
- const byte = digest[i];
58
- if (byte >> 4 === 0) {
59
- level++;
60
- } else {
61
- break;
62
- }
63
- if ((byte & 15) === 0) {
64
- level++;
65
- } else {
66
- break;
67
- }
68
- }
69
- return level;
70
- };
71
- var formatDigest = (digest) => {
72
- return (0, import_util.arrayToHex)(digest.buffer);
73
- };
74
- var getLevelHex = (digest) => {
75
- let level = 0;
76
- for (let i = 0; i < digest.length; i++) {
77
- if (digest[i] === "0") {
78
- level++;
79
- } else {
80
- break;
81
- }
82
- }
83
- return level;
84
- };
85
- var digestEquals = (a, b) => {
86
- if (a.length !== b.length) {
87
- return false;
88
- }
89
- for (let i = 0; i < a.length; i++) {
90
- if (a[i] !== b[i]) {
91
- return false;
92
- }
93
- }
94
- return true;
95
- };
96
- var textEncoder = new TextEncoder();
97
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/merkle-search-tree/src/forest.ts";
98
- var Forest = class {
99
- constructor() {
100
- this.#nodes = /* @__PURE__ */ new Map();
101
- this.itemHashOps = 0;
102
- this.nodeHashOps = 0;
103
- this.#emptyNodeCache = void 0;
104
- }
105
- #nodes;
106
- async createTree(pairs) {
107
- const items = await Promise.all([
108
- ...pairs
109
- ].map(([key, value]) => makeItem2(key, value)));
110
- this.itemHashOps += items.length;
111
- items.sort((a, b) => a.key < b.key ? -1 : 1);
112
- for (let i = 0; i < items.length; i++) {
113
- if (i + 1 < items.length && items[i].key === items[i + 1].key) {
114
- throw new Error("Duplicate key");
115
- }
116
- }
117
- if (items.length === 0) {
118
- return this.#makeNode(0, [], []);
119
- }
120
- const buildLevel = async (level, from, to) => {
121
- (0, import_invariant.invariant)(level >= 0, void 0, {
122
- F: __dxlog_file,
123
- L: 37,
124
- S: this,
125
- A: [
126
- "level >= 0",
127
- ""
128
- ]
129
- });
130
- if (level === 0) {
131
- return this.#makeNode(0, items.slice(from, to), []);
132
- }
133
- let rangeBegin = from;
134
- const childItems = [];
135
- const childNodes = [];
136
- for (let i = from; i < to; i++) {
137
- if (items[i].level > level) {
138
- throw new Error("BUG - Node level is higher then expected");
139
- }
140
- if (items[i].level === level) {
141
- const node = await buildLevel(level - 1, rangeBegin, i);
142
- childNodes.push(node);
143
- childItems.push(items[i]);
144
- rangeBegin = i + 1;
145
- }
146
- }
147
- childNodes.push(await buildLevel(level - 1, rangeBegin, to));
148
- return this.#makeNode(level, childItems, childNodes);
149
- };
150
- const maxLevel = Math.max(...items.map((item) => item.level));
151
- const root = await buildLevel(maxLevel, 0, items.length);
152
- return root;
153
- }
154
- async get(root, key) {
155
- const keyLevel = await getKeyLevel(key);
156
- let node = this.#nodes.get(root);
157
- if (node !== void 0 && node.level < keyLevel) {
158
- return {
159
- kind: "missing"
160
- };
161
- }
162
- while (node !== void 0) {
163
- if (node.level === keyLevel) {
164
- for (let i = 0; i < node.items.length; i++) {
165
- if (node.items[i].key === key) {
166
- return {
167
- kind: "present",
168
- value: node.items[i].value
169
- };
170
- }
171
- }
172
- return {
173
- kind: "missing"
174
- };
175
- } else {
176
- let found = false;
177
- for (let i = 0; i < node.items.length; i++) {
178
- if (node.items[i].key > key) {
179
- node = this.#nodes.get(node.children[i]);
180
- found = true;
181
- break;
182
- }
183
- }
184
- if (!found) {
185
- (0, import_invariant.invariant)(node.level > 0, void 0, {
186
- F: __dxlog_file,
187
- L: 96,
188
- S: this,
189
- A: [
190
- "node!.level > 0",
191
- ""
192
- ]
193
- });
194
- node = this.#nodes.get(node.children[node.items.length]);
195
- }
196
- }
197
- }
198
- return {
199
- kind: "not-available"
200
- };
201
- }
202
- async merge(digest1, digest2, mergeFn) {
203
- if (digest1 === digest2) {
204
- return digest1;
205
- }
206
- const node1 = this.#requireNode(digest1);
207
- const node2 = this.#requireNode(digest2);
208
- if (node2.level < node1.level) {
209
- return await this.merge(digest1, await this.#makeNode(node2.level + 1, [], [
210
- digest2
211
- ]), mergeFn);
212
- } else if (node1.level < node2.level) {
213
- return await this.merge(await this.#makeNode(node1.level + 1, [], [
214
- digest1
215
- ]), digest2, mergeFn);
216
- }
217
- (0, import_invariant.invariant)(node1.level === node2.level, void 0, {
218
- F: __dxlog_file,
219
- L: 119,
220
- S: this,
221
- A: [
222
- "node1.level === node2.level",
223
- ""
224
- ]
225
- });
226
- const resultItems = [];
227
- const resultChildren = [];
228
- let carry1 = null;
229
- let carry2 = null;
230
- for (let i1 = 0, i2 = 0; i1 < node1.items.length || i2 < node2.items.length; void 0) {
231
- (0, import_invariant.invariant)(i1 <= node1.items.length, void 0, {
232
- F: __dxlog_file,
233
- L: 132,
234
- S: this,
235
- A: [
236
- "i1 <= node1.items.length",
237
- ""
238
- ]
239
- });
240
- (0, import_invariant.invariant)(i2 <= node2.items.length, void 0, {
241
- F: __dxlog_file,
242
- L: 133,
243
- S: this,
244
- A: [
245
- "i2 <= node2.items.length",
246
- ""
247
- ]
248
- });
249
- const key1 = i1 < node1.items.length ? node1.items[i1].key : null;
250
- const key2 = i2 < node2.items.length ? node2.items[i2].key : null;
251
- (0, import_invariant.invariant)(key1 !== null || key2 !== null, void 0, {
252
- F: __dxlog_file,
253
- L: 137,
254
- S: this,
255
- A: [
256
- "key1 !== null || key2 !== null",
257
- ""
258
- ]
259
- });
260
- const child1 = carry1 !== null ? carry1 : node1.children[i1];
261
- const child2 = carry2 !== null ? carry2 : node2.children[i2];
262
- if (node1.level > 0) {
263
- (0, import_invariant.invariant)(validDigest(child1), void 0, {
264
- F: __dxlog_file,
265
- L: 142,
266
- S: this,
267
- A: [
268
- "validDigest(child1)",
269
- ""
270
- ]
271
- });
272
- (0, import_invariant.invariant)(validDigest(child2), void 0, {
273
- F: __dxlog_file,
274
- L: 143,
275
- S: this,
276
- A: [
277
- "validDigest(child2)",
278
- ""
279
- ]
280
- });
281
- }
282
- if (key1 === key2) {
283
- if (node1.level > 0) {
284
- resultChildren.push(await this.merge(child1, child2, mergeFn));
285
- }
286
- resultItems.push(await this.#mergeItem(mergeFn, node1.items[i1], node2.items[i2]));
287
- carry1 = null;
288
- carry2 = null;
289
- i1++;
290
- i2++;
291
- } else if (key2 !== null && (key1 === null || key1 > key2)) {
292
- (0, import_invariant.invariant)(key2 !== null, void 0, {
293
- F: __dxlog_file,
294
- L: 157,
295
- S: this,
296
- A: [
297
- "key2 !== null",
298
- ""
299
- ]
300
- });
301
- resultItems.push(await this.#mergeItem(mergeFn, null, node2.items[i2]));
302
- if (node1.level > 0) {
303
- const [left, right] = await this.#splitAtKey(child1, key2);
304
- resultChildren.push(await this.merge(left, child2, mergeFn));
305
- carry1 = right;
306
- carry2 = null;
307
- }
308
- i2++;
309
- } else {
310
- (0, import_invariant.invariant)(key1 !== null, void 0, {
311
- F: __dxlog_file,
312
- L: 170,
313
- S: this,
314
- A: [
315
- "key1 !== null",
316
- ""
317
- ]
318
- });
319
- resultItems.push(await this.#mergeItem(mergeFn, node1.items[i1], null));
320
- if (node1.level > 0) {
321
- const [left, right] = await this.#splitAtKey(child2, key1);
322
- resultChildren.push(await this.merge(child1, left, mergeFn));
323
- carry1 = null;
324
- carry2 = right;
325
- }
326
- i1++;
327
- }
328
- }
329
- if (node1.level > 0) {
330
- const child1 = carry1 !== null ? carry1 : node1.children[node1.items.length];
331
- const child2 = carry2 !== null ? carry2 : node2.children[node2.items.length];
332
- resultChildren.push(await this.merge(child1, child2, mergeFn));
333
- }
334
- return await this.#makeNode(node1.level, resultItems, resultChildren);
335
- }
336
- async setBatch(root, pairs) {
337
- const newTree = await this.createTree(pairs);
338
- return await this.merge(root, newTree, async (key, value1, value2) => value2 !== null ? value2 : value1);
339
- }
340
- async set(root, key, value) {
341
- return this.setBatch(root, [
342
- [
343
- key,
344
- value
345
- ]
346
- ]);
347
- }
348
- *missingNodes(digest) {
349
- const node = this.#nodes.get(digest);
350
- if (!node) {
351
- yield digest;
352
- } else {
353
- for (const child of node.children) {
354
- yield* this.missingNodes(child);
355
- }
356
- }
357
- }
358
- async insertNodes(nodes) {
359
- const result = [];
360
- for (const node of nodes) {
361
- const items = await Promise.all(node.items.map((item) => makeItem2(item.key, item.value)));
362
- const { digest } = await makeNode(node.level, items, node.children);
363
- (0, import_invariant.invariant)(digest === node.digest, void 0, {
364
- F: __dxlog_file,
365
- L: 218,
366
- S: this,
367
- A: [
368
- "digest === node.digest",
369
- ""
370
- ]
371
- });
372
- this.#nodes.set(node.digest, {
373
- level: node.level,
374
- digest: node.digest,
375
- items,
376
- children: node.children
377
- });
378
- result.push(node.digest);
379
- }
380
- return result;
381
- }
382
- async getNodes(digests) {
383
- const result = [];
384
- for (const digest of digests) {
385
- const node = this.#nodes.get(digest);
386
- if (!node) {
387
- continue;
388
- }
389
- result.push({
390
- level: node.level,
391
- digest: node.digest,
392
- items: node.items.map((item) => ({
393
- key: item.key,
394
- value: item.value
395
- })),
396
- children: node.children
397
- });
398
- }
399
- return result;
400
- }
401
- treeMut(root) {
402
- return new TreeMut(this, root);
403
- }
404
- formatToString(digest, { pad = 0 } = {}) {
405
- const padStr = " ".repeat(pad);
406
- const node = this.#nodes.get(digest);
407
- if (!node) {
408
- return `${padStr} o (${digest.slice(0, 8)}) NOT AVAILABLE`;
409
- }
410
- let string = `${padStr} o (${digest.slice(0, 8)}) level=${node.level} size=${node.items.length}
411
- `;
412
- for (let i = 0; i < node.items.length; i++) {
413
- if (node.level > 0) {
414
- string += this.formatToString(node.children[i], {
415
- pad: pad + 1
416
- });
417
- }
418
- string += `${padStr} - [${node.items[i].itemDigest.slice(0, 8)}] level=${node.items[i].level} ${node.items[i].key.slice(0, 10)} -> ${(0, import_util2.arrayToHex)(node.items[i].value.slice(0, 10).buffer)}
419
- `;
420
- }
421
- if (node.level > 0) {
422
- string += this.formatToString(node.children[node.items.length], {
423
- pad: pad + 1
424
- });
425
- }
426
- return string;
427
- }
428
- /**
429
- * Items iterator ordered by key.
430
- */
431
- *items(digest) {
432
- const node = this.#requireNode(digest);
433
- for (let i = 0; i < node.items.length; i++) {
434
- if (node.level > 0) {
435
- yield* this.items(node.children[i]);
436
- }
437
- yield node.items[i];
438
- }
439
- if (node.level > 0) {
440
- yield* this.items(node.children[node.items.length]);
441
- }
442
- }
443
- #requireNode(digest) {
444
- (0, import_invariant.invariant)(validDigest(digest), void 0, {
445
- F: __dxlog_file,
446
- L: 295,
447
- S: this,
448
- A: [
449
- "validDigest(digest)",
450
- ""
451
- ]
452
- });
453
- const node = this.#nodes.get(digest);
454
- if (!node) {
455
- throw new Error(`Node not available: ${digest}`);
456
- }
457
- return node;
458
- }
459
- async #mergeItem(mergeFn, item1, item2) {
460
- (0, import_invariant.invariant)(item1 !== null || item2 !== null, void 0, {
461
- F: __dxlog_file,
462
- L: 304,
463
- S: this,
464
- A: [
465
- "item1 !== null || item2 !== null",
466
- ""
467
- ]
468
- });
469
- const key = item1?.key ?? item2?.key;
470
- if (item1 !== null && item2 !== null && (0, import_util2.arraysEqual)(item1.value, item2.value)) {
471
- return item1;
472
- } else {
473
- const mergeResult = await mergeFn(key, item1?.value ?? null, item2?.value ?? null);
474
- if (item1 !== null && (0, import_util2.arraysEqual)(item1.value, mergeResult)) {
475
- return item1;
476
- } else if (item2 !== null && (0, import_util2.arraysEqual)(item2.value, mergeResult)) {
477
- return item2;
478
- } else {
479
- this.itemHashOps++;
480
- return await makeItem2(key, mergeResult);
481
- }
482
- }
483
- }
484
- #emptyNodeCache;
485
- async #makeNode(level, items, children) {
486
- (0, import_invariant.invariant)(level > 0 ? items.length + 1 === children.length : children.length === 0, void 0, {
487
- F: __dxlog_file,
488
- L: 328,
489
- S: this,
490
- A: [
491
- "level > 0 ? items.length + 1 === children.length : children.length === 0",
492
- ""
493
- ]
494
- });
495
- let node;
496
- if (level === 0 && items.length === 0) {
497
- node = await (this.#emptyNodeCache ??= makeNode(0, [], []));
498
- } else {
499
- node = await makeNode(level, items, children);
500
- this.nodeHashOps++;
501
- }
502
- if (!this.#nodes.has(node.digest)) {
503
- this.#nodes.set(node.digest, node);
504
- }
505
- return node.digest;
506
- }
507
- async #splitAtKey(digest, key) {
508
- const node = this.#requireNode(digest);
509
- let splitIndex = node.items.length;
510
- for (let i = 0; i < node.items.length; i++) {
511
- if (node.items[i].key === key) {
512
- return [
513
- await this.#makeNode(node.level, node.items.slice(0, i), node.children.slice(0, i + 1)),
514
- await this.#makeNode(node.level, node.items.slice(i + 1), node.children.slice(i + 2))
515
- ];
516
- }
517
- if (node.items[i].key > key) {
518
- splitIndex = i;
519
- break;
520
- }
521
- }
522
- if (node.level === 0) {
523
- if (splitIndex === 0) {
524
- return [
525
- await this.#makeNode(0, [], []),
526
- digest
527
- ];
528
- } else if (splitIndex === node.items.length) {
529
- return [
530
- digest,
531
- await this.#makeNode(0, [], [])
532
- ];
533
- }
534
- return [
535
- await this.#makeNode(node.level, node.items.slice(0, splitIndex), []),
536
- await this.#makeNode(node.level, node.items.slice(splitIndex), [])
537
- ];
538
- } else {
539
- const [left, right] = await this.#splitAtKey(node.children[splitIndex], key);
540
- return [
541
- await this.#makeNode(node.level, node.items.slice(0, splitIndex), [
542
- ...node.children.slice(0, splitIndex),
543
- left
544
- ]),
545
- await this.#makeNode(node.level, node.items.slice(splitIndex), [
546
- right,
547
- ...node.children.slice(splitIndex + 1)
548
- ])
549
- ];
550
- }
551
- }
552
- };
553
- var TreeMut = class {
554
- #forest;
555
- #root;
556
- constructor(forest, root) {
557
- this.#forest = forest;
558
- this.#root = root;
559
- }
560
- get root() {
561
- return this.#root;
562
- }
563
- async get(key) {
564
- return this.#forest.get(this.#root, key);
565
- }
566
- async setBatch(pairs) {
567
- this.#root = await this.#forest.setBatch(this.#root, pairs);
568
- }
569
- async set(key, value) {
570
- this.#root = await this.#forest.set(this.#root, key, value);
571
- }
572
- items() {
573
- return this.#forest.items(this.root);
574
- }
575
- };
576
- var makeNode = async (level, items, children) => {
577
- (0, import_invariant.invariant)(level > 0 ? items.length + 1 === children.length : children.length === 0, void 0, {
578
- F: __dxlog_file,
579
- L: 479,
580
- S: void 0,
581
- A: [
582
- "level > 0 ? items.length + 1 === children.length : children.length === 0",
583
- ""
584
- ]
585
- });
586
- const nodeInputData = textEncoder2.encode(items.map((item) => item.itemDigest).join("") + children.join(""));
587
- const digest = await crypto.subtle.digest({
588
- name: "SHA-256"
589
- }, nodeInputData);
590
- return {
591
- level,
592
- digest: formatDigest(new Uint8Array(digest)),
593
- items,
594
- children
595
- };
596
- };
597
- var makeItem2 = async (key, value) => {
598
- (0, import_invariant.invariant)(typeof key === "string", void 0, {
599
- F: __dxlog_file,
600
- L: 501,
601
- S: void 0,
602
- A: [
603
- "typeof key === 'string'",
604
- ""
605
- ]
606
- });
607
- (0, import_invariant.invariant)(value !== null, void 0, {
608
- F: __dxlog_file,
609
- L: 502,
610
- S: void 0,
611
- A: [
612
- "value !== null",
613
- ""
614
- ]
615
- });
616
- const keyBytes = textEncoder2.encode(key);
617
- const keyDigest = await crypto.subtle.digest({
618
- name: "SHA-256"
619
- }, keyBytes);
620
- const keyDigestHex = formatDigest(new Uint8Array(keyDigest));
621
- const data = new Uint8Array(keyBytes.length + value.length);
622
- data.set(keyBytes, 0);
623
- data.set(value, keyBytes.length);
624
- const itemDigest = await crypto.subtle.digest({
625
- name: "SHA-256"
626
- }, data);
627
- return {
628
- level: getLevelHex(keyDigestHex),
629
- key,
630
- value,
631
- keyDigest: keyDigestHex,
632
- itemDigest: formatDigest(new Uint8Array(itemDigest))
633
- };
634
- };
635
- var getKeyLevel = async (key) => {
636
- const keyBytes = textEncoder2.encode(key);
637
- const keyDigest = await crypto.subtle.digest({
638
- name: "SHA-256"
639
- }, keyBytes);
640
- const keyDigestHex = formatDigest(new Uint8Array(keyDigest));
641
- return getLevelHex(keyDigestHex);
642
- };
643
- var textEncoder2 = new TextEncoder();
644
- var validDigest = (digest) => typeof digest === "string" && digest.length > 0;
645
- var LWWTree = class _LWWTree {
646
- static async new(params) {
647
- const tree = new _LWWTree(params);
648
- tree.#currentRoot = await tree.#forest.createTree([]);
649
- return tree;
650
- }
651
- #actor;
652
- #forest = new Forest();
653
- #currentRoot;
654
- get currentRoot() {
655
- return this.#currentRoot;
656
- }
657
- constructor(params) {
658
- this.#actor = params.actor;
659
- }
660
- async get(key) {
661
- const data = await this.#getData(key);
662
- return data?.value;
663
- }
664
- async setBatch(pairs) {
665
- const prevDataBatch = await Promise.all(pairs.map(([key]) => this.#getData(key)));
666
- const updates = pairs.map(([key, value], i) => {
667
- const prevData = prevDataBatch[i];
668
- const newClock = !prevData ? [
669
- this.#actor,
670
- 0
671
- ] : [
672
- this.#actor,
673
- prevData.clock[1] + 1
674
- ];
675
- const data = this.#encode({
676
- clock: newClock,
677
- value
678
- });
679
- return [
680
- key,
681
- data
682
- ];
683
- });
684
- this.#currentRoot = await this.#forest.setBatch(this.#currentRoot, updates);
685
- }
686
- async set(key, value) {
687
- await this.setBatch([
688
- [
689
- key,
690
- value
691
- ]
692
- ]);
693
- }
694
- async receiveSyncMessage(state, message) {
695
- await this.#forest.insertNodes(message.nodes);
696
- const remoteRoot = message.root ?? state.remoteRoot;
697
- if (remoteRoot !== null) {
698
- const missing = [
699
- ...await this.#forest.missingNodes(remoteRoot)
700
- ];
701
- if (missing.length === 0) {
702
- this.#currentRoot = await this.#forest.merge(remoteRoot, this.#currentRoot, this.#merge.bind(this));
703
- } else if (state.remoteRoot !== null && state.remoteRoot !== remoteRoot) {
704
- const missingFromPrevRoot = [
705
- ...await this.#forest.missingNodes(state.remoteRoot)
706
- ];
707
- if (missingFromPrevRoot.length === 0) {
708
- await this.#forest.merge(state.remoteRoot, this.#currentRoot, this.#merge.bind(this));
709
- const missing2 = [
710
- ...await this.#forest.missingNodes(remoteRoot)
711
- ];
712
- if (missing2.length === 0) {
713
- this.#currentRoot = await this.#forest.merge(remoteRoot, this.#currentRoot, this.#merge.bind(this));
714
- }
715
- }
716
- }
717
- }
718
- return {
719
- remoteRoot,
720
- remoteWant: message.want,
721
- needsAck: message.nodes.length > 0
722
- };
723
- }
724
- async generateSyncMessage(state) {
725
- if (state.remoteRoot === this.#currentRoot && state.remoteWant.length === 0 && !state.needsAck) {
726
- return [
727
- state,
728
- null
729
- ];
730
- }
731
- const nodes = await this.#forest.getNodes(state.remoteWant);
732
- const want = state.remoteRoot === null ? [] : [
733
- ...await this.#forest.missingNodes(state.remoteRoot)
734
- ];
735
- return [
736
- {
737
- remoteRoot: state.remoteRoot,
738
- remoteWant: state.remoteWant,
739
- needsAck: false
740
- },
741
- {
742
- root: this.#currentRoot,
743
- want,
744
- nodes
745
- }
746
- ];
747
- }
748
- async #getData(key) {
749
- const res = await this.#forest.get(this.#currentRoot, key);
750
- switch (res.kind) {
751
- case "present": {
752
- return this.#decode(res.value);
753
- }
754
- case "missing":
755
- return void 0;
756
- case "not-available":
757
- throw new Error("Key not available");
758
- }
759
- }
760
- async #merge(key, left, right) {
761
- if (!left) {
762
- return right;
763
- }
764
- if (!right) {
765
- return left;
766
- }
767
- const leftData = this.#decode(left);
768
- const rightData = this.#decode(right);
769
- const cmp = leftData.clock[1] === rightData.clock[1] ? leftData.clock[0].localeCompare(rightData.clock[0]) : leftData.clock[1] - rightData.clock[1];
770
- if (cmp >= 0) {
771
- return left;
772
- } else {
773
- return right;
774
- }
775
- }
776
- #decode(value) {
777
- return JSON.parse(textDecoder.decode(value));
778
- }
779
- #encode(data) {
780
- const { clock, value } = data;
781
- return textEncoder3.encode(JSON.stringify({
782
- clock,
783
- value
784
- }));
785
- }
786
- };
787
- var initLWWTreeSyncState = () => ({
788
- remoteRoot: null,
789
- remoteWant: [],
790
- needsAck: false
791
- });
792
- var textDecoder = new TextDecoder();
793
- var textEncoder3 = new TextEncoder();
794
- var MirrorMultiMap = class _MirrorMultiMap {
795
- static async new(params) {
796
- const tree = new _MirrorMultiMap(params);
797
- tree.#currentRoot = await tree.#forest.createTree([]);
798
- return tree;
799
- }
800
- #forest = new Forest();
801
- #actor;
802
- #currentRoot;
803
- #remoteStates = /* @__PURE__ */ new Map();
804
- constructor(params) {
805
- this.#actor = params.actor;
806
- }
807
- get localActorId() {
808
- return this.#actor;
809
- }
810
- get currentRoot() {
811
- return this.#currentRoot;
812
- }
813
- get forest() {
814
- return this.#forest;
815
- }
816
- async getLocal(key) {
817
- const entry = await this.#forest.get(this.#currentRoot, key);
818
- switch (entry?.kind) {
819
- case "present":
820
- return this.#decode(entry.value);
821
- case "missing":
822
- return void 0;
823
- case "not-available":
824
- throw new Error("Unexpected local entry not available");
825
- }
826
- }
827
- async setLocalBatch(pairs) {
828
- const updates = pairs.map(([key, value]) => [
829
- key,
830
- this.#encode(value)
831
- ]);
832
- this.#currentRoot = await this.#forest.setBatch(this.#currentRoot, updates);
833
- }
834
- async getFor(actorId, key) {
835
- const state = this.#remoteStates.get(actorId);
836
- if (!state) {
837
- throw new Error(`Unknown actorId: ${actorId}`);
838
- }
839
- if (!state.remoteRoot) {
840
- return void 0;
841
- }
842
- const entry = await this.#forest.get(state.remoteRoot, key);
843
- switch (entry?.kind) {
844
- case "present":
845
- return this.#decode(entry.value);
846
- case "missing":
847
- return void 0;
848
- case "not-available":
849
- throw new Error("Unexpected remote entry not available");
850
- }
851
- }
852
- async setForBatch(actorId, pairs) {
853
- const remoteState = this.#remoteStates.get(actorId) ?? initSyncState();
854
- const updates = pairs.map(([key, value]) => [
855
- key,
856
- this.#encode(value)
857
- ]);
858
- const prevRoot = remoteState.remoteRoot ?? await this.#forest.createTree([]);
859
- const nextRoot = await this.#forest.setBatch(prevRoot, updates);
860
- this.#remoteStates.set(actorId, {
861
- remoteRoot: nextRoot,
862
- myRoot: null,
863
- remoteWant: remoteState.remoteWant,
864
- needsAck: remoteState.needsAck
865
- });
866
- }
867
- async getAll(key) {
868
- const result = /* @__PURE__ */ new Map();
869
- result.set(this.#actor, await this.getLocal(key));
870
- for (const [actorId, _state] of this.#remoteStates) {
871
- result.set(actorId, await this.getFor(actorId, key));
872
- }
873
- return result;
874
- }
875
- async getDifferent() {
876
- const resultByKey = /* @__PURE__ */ new Map();
877
- const actors = /* @__PURE__ */ new Set([
878
- this.#actor,
879
- ...this.#remoteStates.keys()
880
- ]);
881
- for (const actor of actors) {
882
- let root;
883
- if (actor === this.#actor) {
884
- root = this.#currentRoot;
885
- } else {
886
- root = this.#remoteStates.get(actor)?.remoteRoot;
887
- }
888
- if (!root) {
889
- continue;
890
- }
891
- for (const item of this.#forest.items(root)) {
892
- let subMap = resultByKey.get(item.key);
893
- if (!subMap) {
894
- subMap = /* @__PURE__ */ new Map();
895
- resultByKey.set(item.key, subMap);
896
- }
897
- subMap.set(actor, item.value);
898
- }
899
- }
900
- const result = /* @__PURE__ */ new Map();
901
- for (const [key, subMap] of resultByKey) {
902
- const first = subMap.values().next().value;
903
- let allEqual = subMap.size === actors.size;
904
- if (allEqual) {
905
- for (const value of subMap.values()) {
906
- if (!(0, import_util3.arraysEqual)(first, value)) {
907
- allEqual = false;
908
- break;
909
- }
910
- }
911
- }
912
- if (!allEqual) {
913
- const resultSubMap = /* @__PURE__ */ new Map();
914
- for (const [actorId, value] of subMap) {
915
- resultSubMap.set(actorId, this.#decode(value));
916
- }
917
- result.set(key, resultSubMap);
918
- }
919
- }
920
- return result;
921
- }
922
- clearActorState(actorId) {
923
- this.#remoteStates.delete(actorId);
924
- }
925
- async receiveSyncMessage(actorId, message) {
926
- await this.#forest.insertNodes(message.nodes);
927
- const state = this.#remoteStates.get(actorId) ?? initSyncState();
928
- const remoteRoot = message.root ?? state.remoteRoot;
929
- const newState = {
930
- remoteRoot,
931
- myRoot: message.remoteRoot ?? state.myRoot,
932
- remoteWant: message.want,
933
- needsAck: message.nodes.length > 0
934
- };
935
- this.#remoteStates.set(actorId, newState);
936
- }
937
- async generateSyncMessage(actorId) {
938
- const state = this.#remoteStates.get(actorId) ?? initSyncState();
939
- if (state.myRoot === this.#currentRoot && state.remoteWant.length === 0 && !state.needsAck) {
940
- return null;
941
- }
942
- const nodes = await this.#forest.getNodes(state.remoteWant);
943
- const want = state.remoteRoot === null ? [] : [
944
- ...await this.#forest.missingNodes(state.remoteRoot)
945
- ];
946
- this.#remoteStates.set(actorId, {
947
- remoteRoot: state.remoteRoot,
948
- myRoot: state.myRoot,
949
- remoteWant: state.remoteWant,
950
- needsAck: false
951
- });
952
- return {
953
- root: this.#currentRoot,
954
- remoteRoot: state.remoteRoot,
955
- want,
956
- nodes
957
- };
958
- }
959
- #decode(value) {
960
- return JSON.parse(textDecoder2.decode(value));
961
- }
962
- #encode(data) {
963
- return textEncoder4.encode(JSON.stringify(data));
964
- }
965
- };
966
- var initSyncState = () => ({
967
- remoteRoot: null,
968
- myRoot: null,
969
- remoteWant: [],
970
- needsAck: false
971
- });
972
- var textDecoder2 = new TextDecoder();
973
- var textEncoder4 = new TextEncoder();
974
- var createValue = (source) => new Uint8Array(textEncoder5.encode(source));
975
- var textEncoder5 = new TextEncoder();
976
- var randomKey = () => crypto.randomUUID();
977
- var randomSample = (data, count) => data.toSorted(() => Math.random() - 0.5).slice(0, count);
978
- // Annotate the CommonJS export names for ESM import in node:
979
- 0 && (module.exports = {
980
- Forest,
981
- LWWTree,
982
- MirrorMultiMap,
983
- TreeMut,
984
- createValue,
985
- digestEquals,
986
- formatDigest,
987
- getLevel,
988
- getLevelHex,
989
- initLWWTreeSyncState,
990
- makeItem,
991
- randomKey,
992
- randomSample
993
- });
994
- //# sourceMappingURL=index.cjs.map