@symbo.ls/sdk 2.32.1 → 2.32.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/dist/cjs/services/CollabService.js +19 -88
- package/dist/cjs/services/ProjectService.js +7 -2
- package/dist/cjs/utils/changePreprocessor.js +134 -0
- package/dist/cjs/utils/jsonDiff.js +46 -4
- package/dist/cjs/utils/ordering.js +0 -2
- package/dist/esm/index.js +182 -94
- package/dist/esm/services/CollabService.js +176 -92
- package/dist/esm/services/ProjectService.js +194 -4
- package/dist/esm/services/index.js +182 -94
- package/dist/esm/utils/CollabClient.js +46 -4
- package/dist/esm/utils/changePreprocessor.js +442 -0
- package/dist/esm/utils/jsonDiff.js +46 -4
- package/dist/esm/utils/ordering.js +0 -2
- package/dist/node/services/CollabService.js +19 -88
- package/dist/node/services/ProjectService.js +7 -2
- package/dist/node/utils/changePreprocessor.js +115 -0
- package/dist/node/utils/jsonDiff.js +46 -4
- package/dist/node/utils/ordering.js +0 -2
- package/package.json +6 -6
- package/src/services/CollabService.js +18 -108
- package/src/services/ProjectService.js +11 -3
- package/src/utils/changePreprocessor.js +139 -0
- package/src/utils/jsonDiff.js +40 -5
- package/src/utils/ordering.js +2 -2
|
@@ -26,8 +26,7 @@ var import_RootStateManager = require("../state/RootStateManager.js");
|
|
|
26
26
|
var import_rootEventBus = require("../state/rootEventBus.js");
|
|
27
27
|
var import_validation = require("../utils/validation.js");
|
|
28
28
|
var import_utils = require("@domql/utils");
|
|
29
|
-
var
|
|
30
|
-
var import_ordering = require("../utils/ordering.js");
|
|
29
|
+
var import_changePreprocessor = require("../utils/changePreprocessor.js");
|
|
31
30
|
class CollabService extends import_BaseService.BaseService {
|
|
32
31
|
constructor(config) {
|
|
33
32
|
super(config);
|
|
@@ -164,8 +163,8 @@ class CollabService extends import_BaseService.BaseService {
|
|
|
164
163
|
console.log(
|
|
165
164
|
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
166
165
|
);
|
|
167
|
-
this._pendingOps.forEach(({ changes, orders }) => {
|
|
168
|
-
this.socket.emit("ops", { changes, orders, ts: Date.now() });
|
|
166
|
+
this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
|
|
167
|
+
this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
|
|
169
168
|
});
|
|
170
169
|
this._pendingOps.length = 0;
|
|
171
170
|
}
|
|
@@ -207,94 +206,24 @@ class CollabService extends import_BaseService.BaseService {
|
|
|
207
206
|
}
|
|
208
207
|
/* ---------- data helpers ---------- */
|
|
209
208
|
updateData(tuples, options = {}) {
|
|
210
|
-
var _a, _b;
|
|
209
|
+
var _a, _b, _c;
|
|
211
210
|
this._ensureStateManager();
|
|
212
211
|
const { isUndo = false, isRedo = false } = options;
|
|
213
212
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
214
213
|
this._trackForUndo(tuples, options);
|
|
215
214
|
}
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (!state2 || typeof state2.getByPath !== "function") {
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
try {
|
|
226
|
-
return state2.getByPath(path);
|
|
227
|
-
} catch {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
const expandTuple = (t) => {
|
|
232
|
-
const [action, path, value] = t || [];
|
|
233
|
-
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
234
|
-
if (action === "delete" || isSchemaPath) {
|
|
235
|
-
return [t];
|
|
236
|
-
}
|
|
237
|
-
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2) && isPlainObject(value);
|
|
238
|
-
if (!canConsiderExpansion) {
|
|
239
|
-
return [t];
|
|
240
|
-
}
|
|
241
|
-
const prev = getByPath(root, path) || {};
|
|
242
|
-
const next = value || {};
|
|
243
|
-
if (!isPlainObject(prev) || !isPlainObject(next)) {
|
|
244
|
-
return [t];
|
|
245
|
-
}
|
|
246
|
-
const ops = (0, import_jsonDiff.diffJson)(prev, next, []);
|
|
247
|
-
if (!ops.length) {
|
|
248
|
-
return [];
|
|
249
|
-
}
|
|
250
|
-
const arr = [];
|
|
251
|
-
for (let j = 0; j < ops.length; j++) {
|
|
252
|
-
const op = ops[j];
|
|
253
|
-
const fullPath = [...path, ...op.path];
|
|
254
|
-
const last = fullPath[fullPath.length - 1];
|
|
255
|
-
if (op.action === "set") {
|
|
256
|
-
arr.push(["update", fullPath, op.value]);
|
|
257
|
-
} else if (op.action === "del") {
|
|
258
|
-
if (last !== "__order") {
|
|
259
|
-
arr.push(["delete", fullPath]);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return arr;
|
|
264
|
-
};
|
|
265
|
-
const minimizeTuples = (inputTuples) => {
|
|
266
|
-
const out = [];
|
|
267
|
-
for (let i = 0; i < inputTuples.length; i++) {
|
|
268
|
-
const expanded = expandTuple(inputTuples[i]);
|
|
269
|
-
for (let k = 0; k < expanded.length; k++) {
|
|
270
|
-
const tuple = expanded[k];
|
|
271
|
-
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
272
|
-
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
273
|
-
if (!isOrderKey) {
|
|
274
|
-
out.push(tuple);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
console.log(`Minimized tuples`, out);
|
|
279
|
-
return out;
|
|
280
|
-
};
|
|
281
|
-
console.log(`Processing tuples`, tuples);
|
|
282
|
-
return minimizeTuples(tuples);
|
|
283
|
-
} catch (err) {
|
|
284
|
-
console.warn(
|
|
285
|
-
"[CollabService] Minimal diff expansion failed \u2013 using original tuples",
|
|
286
|
-
err
|
|
287
|
-
);
|
|
288
|
-
return tuples;
|
|
289
|
-
}
|
|
290
|
-
})();
|
|
215
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
216
|
+
const { granularChanges: processedTuples, orders } = (0, import_changePreprocessor.preprocessChanges)(
|
|
217
|
+
root,
|
|
218
|
+
tuples,
|
|
219
|
+
options
|
|
220
|
+
);
|
|
291
221
|
if (options.append && options.append.length) {
|
|
292
222
|
processedTuples.push(...options.append);
|
|
293
223
|
}
|
|
294
224
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
295
|
-
const state = (
|
|
225
|
+
const state = (_b = this._stateManager) == null ? void 0 : _b.root;
|
|
296
226
|
const el = state == null ? void 0 : state.__element;
|
|
297
|
-
const orders = (0, import_ordering.computeOrdersForTuples)(state, processedTuples);
|
|
298
227
|
const stringifiedGranularTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
299
228
|
"deepStringifyFunctions",
|
|
300
229
|
processedTuples,
|
|
@@ -307,16 +236,18 @@ class CollabService extends import_BaseService.BaseService {
|
|
|
307
236
|
"deepStringifyFunctions",
|
|
308
237
|
tuples,
|
|
309
238
|
Array.isArray(tuples) ? [] : {}
|
|
310
|
-
) : (0, import_utils.deepStringifyFunctions)(
|
|
311
|
-
tuples,
|
|
312
|
-
Array.isArray(tuples) ? [] : {}
|
|
313
|
-
);
|
|
239
|
+
) : (0, import_utils.deepStringifyFunctions)(tuples, Array.isArray(tuples) ? [] : {});
|
|
314
240
|
if (!this.isConnected()) {
|
|
315
241
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
316
|
-
this._pendingOps.push({
|
|
242
|
+
this._pendingOps.push({
|
|
243
|
+
changes: stringifiedTuples,
|
|
244
|
+
granularChanges: stringifiedGranularTuples,
|
|
245
|
+
orders,
|
|
246
|
+
options
|
|
247
|
+
});
|
|
317
248
|
return;
|
|
318
249
|
}
|
|
319
|
-
if ((
|
|
250
|
+
if ((_c = this.socket) == null ? void 0 : _c.connected) {
|
|
320
251
|
console.log("[CollabService] Sending operations to the backend", {
|
|
321
252
|
changes: stringifiedTuples,
|
|
322
253
|
granularChanges: stringifiedGranularTuples,
|
|
@@ -22,6 +22,8 @@ __export(ProjectService_exports, {
|
|
|
22
22
|
module.exports = __toCommonJS(ProjectService_exports);
|
|
23
23
|
var import_BaseService = require("./BaseService.js");
|
|
24
24
|
var import_ordering = require("../utils/ordering.js");
|
|
25
|
+
var import_changePreprocessor = require("../utils/changePreprocessor.js");
|
|
26
|
+
var import_utils = require("@domql/utils");
|
|
25
27
|
class ProjectService extends import_BaseService.BaseService {
|
|
26
28
|
// ==================== PROJECT METHODS ====================
|
|
27
29
|
async createProject(projectData) {
|
|
@@ -554,12 +556,15 @@ class ProjectService extends import_BaseService.BaseService {
|
|
|
554
556
|
}
|
|
555
557
|
const { message, branch = "main", type = "patch" } = options;
|
|
556
558
|
const state = this._context && this._context.state;
|
|
557
|
-
const
|
|
559
|
+
const { granularChanges, orders: preprocessorOrders } = (0, import_changePreprocessor.preprocessChanges)(state, changes, options);
|
|
560
|
+
const derivedOrders = options.orders || (preprocessorOrders && preprocessorOrders.length ? preprocessorOrders : state ? (0, import_ordering.computeOrdersForTuples)(state, granularChanges) : []);
|
|
561
|
+
const stringify = (val) => (0, import_utils.deepStringifyFunctions)(val, Array.isArray(val) ? [] : {});
|
|
558
562
|
try {
|
|
559
563
|
const response = await this._request(`/projects/${projectId}/changes`, {
|
|
560
564
|
method: "POST",
|
|
561
565
|
body: JSON.stringify({
|
|
562
|
-
changes,
|
|
566
|
+
changes: stringify(changes),
|
|
567
|
+
granularChanges: stringify(granularChanges),
|
|
563
568
|
message,
|
|
564
569
|
branch,
|
|
565
570
|
type,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var changePreprocessor_exports = {};
|
|
19
|
+
__export(changePreprocessor_exports, {
|
|
20
|
+
preprocessChanges: () => preprocessChanges
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(changePreprocessor_exports);
|
|
23
|
+
var import_jsonDiff = require("./jsonDiff.js");
|
|
24
|
+
var import_ordering = require("./ordering.js");
|
|
25
|
+
function isPlainObject(val) {
|
|
26
|
+
return val && typeof val === "object" && !Array.isArray(val);
|
|
27
|
+
}
|
|
28
|
+
function getByPathSafe(root, path) {
|
|
29
|
+
if (!root || typeof root.getByPath !== "function") {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return root.getByPath(path);
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function preprocessChanges(root, tuples = [], options = {}) {
|
|
39
|
+
const expandTuple = (t) => {
|
|
40
|
+
const [action, path, value] = t || [];
|
|
41
|
+
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
42
|
+
if (action === "delete") {
|
|
43
|
+
return [t];
|
|
44
|
+
}
|
|
45
|
+
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2 || isSchemaPath && path.length === 3) && isPlainObject(value);
|
|
46
|
+
if (!canConsiderExpansion) {
|
|
47
|
+
return [t];
|
|
48
|
+
}
|
|
49
|
+
const prev = getByPathSafe(root, path) || {};
|
|
50
|
+
const next = value || {};
|
|
51
|
+
if (!isPlainObject(prev) || !isPlainObject(next)) {
|
|
52
|
+
return [t];
|
|
53
|
+
}
|
|
54
|
+
const ops = (0, import_jsonDiff.diffJson)(prev, next, []);
|
|
55
|
+
if (!ops.length) {
|
|
56
|
+
return [t];
|
|
57
|
+
}
|
|
58
|
+
const out = [];
|
|
59
|
+
for (let i = 0; i < ops.length; i++) {
|
|
60
|
+
const op = ops[i];
|
|
61
|
+
const fullPath = [...path, ...op.path];
|
|
62
|
+
const last = fullPath[fullPath.length - 1];
|
|
63
|
+
if (op.action === "set") {
|
|
64
|
+
out.push(["update", fullPath, op.value]);
|
|
65
|
+
} else if (op.action === "del") {
|
|
66
|
+
if (last !== "__order") {
|
|
67
|
+
out.push(["delete", fullPath]);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
};
|
|
73
|
+
const minimizeTuples = (input) => {
|
|
74
|
+
const out = [];
|
|
75
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
76
|
+
for (let i = 0; i < input.length; i++) {
|
|
77
|
+
const expanded = expandTuple(input[i]);
|
|
78
|
+
for (let k = 0; k < expanded.length; k++) {
|
|
79
|
+
const tuple = expanded[k];
|
|
80
|
+
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
81
|
+
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
82
|
+
if (!isOrderKey) {
|
|
83
|
+
const key = JSON.stringify(tuple);
|
|
84
|
+
if (!seen2.has(key)) {
|
|
85
|
+
seen2.add(key);
|
|
86
|
+
out.push(tuple);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
};
|
|
93
|
+
const granularChanges = (() => {
|
|
94
|
+
try {
|
|
95
|
+
const res = minimizeTuples(tuples);
|
|
96
|
+
if (options.append && options.append.length) {
|
|
97
|
+
res.push(...options.append);
|
|
98
|
+
}
|
|
99
|
+
return res;
|
|
100
|
+
} catch {
|
|
101
|
+
return Array.isArray(tuples) ? tuples.slice() : [];
|
|
102
|
+
}
|
|
103
|
+
})();
|
|
104
|
+
const baseOrders = (0, import_ordering.computeOrdersForTuples)(root, granularChanges);
|
|
105
|
+
const preferOrdersMap = /* @__PURE__ */ new Map();
|
|
106
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
107
|
+
const t = tuples[i];
|
|
108
|
+
if (!Array.isArray(t) || t.length < 3) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const [action, path, value] = t;
|
|
112
|
+
if (action !== "update" || !Array.isArray(path) || path.length !== 1 && path.length !== 2 || !isPlainObject(value)) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const keys = Object.keys(value).filter((k) => k !== "__order");
|
|
116
|
+
const key = JSON.stringify(path);
|
|
117
|
+
preferOrdersMap.set(key, { path, keys });
|
|
118
|
+
}
|
|
119
|
+
const mergedOrders = [];
|
|
120
|
+
const seen = /* @__PURE__ */ new Set();
|
|
121
|
+
preferOrdersMap.forEach((v, k) => {
|
|
122
|
+
seen.add(k);
|
|
123
|
+
mergedOrders.push(v);
|
|
124
|
+
});
|
|
125
|
+
for (let i = 0; i < baseOrders.length; i++) {
|
|
126
|
+
const v = baseOrders[i];
|
|
127
|
+
const k = JSON.stringify(v.path);
|
|
128
|
+
if (!seen.has(k)) {
|
|
129
|
+
seen.add(k);
|
|
130
|
+
mergedOrders.push(v);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { granularChanges, orders: mergedOrders };
|
|
134
|
+
}
|
|
@@ -36,12 +36,54 @@ function isPlainObject(o) {
|
|
|
36
36
|
return o && typeof o === "object" && !Array.isArray(o);
|
|
37
37
|
}
|
|
38
38
|
function deepEqual(a, b) {
|
|
39
|
-
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
39
|
+
if (Object.is(a, b)) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
if (typeof a === "function" && typeof b === "function") {
|
|
43
|
+
try {
|
|
44
|
+
return a.toString() === b.toString();
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (typeof a === "function" || typeof b === "function") {
|
|
43
50
|
return false;
|
|
44
51
|
}
|
|
52
|
+
if (a instanceof Date && b instanceof Date) {
|
|
53
|
+
return a.getTime() === b.getTime();
|
|
54
|
+
}
|
|
55
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
56
|
+
return String(a) === String(b);
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
59
|
+
if (a.length !== b.length) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i < a.length; i++) {
|
|
63
|
+
if (!deepEqual(a[i], b[i])) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
70
|
+
const aKeys = Object.keys(a);
|
|
71
|
+
const bKeys = Object.keys(b);
|
|
72
|
+
if (aKeys.length !== bKeys.length) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
for (let i = 0; i < aKeys.length; i++) {
|
|
76
|
+
const key = aKeys[i];
|
|
77
|
+
if (!Object.hasOwn(b, key)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (!deepEqual(a[key], b[key])) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
45
87
|
}
|
|
46
88
|
function getRootMap(ydoc) {
|
|
47
89
|
return ydoc.getMap("root");
|
|
@@ -47,14 +47,12 @@ function getParentPathsFromTuples(tuples = []) {
|
|
|
47
47
|
"attr",
|
|
48
48
|
"state",
|
|
49
49
|
"scope",
|
|
50
|
-
"props",
|
|
51
50
|
"define",
|
|
52
51
|
"on",
|
|
53
52
|
"extend",
|
|
54
53
|
"extends",
|
|
55
54
|
"childExtend",
|
|
56
55
|
"childExtends",
|
|
57
|
-
"childProps",
|
|
58
56
|
"children",
|
|
59
57
|
"component",
|
|
60
58
|
"context",
|