@coaction/yjs 1.5.0 → 2.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/README.md +6 -5
- package/dist/index.d.mts +28 -22
- package/dist/index.d.ts +28 -22
- package/dist/index.js +686 -554
- package/dist/index.mjs +661 -548
- package/package.json +39 -42
package/dist/index.js
CHANGED
|
@@ -1,605 +1,737 @@
|
|
|
1
|
-
"
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
9
|
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
19
18
|
};
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
Promise.resolve().then(callback);
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let coaction = require("coaction");
|
|
25
|
+
let yjs = require("yjs");
|
|
26
|
+
yjs = __toESM(yjs);
|
|
27
|
+
//#region packages/coaction-yjs/src/shared.ts
|
|
28
|
+
const scheduleMicrotask = (callback) => {
|
|
29
|
+
if (typeof queueMicrotask === "function") {
|
|
30
|
+
queueMicrotask(callback);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
Promise.resolve().then(callback);
|
|
34
|
+
};
|
|
35
|
+
const isUnsafeKey = (key) => key === "__proto__" || key === "prototype" || key === "constructor";
|
|
36
|
+
const isUnsafePathSegment = (segment) => typeof segment === "string" && isUnsafeKey(segment);
|
|
37
|
+
const cloneFallback = (value, seen = /* @__PURE__ */ new WeakMap()) => {
|
|
38
|
+
if (typeof value !== "object" || value === null) return value;
|
|
39
|
+
const cached = seen.get(value);
|
|
40
|
+
if (cached) return cached;
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
const next = [];
|
|
43
|
+
seen.set(value, next);
|
|
44
|
+
for (let index = 0; index < value.length; index += 1) if (Object.prototype.hasOwnProperty.call(value, index)) next[index] = cloneFallback(value[index], seen);
|
|
45
|
+
return next;
|
|
46
|
+
}
|
|
47
|
+
if (isPlainObject(value)) {
|
|
48
|
+
const next = Object.create(Object.getPrototypeOf(value));
|
|
49
|
+
seen.set(value, next);
|
|
50
|
+
for (const key of Reflect.ownKeys(value)) if (Object.prototype.propertyIsEnumerable.call(value, key)) {
|
|
51
|
+
if (typeof key === "string" && isUnsafeKey(key)) continue;
|
|
52
|
+
next[key] = cloneFallback(value[key], seen);
|
|
53
|
+
}
|
|
54
|
+
return next;
|
|
55
|
+
}
|
|
56
|
+
return JSON.parse(JSON.stringify(value));
|
|
59
57
|
};
|
|
60
58
|
function clone(value) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
if (Array.isArray(value) || isPlainObject(value)) return cloneFallback(value);
|
|
60
|
+
if (typeof structuredClone === "function") try {
|
|
61
|
+
return structuredClone(value);
|
|
62
|
+
} catch {
|
|
63
|
+
return cloneFallback(value);
|
|
64
|
+
}
|
|
65
|
+
return cloneFallback(value);
|
|
65
66
|
}
|
|
66
67
|
function isPlainObject(value) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const prototype = Object.getPrototypeOf(value);
|
|
71
|
-
return prototype === Object.prototype || prototype === null;
|
|
68
|
+
if (typeof value !== "object" || value === null) return false;
|
|
69
|
+
const prototype = Object.getPrototypeOf(value);
|
|
70
|
+
return prototype === Object.prototype || prototype === null;
|
|
72
71
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
function sanitizePlainValue(value, seen = /* @__PURE__ */ new WeakMap()) {
|
|
73
|
+
if (typeof value !== "object" || value === null) return value;
|
|
74
|
+
const cached = seen.get(value);
|
|
75
|
+
if (cached) return cached;
|
|
76
|
+
if (Array.isArray(value)) {
|
|
77
|
+
const next = [];
|
|
78
|
+
seen.set(value, next);
|
|
79
|
+
for (let index = 0; index < value.length; index += 1) if (Object.prototype.hasOwnProperty.call(value, index)) next[index] = sanitizePlainValue(value[index], seen);
|
|
80
|
+
return next;
|
|
81
|
+
}
|
|
82
|
+
if (!isPlainObject(value)) return clone(value);
|
|
83
|
+
const next = {};
|
|
84
|
+
seen.set(value, next);
|
|
85
|
+
for (const key of Object.keys(value)) {
|
|
86
|
+
if (isUnsafeKey(key)) continue;
|
|
87
|
+
next[key] = sanitizePlainValue(value[key], seen);
|
|
88
|
+
}
|
|
89
|
+
return next;
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region packages/coaction-yjs/src/yjsValue.ts
|
|
76
93
|
function toPlainObject(value) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
const next = {};
|
|
95
|
+
value.forEach((item, key) => {
|
|
96
|
+
if (isUnsafeKey(key)) return;
|
|
97
|
+
next[key] = toPlainValue(item);
|
|
98
|
+
});
|
|
99
|
+
return next;
|
|
82
100
|
}
|
|
83
101
|
function toPlainArray(value) {
|
|
84
|
-
|
|
102
|
+
return value.toArray().map((item) => toPlainValue(item));
|
|
85
103
|
}
|
|
86
104
|
function toPlainValue(value) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
return value;
|
|
105
|
+
if (value instanceof yjs.Map) return toPlainObject(value);
|
|
106
|
+
if (value instanceof yjs.Array) return toPlainArray(value);
|
|
107
|
+
if (value instanceof yjs.AbstractType) return toPlainValue(value.toJSON());
|
|
108
|
+
if (Array.isArray(value) || isPlainObject(value)) return sanitizePlainValue(value);
|
|
109
|
+
return value;
|
|
94
110
|
}
|
|
95
111
|
function createYMap(value) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
112
|
+
const next = new yjs.Map();
|
|
113
|
+
for (const [key, item] of Object.entries(value)) {
|
|
114
|
+
if (isUnsafeKey(key)) continue;
|
|
115
|
+
next.set(key, toYValue(item));
|
|
116
|
+
}
|
|
117
|
+
return next;
|
|
101
118
|
}
|
|
102
119
|
function createYArray(value) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
0,
|
|
107
|
-
value.map((item) => toYValue(item))
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
return next;
|
|
120
|
+
const next = new yjs.Array();
|
|
121
|
+
if (value.length > 0) next.insert(0, value.map((item) => toYValue(item)));
|
|
122
|
+
return next;
|
|
111
123
|
}
|
|
112
124
|
function toYValue(value) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return createYMap(value);
|
|
118
|
-
}
|
|
119
|
-
if (typeof value === "object" && value !== null) {
|
|
120
|
-
return clone(value);
|
|
121
|
-
}
|
|
122
|
-
return value;
|
|
125
|
+
if (Array.isArray(value)) return createYArray(value);
|
|
126
|
+
if (isPlainObject(value)) return createYMap(value);
|
|
127
|
+
if (typeof value === "object" && value !== null) return clone(value);
|
|
128
|
+
return value;
|
|
123
129
|
}
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region packages/coaction-yjs/src/remoteOperations.ts
|
|
126
132
|
function isSetStateReentryError(error) {
|
|
127
|
-
|
|
133
|
+
return error instanceof Error && error.message === "setState cannot be called within the updater";
|
|
128
134
|
}
|
|
129
135
|
function cloneForStore(value) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return value;
|
|
136
|
+
if (typeof value === "object" && value !== null) return sanitizePlainValue(value);
|
|
137
|
+
return value;
|
|
134
138
|
}
|
|
135
139
|
function toPathKey(path) {
|
|
136
|
-
|
|
140
|
+
return path.map((segment) => `${typeof segment}:${String(segment)}`).join("|");
|
|
141
|
+
}
|
|
142
|
+
function toArrayIndex(segment) {
|
|
143
|
+
const index = typeof segment === "number" ? segment : Number.parseInt(segment, 10);
|
|
144
|
+
if (!Number.isInteger(index) || index < 0) return;
|
|
145
|
+
if (typeof segment === "string" && String(index) !== segment) return;
|
|
146
|
+
return index;
|
|
147
|
+
}
|
|
148
|
+
function assertCanSetPathSegment(target, key, path) {
|
|
149
|
+
if (Object.prototype.hasOwnProperty.call(target, key)) return;
|
|
150
|
+
if (Object.isExtensible(target)) return;
|
|
151
|
+
throw new coaction.StateSchemaError(`Unknown state key '${path.map((segment) => String(segment)).join(".")}' cannot be added after store initialization. Coaction state schema is fixed.`);
|
|
152
|
+
}
|
|
153
|
+
function clearObjectKey(target, key) {
|
|
154
|
+
if (!Object.prototype.hasOwnProperty.call(target, key)) return;
|
|
155
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, key);
|
|
156
|
+
if (descriptor?.configurable) {
|
|
157
|
+
delete target[key];
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (descriptor && "set" in descriptor && descriptor.set) {
|
|
161
|
+
target[key] = void 0;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (descriptor && "writable" in descriptor && descriptor.writable) target[key] = void 0;
|
|
137
165
|
}
|
|
138
166
|
function compactOperations(operations) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
return Array.from(deduplicated.values()).sort(
|
|
148
|
-
(left, right) => left.path.length - right.path.length
|
|
149
|
-
);
|
|
167
|
+
const deduplicated = /* @__PURE__ */ new Map();
|
|
168
|
+
for (const operation of operations) {
|
|
169
|
+
const key = toPathKey(operation.path);
|
|
170
|
+
if (deduplicated.has(key)) deduplicated.delete(key);
|
|
171
|
+
deduplicated.set(key, operation);
|
|
172
|
+
}
|
|
173
|
+
return Array.from(deduplicated.values()).sort((left, right) => left.path.length - right.path.length);
|
|
150
174
|
}
|
|
151
175
|
function getYValueAtPath(root, path) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
return current;
|
|
176
|
+
let current = root;
|
|
177
|
+
for (const segment of path) {
|
|
178
|
+
if (current instanceof yjs.Map) {
|
|
179
|
+
current = current.get(String(segment));
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (current instanceof yjs.Array) {
|
|
183
|
+
const index = toArrayIndex(segment);
|
|
184
|
+
if (typeof index === "undefined") return;
|
|
185
|
+
current = current.get(index);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
return current;
|
|
169
191
|
}
|
|
170
192
|
function setAtPath(target, path, value) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
193
|
+
if (path.length === 0) return;
|
|
194
|
+
if (path.some(isUnsafePathSegment)) return;
|
|
195
|
+
let current = target;
|
|
196
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
197
|
+
const segment = path[index];
|
|
198
|
+
const nextSegment = path[index + 1];
|
|
199
|
+
const segmentIndex = Array.isArray(current) ? toArrayIndex(segment) : void 0;
|
|
200
|
+
const targetKey = typeof segmentIndex === "undefined" ? segment : segmentIndex;
|
|
201
|
+
const nextValue = current[targetKey];
|
|
202
|
+
const needsArray = typeof nextSegment === "number" || Array.isArray(nextValue) && typeof toArrayIndex(nextSegment) !== "undefined";
|
|
203
|
+
if (typeof nextValue !== "object" || nextValue === null || (needsArray ? !Array.isArray(nextValue) : Array.isArray(nextValue))) {
|
|
204
|
+
assertCanSetPathSegment(current, targetKey, path.slice(0, index + 1));
|
|
205
|
+
current[targetKey] = typeof nextSegment === "number" ? [] : {};
|
|
206
|
+
}
|
|
207
|
+
current = current[targetKey];
|
|
208
|
+
}
|
|
209
|
+
const leaf = path[path.length - 1];
|
|
210
|
+
const leafIndex = Array.isArray(current) ? toArrayIndex(leaf) : void 0;
|
|
211
|
+
const leafKey = typeof leafIndex === "undefined" ? leaf : leafIndex;
|
|
212
|
+
assertCanSetPathSegment(current, leafKey, path);
|
|
213
|
+
current[leafKey] = cloneForStore(value);
|
|
186
214
|
}
|
|
187
215
|
function deleteAtPath(target, path) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
delete current[leaf];
|
|
216
|
+
if (path.length === 0) return;
|
|
217
|
+
if (path.some(isUnsafePathSegment)) return;
|
|
218
|
+
let current = target;
|
|
219
|
+
for (let index = 0; index < path.length - 1; index += 1) {
|
|
220
|
+
const segment = path[index];
|
|
221
|
+
const segmentIndex = Array.isArray(current) ? toArrayIndex(segment) : void 0;
|
|
222
|
+
current = current[typeof segmentIndex === "undefined" ? segment : segmentIndex];
|
|
223
|
+
if (typeof current !== "object" || current === null) return;
|
|
224
|
+
}
|
|
225
|
+
const leaf = path[path.length - 1];
|
|
226
|
+
if (Array.isArray(current)) {
|
|
227
|
+
const leafIndex = toArrayIndex(leaf);
|
|
228
|
+
if (typeof leafIndex !== "undefined" && leafIndex >= 0 && leafIndex < current.length) current.splice(leafIndex, 1);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
clearObjectKey(current, leaf);
|
|
206
232
|
}
|
|
207
233
|
function collectRemoteOperations(events, stateMap) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
234
|
+
const operations = [];
|
|
235
|
+
for (const event of events) {
|
|
236
|
+
if (event instanceof yjs.YMapEvent) {
|
|
237
|
+
for (const changedKey of event.keysChanged) {
|
|
238
|
+
const path = [...event.path, changedKey];
|
|
239
|
+
if (path.some(isUnsafePathSegment)) continue;
|
|
240
|
+
if (event.changes.keys.get(changedKey)?.action === "delete") {
|
|
241
|
+
operations.push({
|
|
242
|
+
type: "delete",
|
|
243
|
+
path
|
|
244
|
+
});
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
operations.push({
|
|
248
|
+
type: "set",
|
|
249
|
+
path,
|
|
250
|
+
value: toPlainValue(getYValueAtPath(stateMap, path))
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (event instanceof yjs.YArrayEvent) {
|
|
256
|
+
const path = [...event.path];
|
|
257
|
+
operations.push({
|
|
258
|
+
type: "set",
|
|
259
|
+
path,
|
|
260
|
+
value: toPlainValue(getYValueAtPath(stateMap, path))
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return operations;
|
|
239
265
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
var Y3 = __toESM(require("yjs"));
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region packages/coaction-yjs/src/sync.ts
|
|
243
268
|
function isEqualValue(left, right) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (leftKeys.length !== rightKeys.length) {
|
|
262
|
-
return false;
|
|
263
|
-
}
|
|
264
|
-
for (const key of leftKeys) {
|
|
265
|
-
if (!Object.prototype.hasOwnProperty.call(right, key)) {
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
if (!isEqualValue(left[key], right[key])) {
|
|
269
|
-
return false;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return true;
|
|
273
|
-
}
|
|
274
|
-
return false;
|
|
269
|
+
if (Object.is(left, right)) return true;
|
|
270
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
271
|
+
if (left.length !== right.length) return false;
|
|
272
|
+
for (let index = 0; index < left.length; index += 1) if (!isEqualValue(left[index], right[index])) return false;
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
if (isPlainObject(left) && isPlainObject(right)) {
|
|
276
|
+
const leftKeys = Object.keys(left);
|
|
277
|
+
const rightKeys = Object.keys(right);
|
|
278
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
279
|
+
for (const key of leftKeys) {
|
|
280
|
+
if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
|
|
281
|
+
if (!isEqualValue(left[key], right[key])) return false;
|
|
282
|
+
}
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
return false;
|
|
275
286
|
}
|
|
276
287
|
function syncObjectToYMap(target, previous, source) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (!Object.is(current, normalized)) {
|
|
309
|
-
target.set(key, normalized);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
288
|
+
target.forEach((_value, key) => {
|
|
289
|
+
if (isUnsafeKey(key)) target.delete(key);
|
|
290
|
+
});
|
|
291
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(previous), ...Object.keys(source)]);
|
|
292
|
+
for (const key of keys) {
|
|
293
|
+
if (isUnsafeKey(key)) {
|
|
294
|
+
target.delete(key);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const hasPrevious = Object.prototype.hasOwnProperty.call(previous, key);
|
|
298
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
299
|
+
target.delete(key);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const previousValue = hasPrevious ? previous[key] : void 0;
|
|
303
|
+
const nextValue = source[key];
|
|
304
|
+
if (hasPrevious && isEqualValue(previousValue, nextValue)) continue;
|
|
305
|
+
const current = target.get(key);
|
|
306
|
+
if (Array.isArray(nextValue)) {
|
|
307
|
+
if (Array.isArray(previousValue) && current instanceof yjs.Array) syncArrayToYArray(current, previousValue, nextValue);
|
|
308
|
+
else target.set(key, createYArray(nextValue));
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (isPlainObject(nextValue)) {
|
|
312
|
+
if (isPlainObject(previousValue) && current instanceof yjs.Map) syncObjectToYMap(current, previousValue, nextValue);
|
|
313
|
+
else target.set(key, createYMap(nextValue));
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const normalized = typeof nextValue === "object" && nextValue !== null ? clone(nextValue) : nextValue;
|
|
317
|
+
if (!Object.is(current, normalized)) target.set(key, normalized);
|
|
318
|
+
}
|
|
312
319
|
}
|
|
313
320
|
function syncArrayToYArray(target, previous, source) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
continue;
|
|
351
|
-
}
|
|
352
|
-
const normalized = typeof nextValue === "object" && nextValue !== null ? clone(nextValue) : nextValue;
|
|
353
|
-
if (!Object.is(current, normalized)) {
|
|
354
|
-
target.delete(index, 1);
|
|
355
|
-
target.insert(index, [normalized]);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
321
|
+
if (target.length > source.length) target.delete(source.length, target.length - source.length);
|
|
322
|
+
const maxLength = Math.max(previous.length, source.length);
|
|
323
|
+
for (let index = 0; index < maxLength; index += 1) {
|
|
324
|
+
const hasPrevious = index < previous.length;
|
|
325
|
+
if (!(index < source.length)) continue;
|
|
326
|
+
const previousValue = hasPrevious ? previous[index] : void 0;
|
|
327
|
+
const nextValue = source[index];
|
|
328
|
+
if (hasPrevious && isEqualValue(previousValue, nextValue)) continue;
|
|
329
|
+
if (index >= target.length) {
|
|
330
|
+
target.insert(index, [toYValue(nextValue)]);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const current = target.get(index);
|
|
334
|
+
if (Array.isArray(nextValue)) {
|
|
335
|
+
if (Array.isArray(previousValue) && current instanceof yjs.Array) syncArrayToYArray(current, previousValue, nextValue);
|
|
336
|
+
else {
|
|
337
|
+
target.delete(index, 1);
|
|
338
|
+
target.insert(index, [createYArray(nextValue)]);
|
|
339
|
+
}
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (isPlainObject(nextValue)) {
|
|
343
|
+
if (isPlainObject(previousValue) && current instanceof yjs.Map) syncObjectToYMap(current, previousValue, nextValue);
|
|
344
|
+
else {
|
|
345
|
+
target.delete(index, 1);
|
|
346
|
+
target.insert(index, [createYMap(nextValue)]);
|
|
347
|
+
}
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const normalized = typeof nextValue === "object" && nextValue !== null ? clone(nextValue) : nextValue;
|
|
351
|
+
if (!Object.is(current, normalized)) {
|
|
352
|
+
target.delete(index, 1);
|
|
353
|
+
target.insert(index, [normalized]);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
358
356
|
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region packages/coaction-yjs/src/index.ts
|
|
359
|
+
const STATE_KEY = "state";
|
|
360
|
+
const historySuppressionSymbol = Symbol.for("coaction.history.suppress");
|
|
361
|
+
const runWithoutHistoryRecording = (store, callback) => {
|
|
362
|
+
const runner = store[historySuppressionSymbol];
|
|
363
|
+
return typeof runner === "function" ? runner(callback) : callback();
|
|
364
|
+
};
|
|
365
|
+
const getOwnEnumerableKeys = (value) => Reflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key) && !(typeof key === "string" && isUnsafeKey(key)));
|
|
366
|
+
const formatPropertyPath = (path) => path.length ? path.map((key) => String(key)).join(".") : "<root>";
|
|
367
|
+
var YjsSerializableStateError = class extends Error {};
|
|
368
|
+
const isYjsSerializableStateError = (error) => error instanceof YjsSerializableStateError;
|
|
369
|
+
const isArrayIndexKey = (key, length) => {
|
|
370
|
+
if (key === "") return false;
|
|
371
|
+
const index = Number(key);
|
|
372
|
+
return Number.isInteger(index) && index >= 0 && index < length && String(index) === key;
|
|
373
|
+
};
|
|
374
|
+
const findYjsStateViolation = (value, path = [], ancestors = /* @__PURE__ */ new WeakSet()) => {
|
|
375
|
+
switch (typeof value) {
|
|
376
|
+
case "symbol": return {
|
|
377
|
+
type: "symbol-value",
|
|
378
|
+
path
|
|
379
|
+
};
|
|
380
|
+
case "function": return {
|
|
381
|
+
type: "function",
|
|
382
|
+
path
|
|
383
|
+
};
|
|
384
|
+
default: break;
|
|
385
|
+
}
|
|
386
|
+
if (typeof value !== "object" || value === null) return;
|
|
387
|
+
if (ancestors.has(value)) return {
|
|
388
|
+
type: "circular-reference",
|
|
389
|
+
path
|
|
390
|
+
};
|
|
391
|
+
if (Array.isArray(value)) {
|
|
392
|
+
ancestors.add(value);
|
|
393
|
+
for (let index = 0; index < value.length; index += 1) if (!Object.prototype.hasOwnProperty.call(value, index)) return {
|
|
394
|
+
type: "array-hole",
|
|
395
|
+
path: [...path, index]
|
|
396
|
+
};
|
|
397
|
+
for (const key of getOwnEnumerableKeys(value)) {
|
|
398
|
+
const nextPath = [...path, key];
|
|
399
|
+
if (typeof key === "symbol") return {
|
|
400
|
+
type: "symbol-key",
|
|
401
|
+
path: nextPath
|
|
402
|
+
};
|
|
403
|
+
if (!isArrayIndexKey(key, value.length)) return {
|
|
404
|
+
type: "array-property",
|
|
405
|
+
path: nextPath
|
|
406
|
+
};
|
|
407
|
+
const violation = findYjsStateViolation(value[Number(key)], nextPath, ancestors);
|
|
408
|
+
if (violation) return violation;
|
|
409
|
+
}
|
|
410
|
+
ancestors.delete(value);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (!isPlainObject(value)) return {
|
|
414
|
+
type: "non-plain-object",
|
|
415
|
+
path
|
|
416
|
+
};
|
|
417
|
+
ancestors.add(value);
|
|
418
|
+
for (const key of getOwnEnumerableKeys(value)) {
|
|
419
|
+
const nextPath = [...path, key];
|
|
420
|
+
if (typeof key === "symbol") return {
|
|
421
|
+
type: "symbol-key",
|
|
422
|
+
path: nextPath
|
|
423
|
+
};
|
|
424
|
+
const child = value[key];
|
|
425
|
+
const violation = findYjsStateViolation(child, nextPath, ancestors);
|
|
426
|
+
if (violation) return violation;
|
|
427
|
+
}
|
|
428
|
+
ancestors.delete(value);
|
|
429
|
+
};
|
|
430
|
+
const assertYjsSerializableState = (state, path = []) => {
|
|
431
|
+
const violation = findYjsStateViolation(state, path);
|
|
432
|
+
if (!violation) return;
|
|
433
|
+
if (violation.type === "symbol-key") throw new YjsSerializableStateError(`Yjs binding does not support symbol-keyed state because Y.Map keys are strings. Found symbol key at ${formatPropertyPath(violation.path)}.`);
|
|
434
|
+
if (violation.type === "symbol-value") throw new YjsSerializableStateError(`Yjs binding does not support symbol-valued state because symbols cannot be cloned into Yjs documents. Found symbol value at ${formatPropertyPath(violation.path)}.`);
|
|
435
|
+
throw new YjsSerializableStateError(`Yjs binding does not support ${violation.type} state because only plain objects, arrays, and primitive values round-trip through Yjs updates. Found unsupported value at ${formatPropertyPath(violation.path)}.`);
|
|
436
|
+
};
|
|
437
|
+
const assertRemoteOperationsSerializable = (operations) => {
|
|
438
|
+
for (const operation of operations) if (operation.type === "set") assertYjsSerializableState(operation.value, operation.path);
|
|
439
|
+
};
|
|
440
|
+
const __unsafeTestOnly__ = {
|
|
441
|
+
getYValueAtPath: (root, path) => getYValueAtPath(root, path),
|
|
442
|
+
setAtPath: (target, path, value) => {
|
|
443
|
+
setAtPath(target, path, value);
|
|
444
|
+
},
|
|
445
|
+
deleteAtPath: (target, path) => {
|
|
446
|
+
deleteAtPath(target, path);
|
|
447
|
+
}
|
|
371
448
|
};
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
449
|
+
const bindYjs = (store, options = {}) => {
|
|
450
|
+
if (store.share === "client") throw new Error("Yjs binding is not supported in client store mode.");
|
|
451
|
+
const doc = options.doc ?? new yjs.Doc();
|
|
452
|
+
const key = options.key ?? `coaction:${store.name}`;
|
|
453
|
+
const map = doc.getMap(key);
|
|
454
|
+
const localOrigin = Symbol(`coaction-yjs:${store.name}`);
|
|
455
|
+
let destroyed = false;
|
|
456
|
+
let syncingFromYjs = false;
|
|
457
|
+
assertYjsSerializableState(store.getPureState());
|
|
458
|
+
let lastSyncedState = (() => {
|
|
459
|
+
const pureState = clone(store.getPureState());
|
|
460
|
+
return isPlainObject(pureState) ? pureState : {};
|
|
461
|
+
})();
|
|
462
|
+
let flushScheduled = false;
|
|
463
|
+
let pendingSnapshot = null;
|
|
464
|
+
let pendingOperations = [];
|
|
465
|
+
const restoreLastSyncedState = () => {
|
|
466
|
+
syncingFromYjs = true;
|
|
467
|
+
try {
|
|
468
|
+
store.apply(lastSyncedState);
|
|
469
|
+
} finally {
|
|
470
|
+
syncingFromYjs = false;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
const applyReplacementState = (next) => {
|
|
474
|
+
if (store.share === "main") {
|
|
475
|
+
store.setState(next, () => {
|
|
476
|
+
return (0, coaction.applyRootReplacementWithPatches)(store, next);
|
|
477
|
+
});
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
store.setState(null);
|
|
481
|
+
store.apply(next);
|
|
482
|
+
};
|
|
483
|
+
const applyRemoteState = (state) => {
|
|
484
|
+
assertYjsSerializableState(state);
|
|
485
|
+
const next = sanitizePlainValue(state);
|
|
486
|
+
syncingFromYjs = true;
|
|
487
|
+
try {
|
|
488
|
+
applyReplacementState(next);
|
|
489
|
+
const pureState = clone(store.getPureState());
|
|
490
|
+
lastSyncedState = isPlainObject(pureState) ? pureState : {};
|
|
491
|
+
} finally {
|
|
492
|
+
syncingFromYjs = false;
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const applyRemoteOperations = (operations) => {
|
|
496
|
+
if (operations.length === 0) return;
|
|
497
|
+
assertRemoteOperationsSerializable(operations);
|
|
498
|
+
syncingFromYjs = true;
|
|
499
|
+
try {
|
|
500
|
+
if (operations.some((operation) => operation.type === "delete" && operation.path.length === 1)) {
|
|
501
|
+
const next = clone(store.getPureState());
|
|
502
|
+
if (!isPlainObject(next)) return;
|
|
503
|
+
for (const operation of operations) if (operation.type === "set") setAtPath(next, operation.path, operation.value);
|
|
504
|
+
else deleteAtPath(next, operation.path);
|
|
505
|
+
applyReplacementState(next);
|
|
506
|
+
const pureState = clone(store.getPureState());
|
|
507
|
+
lastSyncedState = isPlainObject(pureState) ? pureState : {};
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
store.setState((draft) => {
|
|
511
|
+
const mutableDraft = draft;
|
|
512
|
+
for (const operation of operations) if (operation.type === "set") setAtPath(mutableDraft, operation.path, operation.value);
|
|
513
|
+
else deleteAtPath(mutableDraft, operation.path);
|
|
514
|
+
});
|
|
515
|
+
const pureState = clone(store.getPureState());
|
|
516
|
+
lastSyncedState = isPlainObject(pureState) ? pureState : {};
|
|
517
|
+
} finally {
|
|
518
|
+
syncingFromYjs = false;
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
const getStateMap = () => {
|
|
522
|
+
const state = map.get(STATE_KEY);
|
|
523
|
+
if (state instanceof yjs.Map) return state;
|
|
524
|
+
return null;
|
|
525
|
+
};
|
|
526
|
+
const scheduleFlushFromYjs = () => {
|
|
527
|
+
if (destroyed || flushScheduled) return;
|
|
528
|
+
flushScheduled = true;
|
|
529
|
+
scheduleMicrotask(flushFromYjs);
|
|
530
|
+
};
|
|
531
|
+
const flushFromYjs = () => {
|
|
532
|
+
flushScheduled = false;
|
|
533
|
+
if (destroyed) return;
|
|
534
|
+
if (pendingSnapshot) {
|
|
535
|
+
const snapshot = pendingSnapshot;
|
|
536
|
+
pendingSnapshot = null;
|
|
537
|
+
pendingOperations = [];
|
|
538
|
+
try {
|
|
539
|
+
applyRemoteState(snapshot);
|
|
540
|
+
} catch (error) {
|
|
541
|
+
if (isSetStateReentryError(error)) {
|
|
542
|
+
pendingSnapshot = snapshot;
|
|
543
|
+
setTimeout(scheduleFlushFromYjs, 0);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
if (isYjsSerializableStateError(error) || (0, coaction.isStateSchemaError)(error)) {
|
|
547
|
+
restoreRootState();
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
throw error;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (pendingOperations.length === 0) return;
|
|
554
|
+
const operations = compactOperations(pendingOperations);
|
|
555
|
+
pendingOperations = [];
|
|
556
|
+
try {
|
|
557
|
+
applyRemoteOperations(operations);
|
|
558
|
+
} catch (error) {
|
|
559
|
+
if (isSetStateReentryError(error)) {
|
|
560
|
+
pendingOperations = [...operations, ...pendingOperations];
|
|
561
|
+
setTimeout(scheduleFlushFromYjs, 0);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (isYjsSerializableStateError(error) || (0, coaction.isStateSchemaError)(error)) {
|
|
565
|
+
restoreRootState();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
throw error;
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
const enqueueSnapshot = (snapshot) => {
|
|
572
|
+
pendingSnapshot = snapshot;
|
|
573
|
+
pendingOperations = [];
|
|
574
|
+
scheduleFlushFromYjs();
|
|
575
|
+
};
|
|
576
|
+
const enqueueOperations = (operations) => {
|
|
577
|
+
if (operations.length === 0) return;
|
|
578
|
+
if (!pendingSnapshot) pendingOperations.push(...operations);
|
|
579
|
+
scheduleFlushFromYjs();
|
|
580
|
+
};
|
|
581
|
+
const syncNow = () => {
|
|
582
|
+
if (destroyed || syncingFromYjs) return;
|
|
583
|
+
try {
|
|
584
|
+
assertYjsSerializableState(store.getPureState());
|
|
585
|
+
} catch (error) {
|
|
586
|
+
restoreLastSyncedState();
|
|
587
|
+
throw error;
|
|
588
|
+
}
|
|
589
|
+
const pureState = clone(store.getPureState());
|
|
590
|
+
if (!isPlainObject(pureState)) return;
|
|
591
|
+
doc.transact(() => {
|
|
592
|
+
syncObjectToYMap(stateMap, lastSyncedState, pureState);
|
|
593
|
+
}, localOrigin);
|
|
594
|
+
lastSyncedState = pureState;
|
|
595
|
+
};
|
|
596
|
+
const stateObserver = (events, transaction) => {
|
|
597
|
+
if (transaction.origin === localOrigin) return;
|
|
598
|
+
enqueueOperations(collectRemoteOperations(events, stateMap));
|
|
599
|
+
};
|
|
600
|
+
let stateMap;
|
|
601
|
+
let stateMapObserved = false;
|
|
602
|
+
const unobserveStateMap = () => {
|
|
603
|
+
if (!stateMapObserved) return;
|
|
604
|
+
stateMap.unobserveDeep(stateObserver);
|
|
605
|
+
stateMapObserved = false;
|
|
606
|
+
};
|
|
607
|
+
const observeStateMap = (nextStateMap) => {
|
|
608
|
+
if (stateMap === nextStateMap && stateMapObserved) return;
|
|
609
|
+
unobserveStateMap();
|
|
610
|
+
stateMap = nextStateMap;
|
|
611
|
+
stateMap.observeDeep(stateObserver);
|
|
612
|
+
stateMapObserved = true;
|
|
613
|
+
};
|
|
614
|
+
const migrateRootState = (nextState) => {
|
|
615
|
+
const migrated = createYMap(nextState);
|
|
616
|
+
doc.transact(() => {
|
|
617
|
+
map.set(STATE_KEY, migrated);
|
|
618
|
+
}, localOrigin);
|
|
619
|
+
observeStateMap(migrated);
|
|
620
|
+
enqueueSnapshot(nextState);
|
|
621
|
+
};
|
|
622
|
+
const restoreRootState = () => {
|
|
623
|
+
const pureState = clone(store.getPureState());
|
|
624
|
+
const nextState = isPlainObject(pureState) ? pureState : lastSyncedState;
|
|
625
|
+
const restored = createYMap(nextState);
|
|
626
|
+
doc.transact(() => {
|
|
627
|
+
map.set(STATE_KEY, restored);
|
|
628
|
+
}, localOrigin);
|
|
629
|
+
observeStateMap(restored);
|
|
630
|
+
lastSyncedState = nextState;
|
|
631
|
+
};
|
|
632
|
+
const applyInitialRemoteState = (state) => {
|
|
633
|
+
runWithoutHistoryRecording(store, () => {
|
|
634
|
+
try {
|
|
635
|
+
applyRemoteState(state);
|
|
636
|
+
} catch (error) {
|
|
637
|
+
if (isYjsSerializableStateError(error) || (0, coaction.isStateSchemaError)(error)) {
|
|
638
|
+
restoreRootState();
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
const existingStateMap = getStateMap();
|
|
646
|
+
if (existingStateMap) {
|
|
647
|
+
stateMap = existingStateMap;
|
|
648
|
+
applyInitialRemoteState(toPlainObject(stateMap));
|
|
649
|
+
} else {
|
|
650
|
+
const currentState = map.get(STATE_KEY);
|
|
651
|
+
if (isPlainObject(currentState)) {
|
|
652
|
+
stateMap = createYMap(currentState);
|
|
653
|
+
doc.transact(() => {
|
|
654
|
+
map.set(STATE_KEY, stateMap);
|
|
655
|
+
}, localOrigin);
|
|
656
|
+
applyInitialRemoteState(currentState);
|
|
657
|
+
} else {
|
|
658
|
+
const pureState = clone(store.getPureState());
|
|
659
|
+
stateMap = createYMap(isPlainObject(pureState) ? pureState : {});
|
|
660
|
+
doc.transact(() => {
|
|
661
|
+
map.set(STATE_KEY, stateMap);
|
|
662
|
+
}, localOrigin);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
observeStateMap(stateMap);
|
|
666
|
+
const observer = (event) => {
|
|
667
|
+
if (event.transaction.origin === localOrigin) return;
|
|
668
|
+
if (!event.keysChanged.has(STATE_KEY)) return;
|
|
669
|
+
const stateChange = event.changes.keys.get(STATE_KEY);
|
|
670
|
+
const nextStateMap = getStateMap();
|
|
671
|
+
if (nextStateMap) {
|
|
672
|
+
observeStateMap(nextStateMap);
|
|
673
|
+
enqueueSnapshot(toPlainObject(nextStateMap));
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
const currentState = map.get(STATE_KEY);
|
|
677
|
+
if (isPlainObject(currentState)) {
|
|
678
|
+
migrateRootState(currentState);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
if (stateChange?.action === "delete") {
|
|
682
|
+
migrateRootState({});
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
restoreRootState();
|
|
686
|
+
};
|
|
687
|
+
map.observe(observer);
|
|
688
|
+
const unsubscribe = store.subscribe(() => {
|
|
689
|
+
syncNow();
|
|
690
|
+
});
|
|
691
|
+
const binding = {
|
|
692
|
+
doc,
|
|
693
|
+
map,
|
|
694
|
+
syncNow,
|
|
695
|
+
destroy: () => {
|
|
696
|
+
if (destroyed) return;
|
|
697
|
+
destroyed = true;
|
|
698
|
+
unsubscribe();
|
|
699
|
+
map.unobserve(observer);
|
|
700
|
+
unobserveStateMap();
|
|
701
|
+
if (!options.doc) doc.destroy();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
if (process.env.NODE_ENV === "test") binding.__unsafeTestOnly__ = { applyRemoteOperations: (operations) => {
|
|
705
|
+
applyRemoteOperations(operations);
|
|
706
|
+
} };
|
|
707
|
+
return binding;
|
|
587
708
|
};
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
709
|
+
const yjs$1 = (options = {}) => (store) => {
|
|
710
|
+
let binding;
|
|
711
|
+
const cancelBinding = (0, coaction.onStoreReady)(store, () => {
|
|
712
|
+
binding = bindYjs(store, options);
|
|
713
|
+
});
|
|
714
|
+
const baseDestroy = store.destroy;
|
|
715
|
+
let destroyed = false;
|
|
716
|
+
store.destroy = () => {
|
|
717
|
+
if (destroyed) return;
|
|
718
|
+
destroyed = true;
|
|
719
|
+
cancelBinding();
|
|
720
|
+
binding?.destroy();
|
|
721
|
+
binding = void 0;
|
|
722
|
+
baseDestroy();
|
|
723
|
+
};
|
|
724
|
+
return store;
|
|
596
725
|
};
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
726
|
+
//#endregion
|
|
727
|
+
exports.__unsafeTestOnly__ = __unsafeTestOnly__;
|
|
728
|
+
exports.bindYjs = bindYjs;
|
|
729
|
+
exports.yjs = yjs$1;
|
|
730
|
+
Object.keys(yjs).forEach(function(k) {
|
|
731
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
732
|
+
enumerable: true,
|
|
733
|
+
get: function() {
|
|
734
|
+
return yjs[k];
|
|
735
|
+
}
|
|
736
|
+
});
|
|
605
737
|
});
|