@symbo.ls/sdk 2.31.37 → 2.32.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.
- package/dist/cjs/services/CollabService.js +153 -51
- package/dist/cjs/services/ProjectService.js +5 -1
- package/dist/cjs/services/ScreenshotService.js +2 -2
- package/dist/cjs/utils/ordering.js +276 -0
- package/dist/esm/index.js +506 -122
- package/dist/esm/services/CollabService.js +500 -119
- package/dist/esm/services/ProjectService.js +258 -1
- package/dist/esm/services/ScreenshotService.js +2 -2
- package/dist/esm/services/index.js +506 -122
- package/dist/esm/utils/CollabClient.js +93 -68
- package/dist/esm/utils/ordering.js +258 -0
- package/dist/node/services/CollabService.js +153 -51
- package/dist/node/services/ProjectService.js +5 -1
- package/dist/node/services/ScreenshotService.js +2 -2
- package/dist/node/utils/ordering.js +257 -0
- package/package.json +6 -6
- package/src/services/CollabService.js +191 -61
- package/src/services/ProjectService.js +7 -1
- package/src/services/ScreenshotService.js +2 -2
- package/src/utils/ordering.js +244 -0
|
@@ -9166,7 +9166,7 @@ var require_dexie = __commonJS({
|
|
|
9166
9166
|
});
|
|
9167
9167
|
}
|
|
9168
9168
|
}
|
|
9169
|
-
var DEXIE_VERSION = "4.2.
|
|
9169
|
+
var DEXIE_VERSION = "4.2.1";
|
|
9170
9170
|
var maxString = String.fromCharCode(65535);
|
|
9171
9171
|
var minKey = -Infinity;
|
|
9172
9172
|
var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
|
|
@@ -9291,6 +9291,73 @@ var require_dexie = __commonJS({
|
|
|
9291
9291
|
return res;
|
|
9292
9292
|
});
|
|
9293
9293
|
}
|
|
9294
|
+
var PropModification2 = (function() {
|
|
9295
|
+
function PropModification3(spec) {
|
|
9296
|
+
this["@@propmod"] = spec;
|
|
9297
|
+
}
|
|
9298
|
+
PropModification3.prototype.execute = function(value2) {
|
|
9299
|
+
var _a2;
|
|
9300
|
+
var spec = this["@@propmod"];
|
|
9301
|
+
if (spec.add !== void 0) {
|
|
9302
|
+
var term = spec.add;
|
|
9303
|
+
if (isArray2(term)) {
|
|
9304
|
+
return __spreadArray(__spreadArray([], isArray2(value2) ? value2 : [], true), term, true).sort();
|
|
9305
|
+
}
|
|
9306
|
+
if (typeof term === "number")
|
|
9307
|
+
return (Number(value2) || 0) + term;
|
|
9308
|
+
if (typeof term === "bigint") {
|
|
9309
|
+
try {
|
|
9310
|
+
return BigInt(value2) + term;
|
|
9311
|
+
} catch (_b) {
|
|
9312
|
+
return BigInt(0) + term;
|
|
9313
|
+
}
|
|
9314
|
+
}
|
|
9315
|
+
throw new TypeError("Invalid term ".concat(term));
|
|
9316
|
+
}
|
|
9317
|
+
if (spec.remove !== void 0) {
|
|
9318
|
+
var subtrahend_1 = spec.remove;
|
|
9319
|
+
if (isArray2(subtrahend_1)) {
|
|
9320
|
+
return isArray2(value2) ? value2.filter(function(item) {
|
|
9321
|
+
return !subtrahend_1.includes(item);
|
|
9322
|
+
}).sort() : [];
|
|
9323
|
+
}
|
|
9324
|
+
if (typeof subtrahend_1 === "number")
|
|
9325
|
+
return Number(value2) - subtrahend_1;
|
|
9326
|
+
if (typeof subtrahend_1 === "bigint") {
|
|
9327
|
+
try {
|
|
9328
|
+
return BigInt(value2) - subtrahend_1;
|
|
9329
|
+
} catch (_c) {
|
|
9330
|
+
return BigInt(0) - subtrahend_1;
|
|
9331
|
+
}
|
|
9332
|
+
}
|
|
9333
|
+
throw new TypeError("Invalid subtrahend ".concat(subtrahend_1));
|
|
9334
|
+
}
|
|
9335
|
+
var prefixToReplace = (_a2 = spec.replacePrefix) === null || _a2 === void 0 ? void 0 : _a2[0];
|
|
9336
|
+
if (prefixToReplace && typeof value2 === "string" && value2.startsWith(prefixToReplace)) {
|
|
9337
|
+
return spec.replacePrefix[1] + value2.substring(prefixToReplace.length);
|
|
9338
|
+
}
|
|
9339
|
+
return value2;
|
|
9340
|
+
};
|
|
9341
|
+
return PropModification3;
|
|
9342
|
+
})();
|
|
9343
|
+
function applyUpdateSpec(obj, changes) {
|
|
9344
|
+
var keyPaths = keys2(changes);
|
|
9345
|
+
var numKeys = keyPaths.length;
|
|
9346
|
+
var anythingModified = false;
|
|
9347
|
+
for (var i = 0; i < numKeys; ++i) {
|
|
9348
|
+
var keyPath = keyPaths[i];
|
|
9349
|
+
var value2 = changes[keyPath];
|
|
9350
|
+
var origValue = getByKeyPath(obj, keyPath);
|
|
9351
|
+
if (value2 instanceof PropModification2) {
|
|
9352
|
+
setByKeyPath(obj, keyPath, value2.execute(origValue));
|
|
9353
|
+
anythingModified = true;
|
|
9354
|
+
} else if (origValue !== value2) {
|
|
9355
|
+
setByKeyPath(obj, keyPath, value2);
|
|
9356
|
+
anythingModified = true;
|
|
9357
|
+
}
|
|
9358
|
+
}
|
|
9359
|
+
return anythingModified;
|
|
9360
|
+
}
|
|
9294
9361
|
var Table = (function() {
|
|
9295
9362
|
function Table2() {
|
|
9296
9363
|
}
|
|
@@ -9486,6 +9553,28 @@ var require_dexie = __commonJS({
|
|
|
9486
9553
|
return lastResult;
|
|
9487
9554
|
});
|
|
9488
9555
|
};
|
|
9556
|
+
Table2.prototype.upsert = function(key, modifications) {
|
|
9557
|
+
var _this = this;
|
|
9558
|
+
var keyPath = this.schema.primKey.keyPath;
|
|
9559
|
+
return this._trans("readwrite", function(trans) {
|
|
9560
|
+
return _this.core.get({ trans, key }).then(function(existing) {
|
|
9561
|
+
var obj = existing !== null && existing !== void 0 ? existing : {};
|
|
9562
|
+
applyUpdateSpec(obj, modifications);
|
|
9563
|
+
if (keyPath)
|
|
9564
|
+
setByKeyPath(obj, keyPath, key);
|
|
9565
|
+
return _this.core.mutate({
|
|
9566
|
+
trans,
|
|
9567
|
+
type: "put",
|
|
9568
|
+
values: [obj],
|
|
9569
|
+
keys: [key],
|
|
9570
|
+
upsert: true,
|
|
9571
|
+
updates: { keys: [key], changeSpecs: [modifications] }
|
|
9572
|
+
}).then(function(res) {
|
|
9573
|
+
return res.numFailures ? DexiePromise.reject(res.failures[0]) : !!existing;
|
|
9574
|
+
});
|
|
9575
|
+
});
|
|
9576
|
+
});
|
|
9577
|
+
};
|
|
9489
9578
|
Table2.prototype.update = function(keyOrObject, modifications) {
|
|
9490
9579
|
if (typeof keyOrObject === "object" && !isArray2(keyOrObject)) {
|
|
9491
9580
|
var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);
|
|
@@ -9848,55 +9937,6 @@ var require_dexie = __commonJS({
|
|
|
9848
9937
|
}
|
|
9849
9938
|
});
|
|
9850
9939
|
}
|
|
9851
|
-
var PropModification2 = (function() {
|
|
9852
|
-
function PropModification3(spec) {
|
|
9853
|
-
this["@@propmod"] = spec;
|
|
9854
|
-
}
|
|
9855
|
-
PropModification3.prototype.execute = function(value2) {
|
|
9856
|
-
var _a2;
|
|
9857
|
-
var spec = this["@@propmod"];
|
|
9858
|
-
if (spec.add !== void 0) {
|
|
9859
|
-
var term = spec.add;
|
|
9860
|
-
if (isArray2(term)) {
|
|
9861
|
-
return __spreadArray(__spreadArray([], isArray2(value2) ? value2 : [], true), term, true).sort();
|
|
9862
|
-
}
|
|
9863
|
-
if (typeof term === "number")
|
|
9864
|
-
return (Number(value2) || 0) + term;
|
|
9865
|
-
if (typeof term === "bigint") {
|
|
9866
|
-
try {
|
|
9867
|
-
return BigInt(value2) + term;
|
|
9868
|
-
} catch (_b) {
|
|
9869
|
-
return BigInt(0) + term;
|
|
9870
|
-
}
|
|
9871
|
-
}
|
|
9872
|
-
throw new TypeError("Invalid term ".concat(term));
|
|
9873
|
-
}
|
|
9874
|
-
if (spec.remove !== void 0) {
|
|
9875
|
-
var subtrahend_1 = spec.remove;
|
|
9876
|
-
if (isArray2(subtrahend_1)) {
|
|
9877
|
-
return isArray2(value2) ? value2.filter(function(item) {
|
|
9878
|
-
return !subtrahend_1.includes(item);
|
|
9879
|
-
}).sort() : [];
|
|
9880
|
-
}
|
|
9881
|
-
if (typeof subtrahend_1 === "number")
|
|
9882
|
-
return Number(value2) - subtrahend_1;
|
|
9883
|
-
if (typeof subtrahend_1 === "bigint") {
|
|
9884
|
-
try {
|
|
9885
|
-
return BigInt(value2) - subtrahend_1;
|
|
9886
|
-
} catch (_c) {
|
|
9887
|
-
return BigInt(0) - subtrahend_1;
|
|
9888
|
-
}
|
|
9889
|
-
}
|
|
9890
|
-
throw new TypeError("Invalid subtrahend ".concat(subtrahend_1));
|
|
9891
|
-
}
|
|
9892
|
-
var prefixToReplace = (_a2 = spec.replacePrefix) === null || _a2 === void 0 ? void 0 : _a2[0];
|
|
9893
|
-
if (prefixToReplace && typeof value2 === "string" && value2.startsWith(prefixToReplace)) {
|
|
9894
|
-
return spec.replacePrefix[1] + value2.substring(prefixToReplace.length);
|
|
9895
|
-
}
|
|
9896
|
-
return value2;
|
|
9897
|
-
};
|
|
9898
|
-
return PropModification3;
|
|
9899
|
-
})();
|
|
9900
9940
|
var Collection = (function() {
|
|
9901
9941
|
function Collection2() {
|
|
9902
9942
|
}
|
|
@@ -10176,23 +10216,8 @@ var require_dexie = __commonJS({
|
|
|
10176
10216
|
if (typeof changes === "function") {
|
|
10177
10217
|
modifyer = changes;
|
|
10178
10218
|
} else {
|
|
10179
|
-
var keyPaths = keys2(changes);
|
|
10180
|
-
var numKeys = keyPaths.length;
|
|
10181
10219
|
modifyer = function(item) {
|
|
10182
|
-
|
|
10183
|
-
for (var i = 0; i < numKeys; ++i) {
|
|
10184
|
-
var keyPath = keyPaths[i];
|
|
10185
|
-
var val = changes[keyPath];
|
|
10186
|
-
var origVal = getByKeyPath(item, keyPath);
|
|
10187
|
-
if (val instanceof PropModification2) {
|
|
10188
|
-
setByKeyPath(item, keyPath, val.execute(origVal));
|
|
10189
|
-
anythingModified = true;
|
|
10190
|
-
} else if (origVal !== val) {
|
|
10191
|
-
setByKeyPath(item, keyPath, val);
|
|
10192
|
-
anythingModified = true;
|
|
10193
|
-
}
|
|
10194
|
-
}
|
|
10195
|
-
return anythingModified;
|
|
10220
|
+
return applyUpdateSpec(item, changes);
|
|
10196
10221
|
};
|
|
10197
10222
|
}
|
|
10198
10223
|
var coreTable = ctx.table.core;
|
|
@@ -12196,8 +12221,8 @@ var require_dexie = __commonJS({
|
|
|
12196
12221
|
state.vcFired = true;
|
|
12197
12222
|
db.on("versionchange").fire(ev);
|
|
12198
12223
|
});
|
|
12199
|
-
idbdb.onclose = wrap(function(
|
|
12200
|
-
db.
|
|
12224
|
+
idbdb.onclose = wrap(function() {
|
|
12225
|
+
db.close({ disableAutoOpen: false });
|
|
12201
12226
|
});
|
|
12202
12227
|
if (wasCreated)
|
|
12203
12228
|
_onDatabaseCreated(db._deps, dbName);
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// src/utils/ordering.js
|
|
2
|
+
function isObjectLike(val) {
|
|
3
|
+
return val && typeof val === "object" && !Array.isArray(val);
|
|
4
|
+
}
|
|
5
|
+
function normalizePath(path) {
|
|
6
|
+
if (Array.isArray(path)) {
|
|
7
|
+
return path;
|
|
8
|
+
}
|
|
9
|
+
if (typeof path === "string") {
|
|
10
|
+
return [path];
|
|
11
|
+
}
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
function getParentPathsFromTuples(tuples = []) {
|
|
15
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16
|
+
const parents = [];
|
|
17
|
+
const META_KEYS = /* @__PURE__ */ new Set([
|
|
18
|
+
"style",
|
|
19
|
+
"class",
|
|
20
|
+
"text",
|
|
21
|
+
"html",
|
|
22
|
+
"content",
|
|
23
|
+
"data",
|
|
24
|
+
"attr",
|
|
25
|
+
"state",
|
|
26
|
+
"scope",
|
|
27
|
+
"props",
|
|
28
|
+
"define",
|
|
29
|
+
"on",
|
|
30
|
+
"extend",
|
|
31
|
+
"extends",
|
|
32
|
+
"childExtend",
|
|
33
|
+
"childExtends",
|
|
34
|
+
"childProps",
|
|
35
|
+
"children",
|
|
36
|
+
"component",
|
|
37
|
+
"context",
|
|
38
|
+
"tag",
|
|
39
|
+
"key",
|
|
40
|
+
"__order",
|
|
41
|
+
"if"
|
|
42
|
+
]);
|
|
43
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
44
|
+
const tuple = tuples[i];
|
|
45
|
+
if (!Array.isArray(tuple) || tuple.length < 2) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const path = normalizePath(tuple[1]);
|
|
49
|
+
if (!path.length) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (path[0] === "schema") {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const immediateParent = path.slice(0, -1);
|
|
56
|
+
if (immediateParent.length) {
|
|
57
|
+
const key = JSON.stringify(immediateParent);
|
|
58
|
+
if (!seen.has(key)) {
|
|
59
|
+
seen.add(key);
|
|
60
|
+
parents.push(immediateParent);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const last = path[path.length - 1];
|
|
64
|
+
if (META_KEYS.has(last) && path.length >= 2) {
|
|
65
|
+
const containerParent = path.slice(0, -2);
|
|
66
|
+
if (containerParent.length) {
|
|
67
|
+
const key2 = JSON.stringify(containerParent);
|
|
68
|
+
if (!seen.has(key2)) {
|
|
69
|
+
seen.add(key2);
|
|
70
|
+
parents.push(containerParent);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (let j = 0; j < path.length; j++) {
|
|
75
|
+
const seg = path[j];
|
|
76
|
+
if (!META_KEYS.has(seg)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const containerParent2 = path.slice(0, j);
|
|
80
|
+
if (!containerParent2.length) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const key3 = JSON.stringify(containerParent2);
|
|
84
|
+
if (!seen.has(key3)) {
|
|
85
|
+
seen.add(key3);
|
|
86
|
+
parents.push(containerParent2);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return parents;
|
|
91
|
+
}
|
|
92
|
+
function computeOrdersFromState(root, parentPaths = []) {
|
|
93
|
+
if (!root || typeof root.getByPath !== "function") {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
const orders = [];
|
|
97
|
+
const EXCLUDE_KEYS = /* @__PURE__ */ new Set(["__order"]);
|
|
98
|
+
for (let i = 0; i < parentPaths.length; i++) {
|
|
99
|
+
const parentPath = parentPaths[i];
|
|
100
|
+
const obj = (() => {
|
|
101
|
+
try {
|
|
102
|
+
return root.getByPath(parentPath);
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
if (!isObjectLike(obj)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const keys = Object.keys(obj).filter((k) => !EXCLUDE_KEYS.has(k));
|
|
111
|
+
orders.push({ path: parentPath, keys });
|
|
112
|
+
}
|
|
113
|
+
return orders;
|
|
114
|
+
}
|
|
115
|
+
function normaliseSchemaCode(code) {
|
|
116
|
+
if (typeof code !== "string" || !code.length) {
|
|
117
|
+
return "";
|
|
118
|
+
}
|
|
119
|
+
return code.replaceAll("/////n", "\n").replaceAll("/////tilde", "`");
|
|
120
|
+
}
|
|
121
|
+
function parseExportedObject(code) {
|
|
122
|
+
const src = normaliseSchemaCode(code);
|
|
123
|
+
if (!src) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const body = src.replace(/^\s*export\s+default\s*/u, "return ");
|
|
127
|
+
try {
|
|
128
|
+
return new Function(body)();
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function extractTopLevelKeysFromCode(code) {
|
|
134
|
+
const obj = parseExportedObject(code);
|
|
135
|
+
if (!obj || typeof obj !== "object") {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
return Object.keys(obj);
|
|
139
|
+
}
|
|
140
|
+
function computeOrdersForTuples(root, tuples = []) {
|
|
141
|
+
const pendingChildrenByContainer = /* @__PURE__ */ new Map();
|
|
142
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
143
|
+
const t = tuples[i];
|
|
144
|
+
if (!Array.isArray(t)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const [action, path] = t;
|
|
148
|
+
const p = normalizePath(path);
|
|
149
|
+
if (!Array.isArray(p) || p.length < 3) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (p[0] === "schema") {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const [typeName, containerKey, childKey] = p;
|
|
156
|
+
const containerPath = [typeName, containerKey];
|
|
157
|
+
const key = JSON.stringify(containerPath);
|
|
158
|
+
if (!pendingChildrenByContainer.has(key)) {
|
|
159
|
+
pendingChildrenByContainer.set(key, /* @__PURE__ */ new Set());
|
|
160
|
+
}
|
|
161
|
+
if (action === "update" || action === "set") {
|
|
162
|
+
pendingChildrenByContainer.get(key).add(childKey);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const preferredOrderMap = /* @__PURE__ */ new Map();
|
|
166
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
167
|
+
const t = tuples[i];
|
|
168
|
+
if (!Array.isArray(t)) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const [action, path, value] = t;
|
|
172
|
+
const p = normalizePath(path);
|
|
173
|
+
if (action !== "update" || !Array.isArray(p) || p.length < 3) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (p[0] !== "schema") {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const [, type, key] = p;
|
|
180
|
+
const containerPath = [type, key];
|
|
181
|
+
const uses = value && Array.isArray(value.uses) ? value.uses : null;
|
|
182
|
+
const code = value && value.code;
|
|
183
|
+
const obj = (() => {
|
|
184
|
+
try {
|
|
185
|
+
return root && typeof root.getByPath === "function" ? root.getByPath(containerPath) : null;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
})();
|
|
190
|
+
if (!obj) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const present = new Set(Object.keys(obj));
|
|
194
|
+
const EXCLUDE_KEYS = /* @__PURE__ */ new Set(["__order"]);
|
|
195
|
+
const codeKeys = extractTopLevelKeysFromCode(code);
|
|
196
|
+
let resolved = [];
|
|
197
|
+
const pendingKey = JSON.stringify(containerPath);
|
|
198
|
+
const pendingChildren = pendingChildrenByContainer.get(pendingKey) || /* @__PURE__ */ new Set();
|
|
199
|
+
const eligible = /* @__PURE__ */ new Set([...present, ...pendingChildren]);
|
|
200
|
+
if (Array.isArray(codeKeys) && codeKeys.length) {
|
|
201
|
+
resolved = codeKeys.filter((k) => eligible.has(k) && !EXCLUDE_KEYS.has(k));
|
|
202
|
+
}
|
|
203
|
+
if (Array.isArray(uses) && uses.length) {
|
|
204
|
+
for (let u = 0; u < uses.length; u++) {
|
|
205
|
+
const keyName = uses[u];
|
|
206
|
+
if (eligible.has(keyName) && !EXCLUDE_KEYS.has(keyName) && !resolved.includes(keyName)) {
|
|
207
|
+
resolved.push(keyName);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (pendingChildren.size) {
|
|
212
|
+
for (const child of pendingChildren) {
|
|
213
|
+
if (!EXCLUDE_KEYS.has(child) && !resolved.includes(child)) {
|
|
214
|
+
resolved.push(child);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (resolved.length) {
|
|
219
|
+
preferredOrderMap.set(JSON.stringify(containerPath), { path: containerPath, keys: resolved });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const parents = getParentPathsFromTuples(tuples);
|
|
223
|
+
const orders = [];
|
|
224
|
+
const seen = /* @__PURE__ */ new Set();
|
|
225
|
+
preferredOrderMap.forEach((v) => {
|
|
226
|
+
const k = JSON.stringify(v.path);
|
|
227
|
+
if (!seen.has(k)) {
|
|
228
|
+
seen.add(k);
|
|
229
|
+
orders.push(v);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const fallbackOrders = computeOrdersFromState(root, parents);
|
|
233
|
+
for (let i = 0; i < fallbackOrders.length; i++) {
|
|
234
|
+
const v = fallbackOrders[i];
|
|
235
|
+
const k = JSON.stringify(v.path);
|
|
236
|
+
if (seen.has(k)) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const pending = pendingChildrenByContainer.get(k);
|
|
240
|
+
if (pending && pending.size) {
|
|
241
|
+
const existing = new Set(v.keys);
|
|
242
|
+
for (const child of pending) {
|
|
243
|
+
if (existing.has(child)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
v.keys.push(child);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
seen.add(k);
|
|
250
|
+
orders.push(v);
|
|
251
|
+
}
|
|
252
|
+
return orders;
|
|
253
|
+
}
|
|
254
|
+
export {
|
|
255
|
+
computeOrdersForTuples,
|
|
256
|
+
computeOrdersFromState,
|
|
257
|
+
getParentPathsFromTuples
|
|
258
|
+
};
|
|
@@ -4,6 +4,8 @@ import { RootStateManager } from "../state/RootStateManager.js";
|
|
|
4
4
|
import { rootBus } from "../state/rootEventBus.js";
|
|
5
5
|
import { validateParams } from "../utils/validation.js";
|
|
6
6
|
import { deepStringifyFunctions } from "@domql/utils";
|
|
7
|
+
import { diffJson } from "../utils/jsonDiff.js";
|
|
8
|
+
import { computeOrdersForTuples } from "../utils/ordering.js";
|
|
7
9
|
class CollabService extends BaseService {
|
|
8
10
|
constructor(config) {
|
|
9
11
|
super(config);
|
|
@@ -103,53 +105,49 @@ class CollabService extends BaseService {
|
|
|
103
105
|
if (this._client) {
|
|
104
106
|
await this.disconnect();
|
|
105
107
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
(_b2 = this._client.socket) == null ? void 0 : _b2.once("connect", resolve);
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
(_b = this._client.socket) == null ? void 0 : _b.on("ops", ({ changes }) => {
|
|
122
|
-
console.log(`ops event`);
|
|
123
|
-
this._stateManager.applyChanges(changes, { fromSocket: true });
|
|
124
|
-
});
|
|
125
|
-
(_c = this._client.socket) == null ? void 0 : _c.on("commit", ({ version }) => {
|
|
126
|
-
if (version) {
|
|
127
|
-
this._stateManager.setVersion(version);
|
|
128
|
-
}
|
|
129
|
-
rootBus.emit("checkpoint:done", { version, origin: "auto" });
|
|
130
|
-
});
|
|
131
|
-
(_d = this._client.socket) == null ? void 0 : _d.on("clients", this._handleClientsEvent.bind(this));
|
|
132
|
-
(_e = this._client.socket) == null ? void 0 : _e.on(
|
|
133
|
-
"bundle:done",
|
|
134
|
-
this._handleBundleDoneEvent.bind(this)
|
|
135
|
-
);
|
|
136
|
-
(_f = this._client.socket) == null ? void 0 : _f.on(
|
|
137
|
-
"bundle:error",
|
|
138
|
-
this._handleBundleErrorEvent.bind(this)
|
|
139
|
-
);
|
|
140
|
-
if (this._pendingOps.length) {
|
|
141
|
-
console.log(
|
|
142
|
-
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
143
|
-
);
|
|
144
|
-
this._pendingOps.forEach(({ tuples }) => {
|
|
145
|
-
this.socket.emit("ops", { changes: tuples, ts: Date.now() });
|
|
146
|
-
});
|
|
147
|
-
this._pendingOps.length = 0;
|
|
108
|
+
this._client = new CollabClient({
|
|
109
|
+
jwt,
|
|
110
|
+
projectId,
|
|
111
|
+
branch,
|
|
112
|
+
live: Boolean(pro)
|
|
113
|
+
});
|
|
114
|
+
await new Promise((resolve) => {
|
|
115
|
+
var _a2, _b2;
|
|
116
|
+
if ((_a2 = this._client.socket) == null ? void 0 : _a2.connected) {
|
|
117
|
+
resolve();
|
|
118
|
+
} else {
|
|
119
|
+
(_b2 = this._client.socket) == null ? void 0 : _b2.once("connect", resolve);
|
|
148
120
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
121
|
+
});
|
|
122
|
+
(_b = this._client.socket) == null ? void 0 : _b.on("ops", ({ changes }) => {
|
|
123
|
+
console.log(`ops event`);
|
|
124
|
+
this._stateManager.applyChanges(changes, { fromSocket: true });
|
|
125
|
+
});
|
|
126
|
+
(_c = this._client.socket) == null ? void 0 : _c.on("commit", ({ version }) => {
|
|
127
|
+
if (version) {
|
|
128
|
+
this._stateManager.setVersion(version);
|
|
129
|
+
}
|
|
130
|
+
rootBus.emit("checkpoint:done", { version, origin: "auto" });
|
|
131
|
+
});
|
|
132
|
+
(_d = this._client.socket) == null ? void 0 : _d.on("clients", this._handleClientsEvent.bind(this));
|
|
133
|
+
(_e = this._client.socket) == null ? void 0 : _e.on(
|
|
134
|
+
"bundle:done",
|
|
135
|
+
this._handleBundleDoneEvent.bind(this)
|
|
136
|
+
);
|
|
137
|
+
(_f = this._client.socket) == null ? void 0 : _f.on(
|
|
138
|
+
"bundle:error",
|
|
139
|
+
this._handleBundleErrorEvent.bind(this)
|
|
140
|
+
);
|
|
141
|
+
if (this._pendingOps.length) {
|
|
142
|
+
console.log(
|
|
143
|
+
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
144
|
+
);
|
|
145
|
+
this._pendingOps.forEach(({ changes, orders }) => {
|
|
146
|
+
this.socket.emit("ops", { changes, orders, ts: Date.now() });
|
|
147
|
+
});
|
|
148
|
+
this._pendingOps.length = 0;
|
|
152
149
|
}
|
|
150
|
+
this._connected = true;
|
|
153
151
|
}
|
|
154
152
|
disconnect() {
|
|
155
153
|
var _a;
|
|
@@ -187,24 +185,128 @@ class CollabService extends BaseService {
|
|
|
187
185
|
}
|
|
188
186
|
/* ---------- data helpers ---------- */
|
|
189
187
|
updateData(tuples, options = {}) {
|
|
190
|
-
var _a;
|
|
188
|
+
var _a, _b;
|
|
191
189
|
this._ensureStateManager();
|
|
192
190
|
const { isUndo = false, isRedo = false } = options;
|
|
193
191
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
194
192
|
this._trackForUndo(tuples, options);
|
|
195
193
|
}
|
|
194
|
+
const processedTuples = (() => {
|
|
195
|
+
var _a2;
|
|
196
|
+
try {
|
|
197
|
+
const root = (_a2 = this._stateManager) == null ? void 0 : _a2.root;
|
|
198
|
+
const isPlainObject = (o) => o && typeof o === "object" && !Array.isArray(o);
|
|
199
|
+
const getByPath = (state2, path) => {
|
|
200
|
+
if (!state2 || typeof state2.getByPath !== "function") {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
return state2.getByPath(path);
|
|
205
|
+
} catch {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
const expandTuple = (t) => {
|
|
210
|
+
const [action, path, value] = t || [];
|
|
211
|
+
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
212
|
+
if (action === "delete" || isSchemaPath) {
|
|
213
|
+
return [t];
|
|
214
|
+
}
|
|
215
|
+
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2) && isPlainObject(value);
|
|
216
|
+
if (!canConsiderExpansion) {
|
|
217
|
+
return [t];
|
|
218
|
+
}
|
|
219
|
+
const prev = getByPath(root, path) || {};
|
|
220
|
+
const next = value || {};
|
|
221
|
+
if (!isPlainObject(prev) || !isPlainObject(next)) {
|
|
222
|
+
return [t];
|
|
223
|
+
}
|
|
224
|
+
const ops = diffJson(prev, next, []);
|
|
225
|
+
if (!ops.length) {
|
|
226
|
+
return [];
|
|
227
|
+
}
|
|
228
|
+
const arr = [];
|
|
229
|
+
for (let j = 0; j < ops.length; j++) {
|
|
230
|
+
const op = ops[j];
|
|
231
|
+
const fullPath = [...path, ...op.path];
|
|
232
|
+
const last = fullPath[fullPath.length - 1];
|
|
233
|
+
if (op.action === "set") {
|
|
234
|
+
arr.push(["update", fullPath, op.value]);
|
|
235
|
+
} else if (op.action === "del") {
|
|
236
|
+
if (last !== "__order") {
|
|
237
|
+
arr.push(["delete", fullPath]);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return arr;
|
|
242
|
+
};
|
|
243
|
+
const minimizeTuples = (inputTuples) => {
|
|
244
|
+
const out = [];
|
|
245
|
+
for (let i = 0; i < inputTuples.length; i++) {
|
|
246
|
+
const expanded = expandTuple(inputTuples[i]);
|
|
247
|
+
for (let k = 0; k < expanded.length; k++) {
|
|
248
|
+
const tuple = expanded[k];
|
|
249
|
+
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
250
|
+
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
251
|
+
if (!isOrderKey) {
|
|
252
|
+
out.push(tuple);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
console.log(`Minimized tuples`, out);
|
|
257
|
+
return out;
|
|
258
|
+
};
|
|
259
|
+
console.log(`Processing tuples`, tuples);
|
|
260
|
+
return minimizeTuples(tuples);
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.warn(
|
|
263
|
+
"[CollabService] Minimal diff expansion failed \u2013 using original tuples",
|
|
264
|
+
err
|
|
265
|
+
);
|
|
266
|
+
return tuples;
|
|
267
|
+
}
|
|
268
|
+
})();
|
|
196
269
|
if (options.append && options.append.length) {
|
|
197
|
-
|
|
270
|
+
processedTuples.push(...options.append);
|
|
198
271
|
}
|
|
199
272
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
200
|
-
|
|
273
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
274
|
+
const el = state == null ? void 0 : state.__element;
|
|
275
|
+
const orders = computeOrdersForTuples(state, processedTuples);
|
|
276
|
+
const stringifiedGranularTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
277
|
+
"deepStringifyFunctions",
|
|
278
|
+
processedTuples,
|
|
279
|
+
Array.isArray(processedTuples) ? [] : {}
|
|
280
|
+
) : deepStringifyFunctions(
|
|
281
|
+
processedTuples,
|
|
282
|
+
Array.isArray(processedTuples) ? [] : {}
|
|
283
|
+
);
|
|
284
|
+
const stringifiedTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
285
|
+
"deepStringifyFunctions",
|
|
286
|
+
tuples,
|
|
287
|
+
Array.isArray(tuples) ? [] : {}
|
|
288
|
+
) : deepStringifyFunctions(
|
|
289
|
+
tuples,
|
|
290
|
+
Array.isArray(tuples) ? [] : {}
|
|
291
|
+
);
|
|
201
292
|
if (!this.isConnected()) {
|
|
202
293
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
203
|
-
this._pendingOps.push({
|
|
294
|
+
this._pendingOps.push({ changes: stringifiedTuples, granularChanges: stringifiedGranularTuples, orders, options });
|
|
204
295
|
return;
|
|
205
296
|
}
|
|
206
|
-
if ((
|
|
207
|
-
|
|
297
|
+
if ((_b = this.socket) == null ? void 0 : _b.connected) {
|
|
298
|
+
console.log("[CollabService] Sending operations to the backend", {
|
|
299
|
+
changes: stringifiedTuples,
|
|
300
|
+
granularChanges: stringifiedGranularTuples,
|
|
301
|
+
orders,
|
|
302
|
+
ts: Date.now()
|
|
303
|
+
});
|
|
304
|
+
this.socket.emit("ops", {
|
|
305
|
+
changes: stringifiedTuples,
|
|
306
|
+
granularChanges: stringifiedGranularTuples,
|
|
307
|
+
orders,
|
|
308
|
+
ts: Date.now()
|
|
309
|
+
});
|
|
208
310
|
}
|
|
209
311
|
return { success: true };
|
|
210
312
|
}
|