reptree 0.5.0 → 0.7.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.d.ts CHANGED
@@ -10,8 +10,8 @@ declare class VertexState {
10
10
  private transientProperties;
11
11
  children: string[];
12
12
  constructor(id: string, parentId: TreeVertexId | null);
13
- setProperty(key: string, value: any): void;
14
- setTransientProperty(key: string, value: any): void;
13
+ setProperty(key: string, value: VertexPropertyType): void;
14
+ setTransientProperty(key: string, value: VertexPropertyType): void;
15
15
  getProperty(key: string, includingTransient?: boolean): VertexPropertyType | undefined;
16
16
  getAllProperties(includingTransient?: boolean): ReadonlyArray<TreeVertexProperty>;
17
17
  removeProperty(key: string): void;
@@ -21,11 +21,12 @@ declare class VertexState {
21
21
  }
22
22
 
23
23
  type TreeVertexId = string;
24
- /**
25
- * Serializable CRDT data for operations
26
- */
27
- /** Property type for state */
28
- type VertexPropertyType = string | number | boolean | string[] | number[] | boolean[] | undefined;
24
+ type JsonPrimitive = string | number | boolean | null;
25
+ type JsonValue = JsonPrimitive | JsonValue[] | {
26
+ [key: string]: JsonValue;
27
+ };
28
+ /** Property type for state (undefined means removal) */
29
+ type VertexPropertyType = JsonValue | undefined;
29
30
  type TreeVertexProperty = {
30
31
  readonly key: string;
31
32
  readonly value: VertexPropertyType;
@@ -95,16 +96,8 @@ type SchemaLike<T> = {
95
96
  parse?: (input: unknown) => T;
96
97
  shape?: Record<string, FieldSchemaLike>;
97
98
  };
98
- type AliasRule = {
99
- publicKey: string;
100
- internalKey: string;
101
- toPublic?: (value: unknown) => unknown;
102
- toInternal?: (value: unknown) => unknown;
103
- };
104
- declare const defaultAliases: AliasRule[];
105
99
  type BindOptions<T> = {
106
100
  schema?: SchemaLike<T>;
107
- aliases?: AliasRule[];
108
101
  includeInternalKeys?: boolean;
109
102
  };
110
103
  /**
@@ -205,7 +198,6 @@ declare class Vertex {
205
198
  bind<T extends Record<string, unknown>>(schemaOrOptions?: SchemaLike<T> | BindOptions<T>): BindedVertex<T>;
206
199
  /**
207
200
  * Normalizes an input props object for vertex creation:
208
- * - Aliases name -> _n, createdAt -> _c (Date -> ISO string)
209
201
  * - Filters unsupported field types with a console warning
210
202
  * - When a name param is provided to newNamedChild, ignores conflicting name in props
211
203
  */
@@ -353,8 +345,8 @@ declare class TreeState {
353
345
  getChildrenIds(vertexId: TreeVertexId): string[];
354
346
  getChildren(vertexId: TreeVertexId): VertexState[];
355
347
  moveVertex(vertexId: TreeVertexId, newParentId: TreeVertexId | null): VertexState;
356
- setProperty(vertexId: string, key: string, value: any): void;
357
- setTransientProperty(vertexId: string, key: string, value: any): void;
348
+ setProperty(vertexId: string, key: string, value: VertexPropertyType): void;
349
+ setTransientProperty(vertexId: string, key: string, value: VertexPropertyType): void;
358
350
  addChangeCallback(vertexId: TreeVertexId, listener: (events: VertexChangeEvent[]) => void): void;
359
351
  removeChangeCallback(vertexId: TreeVertexId, listener: (events: VertexChangeEvent[]) => void): void;
360
352
  addGlobalChangeCallback(listener: (events: VertexChangeEvent[]) => void): void;
@@ -422,4 +414,4 @@ declare class StateVector {
422
414
 
423
415
  declare function uuid(): string;
424
416
 
425
- export { type AliasRule, type BindOptions, type BindedVertex, type MoveVertex, type OpId, type OpIdRange, RepTree, type SchemaLike, type SetVertexProperty, StateVector, TreeState, type TreeVertexId, type TreeVertexProperty, Vertex, type VertexChangeEvent, type VertexChildrenChangeEvent, type VertexMoveEvent, type VertexOperation, type VertexPropertyChangeEvent, type VertexPropertyType, VertexState, bindVertex, defaultAliases, isAnyPropertyOp, isMoveVertexOp, newMoveVertexOp, newSetTransientVertexPropertyOp, newSetVertexPropertyOp, uuid };
417
+ export { type BindOptions, type BindedVertex, type JsonPrimitive, type JsonValue, type MoveVertex, type OpId, type OpIdRange, RepTree, type SchemaLike, type SetVertexProperty, StateVector, TreeState, type TreeVertexId, type TreeVertexProperty, Vertex, type VertexChangeEvent, type VertexChildrenChangeEvent, type VertexMoveEvent, type VertexOperation, type VertexPropertyChangeEvent, type VertexPropertyType, VertexState, bindVertex, isAnyPropertyOp, isMoveVertexOp, newMoveVertexOp, newSetTransientVertexPropertyOp, newSetVertexPropertyOp, uuid };
package/dist/index.js CHANGED
@@ -317,7 +317,7 @@ var TreeState = class {
317
317
  const vertex = this.getVertex(vertexId);
318
318
  if (vertex) {
319
319
  for (const prop of vertex.getAllProperties()) {
320
- if (prop.key === "_n") {
320
+ if (prop.key === "name") {
321
321
  vertexName = prop.value;
322
322
  }
323
323
  const propPrefix = indent + (isLast ? " " : "\u2502 ") + "\u2022 ";
@@ -330,8 +330,8 @@ var TreeState = class {
330
330
  const sortedChildren = [...children].sort((a, b) => {
331
331
  const vertexA = this.getVertex(a);
332
332
  const vertexB = this.getVertex(b);
333
- const nameA = vertexA?.getProperty("_n");
334
- const nameB = vertexB?.getProperty("_n");
333
+ const nameA = vertexA?.getProperty("name");
334
+ const nameB = vertexB?.getProperty("name");
335
335
  if (nameA && nameB) {
336
336
  return nameA.localeCompare(nameB);
337
337
  }
@@ -348,37 +348,17 @@ var TreeState = class {
348
348
  }
349
349
  };
350
350
 
351
- // src/uuid.ts
351
+ // src/utils/uuid.ts
352
352
  var removeDashes = (guid) => guid.replace(/-/g, "");
353
353
  function uuid() {
354
354
  return removeDashes(crypto.randomUUID());
355
355
  }
356
356
 
357
357
  // src/reactive.ts
358
- var defaultAliases = [
359
- { publicKey: "name", internalKey: "_n" },
360
- {
361
- publicKey: "createdAt",
362
- internalKey: "_c",
363
- toPublic: (v) => typeof v === "string" ? new Date(v) : v,
364
- toInternal: (v) => v instanceof Date ? v.toISOString() : v
365
- }
366
- ];
367
- function buildAliasMaps(aliases) {
368
- const publicToInternal = /* @__PURE__ */ new Map();
369
- const internalToPublic = /* @__PURE__ */ new Map();
370
- for (const rule of aliases) {
371
- publicToInternal.set(rule.publicKey, rule);
372
- internalToPublic.set(rule.internalKey, rule);
373
- }
374
- return { publicToInternal, internalToPublic };
375
- }
376
358
  function bindVertex(tree, id, schemaOrOptions) {
377
- 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"));
359
+ const isOptions = typeof schemaOrOptions === "object" && schemaOrOptions !== null && (Object.prototype.hasOwnProperty.call(schemaOrOptions, "includeInternalKeys") || Object.prototype.hasOwnProperty.call(schemaOrOptions, "schema"));
378
360
  const options = isOptions ? schemaOrOptions : { schema: schemaOrOptions };
379
361
  const schema = options.schema;
380
- const aliases = options.aliases ?? defaultAliases;
381
- const { publicToInternal } = buildAliasMaps(aliases);
382
362
  const obj = {};
383
363
  Object.defineProperties(obj, {
384
364
  $vertex: { get: () => tree.getVertex(id), enumerable: false, configurable: true },
@@ -415,19 +395,14 @@ function bindVertex(tree, id, schemaOrOptions) {
415
395
  const transientProxy = new Proxy({}, {
416
396
  set(_, prop, value) {
417
397
  if (typeof prop === "string") {
418
- const rule = publicToInternal.get(prop);
419
- const internalKey = rule?.internalKey ?? prop;
420
- const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
421
- tree.setTransientVertexProperty(id, internalKey, internalValue);
398
+ tree.setTransientVertexProperty(id, prop, value);
422
399
  }
423
400
  return true;
424
401
  },
425
402
  get(_, prop) {
426
403
  if (typeof prop !== "string") return void 0;
427
- const rule = publicToInternal.get(prop);
428
- const internalKey = rule?.internalKey ?? prop;
429
- const rawValue = tree.getVertexProperty(id, internalKey, true);
430
- return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
404
+ const rawValue = tree.getVertexProperty(id, prop, true);
405
+ return rawValue;
431
406
  }
432
407
  });
433
408
  fn(transientProxy);
@@ -457,10 +432,8 @@ function bindVertex(tree, id, schemaOrOptions) {
457
432
  if (prop in target) {
458
433
  return Reflect.get(target, prop, receiver);
459
434
  }
460
- const rule = publicToInternal.get(prop);
461
- const internalKey = rule?.internalKey ?? prop;
462
- const rawValue = tree.getVertexProperty(id, internalKey, true);
463
- return rule?.toPublic ? rule.toPublic(rawValue) : rawValue;
435
+ const rawValue = tree.getVertexProperty(id, prop, true);
436
+ return rawValue;
464
437
  },
465
438
  set(target, prop, value) {
466
439
  if (typeof prop !== "string") {
@@ -474,19 +447,14 @@ function bindVertex(tree, id, schemaOrOptions) {
474
447
  value = res.data;
475
448
  }
476
449
  }
477
- const rule = publicToInternal.get(prop);
478
- const internalKey = rule?.internalKey ?? prop;
479
- const internalValue = rule?.toInternal ? rule.toInternal(value) : value;
480
- tree.setVertexProperty(id, internalKey, internalValue);
450
+ tree.setVertexProperty(id, prop, value);
481
451
  return true;
482
452
  },
483
453
  deleteProperty(_target, prop) {
484
454
  if (typeof prop !== "string") {
485
455
  return true;
486
456
  }
487
- const rule = publicToInternal.get(prop);
488
- const internalKey = rule?.internalKey ?? prop;
489
- tree.setVertexProperty(id, internalKey, void 0);
457
+ tree.setVertexProperty(id, prop, void 0);
490
458
  return true;
491
459
  }
492
460
  });
@@ -503,10 +471,10 @@ var Vertex = class _Vertex {
503
471
  return this.state.id;
504
472
  }
505
473
  get name() {
506
- return this.getProperty("_n");
474
+ return this.getProperty("name");
507
475
  }
508
476
  set name(name) {
509
- this.tree.setVertexProperty(this.id, "_n", name);
477
+ this.tree.setVertexProperty(this.id, "name", name);
510
478
  }
511
479
  get createdAt() {
512
480
  const createdAt = this.getProperty("_c");
@@ -550,7 +518,7 @@ var Vertex = class _Vertex {
550
518
  if (props && typeof props === "object" && "children" in props) {
551
519
  throw new Error("Passing children inside props is not supported at the moment");
552
520
  }
553
- const normalized = _Vertex.normalizePropsForCreation(props, name);
521
+ const normalized = _Vertex.normalizePropsForCreation(props);
554
522
  return this.tree.newNamedVertex(this.id, name, normalized);
555
523
  }
556
524
  setProperty(key, value) {
@@ -626,30 +594,35 @@ var Vertex = class _Vertex {
626
594
  }
627
595
  /**
628
596
  * Normalizes an input props object for vertex creation:
629
- * - Aliases name -> _n, createdAt -> _c (Date -> ISO string)
630
597
  * - Filters unsupported field types with a console warning
631
598
  * - When a name param is provided to newNamedChild, ignores conflicting name in props
632
599
  */
633
- static normalizePropsForCreation(props, explicitName) {
600
+ static normalizePropsForCreation(props) {
634
601
  if (!props) return null;
635
602
  const input = props;
636
603
  const out = {};
637
604
  const skipped = [];
605
+ const isJsonValue2 = (v) => {
606
+ if (v === null) return true;
607
+ const t = typeof v;
608
+ if (t === "string" || t === "number" || t === "boolean") return true;
609
+ if (Array.isArray(v)) return v.every(isJsonValue2);
610
+ if (t === "object") {
611
+ const proto = Object.getPrototypeOf(v);
612
+ if (proto !== Object.prototype && proto !== null) return false;
613
+ for (const val of Object.values(v)) {
614
+ if (!isJsonValue2(val)) return false;
615
+ }
616
+ return true;
617
+ }
618
+ return false;
619
+ };
638
620
  for (const [rawKey, rawValue] of Object.entries(input)) {
639
621
  if (rawValue === void 0) {
640
622
  continue;
641
623
  }
642
624
  if (rawKey === "children") continue;
643
625
  let key = rawKey;
644
- if (rawKey === "name") {
645
- if (explicitName !== void 0) {
646
- console.warn('newNamedChild: "name" in props is ignored because a name argument was provided');
647
- continue;
648
- }
649
- key = "_n";
650
- } else if (rawKey === "createdAt") {
651
- key = "_c";
652
- }
653
626
  let value = rawValue;
654
627
  if (key === "_c") {
655
628
  if (value instanceof Date) {
@@ -660,23 +633,14 @@ var Vertex = class _Vertex {
660
633
  continue;
661
634
  }
662
635
  }
663
- const isPrimitive = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean";
664
- if (Array.isArray(value)) {
665
- if (!value.every(isPrimitive)) {
666
- skipped.push(rawKey);
667
- continue;
668
- }
669
- } else if (typeof value === "object" && value !== null) {
670
- skipped.push(rawKey);
671
- continue;
672
- } else if (!isPrimitive(value)) {
636
+ if (!isJsonValue2(value)) {
673
637
  skipped.push(rawKey);
674
638
  continue;
675
639
  }
676
640
  out[key] = value;
677
641
  }
678
642
  if (skipped.length > 0) {
679
- console.warn(`Some fields were skipped due to unsupported types: ${skipped.join(", ")}`);
643
+ throw new Error(`Unsupported property types for keys: ${skipped.join(", ")}`);
680
644
  }
681
645
  return Object.keys(out).length > 0 ? out : null;
682
646
  }
@@ -867,6 +831,61 @@ var StateVector = class _StateVector {
867
831
  }
868
832
  };
869
833
 
834
+ // src/utils/deepEqual.ts
835
+ function deepEqual(a, b) {
836
+ if (a === b) return true;
837
+ if (a === null || b === null) return a === b;
838
+ const ta = typeof a;
839
+ const tb = typeof b;
840
+ if (ta !== tb) return false;
841
+ if (ta !== "object") return false;
842
+ const aIsArr = Array.isArray(a);
843
+ const bIsArr = Array.isArray(b);
844
+ if (aIsArr || bIsArr) {
845
+ if (!(aIsArr && bIsArr)) return false;
846
+ if (a.length !== b.length) return false;
847
+ for (let i = 0; i < a.length; i++) {
848
+ if (!deepEqual(a[i], b[i])) return false;
849
+ }
850
+ return true;
851
+ }
852
+ const aProto = Object.getPrototypeOf(a);
853
+ const bProto = Object.getPrototypeOf(b);
854
+ if (aProto !== Object.prototype && aProto !== null || bProto !== Object.prototype && bProto !== null) {
855
+ return false;
856
+ }
857
+ const aKeys = Object.keys(a);
858
+ const bKeys = Object.keys(b);
859
+ if (aKeys.length !== bKeys.length) return false;
860
+ for (const key of aKeys) {
861
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
862
+ if (!deepEqual(a[key], b[key])) return false;
863
+ }
864
+ return true;
865
+ }
866
+
867
+ // src/utils/isJsonValue.ts
868
+ function isJsonValue(v) {
869
+ if (v === void 0) return true;
870
+ if (v === null) return true;
871
+ const t = typeof v;
872
+ if (t === "string" || t === "number" || t === "boolean") return true;
873
+ if (t === "bigint" || t === "function" || t === "symbol") return false;
874
+ if (Array.isArray(v)) return v.every(isJsonValue);
875
+ if (t === "object") {
876
+ if (v instanceof Date) return false;
877
+ if (v instanceof Map || v instanceof Set || v instanceof RegExp) return false;
878
+ if (ArrayBuffer.isView(v)) return false;
879
+ const proto = Object.getPrototypeOf(v);
880
+ if (proto !== Object.prototype && proto !== null) return false;
881
+ for (const val of Object.values(v)) {
882
+ if (!isJsonValue(val)) return false;
883
+ }
884
+ return true;
885
+ }
886
+ return false;
887
+ }
888
+
870
889
  // src/RepTree.ts
871
890
  var _RepTree = class _RepTree {
872
891
  /**
@@ -1016,7 +1035,7 @@ var _RepTree = class _RepTree {
1016
1035
  if (typedProps) {
1017
1036
  this.setVertexProperties(vertexId, typedProps);
1018
1037
  }
1019
- this.setVertexProperty(vertexId, "_n", name);
1038
+ this.setVertexProperty(vertexId, "name", name);
1020
1039
  const vertex = this.state.getVertex(vertexId);
1021
1040
  if (!vertex) {
1022
1041
  throw new Error("Failed to create named vertex");
@@ -1033,6 +1052,9 @@ var _RepTree = class _RepTree {
1033
1052
  this.moveVertex(vertexId, _RepTree.NULL_VERTEX_ID);
1034
1053
  }
1035
1054
  setTransientVertexProperty(vertexId, key, value) {
1055
+ if (!isJsonValue(value)) {
1056
+ throw new Error(`Unsupported transient property value for key "${key}"`);
1057
+ }
1036
1058
  this.lamportClock++;
1037
1059
  const op = newSetTransientVertexPropertyOp(this.lamportClock, this.peerId, vertexId, key, value);
1038
1060
  this.localOps.push(op);
@@ -1058,6 +1080,29 @@ var _RepTree = class _RepTree {
1058
1080
  vertex.clearAllTransientProperties();
1059
1081
  }
1060
1082
  setVertexProperty(vertexId, key, value) {
1083
+ const isJsonValue2 = (v) => {
1084
+ if (v === void 0) return true;
1085
+ if (v === null) return true;
1086
+ const t = typeof v;
1087
+ if (t === "string" || t === "number" || t === "boolean") return true;
1088
+ if (t === "bigint" || t === "function" || t === "symbol") return false;
1089
+ if (Array.isArray(v)) return v.every(isJsonValue2);
1090
+ if (t === "object") {
1091
+ if (v instanceof Date) return false;
1092
+ if (v instanceof Map || v instanceof Set || v instanceof RegExp) return false;
1093
+ if (ArrayBuffer.isView(v)) return false;
1094
+ const proto = Object.getPrototypeOf(v);
1095
+ if (proto !== Object.prototype && proto !== null) return false;
1096
+ for (const val of Object.values(v)) {
1097
+ if (!isJsonValue2(val)) return false;
1098
+ }
1099
+ return true;
1100
+ }
1101
+ return false;
1102
+ };
1103
+ if (!isJsonValue2(value)) {
1104
+ throw new Error(`Unsupported property value for key "${key}"`);
1105
+ }
1061
1106
  this.lamportClock++;
1062
1107
  const op = newSetVertexPropertyOp(this.lamportClock, this.peerId, vertexId, key, value);
1063
1108
  this.localOps.push(op);
@@ -1090,7 +1135,7 @@ var _RepTree = class _RepTree {
1090
1135
  const targetName = path[0];
1091
1136
  const children = this.getChildren(vertex.id);
1092
1137
  for (const child of children) {
1093
- if (child.getProperty("_n") === targetName) {
1138
+ if (child.getProperty("name") === targetName) {
1094
1139
  return this.getVertexByPathArray(child, path.slice(1));
1095
1140
  }
1096
1141
  }
@@ -1219,12 +1264,8 @@ var _RepTree = class _RepTree {
1219
1264
  }
1220
1265
  for (const propA of propertiesA) {
1221
1266
  const propB = propertiesB.find((p) => p.key === propA.key);
1222
- if (!propB) {
1223
- return false;
1224
- }
1225
- if (propA.value !== propB.value) {
1226
- return false;
1227
- }
1267
+ if (!propB) return false;
1268
+ if (!deepEqual(propA.value, propB.value)) return false;
1228
1269
  }
1229
1270
  }
1230
1271
  for (const childId of childrenA) {
@@ -1354,7 +1395,6 @@ var _RepTree = class _RepTree {
1354
1395
  }
1355
1396
  }
1356
1397
  }
1357
- // Non-LWW modify-property flow removed
1358
1398
  applyOperation(op) {
1359
1399
  if (isMoveVertexOp(op)) {
1360
1400
  this.applyMove(op);
@@ -1477,7 +1517,6 @@ export {
1477
1517
  Vertex,
1478
1518
  VertexState,
1479
1519
  bindVertex,
1480
- defaultAliases,
1481
1520
  isAnyPropertyOp,
1482
1521
  isMoveVertexOp,
1483
1522
  newMoveVertexOp,