@vuer-ai/vuer-rtc 0.0.1

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.
Files changed (169) hide show
  1. package/dist/client/EditBuffer.d.ts +43 -0
  2. package/dist/client/EditBuffer.d.ts.map +1 -0
  3. package/dist/client/EditBuffer.js +96 -0
  4. package/dist/client/EditBuffer.js.map +1 -0
  5. package/dist/client/actions.d.ts +66 -0
  6. package/dist/client/actions.d.ts.map +1 -0
  7. package/dist/client/actions.js +345 -0
  8. package/dist/client/actions.js.map +1 -0
  9. package/dist/client/createGraph.d.ts +30 -0
  10. package/dist/client/createGraph.d.ts.map +1 -0
  11. package/dist/client/createGraph.js +91 -0
  12. package/dist/client/createGraph.js.map +1 -0
  13. package/dist/client/hooks.d.ts +81 -0
  14. package/dist/client/hooks.d.ts.map +1 -0
  15. package/dist/client/hooks.js +161 -0
  16. package/dist/client/hooks.js.map +1 -0
  17. package/dist/client/index.d.ts +8 -0
  18. package/dist/client/index.d.ts.map +1 -0
  19. package/dist/client/index.js +10 -0
  20. package/dist/client/index.js.map +1 -0
  21. package/dist/client/types.d.ts +74 -0
  22. package/dist/client/types.d.ts.map +1 -0
  23. package/dist/client/types.js +11 -0
  24. package/dist/client/types.js.map +1 -0
  25. package/dist/hooks.d.ts +8 -0
  26. package/dist/hooks.d.ts.map +1 -0
  27. package/dist/hooks.js +7 -0
  28. package/dist/hooks.js.map +1 -0
  29. package/dist/index.d.ts +9 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +12 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/operations/OperationTypes.d.ts +239 -0
  34. package/dist/operations/OperationTypes.d.ts.map +1 -0
  35. package/dist/operations/OperationTypes.js +10 -0
  36. package/dist/operations/OperationTypes.js.map +1 -0
  37. package/dist/operations/OperationValidator.d.ts +32 -0
  38. package/dist/operations/OperationValidator.d.ts.map +1 -0
  39. package/dist/operations/OperationValidator.js +208 -0
  40. package/dist/operations/OperationValidator.js.map +1 -0
  41. package/dist/operations/apply/array.d.ts +22 -0
  42. package/dist/operations/apply/array.d.ts.map +1 -0
  43. package/dist/operations/apply/array.js +64 -0
  44. package/dist/operations/apply/array.js.map +1 -0
  45. package/dist/operations/apply/boolean.d.ts +18 -0
  46. package/dist/operations/apply/boolean.d.ts.map +1 -0
  47. package/dist/operations/apply/boolean.js +34 -0
  48. package/dist/operations/apply/boolean.js.map +1 -0
  49. package/dist/operations/apply/color.d.ts +14 -0
  50. package/dist/operations/apply/color.d.ts.map +1 -0
  51. package/dist/operations/apply/color.js +46 -0
  52. package/dist/operations/apply/color.js.map +1 -0
  53. package/dist/operations/apply/index.d.ts +18 -0
  54. package/dist/operations/apply/index.d.ts.map +1 -0
  55. package/dist/operations/apply/index.js +26 -0
  56. package/dist/operations/apply/index.js.map +1 -0
  57. package/dist/operations/apply/node.d.ts +24 -0
  58. package/dist/operations/apply/node.d.ts.map +1 -0
  59. package/dist/operations/apply/node.js +77 -0
  60. package/dist/operations/apply/node.js.map +1 -0
  61. package/dist/operations/apply/number.d.ts +26 -0
  62. package/dist/operations/apply/number.d.ts.map +1 -0
  63. package/dist/operations/apply/number.js +54 -0
  64. package/dist/operations/apply/number.js.map +1 -0
  65. package/dist/operations/apply/object.d.ts +14 -0
  66. package/dist/operations/apply/object.d.ts.map +1 -0
  67. package/dist/operations/apply/object.js +47 -0
  68. package/dist/operations/apply/object.js.map +1 -0
  69. package/dist/operations/apply/quaternion.d.ts +15 -0
  70. package/dist/operations/apply/quaternion.d.ts.map +1 -0
  71. package/dist/operations/apply/quaternion.js +33 -0
  72. package/dist/operations/apply/quaternion.js.map +1 -0
  73. package/dist/operations/apply/string.d.ts +14 -0
  74. package/dist/operations/apply/string.d.ts.map +1 -0
  75. package/dist/operations/apply/string.js +26 -0
  76. package/dist/operations/apply/string.js.map +1 -0
  77. package/dist/operations/apply/types.d.ts +34 -0
  78. package/dist/operations/apply/types.d.ts.map +1 -0
  79. package/dist/operations/apply/types.js +32 -0
  80. package/dist/operations/apply/types.js.map +1 -0
  81. package/dist/operations/apply/vector3.d.ts +18 -0
  82. package/dist/operations/apply/vector3.d.ts.map +1 -0
  83. package/dist/operations/apply/vector3.js +44 -0
  84. package/dist/operations/apply/vector3.js.map +1 -0
  85. package/dist/operations/dispatcher.d.ts +35 -0
  86. package/dist/operations/dispatcher.d.ts.map +1 -0
  87. package/dist/operations/dispatcher.js +107 -0
  88. package/dist/operations/dispatcher.js.map +1 -0
  89. package/dist/operations/index.d.ts +10 -0
  90. package/dist/operations/index.d.ts.map +1 -0
  91. package/dist/operations/index.js +17 -0
  92. package/dist/operations/index.js.map +1 -0
  93. package/dist/state/ConflictResolver.d.ts +36 -0
  94. package/dist/state/ConflictResolver.d.ts.map +1 -0
  95. package/dist/state/ConflictResolver.js +167 -0
  96. package/dist/state/ConflictResolver.js.map +1 -0
  97. package/dist/state/DType.d.ts +160 -0
  98. package/dist/state/DType.d.ts.map +1 -0
  99. package/dist/state/DType.js +282 -0
  100. package/dist/state/DType.js.map +1 -0
  101. package/dist/state/Schema.d.ts +32 -0
  102. package/dist/state/Schema.d.ts.map +1 -0
  103. package/dist/state/Schema.js +175 -0
  104. package/dist/state/Schema.js.map +1 -0
  105. package/dist/state/VectorClock.d.ts +42 -0
  106. package/dist/state/VectorClock.d.ts.map +1 -0
  107. package/dist/state/VectorClock.js +84 -0
  108. package/dist/state/VectorClock.js.map +1 -0
  109. package/dist/state/index.d.ts +11 -0
  110. package/dist/state/index.d.ts.map +1 -0
  111. package/dist/state/index.js +13 -0
  112. package/dist/state/index.js.map +1 -0
  113. package/docs/OPERATION_HINTS.md +222 -0
  114. package/docs/SCENE_GRAPH.md +373 -0
  115. package/docs/TYPE_BEHAVIORS.md +348 -0
  116. package/examples/01-basic-usage.ts +139 -0
  117. package/examples/02-concurrent-edits.ts +208 -0
  118. package/examples/03-scene-building.ts +258 -0
  119. package/examples/04-conflict-resolution.ts +339 -0
  120. package/examples/README.md +86 -0
  121. package/jest.config.js +19 -0
  122. package/package.json +57 -0
  123. package/src/client/EditBuffer.ts +105 -0
  124. package/src/client/actions.ts +397 -0
  125. package/src/client/createGraph.ts +132 -0
  126. package/src/client/hooks.tsx +249 -0
  127. package/src/client/index.ts +35 -0
  128. package/src/client/types.ts +94 -0
  129. package/src/hooks.ts +20 -0
  130. package/src/index.ts +14 -0
  131. package/src/operations/OperationTypes.ts +340 -0
  132. package/src/operations/OperationValidator.ts +260 -0
  133. package/src/operations/apply/array.ts +84 -0
  134. package/src/operations/apply/boolean.ts +48 -0
  135. package/src/operations/apply/color.ts +65 -0
  136. package/src/operations/apply/index.ts +37 -0
  137. package/src/operations/apply/node.ts +98 -0
  138. package/src/operations/apply/number.ts +76 -0
  139. package/src/operations/apply/object.ts +63 -0
  140. package/src/operations/apply/quaternion.ts +47 -0
  141. package/src/operations/apply/string.ts +36 -0
  142. package/src/operations/apply/types.ts +66 -0
  143. package/src/operations/apply/vector3.ts +60 -0
  144. package/src/operations/dispatcher.ts +127 -0
  145. package/src/operations/index.ts +80 -0
  146. package/src/state/ConflictResolver.ts +205 -0
  147. package/src/state/DType.ts +333 -0
  148. package/src/state/Schema.ts +236 -0
  149. package/src/state/VectorClock.ts +98 -0
  150. package/src/state/index.ts +14 -0
  151. package/tests/client/actions.test.ts +371 -0
  152. package/tests/client/edit-buffer.test.ts +117 -0
  153. package/tests/fixtures/array-ops.jsonl +6 -0
  154. package/tests/fixtures/boolean-ops.jsonl +6 -0
  155. package/tests/fixtures/color-ops.jsonl +4 -0
  156. package/tests/fixtures/edit-buffer.jsonl +3 -0
  157. package/tests/fixtures/node-ops.jsonl +6 -0
  158. package/tests/fixtures/number-ops.jsonl +7 -0
  159. package/tests/fixtures/object-ops.jsonl +4 -0
  160. package/tests/fixtures/operations.jsonl +7 -0
  161. package/tests/fixtures/string-ops.jsonl +4 -0
  162. package/tests/fixtures/undo-redo.jsonl +3 -0
  163. package/tests/fixtures/vector-ops.jsonl +9 -0
  164. package/tests/operations/collections.test.ts +193 -0
  165. package/tests/operations/nodes.test.ts +228 -0
  166. package/tests/operations/primitives.test.ts +222 -0
  167. package/tests/operations/vectors.test.ts +150 -0
  168. package/tsconfig.json +21 -0
  169. package/tsconfig.test.json +9 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Operation Dispatcher
