reptree 0.2.2 → 0.2.4
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 +46 -0
- package/dist/index.cjs +305 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +303 -19
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -23,6 +23,43 @@ npm install reptree
|
|
|
23
23
|
|
|
24
24
|
## Usage
|
|
25
25
|
|
|
26
|
+
### Reactive vertex with Zod (optional)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { RepTree, bindVertex } from 'reptree';
|
|
30
|
+
import { z } from 'zod';
|
|
31
|
+
|
|
32
|
+
const tree = new RepTree('peer1');
|
|
33
|
+
const root = tree.createRoot();
|
|
34
|
+
const v = root.newChild();
|
|
35
|
+
|
|
36
|
+
const Person = z.object({ name: z.string(), age: z.number().int().min(0) });
|
|
37
|
+
|
|
38
|
+
// Helper function form
|
|
39
|
+
const person = bindVertex(tree, v.id, Person);
|
|
40
|
+
|
|
41
|
+
// Or via instance method on Vertex
|
|
42
|
+
// const person = v.bind(Person);
|
|
43
|
+
|
|
44
|
+
person.name = 'Alice'; // validated and persisted
|
|
45
|
+
person.age = 33; // validated and persisted
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### Aliases for internal fields
|
|
49
|
+
|
|
50
|
+
- `name` ↔ `_n`
|
|
51
|
+
- `createdAt` ↔ `_c` (Date exposed, ISO stored)
|
|
52
|
+
|
|
53
|
+
These aliases are applied by default when using `bindVertex` or `vertex.bind()`.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
person.name = 'Alice'; // writes _n
|
|
57
|
+
person.createdAt = new Date(); // writes _c (ISO)
|
|
58
|
+
console.log(person.createdAt instanceof Date); // true
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For more, see `docs/reactive-vertices.md`.
|
|
62
|
+
|
|
26
63
|
```typescript
|
|
27
64
|
import { RepTree } from 'reptree';
|
|
28
65
|
|
|
@@ -74,6 +111,15 @@ const ops = tree.getAllOps();
|
|
|
74
111
|
otherTree.merge(ops);
|
|
75
112
|
```
|
|
76
113
|
|
|
114
|
+
### Creating children with normalized props
|
|
115
|
+
|
|
116
|
+
`vertex.newChild(props)` and `vertex.newNamedChild(name, props)` accept plain objects. RepTree will:
|
|
117
|
+
|
|
118
|
+
- Map `name` → `_n`, `createdAt` (Date) → `_c` (ISO)
|
|
119
|
+
- Filter unsupported types (non-primitive objects except Y.Doc)
|
|
120
|
+
- Ignore `props.name` if `newNamedChild` has an explicit `name`
|
|
121
|
+
- Forbid nested children in props for now
|
|
122
|
+
|
|
77
123
|
## Yjs Integration
|
|
78
124
|
|
|
79
125
|
RepTree supports [Yjs](https://github.com/yjs/yjs) documents as vertex properties, enabling real-time collaborative editing with a variety of shared data types:
|
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,8 @@ __export(index_exports, {
|
|
|
35
35
|
TreeState: () => TreeState,
|
|
36
36
|
Vertex: () => Vertex,
|
|
37
37
|
VertexState: () => VertexState,
|
|
38
|
+
bindVertex: () => bindVertex,
|
|
39
|
+
defaultAliases: () => defaultAliases,
|
|
38
40
|
isAnyPropertyOp: () => isAnyPropertyOp,
|
|
39
41
|
isLWWPropertyOp: () => isLWWPropertyOp,
|
|
40
42
|
isModifyPropertyOp: () => isModifyPropertyOp,
|
|
@@ -402,8 +404,211 @@ function uuid() {
|
|
|
402
404
|
return removeDashes(crypto.randomUUID());
|
|
403
405
|
}
|
|
404
406
|
|
|
407
|
+
// src/reactive.ts
|
|
408
|
+
var defaultAliases = [
|
|
409
|
+
{ publicKey: "name", internalKey: "_n" },
|
|
410
|
+
{
|
|
411
|
+
publicKey: "createdAt",
|
|
412
|
+
internalKey: "_c",
|
|
413
|
+
toPublic: (v) => typeof v === "string" ? new Date(v) : v,
|
|
414
|
+
toInternal: (v) => v instanceof Date ? v.toISOString() : v
|
|
415
|
+
}
|
|
416
|
+
];
|
|
417
|
+
function buildAliasMaps(aliases) {
|
|
418
|
+
const publicToInternal = /* @__PURE__ */ new Map();
|
|
419
|
+
const internalToPublic = /* @__PURE__ */ new Map();
|
|
420
|
+
for (const rule of aliases) {
|
|
421
|
+
publicToInternal.set(rule.publicKey, rule);
|
|
422
|
+
internalToPublic.set(rule.internalKey, rule);
|
|
423
|
+
}
|
|
424
|
+
return { publicToInternal, internalToPublic };
|
|
425
|
+
}
|
|
426
|
+
function toPublicObject(tree, id, internalToPublic) {
|
|
427
|
+
const obj = {};
|
|
428
|
+
for (const { key, value } of tree.getVertexProperties(id)) {
|
|
429
|
+
const rule = internalToPublic.get(key);
|
|
430
|
+
if (rule) {
|
|
431
|
+
const converted = rule.toPublic ? rule.toPublic(value) : value;
|
|
432
|
+
obj[rule.publicKey] = converted;
|
|
433
|
+
} else {
|
|
434
|
+
obj[key] = value;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return obj;
|
|
438
|
+
}
|
|
439
|
+
var RESERVED_METHOD_USE_TRANSIENT = "useTransient";
|
|
440
|
+
var RESERVED_METHOD_COMMIT_TRANSIENTS = "commitTransients";
|
|
441
|
+
function bindVertex(tree, id, schemaOrOptions) {
|
|
442
|
+
const isOptions = typeof schemaOrOptions === "object" && schemaOrOptions !== null && (Object.prototype.hasOwnProperty.call(schemaOrOptions, "aliases") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "includeInternalKeys") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "schema"));
|
|
443
|
+
const options = isOptions ? schemaOrOptions : { schema: schemaOrOptions };
|
|
444
|
+
const schema = options.schema;
|
|
445
|
+
const aliases = options.aliases ?? defaultAliases;
|
|
446
|
+
const includeInternalKeys = options.includeInternalKeys ?? false;
|
|
447
|
+
const { publicToInternal, internalToPublic } = buildAliasMaps(aliases);
|
|
448
|
+
return new Proxy({}, {
|
|
449
|
+
get(_target, prop) {
|
|
450
|
+
if (prop === RESERVED_METHOD_USE_TRANSIENT) {
|
|
451
|
+
return (fn) => {
|
|
452
|
+
const transientProxy = new Proxy({}, {
|
|
453
|
+
get(_t, p) {
|
|
454
|
+
if (typeof p !== "string") return void 0;
|
|
455
|
+
const rule2 = publicToInternal.get(p);
|
|
456
|
+
if (rule2) {
|
|
457
|
+
const raw = tree.getVertexProperty(id, rule2.internalKey);
|
|
458
|
+
return rule2.toPublic ? rule2.toPublic(raw) : raw;
|
|
459
|
+
}
|
|
460
|
+
return tree.getVertexProperty(id, p);
|
|
461
|
+
},
|
|
462
|
+
set(_t, p, value) {
|
|
463
|
+
if (typeof p !== "string") return true;
|
|
464
|
+
if (schema?.shape && schema.shape[p]) {
|
|
465
|
+
const field = schema.shape[p];
|
|
466
|
+
if (field.safeParse) {
|
|
467
|
+
const res = field.safeParse(value);
|
|
468
|
+
if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
|
|
469
|
+
value = res.data ?? value;
|
|
470
|
+
}
|
|
471
|
+
} else if (schema?.safeParse) {
|
|
472
|
+
const next = { ...toPublicObject(tree, id, internalToPublic), [p]: value };
|
|
473
|
+
const res = schema.safeParse(next);
|
|
474
|
+
if (!res.success) throw new Error(`Invalid value for ${String(p)}`);
|
|
475
|
+
const parsed = res.data;
|
|
476
|
+
if (parsed && Object.prototype.hasOwnProperty.call(parsed, p)) {
|
|
477
|
+
value = parsed[p];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const rule2 = publicToInternal.get(p);
|
|
481
|
+
if (rule2) {
|
|
482
|
+
const converted = rule2.toInternal ? rule2.toInternal(value) : value;
|
|
483
|
+
tree.setTransientVertexProperty(id, rule2.internalKey, converted);
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
tree.setTransientVertexProperty(id, p, value);
|
|
487
|
+
return true;
|
|
488
|
+
},
|
|
489
|
+
deleteProperty(_t, p) {
|
|
490
|
+
if (typeof p !== "string") return true;
|
|
491
|
+
const rule2 = publicToInternal.get(p);
|
|
492
|
+
if (rule2) {
|
|
493
|
+
tree.setTransientVertexProperty(id, rule2.internalKey, void 0);
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
tree.setTransientVertexProperty(id, p, void 0);
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
fn(transientProxy);
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
if (prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
|
|
504
|
+
return () => {
|
|
505
|
+
const entries = tree.getVertexProperties(id);
|
|
506
|
+
const currentPublic = schema?.safeParse ? toPublicObject(tree, id, internalToPublic) : void 0;
|
|
507
|
+
for (const { key: internalKey, value: overlayValue } of entries) {
|
|
508
|
+
const persistentValue = tree.getVertexProperty(id, internalKey, false);
|
|
509
|
+
if (overlayValue === persistentValue) continue;
|
|
510
|
+
const aliasRule = internalToPublic.get(internalKey);
|
|
511
|
+
const publicKey = aliasRule ? aliasRule.publicKey : internalKey;
|
|
512
|
+
const publicValue = aliasRule && aliasRule.toPublic ? aliasRule.toPublic(overlayValue) : overlayValue;
|
|
513
|
+
let valueToPersistInternal = overlayValue;
|
|
514
|
+
if (schema?.shape && schema.shape[publicKey]) {
|
|
515
|
+
const field = schema.shape[publicKey];
|
|
516
|
+
if (field.safeParse) {
|
|
517
|
+
const res = field.safeParse(publicValue);
|
|
518
|
+
if (!res.success) throw new Error(`Invalid value for ${String(publicKey)}`);
|
|
519
|
+
const coerced = res.data;
|
|
520
|
+
const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(coerced) : coerced;
|
|
521
|
+
valueToPersistInternal = maybeInternal;
|
|
522
|
+
}
|
|
523
|
+
} else if (schema?.safeParse && currentPublic) {
|
|
524
|
+
const nextPublic = { ...currentPublic, [publicKey]: publicValue };
|
|
525
|
+
const res = schema.safeParse(nextPublic);
|
|
526
|
+
if (!res.success) throw new Error("Invalid values for commitTransients");
|
|
527
|
+
const parsed = res.data;
|
|
528
|
+
const parsedPublic = Object.prototype.hasOwnProperty.call(parsed, publicKey) ? parsed[publicKey] : publicValue;
|
|
529
|
+
const maybeInternal = aliasRule && aliasRule.toInternal ? aliasRule.toInternal(parsedPublic) : parsedPublic;
|
|
530
|
+
valueToPersistInternal = maybeInternal;
|
|
531
|
+
}
|
|
532
|
+
tree.setVertexProperty(id, internalKey, valueToPersistInternal);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
if (typeof prop !== "string") return void 0;
|
|
537
|
+
const rule = publicToInternal.get(prop);
|
|
538
|
+
if (rule) {
|
|
539
|
+
const raw = tree.getVertexProperty(id, rule.internalKey);
|
|
540
|
+
return rule.toPublic ? rule.toPublic(raw) : raw;
|
|
541
|
+
}
|
|
542
|
+
return tree.getVertexProperty(id, prop);
|
|
543
|
+
},
|
|
544
|
+
set(_target, prop, value) {
|
|
545
|
+
if (typeof prop !== "string") return true;
|
|
546
|
+
if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
if (schema?.shape && schema.shape[prop]) {
|
|
550
|
+
const field = schema.shape[prop];
|
|
551
|
+
if (field.safeParse) {
|
|
552
|
+
const res = field.safeParse(value);
|
|
553
|
+
if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
|
|
554
|
+
value = res.data ?? value;
|
|
555
|
+
}
|
|
556
|
+
} else if (schema?.safeParse) {
|
|
557
|
+
const next = { ...toPublicObject(tree, id, internalToPublic), [prop]: value };
|
|
558
|
+
const res = schema.safeParse(next);
|
|
559
|
+
if (!res.success) throw new Error(`Invalid value for ${String(prop)}`);
|
|
560
|
+
const parsed = res.data;
|
|
561
|
+
if (parsed && Object.prototype.hasOwnProperty.call(parsed, prop)) {
|
|
562
|
+
value = parsed[prop];
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const rule = publicToInternal.get(prop);
|
|
566
|
+
if (rule) {
|
|
567
|
+
const converted = rule.toInternal ? rule.toInternal(value) : value;
|
|
568
|
+
tree.setVertexProperty(id, rule.internalKey, converted);
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
tree.setVertexProperty(id, prop, value);
|
|
572
|
+
return true;
|
|
573
|
+
},
|
|
574
|
+
deleteProperty(_target, prop) {
|
|
575
|
+
if (typeof prop !== "string") return true;
|
|
576
|
+
if (prop === RESERVED_METHOD_USE_TRANSIENT || prop === RESERVED_METHOD_COMMIT_TRANSIENTS) {
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
const rule = publicToInternal.get(prop);
|
|
580
|
+
if (rule) {
|
|
581
|
+
tree.setVertexProperty(id, rule.internalKey, void 0);
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
tree.setVertexProperty(id, prop, void 0);
|
|
585
|
+
return true;
|
|
586
|
+
},
|
|
587
|
+
has(_target, prop) {
|
|
588
|
+
if (typeof prop !== "string") return false;
|
|
589
|
+
if (schema?.shape && Object.prototype.hasOwnProperty.call(schema.shape, prop)) return true;
|
|
590
|
+
if (includeInternalKeys) {
|
|
591
|
+
return publicToInternal.has(prop) || internalToPublic.has(prop);
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
},
|
|
595
|
+
ownKeys() {
|
|
596
|
+
const keys = /* @__PURE__ */ new Set();
|
|
597
|
+
for (const k of Object.keys(schema?.shape ?? {})) keys.add(k);
|
|
598
|
+
if (includeInternalKeys) {
|
|
599
|
+
for (const rule of aliases) keys.add(rule.internalKey);
|
|
600
|
+
}
|
|
601
|
+
return Array.from(keys);
|
|
602
|
+
},
|
|
603
|
+
getOwnPropertyDescriptor() {
|
|
604
|
+
return { enumerable: true, configurable: true };
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
405
609
|
// src/Vertex.ts
|
|
406
|
-
var
|
|
610
|
+
var Y = __toESM(require("yjs"), 1);
|
|
611
|
+
var Vertex = class _Vertex {
|
|
407
612
|
constructor(tree, state) {
|
|
408
613
|
this.tree = tree;
|
|
409
614
|
this.state = state;
|
|
@@ -449,12 +654,18 @@ var Vertex = class {
|
|
|
449
654
|
return this.children.map((v) => v.getAsTypedObject());
|
|
450
655
|
}
|
|
451
656
|
newChild(props) {
|
|
452
|
-
|
|
453
|
-
|
|
657
|
+
if (props && typeof props === "object" && "children" in props) {
|
|
658
|
+
throw new Error("Passing children inside props is not supported at the moment");
|
|
659
|
+
}
|
|
660
|
+
const normalized = _Vertex.normalizePropsForCreation(props);
|
|
661
|
+
return this.tree.newVertex(this.id, normalized);
|
|
454
662
|
}
|
|
455
663
|
newNamedChild(name, props) {
|
|
456
|
-
|
|
457
|
-
|
|
664
|
+
if (props && typeof props === "object" && "children" in props) {
|
|
665
|
+
throw new Error("Passing children inside props is not supported at the moment");
|
|
666
|
+
}
|
|
667
|
+
const normalized = _Vertex.normalizePropsForCreation(props, name);
|
|
668
|
+
return this.tree.newNamedVertex(this.id, name, normalized);
|
|
458
669
|
}
|
|
459
670
|
setProperty(key, value) {
|
|
460
671
|
const existingValue = this.getProperty(key, false);
|
|
@@ -520,6 +731,68 @@ var Vertex = class {
|
|
|
520
731
|
moveTo(parent) {
|
|
521
732
|
this.tree.moveVertex(this.id, parent.id);
|
|
522
733
|
}
|
|
734
|
+
/** Returns a live reactive object bound to this vertex. Accepts schema or options. */
|
|
735
|
+
bind(schemaOrOptions) {
|
|
736
|
+
return bindVertex(this.tree, this.id, schemaOrOptions);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Normalizes an input props object for vertex creation:
|
|
740
|
+
* - Aliases name -> _n, createdAt -> _c (Date -> ISO string)
|
|
741
|
+
* - Filters unsupported field types with a console warning
|
|
742
|
+
* - When a name param is provided to newNamedChild, ignores conflicting name in props
|
|
743
|
+
*/
|
|
744
|
+
static normalizePropsForCreation(props, explicitName) {
|
|
745
|
+
if (!props) return null;
|
|
746
|
+
const input = props;
|
|
747
|
+
const out = {};
|
|
748
|
+
const skipped = [];
|
|
749
|
+
for (const [rawKey, rawValue] of Object.entries(input)) {
|
|
750
|
+
if (rawValue === void 0) {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
if (rawKey === "children") continue;
|
|
754
|
+
let key = rawKey;
|
|
755
|
+
if (rawKey === "name") {
|
|
756
|
+
if (explicitName !== void 0) {
|
|
757
|
+
console.warn('newNamedChild: "name" in props is ignored because a name argument was provided');
|
|
758
|
+
continue;
|
|
759
|
+
}
|
|
760
|
+
key = "_n";
|
|
761
|
+
} else if (rawKey === "createdAt") {
|
|
762
|
+
key = "_c";
|
|
763
|
+
}
|
|
764
|
+
let value = rawValue;
|
|
765
|
+
if (key === "_c") {
|
|
766
|
+
if (value instanceof Date) {
|
|
767
|
+
value = value.toISOString();
|
|
768
|
+
} else if (typeof value === "string") {
|
|
769
|
+
} else {
|
|
770
|
+
skipped.push(rawKey);
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const isPrimitive = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
775
|
+
if (Array.isArray(value)) {
|
|
776
|
+
if (!value.every(isPrimitive)) {
|
|
777
|
+
skipped.push(rawKey);
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
} else if (typeof value === "object" && value !== null) {
|
|
781
|
+
if (!(value instanceof Y.Doc)) {
|
|
782
|
+
skipped.push(rawKey);
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
} else if (!isPrimitive(value)) {
|
|
786
|
+
skipped.push(rawKey);
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
out[key] = value;
|
|
790
|
+
}
|
|
791
|
+
if (skipped.length > 0) {
|
|
792
|
+
console.warn(`Some fields were skipped due to unsupported types: ${skipped.join(", ")}`);
|
|
793
|
+
}
|
|
794
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
795
|
+
}
|
|
523
796
|
};
|
|
524
797
|
|
|
525
798
|
// src/StateVector.ts
|
|
@@ -708,7 +981,7 @@ var StateVector = class _StateVector {
|
|
|
708
981
|
};
|
|
709
982
|
|
|
710
983
|
// src/RepTree.ts
|
|
711
|
-
var
|
|
984
|
+
var Y2 = __toESM(require("yjs"), 1);
|
|
712
985
|
var _RepTree = class _RepTree {
|
|
713
986
|
/**
|
|
714
987
|
* @param peerId - The peer ID of the current client. Should be unique across all peers.
|
|
@@ -870,8 +1143,8 @@ var _RepTree = class _RepTree {
|
|
|
870
1143
|
setTransientVertexProperty(vertexId, key, value) {
|
|
871
1144
|
this.lamportClock++;
|
|
872
1145
|
let opValue;
|
|
873
|
-
if (value instanceof
|
|
874
|
-
const state =
|
|
1146
|
+
if (value instanceof Y2.Doc) {
|
|
1147
|
+
const state = Y2.encodeStateAsUpdate(value);
|
|
875
1148
|
opValue = {
|
|
876
1149
|
type: "yjs",
|
|
877
1150
|
value: state
|
|
@@ -887,8 +1160,8 @@ var _RepTree = class _RepTree {
|
|
|
887
1160
|
setVertexProperty(vertexId, key, value) {
|
|
888
1161
|
this.lamportClock++;
|
|
889
1162
|
let opValue;
|
|
890
|
-
if (value instanceof
|
|
891
|
-
const state =
|
|
1163
|
+
if (value instanceof Y2.Doc) {
|
|
1164
|
+
const state = Y2.encodeStateAsUpdate(value);
|
|
892
1165
|
opValue = {
|
|
893
1166
|
type: "yjs",
|
|
894
1167
|
value: state
|
|
@@ -1060,10 +1333,10 @@ var _RepTree = class _RepTree {
|
|
|
1060
1333
|
if (!propB) {
|
|
1061
1334
|
return false;
|
|
1062
1335
|
}
|
|
1063
|
-
if (propA.value instanceof
|
|
1064
|
-
const snapshotA =
|
|
1065
|
-
const snapshotB =
|
|
1066
|
-
if (!
|
|
1336
|
+
if (propA.value instanceof Y2.Doc && propB.value instanceof Y2.Doc) {
|
|
1337
|
+
const snapshotA = Y2.snapshot(propA.value);
|
|
1338
|
+
const snapshotB = Y2.snapshot(propB.value);
|
|
1339
|
+
if (!Y2.equalSnapshots(snapshotA, snapshotB)) {
|
|
1067
1340
|
return false;
|
|
1068
1341
|
}
|
|
1069
1342
|
} else if (propA.value !== propB.value) {
|
|
@@ -1167,7 +1440,7 @@ var _RepTree = class _RepTree {
|
|
|
1167
1440
|
const propertyKey = `${key}@${vertexId}`;
|
|
1168
1441
|
if (this.yjsObservers.has(propertyKey)) {
|
|
1169
1442
|
const existingDoc = this.getVertexProperty(vertexId, key);
|
|
1170
|
-
if (existingDoc instanceof
|
|
1443
|
+
if (existingDoc instanceof Y2.Doc) {
|
|
1171
1444
|
existingDoc.off("update", this.yjsObservers.get(propertyKey));
|
|
1172
1445
|
}
|
|
1173
1446
|
this.yjsObservers.delete(propertyKey);
|
|
@@ -1247,13 +1520,13 @@ var _RepTree = class _RepTree {
|
|
|
1247
1520
|
throw new Error("Unknown CRDT type");
|
|
1248
1521
|
}
|
|
1249
1522
|
const ydoc = targetVertex.getProperty(op.key);
|
|
1250
|
-
if (ydoc instanceof
|
|
1251
|
-
|
|
1523
|
+
if (ydoc instanceof Y2.Doc) {
|
|
1524
|
+
Y2.applyUpdate(ydoc, crdtValue.value);
|
|
1252
1525
|
} else {
|
|
1253
|
-
const newDoc = new
|
|
1526
|
+
const newDoc = new Y2.Doc();
|
|
1254
1527
|
this.setupYjsObserver(newDoc, op.targetId, op.key);
|
|
1255
1528
|
this.state.setProperty(op.targetId, op.key, newDoc);
|
|
1256
|
-
|
|
1529
|
+
Y2.applyUpdate(newDoc, crdtValue.value);
|
|
1257
1530
|
}
|
|
1258
1531
|
this.propertiesAndTheirOpIds.set(`${op.key}@${op.targetId}`, op.id);
|
|
1259
1532
|
this.reportOpAsApplied(op);
|
|
@@ -1359,6 +1632,17 @@ var _RepTree = class _RepTree {
|
|
|
1359
1632
|
this.stateVector = new StateVector();
|
|
1360
1633
|
}
|
|
1361
1634
|
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Parses the vertex properties with a provided schema that has a `parse` method (e.g., Zod schema)
|
|
1637
|
+
*/
|
|
1638
|
+
parseVertex(vertexId, schema) {
|
|
1639
|
+
const propsArray = this.getVertexProperties(vertexId);
|
|
1640
|
+
const propsObject = {};
|
|
1641
|
+
for (const { key, value } of propsArray) {
|
|
1642
|
+
propsObject[key] = value;
|
|
1643
|
+
}
|
|
1644
|
+
return schema.parse(propsObject);
|
|
1645
|
+
}
|
|
1362
1646
|
};
|
|
1363
1647
|
_RepTree.NULL_VERTEX_ID = "0";
|
|
1364
1648
|
var RepTree = _RepTree;
|
|
@@ -1369,6 +1653,8 @@ var RepTree = _RepTree;
|
|
|
1369
1653
|
TreeState,
|
|
1370
1654
|
Vertex,
|
|
1371
1655
|
VertexState,
|
|
1656
|
+
bindVertex,
|
|
1657
|
+
defaultAliases,
|
|
1372
1658
|
isAnyPropertyOp,
|
|
1373
1659
|
isLWWPropertyOp,
|
|
1374
1660
|
isModifyPropertyOp,
|