@symbo.ls/sdk 2.31.37 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/services/CollabService.js +104 -8
- package/dist/cjs/services/ProjectService.js +5 -1
- package/dist/cjs/utils/ordering.js +295 -0
- package/dist/esm/index.js +474 -77
- package/dist/esm/services/CollabService.js +470 -76
- package/dist/esm/services/ProjectService.js +277 -1
- package/dist/esm/services/index.js +474 -77
- package/dist/esm/utils/CollabClient.js +93 -68
- package/dist/esm/utils/ordering.js +277 -0
- package/dist/node/services/CollabService.js +104 -8
- package/dist/node/services/ProjectService.js +5 -1
- package/dist/node/utils/ordering.js +276 -0
- package/package.json +6 -6
- package/src/services/CollabService.js +128 -6
- package/src/services/ProjectService.js +7 -1
- package/src/utils/ordering.js +240 -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,277 @@
|
|
|
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 extractTopLevelKeysFromCode(code) {
|
|
122
|
+
const src = normaliseSchemaCode(code);
|
|
123
|
+
if (!src) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const idx = src.indexOf("export default");
|
|
127
|
+
if (idx === -1) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
let i = src.indexOf("{", idx);
|
|
131
|
+
if (i === -1) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
const keys = [];
|
|
135
|
+
let depth = 0;
|
|
136
|
+
let inStr = false;
|
|
137
|
+
let strCh = "";
|
|
138
|
+
let inEsc = false;
|
|
139
|
+
for (; i < src.length; i++) {
|
|
140
|
+
const ch = src[i];
|
|
141
|
+
if (inStr) {
|
|
142
|
+
if (inEsc) {
|
|
143
|
+
inEsc = false;
|
|
144
|
+
} else if (ch === "\\") {
|
|
145
|
+
inEsc = true;
|
|
146
|
+
} else if (ch === strCh) {
|
|
147
|
+
inStr = false;
|
|
148
|
+
strCh = "";
|
|
149
|
+
}
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
153
|
+
inStr = true;
|
|
154
|
+
strCh = ch;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (ch === "{") {
|
|
158
|
+
depth++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (ch === "}") {
|
|
162
|
+
depth--;
|
|
163
|
+
if (depth === 0) {
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (depth !== 1) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (/[A-Za-z_$]/u.test(ch)) {
|
|
172
|
+
let j = i;
|
|
173
|
+
while (j < src.length && /[A-Za-z0-9_$]/u.test(src[j])) {
|
|
174
|
+
j++;
|
|
175
|
+
}
|
|
176
|
+
let k = j;
|
|
177
|
+
while (k < src.length && /\s/u.test(src[k])) {
|
|
178
|
+
k++;
|
|
179
|
+
}
|
|
180
|
+
if (src[k] === ":") {
|
|
181
|
+
const key = src.slice(i, j);
|
|
182
|
+
keys.push(key);
|
|
183
|
+
}
|
|
184
|
+
i = j;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!keys.length) {
|
|
189
|
+
const bodyStart = src.indexOf("{", idx);
|
|
190
|
+
const bodyEnd = src.lastIndexOf("}");
|
|
191
|
+
if (bodyStart === -1 || bodyEnd === -1 || bodyEnd <= bodyStart) {
|
|
192
|
+
return Array.from(new Set(keys));
|
|
193
|
+
}
|
|
194
|
+
const body = src.slice(bodyStart + 1, bodyEnd);
|
|
195
|
+
const re = /(?:[A-Za-z_$][A-Za-z0-9_$]*|"[^"]+"|'[^']+')\s*:/gu;
|
|
196
|
+
for (const m of body.matchAll(re)) {
|
|
197
|
+
const raw = m[0].split(":")[0].trim();
|
|
198
|
+
const key = raw[0] === '"' || raw[0] === "'" ? raw.slice(1, -1) : raw;
|
|
199
|
+
keys.push(key);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return Array.from(new Set(keys));
|
|
203
|
+
}
|
|
204
|
+
function computeOrdersForTuples(root, tuples = []) {
|
|
205
|
+
const preferredOrderMap = /* @__PURE__ */ new Map();
|
|
206
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
207
|
+
const t = tuples[i];
|
|
208
|
+
if (!Array.isArray(t)) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const [action, path, value] = t;
|
|
212
|
+
const p = normalizePath(path);
|
|
213
|
+
if (action !== "update" || !Array.isArray(p) || p.length < 3) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (p[0] !== "schema") {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const [, type, key] = p;
|
|
220
|
+
const containerPath = [type, key];
|
|
221
|
+
const uses = value && Array.isArray(value.uses) ? value.uses : null;
|
|
222
|
+
const code = value && value.code;
|
|
223
|
+
const obj = (() => {
|
|
224
|
+
try {
|
|
225
|
+
return root && typeof root.getByPath === "function" ? root.getByPath(containerPath) : null;
|
|
226
|
+
} catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
})();
|
|
230
|
+
if (!obj) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const present = new Set(Object.keys(obj));
|
|
234
|
+
const EXCLUDE_KEYS = /* @__PURE__ */ new Set(["__order"]);
|
|
235
|
+
const codeKeys = extractTopLevelKeysFromCode(code);
|
|
236
|
+
let resolved = [];
|
|
237
|
+
if (Array.isArray(codeKeys) && codeKeys.length) {
|
|
238
|
+
resolved = codeKeys.filter((k) => present.has(k) && !EXCLUDE_KEYS.has(k));
|
|
239
|
+
}
|
|
240
|
+
if (resolved.length && Array.isArray(uses) && uses.length) {
|
|
241
|
+
for (let u = 0; u < uses.length; u++) {
|
|
242
|
+
const keyName = uses[u];
|
|
243
|
+
if (present.has(keyName) && !EXCLUDE_KEYS.has(keyName) && !resolved.includes(keyName)) {
|
|
244
|
+
resolved.push(keyName);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (resolved.length) {
|
|
249
|
+
preferredOrderMap.set(JSON.stringify(containerPath), { path: containerPath, keys: resolved });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const parents = getParentPathsFromTuples(tuples);
|
|
253
|
+
const orders = [];
|
|
254
|
+
const seen = /* @__PURE__ */ new Set();
|
|
255
|
+
preferredOrderMap.forEach((v) => {
|
|
256
|
+
const k = JSON.stringify(v.path);
|
|
257
|
+
if (!seen.has(k)) {
|
|
258
|
+
seen.add(k);
|
|
259
|
+
orders.push(v);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const fallbackOrders = computeOrdersFromState(root, parents);
|
|
263
|
+
for (let i = 0; i < fallbackOrders.length; i++) {
|
|
264
|
+
const v = fallbackOrders[i];
|
|
265
|
+
const k = JSON.stringify(v.path);
|
|
266
|
+
if (!seen.has(k)) {
|
|
267
|
+
seen.add(k);
|
|
268
|
+
orders.push(v);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return orders;
|
|
272
|
+
}
|
|
273
|
+
export {
|
|
274
|
+
computeOrdersForTuples,
|
|
275
|
+
computeOrdersFromState,
|
|
276
|
+
getParentPathsFromTuples
|
|
277
|
+
};
|
|
@@ -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);
|
|
@@ -141,8 +143,8 @@ class CollabService extends BaseService {
|
|
|
141
143
|
console.log(
|
|
142
144
|
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
143
145
|
);
|
|
144
|
-
this._pendingOps.forEach(({
|
|
145
|
-
this.socket.emit("ops", { changes
|
|
146
|
+
this._pendingOps.forEach(({ changes, orders }) => {
|
|
147
|
+
this.socket.emit("ops", { changes, orders, ts: Date.now() });
|
|
146
148
|
});
|
|
147
149
|
this._pendingOps.length = 0;
|
|
148
150
|
}
|
|
@@ -187,24 +189,118 @@ class CollabService extends BaseService {
|
|
|
187
189
|
}
|
|
188
190
|
/* ---------- data helpers ---------- */
|
|
189
191
|
updateData(tuples, options = {}) {
|
|
190
|
-
var _a;
|
|
192
|
+
var _a, _b;
|
|
191
193
|
this._ensureStateManager();
|
|
192
194
|
const { isUndo = false, isRedo = false } = options;
|
|
193
195
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
194
196
|
this._trackForUndo(tuples, options);
|
|
195
197
|
}
|
|
198
|
+
const processedTuples = (() => {
|
|
199
|
+
var _a2;
|
|
200
|
+
try {
|
|
201
|
+
const root = (_a2 = this._stateManager) == null ? void 0 : _a2.root;
|
|
202
|
+
const isPlainObject = (o) => o && typeof o === "object" && !Array.isArray(o);
|
|
203
|
+
const getByPath = (state2, path) => {
|
|
204
|
+
if (!state2 || typeof state2.getByPath !== "function") {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
return state2.getByPath(path);
|
|
209
|
+
} catch {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const expandTuple = (t) => {
|
|
214
|
+
const [action, path, value] = t || [];
|
|
215
|
+
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
216
|
+
if (action === "delete" || isSchemaPath) {
|
|
217
|
+
return [t];
|
|
218
|
+
}
|
|
219
|
+
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2) && isPlainObject(value);
|
|
220
|
+
if (!canConsiderExpansion) {
|
|
221
|
+
return [t];
|
|
222
|
+
}
|
|
223
|
+
const prev = getByPath(root, path) || {};
|
|
224
|
+
const next = value || {};
|
|
225
|
+
if (!isPlainObject(prev) || !isPlainObject(next)) {
|
|
226
|
+
return [t];
|
|
227
|
+
}
|
|
228
|
+
const ops = diffJson(prev, next, []);
|
|
229
|
+
if (!ops.length) {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
const arr = [];
|
|
233
|
+
for (let j = 0; j < ops.length; j++) {
|
|
234
|
+
const op = ops[j];
|
|
235
|
+
const fullPath = [...path, ...op.path];
|
|
236
|
+
const last = fullPath[fullPath.length - 1];
|
|
237
|
+
if (op.action === "set") {
|
|
238
|
+
arr.push(["update", fullPath, op.value]);
|
|
239
|
+
} else if (op.action === "del") {
|
|
240
|
+
if (last !== "__order") {
|
|
241
|
+
arr.push(["delete", fullPath]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return arr;
|
|
246
|
+
};
|
|
247
|
+
const minimizeTuples = (inputTuples) => {
|
|
248
|
+
const out = [];
|
|
249
|
+
for (let i = 0; i < inputTuples.length; i++) {
|
|
250
|
+
const expanded = expandTuple(inputTuples[i]);
|
|
251
|
+
for (let k = 0; k < expanded.length; k++) {
|
|
252
|
+
const tuple = expanded[k];
|
|
253
|
+
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
254
|
+
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
255
|
+
if (!isOrderKey) {
|
|
256
|
+
out.push(tuple);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
console.log(`Minimized tuples`, out);
|
|
261
|
+
return out;
|
|
262
|
+
};
|
|
263
|
+
console.log(`Processing tuples`, tuples);
|
|
264
|
+
return minimizeTuples(tuples);
|
|
265
|
+
} catch (err) {
|
|
266
|
+
console.warn(
|
|
267
|
+
"[CollabService] Minimal diff expansion failed \u2013 using original tuples",
|
|
268
|
+
err
|
|
269
|
+
);
|
|
270
|
+
return tuples;
|
|
271
|
+
}
|
|
272
|
+
})();
|
|
196
273
|
if (options.append && options.append.length) {
|
|
197
|
-
|
|
274
|
+
processedTuples.push(...options.append);
|
|
198
275
|
}
|
|
199
276
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
200
|
-
|
|
277
|
+
const state = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
278
|
+
const el = state == null ? void 0 : state.__element;
|
|
279
|
+
const orders = computeOrdersForTuples(state, processedTuples);
|
|
280
|
+
const stringifiedTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
281
|
+
"deepStringifyFunctions",
|
|
282
|
+
processedTuples,
|
|
283
|
+
Array.isArray(processedTuples) ? [] : {}
|
|
284
|
+
) : deepStringifyFunctions(
|
|
285
|
+
processedTuples,
|
|
286
|
+
Array.isArray(processedTuples) ? [] : {}
|
|
287
|
+
);
|
|
201
288
|
if (!this.isConnected()) {
|
|
202
289
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
203
|
-
this._pendingOps.push({
|
|
290
|
+
this._pendingOps.push({ changes: stringifiedTuples, orders, options });
|
|
204
291
|
return;
|
|
205
292
|
}
|
|
206
|
-
if ((
|
|
207
|
-
|
|
293
|
+
if ((_b = this.socket) == null ? void 0 : _b.connected) {
|
|
294
|
+
console.log("[CollabService] Sending operations to the backend", {
|
|
295
|
+
changes: stringifiedTuples,
|
|
296
|
+
orders,
|
|
297
|
+
ts: Date.now()
|
|
298
|
+
});
|
|
299
|
+
this.socket.emit("ops", {
|
|
300
|
+
changes: stringifiedTuples,
|
|
301
|
+
orders,
|
|
302
|
+
ts: Date.now()
|
|
303
|
+
});
|
|
208
304
|
}
|
|
209
305
|
return { success: true };
|
|
210
306
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseService } from "./BaseService.js";
|
|
2
|
+
import { computeOrdersForTuples } from "../utils/ordering.js";
|
|
2
3
|
class ProjectService extends BaseService {
|
|
3
4
|
// ==================== PROJECT METHODS ====================
|
|
4
5
|
async createProject(projectData) {
|
|
@@ -530,6 +531,8 @@ class ProjectService extends BaseService {
|
|
|
530
531
|
throw new Error("Changes must be an array");
|
|
531
532
|
}
|
|
532
533
|
const { message, branch = "main", type = "patch" } = options;
|
|
534
|
+
const state = this._context && this._context.state;
|
|
535
|
+
const derivedOrders = options.orders || (state ? computeOrdersForTuples(state, changes) : []);
|
|
533
536
|
try {
|
|
534
537
|
const response = await this._request(`/projects/${projectId}/changes`, {
|
|
535
538
|
method: "POST",
|
|
@@ -537,7 +540,8 @@ class ProjectService extends BaseService {
|
|
|
537
540
|
changes,
|
|
538
541
|
message,
|
|
539
542
|
branch,
|
|
540
|
-
type
|
|
543
|
+
type,
|
|
544
|
+
...derivedOrders && derivedOrders.length ? { orders: derivedOrders } : {}
|
|
541
545
|
}),
|
|
542
546
|
methodName: "applyProjectChanges"
|
|
543
547
|
});
|