3
+ *
4
+ * Applies CRDTMessage operations to a SceneGraph using immer.
5
+ * Each operation is dispatched to its corresponding "apply" function.
6
+ */
7
+
8
+ import { produce, enableMapSet } from 'immer';
9
+ import type { SceneGraph, CRDTMessage, Operation } from './OperationTypes.js';
10
+ import type { OpMeta } from './apply/types.js';
11
+ import * as registry from './apply/index.js';
12
+
13
+ // Enable immer support for Map and Set
14
+ enableMapSet();
15
+
16
+ /**
17
+ * Handler map: otype -> apply function
18
+ */
19
+ const handlers: Record<string, (draft: SceneGraph, op: Operation, meta: OpMeta) => void> = {
20
+ // Number operations
21
+ 'number.set': registry.NumberSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
22
+ 'number.add': registry.NumberAdd as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
23
+ 'number.multiply': registry.NumberMultiply as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
24
+ 'number.min': registry.NumberMin as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
25
+ 'number.max': registry.NumberMax as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
26
+
27
+ // String operations
28
+ 'string.set': registry.StringSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
29
+ 'string.concat': registry.StringConcat as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
30
+
31
+ // Boolean operations
32
+ 'boolean.set': registry.BooleanSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
33
+ 'boolean.or': registry.BooleanOr as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
34
+ 'boolean.and': registry.BooleanAnd as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
35
+
36
+ // Vector3 operations
37
+ 'vector3.set': registry.Vector3Set as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
38
+ 'vector3.add': registry.Vector3Add as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
39
+ 'vector3.multiply': registry.Vector3Multiply as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
40
+
41
+ // Quaternion operations
42
+ 'quaternion.set': registry.QuaternionSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
43
+ 'quaternion.multiply': registry.QuaternionMultiply as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
44
+
45
+ // Color operations
46
+ 'color.set': registry.ColorSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
47
+ 'color.blend': registry.ColorBlend as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
48
+
49
+ // Array operations
50
+ 'array.set': registry.ArraySet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
51
+ 'array.push': registry.ArrayPush as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
52
+ 'array.remove': registry.ArrayRemove as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
53
+ 'array.union': registry.ArrayUnion as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
54
+
55
+ // Object operations
56
+ 'object.set': registry.ObjectSet as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
57
+ 'object.merge': registry.ObjectMerge as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
58
+
59
+ // Node operations
60
+ 'node.insert': registry.NodeInsert as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
61
+ 'node.remove': registry.NodeRemove as (draft: SceneGraph, op: Operation, meta: OpMeta) => void,
62
+ };
63
+
64
+ /**
65
+ * Apply a single operation to a SceneGraph draft
66
+ */
67
+ export function applyOperation(
68
+ draft: SceneGraph,
69
+ op: Operation,
70
+ meta: OpMeta
71
+ ): void {
72
+ const handler = handlers[op.otype];
73
+ if (handler) {
74
+ handler(draft, op, meta);
75
+ } else {
76
+ console.warn(`Unknown otype: ${op.otype}`);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Apply a CRDTMessage to a SceneGraph (immutable)
82
+ *
83
+ * Uses immer to produce a new state without mutating the original.
84
+ *
85
+ * @param graph - Current scene graph state
86
+ * @param msg - CRDT message containing operations
87
+ * @returns New scene graph state with operations applied
88
+ */
89
+ export function applyMessage(graph: SceneGraph, msg: CRDTMessage): SceneGraph {
90
+ return produce(graph, (draft) => {
91
+ const meta: OpMeta = {
92
+ sessionId: msg.sessionId,
93
+ clock: msg.clock,
94
+ lamportTime: msg.lamportTime,
95
+ timestamp: msg.timestamp,
96
+ };
97
+
98
+ for (const op of msg.ops) {
99
+ applyOperation(draft, op, meta);
100
+ }
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Apply multiple CRDTMessages to a SceneGraph (immutable)
106
+ *
107
+ * @param graph - Current scene graph state
108
+ * @param messages - Array of CRDT messages to apply
109
+ * @returns New scene graph state with all operations applied
110
+ */
111
+ export function applyMessages(graph: SceneGraph, messages: CRDTMessage[]): SceneGraph {
112
+ let current = graph;
113
+ for (const msg of messages) {
114
+ current = applyMessage(current, msg);
115
+ }
116
+ return current;
117
+ }
118
+
119
+ /**
120
+ * Create an empty scene graph
121
+ */
122
+ export function createEmptyGraph(): SceneGraph {
123
+ return {
124
+ nodes: {},
125
+ rootKey: '',
126
+ };
127
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Operations module exports
3
+ */
4
+
5
+ // ============================================
6
+ // Operation Types
7
+ // ============================================
8
+
9
+ export type {
10
+ CRDTMessage,
11
+ BaseOp,
12
+ // Number ops
13
+ NumberSetOp,
14
+ NumberAddOp,
15
+ NumberMultiplyOp,
16
+ NumberMinOp,
17
+ NumberMaxOp,
18
+ // String ops
19
+ StringSetOp,
20
+ StringConcatOp,
21
+ // Boolean ops
22
+ BooleanSetOp,
23
+ BooleanOrOp,
24
+ BooleanAndOp,
25
+ // Vector3 ops
26
+ Vector3SetOp,
27
+ Vector3AddOp,
28
+ Vector3MultiplyOp,
29
+ // Quaternion ops
30
+ QuaternionSetOp,
31
+ QuaternionMultiplyOp,
32
+ // Color ops
33
+ ColorSetOp,
34
+ ColorBlendOp,
35
+ // Array ops
36
+ ArraySetOp,
37
+ ArrayPushOp,
38
+ ArrayUnionOp,
39
+ ArrayRemoveOp,
40
+ // Object ops
41
+ ObjectSetOp,
42
+ ObjectMergeOp,
43
+ // Scene graph ops
44
+ NodeInsertOp,
45
+ NodeRemoveOp,
46
+ // Meta ops (undo/redo)
47
+ MetaUndoOp,
48
+ MetaRedoOp,
49
+ // Union
50
+ Operation,
51
+ // Scene graph types
52
+ SceneNode,
53
+ SceneGraph,
54
+ } from './OperationTypes.js';
55
+
56
+ // ============================================
57
+ // Validation
58
+ // ============================================
59
+
60
+ export { OperationValidator, type ValidationResult } from './OperationValidator.js';
61
+
62
+ // ============================================
63
+ // Apply Registry (individual apply functions)
64
+ // ============================================
65
+
66
+ import * as registry from './apply/index.js';
67
+ export { registry };
68
+
69
+ export type { OpMeta, ApplyFn } from './apply/types.js';
70
+
71
+ // ============================================
72
+ // Dispatcher (high-level API)
73
+ // ============================================
74
+
75
+ export {
76
+ applyMessage,
77
+ applyMessages,
78
+ applyOperation,
79
+ createEmptyGraph,
80
+ } from './dispatcher.js';
@@ -0,0 +1,205 @@
1
+ /**
2
+ * ConflictResolver - Schema-based property conflict resolution
3
+ *
4
+ * Merges concurrent property updates based on:
5
+ * - Property schema (dtype + operation)
6
+ * - DType merge functions
7
+ */
8
+
9
+ import { DType, type ValueWithMeta } from './DType.js';
10
+ import { getPropertySchema, isImmutable } from './Schema.js';
11
+
12
+ export class ConflictResolver {
13
+ /**
14
+ * Merge a single property from multiple concurrent updates
15
+ *
16
+ * @param propertyName - Name of the property being merged
17
+ * @param values - Array of values with metadata
18
+ * @param operationHint - Optional operation override from UPDATE operation
19
+ * @returns Merged value
20
+ */
21
+ mergeProperty<T = any>(
22
+ propertyName: string,
23
+ values: ValueWithMeta<T>[],
24
+ operationHint?: string
25
+ ): T {
26
+ if (values.length === 0) {
27
+ throw new Error(`Cannot merge empty values for property: ${propertyName}`);
28
+ }
29
+
30
+ if (values.length === 1) {
31
+ return values[0].value;
32
+ }
33
+
34
+ // Get schema for this property
35
+ const schema = getPropertySchema(propertyName);
36
+
37
+ // Immutable properties: return earliest value
38
+ if (isImmutable(propertyName)) {
39
+ const sorted = [...values].sort((a, b) => a.lamportTime - b.lamportTime);
40
+ return sorted[0].value;
41
+ }
42
+
43
+ // Use operation hint if provided, otherwise use schema
44
+ const operation = operationHint || schema.operation;
45
+
46
+ // Get merge function based on dtype and operation
47
+ const mergeFn = this.getMergeFunction(schema.dtype, operation);
48
+
49
+ if (!mergeFn) {
50
+ console.warn(
51
+ `No merge function for dtype=${schema.dtype} operation=${operation}, defaulting to LWW`
52
+ );
53
+ return DType.string.set(values as any) as any;
54
+ }
55
+
56
+ return mergeFn(values);
57
+ }
58
+
59
+ /**
60
+ * Merge multiple properties from concurrent updates
61
+ *
62
+ * @param updates - Array of property updates with metadata and operation hints
63
+ * @returns Merged properties
64
+ */
65
+ mergeProperties(
66
+ updates: Array<{
67
+ properties: Record<string, any>;
68
+ operations?: Record<string, string>; // Operation hints per property
69
+ lamportTime: number;
70
+ sessionId: string;
71
+ }>
72
+ ): Record<string, any> {
73
+ // Group values by property name
74
+ const valuesByProperty = new Map<string, ValueWithMeta[]>();
75
+ const operationHints = new Map<string, string>();
76
+
77
+ for (const update of updates) {
78
+ for (const [key, value] of Object.entries(update.properties)) {
79
+ if (key === 'operations') continue; // Skip operations field
80
+
81
+ if (!valuesByProperty.has(key)) {
82
+ valuesByProperty.set(key, []);
83
+ }
84
+
85
+ valuesByProperty.get(key)!.push({
86
+ value,
87
+ lamportTime: update.lamportTime,
88
+ sessionId: update.sessionId,
89
+ });
90
+
91
+ // Store operation hint if provided
92
+ if (update.operations?.[key]) {
93
+ operationHints.set(key, update.operations[key]);
94
+ }
95
+ }
96
+ }
97
+
98
+ // Merge each property
99
+ const result: Record<string, any> = {};
100
+
101
+ for (const [propertyName, values] of valuesByProperty.entries()) {
102
+ const operationHint = operationHints.get(propertyName);
103
+ result[propertyName] = this.mergeProperty(propertyName, values, operationHint);
104
+ }
105
+
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * Get merge function for dtype and operation
111
+ */
112
+ private getMergeFunction(dtype: string, operation: string): ((values: ValueWithMeta[]) => any) | null {
113
+ switch (dtype) {
114
+ case 'number':
115
+ switch (operation) {
116
+ case 'set':
117
+ return DType.number.set;
118
+ case 'add':
119
+ return DType.number.add;
120
+ case 'multiply':
121
+ return DType.number.multiply;
122
+ case 'min':
123
+ return DType.number.min;
124
+ case 'max':
125
+ return DType.number.max;
126
+ }
127
+ break;
128
+
129
+ case 'string':
130
+ switch (operation) {
131
+ case 'set':
132
+ return DType.string.set;
133
+ case 'concat':
134
+ return DType.string.concat as any;
135
+ }
136
+ break;
137
+
138
+ case 'boolean':
139
+ switch (operation) {
140
+ case 'set':
141
+ return DType.boolean.set;
142
+ case 'or':
143
+ return DType.boolean.or;
144
+ case 'and':
145
+ return DType.boolean.and;
146
+ }
147
+ break;
148
+
149
+ case 'vector3':
150
+ switch (operation) {
151
+ case 'set':
152
+ return DType.vector3.set;
153
+ case 'add':
154
+ return DType.vector3.add;
155
+ case 'multiply':
156
+ return DType.vector3.multiply;
157
+ }
158
+ break;
159
+
160
+ case 'quaternion':
161
+ switch (operation) {
162
+ case 'set':
163
+ return DType.quaternion.set;
164
+ case 'multiply':
165
+ return DType.quaternion.multiply;
166
+ }
167
+ break;
168
+
169
+ case 'color':
170
+ switch (operation) {
171
+ case 'set':
172
+ return DType.color.set;
173
+ case 'blend':
174
+ return DType.color.blend;
175
+ }
176
+ break;
177
+
178
+ case 'array':
179
+ switch (operation) {
180
+ case 'set':
181
+ return DType.array.set;
182
+ case 'union':
183
+ return DType.array.union;
184
+ case 'append':
185
+ return DType.array.append;
186
+ }
187
+ break;
188
+
189
+ case 'object':
190
+ switch (operation) {
191
+ case 'set':
192
+ return DType.object.set;
193
+ case 'lww-per-key':
194
+ return DType.object.lwwPerKey;
195
+ }
196
+ break;
197
+
198
+ case 'any':
199
+ // Default to LWW for 'any' type
200
+ return DType.string.set as any;
201
+ }
202
+
203
+ return null;
204
+ }
205
+ }