@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
package/dist/esm/index.js
CHANGED
|
@@ -21885,12 +21885,54 @@ function isPlainObject(o) {
|
|
|
21885
21885
|
return o && typeof o === "object" && !Array.isArray(o);
|
|
21886
21886
|
}
|
|
21887
21887
|
function deepEqual(a, b) {
|
|
21888
|
-
|
|
21889
|
-
return
|
|
21890
|
-
}
|
|
21891
|
-
|
|
21888
|
+
if (Object.is(a, b)) {
|
|
21889
|
+
return true;
|
|
21890
|
+
}
|
|
21891
|
+
if (typeof a === "function" && typeof b === "function") {
|
|
21892
|
+
try {
|
|
21893
|
+
return a.toString() === b.toString();
|
|
21894
|
+
} catch {
|
|
21895
|
+
return false;
|
|
21896
|
+
}
|
|
21897
|
+
}
|
|
21898
|
+
if (typeof a === "function" || typeof b === "function") {
|
|
21892
21899
|
return false;
|
|
21893
21900
|
}
|
|
21901
|
+
if (a instanceof Date && b instanceof Date) {
|
|
21902
|
+
return a.getTime() === b.getTime();
|
|
21903
|
+
}
|
|
21904
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
21905
|
+
return String(a) === String(b);
|
|
21906
|
+
}
|
|
21907
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
21908
|
+
if (a.length !== b.length) {
|
|
21909
|
+
return false;
|
|
21910
|
+
}
|
|
21911
|
+
for (let i = 0; i < a.length; i++) {
|
|
21912
|
+
if (!deepEqual(a[i], b[i])) {
|
|
21913
|
+
return false;
|
|
21914
|
+
}
|
|
21915
|
+
}
|
|
21916
|
+
return true;
|
|
21917
|
+
}
|
|
21918
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
21919
|
+
const aKeys = Object.keys(a);
|
|
21920
|
+
const bKeys = Object.keys(b);
|
|
21921
|
+
if (aKeys.length !== bKeys.length) {
|
|
21922
|
+
return false;
|
|
21923
|
+
}
|
|
21924
|
+
for (let i = 0; i < aKeys.length; i++) {
|
|
21925
|
+
const key = aKeys[i];
|
|
21926
|
+
if (!Object.hasOwn(b, key)) {
|
|
21927
|
+
return false;
|
|
21928
|
+
}
|
|
21929
|
+
if (!deepEqual(a[key], b[key])) {
|
|
21930
|
+
return false;
|
|
21931
|
+
}
|
|
21932
|
+
}
|
|
21933
|
+
return true;
|
|
21934
|
+
}
|
|
21935
|
+
return false;
|
|
21894
21936
|
}
|
|
21895
21937
|
function getRootMap(ydoc) {
|
|
21896
21938
|
return ydoc.getMap("root");
|
|
@@ -28297,14 +28339,12 @@ function getParentPathsFromTuples(tuples = []) {
|
|
|
28297
28339
|
"attr",
|
|
28298
28340
|
"state",
|
|
28299
28341
|
"scope",
|
|
28300
|
-
"props",
|
|
28301
28342
|
"define",
|
|
28302
28343
|
"on",
|
|
28303
28344
|
"extend",
|
|
28304
28345
|
"extends",
|
|
28305
28346
|
"childExtend",
|
|
28306
28347
|
"childExtends",
|
|
28307
|
-
"childProps",
|
|
28308
28348
|
"children",
|
|
28309
28349
|
"component",
|
|
28310
28350
|
"context",
|
|
@@ -28525,6 +28565,118 @@ function computeOrdersForTuples(root, tuples = []) {
|
|
|
28525
28565
|
return orders;
|
|
28526
28566
|
}
|
|
28527
28567
|
|
|
28568
|
+
// src/utils/changePreprocessor.js
|
|
28569
|
+
function isPlainObject2(val) {
|
|
28570
|
+
return val && typeof val === "object" && !Array.isArray(val);
|
|
28571
|
+
}
|
|
28572
|
+
function getByPathSafe(root, path) {
|
|
28573
|
+
if (!root || typeof root.getByPath !== "function") {
|
|
28574
|
+
return null;
|
|
28575
|
+
}
|
|
28576
|
+
try {
|
|
28577
|
+
return root.getByPath(path);
|
|
28578
|
+
} catch {
|
|
28579
|
+
return null;
|
|
28580
|
+
}
|
|
28581
|
+
}
|
|
28582
|
+
function preprocessChanges(root, tuples = [], options = {}) {
|
|
28583
|
+
const expandTuple = (t) => {
|
|
28584
|
+
const [action, path, value2] = t || [];
|
|
28585
|
+
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
28586
|
+
if (action === "delete") {
|
|
28587
|
+
return [t];
|
|
28588
|
+
}
|
|
28589
|
+
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2 || isSchemaPath && path.length === 3) && isPlainObject2(value2);
|
|
28590
|
+
if (!canConsiderExpansion) {
|
|
28591
|
+
return [t];
|
|
28592
|
+
}
|
|
28593
|
+
const prev = getByPathSafe(root, path) || {};
|
|
28594
|
+
const next = value2 || {};
|
|
28595
|
+
if (!isPlainObject2(prev) || !isPlainObject2(next)) {
|
|
28596
|
+
return [t];
|
|
28597
|
+
}
|
|
28598
|
+
const ops = diffJson(prev, next, []);
|
|
28599
|
+
if (!ops.length) {
|
|
28600
|
+
return [t];
|
|
28601
|
+
}
|
|
28602
|
+
const out = [];
|
|
28603
|
+
for (let i = 0; i < ops.length; i++) {
|
|
28604
|
+
const op = ops[i];
|
|
28605
|
+
const fullPath = [...path, ...op.path];
|
|
28606
|
+
const last2 = fullPath[fullPath.length - 1];
|
|
28607
|
+
if (op.action === "set") {
|
|
28608
|
+
out.push(["update", fullPath, op.value]);
|
|
28609
|
+
} else if (op.action === "del") {
|
|
28610
|
+
if (last2 !== "__order") {
|
|
28611
|
+
out.push(["delete", fullPath]);
|
|
28612
|
+
}
|
|
28613
|
+
}
|
|
28614
|
+
}
|
|
28615
|
+
return out;
|
|
28616
|
+
};
|
|
28617
|
+
const minimizeTuples = (input) => {
|
|
28618
|
+
const out = [];
|
|
28619
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
28620
|
+
for (let i = 0; i < input.length; i++) {
|
|
28621
|
+
const expanded = expandTuple(input[i]);
|
|
28622
|
+
for (let k = 0; k < expanded.length; k++) {
|
|
28623
|
+
const tuple = expanded[k];
|
|
28624
|
+
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
28625
|
+
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
28626
|
+
if (!isOrderKey) {
|
|
28627
|
+
const key = JSON.stringify(tuple);
|
|
28628
|
+
if (!seen2.has(key)) {
|
|
28629
|
+
seen2.add(key);
|
|
28630
|
+
out.push(tuple);
|
|
28631
|
+
}
|
|
28632
|
+
}
|
|
28633
|
+
}
|
|
28634
|
+
}
|
|
28635
|
+
return out;
|
|
28636
|
+
};
|
|
28637
|
+
const granularChanges = (() => {
|
|
28638
|
+
try {
|
|
28639
|
+
const res = minimizeTuples(tuples);
|
|
28640
|
+
if (options.append && options.append.length) {
|
|
28641
|
+
res.push(...options.append);
|
|
28642
|
+
}
|
|
28643
|
+
return res;
|
|
28644
|
+
} catch {
|
|
28645
|
+
return Array.isArray(tuples) ? tuples.slice() : [];
|
|
28646
|
+
}
|
|
28647
|
+
})();
|
|
28648
|
+
const baseOrders = computeOrdersForTuples(root, granularChanges);
|
|
28649
|
+
const preferOrdersMap = /* @__PURE__ */ new Map();
|
|
28650
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
28651
|
+
const t = tuples[i];
|
|
28652
|
+
if (!Array.isArray(t) || t.length < 3) {
|
|
28653
|
+
continue;
|
|
28654
|
+
}
|
|
28655
|
+
const [action, path, value2] = t;
|
|
28656
|
+
if (action !== "update" || !Array.isArray(path) || path.length !== 1 && path.length !== 2 || !isPlainObject2(value2)) {
|
|
28657
|
+
continue;
|
|
28658
|
+
}
|
|
28659
|
+
const keys2 = Object.keys(value2).filter((k) => k !== "__order");
|
|
28660
|
+
const key = JSON.stringify(path);
|
|
28661
|
+
preferOrdersMap.set(key, { path, keys: keys2 });
|
|
28662
|
+
}
|
|
28663
|
+
const mergedOrders = [];
|
|
28664
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28665
|
+
preferOrdersMap.forEach((v, k) => {
|
|
28666
|
+
seen.add(k);
|
|
28667
|
+
mergedOrders.push(v);
|
|
28668
|
+
});
|
|
28669
|
+
for (let i = 0; i < baseOrders.length; i++) {
|
|
28670
|
+
const v = baseOrders[i];
|
|
28671
|
+
const k = JSON.stringify(v.path);
|
|
28672
|
+
if (!seen.has(k)) {
|
|
28673
|
+
seen.add(k);
|
|
28674
|
+
mergedOrders.push(v);
|
|
28675
|
+
}
|
|
28676
|
+
}
|
|
28677
|
+
return { granularChanges, orders: mergedOrders };
|
|
28678
|
+
}
|
|
28679
|
+
|
|
28528
28680
|
// src/services/CollabService.js
|
|
28529
28681
|
var CollabService = class extends BaseService {
|
|
28530
28682
|
constructor(config) {
|
|
@@ -28662,8 +28814,8 @@ var CollabService = class extends BaseService {
|
|
|
28662
28814
|
console.log(
|
|
28663
28815
|
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
28664
28816
|
);
|
|
28665
|
-
this._pendingOps.forEach(({ changes, orders }) => {
|
|
28666
|
-
this.socket.emit("ops", { changes, orders, ts: Date.now() });
|
|
28817
|
+
this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
|
|
28818
|
+
this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
|
|
28667
28819
|
});
|
|
28668
28820
|
this._pendingOps.length = 0;
|
|
28669
28821
|
}
|
|
@@ -28705,94 +28857,24 @@ var CollabService = class extends BaseService {
|
|
|
28705
28857
|
}
|
|
28706
28858
|
/* ---------- data helpers ---------- */
|
|
28707
28859
|
updateData(tuples, options = {}) {
|
|
28708
|
-
var _a, _b;
|
|
28860
|
+
var _a, _b, _c;
|
|
28709
28861
|
this._ensureStateManager();
|
|
28710
28862
|
const { isUndo = false, isRedo = false } = options;
|
|
28711
28863
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
28712
28864
|
this._trackForUndo(tuples, options);
|
|
28713
28865
|
}
|
|
28714
|
-
const
|
|
28715
|
-
|
|
28716
|
-
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
if (!state2 || typeof state2.getByPath !== "function") {
|
|
28721
|
-
return null;
|
|
28722
|
-
}
|
|
28723
|
-
try {
|
|
28724
|
-
return state2.getByPath(path);
|
|
28725
|
-
} catch {
|
|
28726
|
-
return null;
|
|
28727
|
-
}
|
|
28728
|
-
};
|
|
28729
|
-
const expandTuple = (t) => {
|
|
28730
|
-
const [action, path, value2] = t || [];
|
|
28731
|
-
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
28732
|
-
if (action === "delete" || isSchemaPath) {
|
|
28733
|
-
return [t];
|
|
28734
|
-
}
|
|
28735
|
-
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2) && isPlainObject2(value2);
|
|
28736
|
-
if (!canConsiderExpansion) {
|
|
28737
|
-
return [t];
|
|
28738
|
-
}
|
|
28739
|
-
const prev = getByPath(root, path) || {};
|
|
28740
|
-
const next = value2 || {};
|
|
28741
|
-
if (!isPlainObject2(prev) || !isPlainObject2(next)) {
|
|
28742
|
-
return [t];
|
|
28743
|
-
}
|
|
28744
|
-
const ops = diffJson(prev, next, []);
|
|
28745
|
-
if (!ops.length) {
|
|
28746
|
-
return [];
|
|
28747
|
-
}
|
|
28748
|
-
const arr = [];
|
|
28749
|
-
for (let j = 0; j < ops.length; j++) {
|
|
28750
|
-
const op = ops[j];
|
|
28751
|
-
const fullPath = [...path, ...op.path];
|
|
28752
|
-
const last2 = fullPath[fullPath.length - 1];
|
|
28753
|
-
if (op.action === "set") {
|
|
28754
|
-
arr.push(["update", fullPath, op.value]);
|
|
28755
|
-
} else if (op.action === "del") {
|
|
28756
|
-
if (last2 !== "__order") {
|
|
28757
|
-
arr.push(["delete", fullPath]);
|
|
28758
|
-
}
|
|
28759
|
-
}
|
|
28760
|
-
}
|
|
28761
|
-
return arr;
|
|
28762
|
-
};
|
|
28763
|
-
const minimizeTuples = (inputTuples) => {
|
|
28764
|
-
const out = [];
|
|
28765
|
-
for (let i = 0; i < inputTuples.length; i++) {
|
|
28766
|
-
const expanded = expandTuple(inputTuples[i]);
|
|
28767
|
-
for (let k = 0; k < expanded.length; k++) {
|
|
28768
|
-
const tuple = expanded[k];
|
|
28769
|
-
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
28770
|
-
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
28771
|
-
if (!isOrderKey) {
|
|
28772
|
-
out.push(tuple);
|
|
28773
|
-
}
|
|
28774
|
-
}
|
|
28775
|
-
}
|
|
28776
|
-
console.log(`Minimized tuples`, out);
|
|
28777
|
-
return out;
|
|
28778
|
-
};
|
|
28779
|
-
console.log(`Processing tuples`, tuples);
|
|
28780
|
-
return minimizeTuples(tuples);
|
|
28781
|
-
} catch (err) {
|
|
28782
|
-
console.warn(
|
|
28783
|
-
"[CollabService] Minimal diff expansion failed \u2013 using original tuples",
|
|
28784
|
-
err
|
|
28785
|
-
);
|
|
28786
|
-
return tuples;
|
|
28787
|
-
}
|
|
28788
|
-
})();
|
|
28866
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
28867
|
+
const { granularChanges: processedTuples, orders } = preprocessChanges(
|
|
28868
|
+
root,
|
|
28869
|
+
tuples,
|
|
28870
|
+
options
|
|
28871
|
+
);
|
|
28789
28872
|
if (options.append && options.append.length) {
|
|
28790
28873
|
processedTuples.push(...options.append);
|
|
28791
28874
|
}
|
|
28792
28875
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
28793
|
-
const state = (
|
|
28876
|
+
const state = (_b = this._stateManager) == null ? void 0 : _b.root;
|
|
28794
28877
|
const el = state == null ? void 0 : state.__element;
|
|
28795
|
-
const orders = computeOrdersForTuples(state, processedTuples);
|
|
28796
28878
|
const stringifiedGranularTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
28797
28879
|
"deepStringifyFunctions",
|
|
28798
28880
|
processedTuples,
|
|
@@ -28805,16 +28887,18 @@ var CollabService = class extends BaseService {
|
|
|
28805
28887
|
"deepStringifyFunctions",
|
|
28806
28888
|
tuples,
|
|
28807
28889
|
Array.isArray(tuples) ? [] : {}
|
|
28808
|
-
) : deepStringifyFunctions(
|
|
28809
|
-
tuples,
|
|
28810
|
-
Array.isArray(tuples) ? [] : {}
|
|
28811
|
-
);
|
|
28890
|
+
) : deepStringifyFunctions(tuples, Array.isArray(tuples) ? [] : {});
|
|
28812
28891
|
if (!this.isConnected()) {
|
|
28813
28892
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
28814
|
-
this._pendingOps.push({
|
|
28893
|
+
this._pendingOps.push({
|
|
28894
|
+
changes: stringifiedTuples,
|
|
28895
|
+
granularChanges: stringifiedGranularTuples,
|
|
28896
|
+
orders,
|
|
28897
|
+
options
|
|
28898
|
+
});
|
|
28815
28899
|
return;
|
|
28816
28900
|
}
|
|
28817
|
-
if ((
|
|
28901
|
+
if ((_c = this.socket) == null ? void 0 : _c.connected) {
|
|
28818
28902
|
console.log("[CollabService] Sending operations to the backend", {
|
|
28819
28903
|
changes: stringifiedTuples,
|
|
28820
28904
|
granularChanges: stringifiedGranularTuples,
|
|
@@ -29140,6 +29224,7 @@ var CollabService = class extends BaseService {
|
|
|
29140
29224
|
};
|
|
29141
29225
|
|
|
29142
29226
|
// src/services/ProjectService.js
|
|
29227
|
+
import { deepStringifyFunctions as deepStringifyFunctions2 } from "@domql/utils";
|
|
29143
29228
|
var ProjectService = class extends BaseService {
|
|
29144
29229
|
// ==================== PROJECT METHODS ====================
|
|
29145
29230
|
async createProject(projectData) {
|
|
@@ -29672,12 +29757,15 @@ var ProjectService = class extends BaseService {
|
|
|
29672
29757
|
}
|
|
29673
29758
|
const { message, branch = "main", type = "patch" } = options;
|
|
29674
29759
|
const state = this._context && this._context.state;
|
|
29675
|
-
const
|
|
29760
|
+
const { granularChanges, orders: preprocessorOrders } = preprocessChanges(state, changes, options);
|
|
29761
|
+
const derivedOrders = options.orders || (preprocessorOrders && preprocessorOrders.length ? preprocessorOrders : state ? computeOrdersForTuples(state, granularChanges) : []);
|
|
29762
|
+
const stringify = (val) => deepStringifyFunctions2(val, Array.isArray(val) ? [] : {});
|
|
29676
29763
|
try {
|
|
29677
29764
|
const response = await this._request(`/projects/${projectId}/changes`, {
|
|
29678
29765
|
method: "POST",
|
|
29679
29766
|
body: JSON.stringify({
|
|
29680
|
-
changes,
|
|
29767
|
+
changes: stringify(changes),
|
|
29768
|
+
granularChanges: stringify(granularChanges),
|
|
29681
29769
|
message,
|
|
29682
29770
|
branch,
|
|
29683
29771
|
type,
|
|
@@ -18170,12 +18170,54 @@ function isPlainObject(o) {
|
|
|
18170
18170
|
return o && typeof o === "object" && !Array.isArray(o);
|
|
18171
18171
|
}
|
|
18172
18172
|
function deepEqual(a, b) {
|
|
18173
|
-
|
|
18174
|
-
return
|
|
18175
|
-
}
|
|
18176
|
-
|
|
18173
|
+
if (Object.is(a, b)) {
|
|
18174
|
+
return true;
|
|
18175
|
+
}
|
|
18176
|
+
if (typeof a === "function" && typeof b === "function") {
|
|
18177
|
+
try {
|
|
18178
|
+
return a.toString() === b.toString();
|
|
18179
|
+
} catch {
|
|
18180
|
+
return false;
|
|
18181
|
+
}
|
|
18182
|
+
}
|
|
18183
|
+
if (typeof a === "function" || typeof b === "function") {
|
|
18177
18184
|
return false;
|
|
18178
18185
|
}
|
|
18186
|
+
if (a instanceof Date && b instanceof Date) {
|
|
18187
|
+
return a.getTime() === b.getTime();
|
|
18188
|
+
}
|
|
18189
|
+
if (a instanceof RegExp && b instanceof RegExp) {
|
|
18190
|
+
return String(a) === String(b);
|
|
18191
|
+
}
|
|
18192
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
18193
|
+
if (a.length !== b.length) {
|
|
18194
|
+
return false;
|
|
18195
|
+
}
|
|
18196
|
+
for (let i = 0; i < a.length; i++) {
|
|
18197
|
+
if (!deepEqual(a[i], b[i])) {
|
|
18198
|
+
return false;
|
|
18199
|
+
}
|
|
18200
|
+
}
|
|
18201
|
+
return true;
|
|
18202
|
+
}
|
|
18203
|
+
if (a && b && typeof a === "object" && typeof b === "object") {
|
|
18204
|
+
const aKeys = Object.keys(a);
|
|
18205
|
+
const bKeys = Object.keys(b);
|
|
18206
|
+
if (aKeys.length !== bKeys.length) {
|
|
18207
|
+
return false;
|
|
18208
|
+
}
|
|
18209
|
+
for (let i = 0; i < aKeys.length; i++) {
|
|
18210
|
+
const key = aKeys[i];
|
|
18211
|
+
if (!Object.hasOwn(b, key)) {
|
|
18212
|
+
return false;
|
|
18213
|
+
}
|
|
18214
|
+
if (!deepEqual(a[key], b[key])) {
|
|
18215
|
+
return false;
|
|
18216
|
+
}
|
|
18217
|
+
}
|
|
18218
|
+
return true;
|
|
18219
|
+
}
|
|
18220
|
+
return false;
|
|
18179
18221
|
}
|
|
18180
18222
|
function getRootMap(ydoc) {
|
|
18181
18223
|
return ydoc.getMap("root");
|
|
@@ -24582,14 +24624,12 @@ function getParentPathsFromTuples(tuples = []) {
|
|
|
24582
24624
|
"attr",
|
|
24583
24625
|
"state",
|
|
24584
24626
|
"scope",
|
|
24585
|
-
"props",
|
|
24586
24627
|
"define",
|
|
24587
24628
|
"on",
|
|
24588
24629
|
"extend",
|
|
24589
24630
|
"extends",
|
|
24590
24631
|
"childExtend",
|
|
24591
24632
|
"childExtends",
|
|
24592
|
-
"childProps",
|
|
24593
24633
|
"children",
|
|
24594
24634
|
"component",
|
|
24595
24635
|
"context",
|
|
@@ -24810,6 +24850,118 @@ function computeOrdersForTuples(root, tuples = []) {
|
|
|
24810
24850
|
return orders;
|
|
24811
24851
|
}
|
|
24812
24852
|
|
|
24853
|
+
// src/utils/changePreprocessor.js
|
|
24854
|
+
function isPlainObject2(val) {
|
|
24855
|
+
return val && typeof val === "object" && !Array.isArray(val);
|
|
24856
|
+
}
|
|
24857
|
+
function getByPathSafe(root, path) {
|
|
24858
|
+
if (!root || typeof root.getByPath !== "function") {
|
|
24859
|
+
return null;
|
|
24860
|
+
}
|
|
24861
|
+
try {
|
|
24862
|
+
return root.getByPath(path);
|
|
24863
|
+
} catch {
|
|
24864
|
+
return null;
|
|
24865
|
+
}
|
|
24866
|
+
}
|
|
24867
|
+
function preprocessChanges(root, tuples = [], options = {}) {
|
|
24868
|
+
const expandTuple = (t) => {
|
|
24869
|
+
const [action, path, value2] = t || [];
|
|
24870
|
+
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
24871
|
+
if (action === "delete") {
|
|
24872
|
+
return [t];
|
|
24873
|
+
}
|
|
24874
|
+
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2 || isSchemaPath && path.length === 3) && isPlainObject2(value2);
|
|
24875
|
+
if (!canConsiderExpansion) {
|
|
24876
|
+
return [t];
|
|
24877
|
+
}
|
|
24878
|
+
const prev = getByPathSafe(root, path) || {};
|
|
24879
|
+
const next = value2 || {};
|
|
24880
|
+
if (!isPlainObject2(prev) || !isPlainObject2(next)) {
|
|
24881
|
+
return [t];
|
|
24882
|
+
}
|
|
24883
|
+
const ops = diffJson(prev, next, []);
|
|
24884
|
+
if (!ops.length) {
|
|
24885
|
+
return [t];
|
|
24886
|
+
}
|
|
24887
|
+
const out = [];
|
|
24888
|
+
for (let i = 0; i < ops.length; i++) {
|
|
24889
|
+
const op = ops[i];
|
|
24890
|
+
const fullPath = [...path, ...op.path];
|
|
24891
|
+
const last2 = fullPath[fullPath.length - 1];
|
|
24892
|
+
if (op.action === "set") {
|
|
24893
|
+
out.push(["update", fullPath, op.value]);
|
|
24894
|
+
} else if (op.action === "del") {
|
|
24895
|
+
if (last2 !== "__order") {
|
|
24896
|
+
out.push(["delete", fullPath]);
|
|
24897
|
+
}
|
|
24898
|
+
}
|
|
24899
|
+
}
|
|
24900
|
+
return out;
|
|
24901
|
+
};
|
|
24902
|
+
const minimizeTuples = (input) => {
|
|
24903
|
+
const out = [];
|
|
24904
|
+
const seen2 = /* @__PURE__ */ new Set();
|
|
24905
|
+
for (let i = 0; i < input.length; i++) {
|
|
24906
|
+
const expanded = expandTuple(input[i]);
|
|
24907
|
+
for (let k = 0; k < expanded.length; k++) {
|
|
24908
|
+
const tuple = expanded[k];
|
|
24909
|
+
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
24910
|
+
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
24911
|
+
if (!isOrderKey) {
|
|
24912
|
+
const key = JSON.stringify(tuple);
|
|
24913
|
+
if (!seen2.has(key)) {
|
|
24914
|
+
seen2.add(key);
|
|
24915
|
+
out.push(tuple);
|
|
24916
|
+
}
|
|
24917
|
+
}
|
|
24918
|
+
}
|
|
24919
|
+
}
|
|
24920
|
+
return out;
|
|
24921
|
+
};
|
|
24922
|
+
const granularChanges = (() => {
|
|
24923
|
+
try {
|
|
24924
|
+
const res = minimizeTuples(tuples);
|
|
24925
|
+
if (options.append && options.append.length) {
|
|
24926
|
+
res.push(...options.append);
|
|
24927
|
+
}
|
|
24928
|
+
return res;
|
|
24929
|
+
} catch {
|
|
24930
|
+
return Array.isArray(tuples) ? tuples.slice() : [];
|
|
24931
|
+
}
|
|
24932
|
+
})();
|
|
24933
|
+
const baseOrders = computeOrdersForTuples(root, granularChanges);
|
|
24934
|
+
const preferOrdersMap = /* @__PURE__ */ new Map();
|
|
24935
|
+
for (let i = 0; i < tuples.length; i++) {
|
|
24936
|
+
const t = tuples[i];
|
|
24937
|
+
if (!Array.isArray(t) || t.length < 3) {
|
|
24938
|
+
continue;
|
|
24939
|
+
}
|
|
24940
|
+
const [action, path, value2] = t;
|
|
24941
|
+
if (action !== "update" || !Array.isArray(path) || path.length !== 1 && path.length !== 2 || !isPlainObject2(value2)) {
|
|
24942
|
+
continue;
|
|
24943
|
+
}
|
|
24944
|
+
const keys2 = Object.keys(value2).filter((k) => k !== "__order");
|
|
24945
|
+
const key = JSON.stringify(path);
|
|
24946
|
+
preferOrdersMap.set(key, { path, keys: keys2 });
|
|
24947
|
+
}
|
|
24948
|
+
const mergedOrders = [];
|
|
24949
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24950
|
+
preferOrdersMap.forEach((v, k) => {
|
|
24951
|
+
seen.add(k);
|
|
24952
|
+
mergedOrders.push(v);
|
|
24953
|
+
});
|
|
24954
|
+
for (let i = 0; i < baseOrders.length; i++) {
|
|
24955
|
+
const v = baseOrders[i];
|
|
24956
|
+
const k = JSON.stringify(v.path);
|
|
24957
|
+
if (!seen.has(k)) {
|
|
24958
|
+
seen.add(k);
|
|
24959
|
+
mergedOrders.push(v);
|
|
24960
|
+
}
|
|
24961
|
+
}
|
|
24962
|
+
return { granularChanges, orders: mergedOrders };
|
|
24963
|
+
}
|
|
24964
|
+
|
|
24813
24965
|
// src/services/CollabService.js
|
|
24814
24966
|
var CollabService = class extends BaseService {
|
|
24815
24967
|
constructor(config) {
|
|
@@ -24947,8 +25099,8 @@ var CollabService = class extends BaseService {
|
|
|
24947
25099
|
console.log(
|
|
24948
25100
|
`[CollabService] Flushing ${this._pendingOps.length} offline operation batch(es)`
|
|
24949
25101
|
);
|
|
24950
|
-
this._pendingOps.forEach(({ changes, orders }) => {
|
|
24951
|
-
this.socket.emit("ops", { changes, orders, ts: Date.now() });
|
|
25102
|
+
this._pendingOps.forEach(({ changes, granularChanges, orders }) => {
|
|
25103
|
+
this.socket.emit("ops", { changes, granularChanges, orders, ts: Date.now() });
|
|
24952
25104
|
});
|
|
24953
25105
|
this._pendingOps.length = 0;
|
|
24954
25106
|
}
|
|
@@ -24990,94 +25142,24 @@ var CollabService = class extends BaseService {
|
|
|
24990
25142
|
}
|
|
24991
25143
|
/* ---------- data helpers ---------- */
|
|
24992
25144
|
updateData(tuples, options = {}) {
|
|
24993
|
-
var _a, _b;
|
|
25145
|
+
var _a, _b, _c;
|
|
24994
25146
|
this._ensureStateManager();
|
|
24995
25147
|
const { isUndo = false, isRedo = false } = options;
|
|
24996
25148
|
if (!isUndo && !isRedo && !this._isUndoRedo) {
|
|
24997
25149
|
this._trackForUndo(tuples, options);
|
|
24998
25150
|
}
|
|
24999
|
-
const
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
|
|
25004
|
-
|
|
25005
|
-
if (!state2 || typeof state2.getByPath !== "function") {
|
|
25006
|
-
return null;
|
|
25007
|
-
}
|
|
25008
|
-
try {
|
|
25009
|
-
return state2.getByPath(path);
|
|
25010
|
-
} catch {
|
|
25011
|
-
return null;
|
|
25012
|
-
}
|
|
25013
|
-
};
|
|
25014
|
-
const expandTuple = (t) => {
|
|
25015
|
-
const [action, path, value2] = t || [];
|
|
25016
|
-
const isSchemaPath = Array.isArray(path) && path[0] === "schema";
|
|
25017
|
-
if (action === "delete" || isSchemaPath) {
|
|
25018
|
-
return [t];
|
|
25019
|
-
}
|
|
25020
|
-
const canConsiderExpansion = action === "update" && Array.isArray(path) && (path.length === 1 || path.length === 2) && isPlainObject2(value2);
|
|
25021
|
-
if (!canConsiderExpansion) {
|
|
25022
|
-
return [t];
|
|
25023
|
-
}
|
|
25024
|
-
const prev = getByPath(root, path) || {};
|
|
25025
|
-
const next = value2 || {};
|
|
25026
|
-
if (!isPlainObject2(prev) || !isPlainObject2(next)) {
|
|
25027
|
-
return [t];
|
|
25028
|
-
}
|
|
25029
|
-
const ops = diffJson(prev, next, []);
|
|
25030
|
-
if (!ops.length) {
|
|
25031
|
-
return [];
|
|
25032
|
-
}
|
|
25033
|
-
const arr = [];
|
|
25034
|
-
for (let j = 0; j < ops.length; j++) {
|
|
25035
|
-
const op = ops[j];
|
|
25036
|
-
const fullPath = [...path, ...op.path];
|
|
25037
|
-
const last2 = fullPath[fullPath.length - 1];
|
|
25038
|
-
if (op.action === "set") {
|
|
25039
|
-
arr.push(["update", fullPath, op.value]);
|
|
25040
|
-
} else if (op.action === "del") {
|
|
25041
|
-
if (last2 !== "__order") {
|
|
25042
|
-
arr.push(["delete", fullPath]);
|
|
25043
|
-
}
|
|
25044
|
-
}
|
|
25045
|
-
}
|
|
25046
|
-
return arr;
|
|
25047
|
-
};
|
|
25048
|
-
const minimizeTuples = (inputTuples) => {
|
|
25049
|
-
const out = [];
|
|
25050
|
-
for (let i = 0; i < inputTuples.length; i++) {
|
|
25051
|
-
const expanded = expandTuple(inputTuples[i]);
|
|
25052
|
-
for (let k = 0; k < expanded.length; k++) {
|
|
25053
|
-
const tuple = expanded[k];
|
|
25054
|
-
const isDelete = Array.isArray(tuple) && tuple[0] === "delete";
|
|
25055
|
-
const isOrderKey = isDelete && Array.isArray(tuple[1]) && tuple[1][tuple[1].length - 1] === "__order";
|
|
25056
|
-
if (!isOrderKey) {
|
|
25057
|
-
out.push(tuple);
|
|
25058
|
-
}
|
|
25059
|
-
}
|
|
25060
|
-
}
|
|
25061
|
-
console.log(`Minimized tuples`, out);
|
|
25062
|
-
return out;
|
|
25063
|
-
};
|
|
25064
|
-
console.log(`Processing tuples`, tuples);
|
|
25065
|
-
return minimizeTuples(tuples);
|
|
25066
|
-
} catch (err) {
|
|
25067
|
-
console.warn(
|
|
25068
|
-
"[CollabService] Minimal diff expansion failed \u2013 using original tuples",
|
|
25069
|
-
err
|
|
25070
|
-
);
|
|
25071
|
-
return tuples;
|
|
25072
|
-
}
|
|
25073
|
-
})();
|
|
25151
|
+
const root = (_a = this._stateManager) == null ? void 0 : _a.root;
|
|
25152
|
+
const { granularChanges: processedTuples, orders } = preprocessChanges(
|
|
25153
|
+
root,
|
|
25154
|
+
tuples,
|
|
25155
|
+
options
|
|
25156
|
+
);
|
|
25074
25157
|
if (options.append && options.append.length) {
|
|
25075
25158
|
processedTuples.push(...options.append);
|
|
25076
25159
|
}
|
|
25077
25160
|
this._stateManager.applyChanges(tuples, { ...options });
|
|
25078
|
-
const state = (
|
|
25161
|
+
const state = (_b = this._stateManager) == null ? void 0 : _b.root;
|
|
25079
25162
|
const el = state == null ? void 0 : state.__element;
|
|
25080
|
-
const orders = computeOrdersForTuples(state, processedTuples);
|
|
25081
25163
|
const stringifiedGranularTuples = (el == null ? void 0 : el.call) ? el.call(
|
|
25082
25164
|
"deepStringifyFunctions",
|
|
25083
25165
|
processedTuples,
|
|
@@ -25090,16 +25172,18 @@ var CollabService = class extends BaseService {
|
|
|
25090
25172
|
"deepStringifyFunctions",
|
|
25091
25173
|
tuples,
|
|
25092
25174
|
Array.isArray(tuples) ? [] : {}
|
|
25093
|
-
) : deepStringifyFunctions(
|
|
25094
|
-
tuples,
|
|
25095
|
-
Array.isArray(tuples) ? [] : {}
|
|
25096
|
-
);
|
|
25175
|
+
) : deepStringifyFunctions(tuples, Array.isArray(tuples) ? [] : {});
|
|
25097
25176
|
if (!this.isConnected()) {
|
|
25098
25177
|
console.warn("[CollabService] Not connected, queuing real-time update");
|
|
25099
|
-
this._pendingOps.push({
|
|
25178
|
+
this._pendingOps.push({
|
|
25179
|
+
changes: stringifiedTuples,
|
|
25180
|
+
granularChanges: stringifiedGranularTuples,
|
|
25181
|
+
orders,
|
|
25182
|
+
options
|
|
25183
|
+
});
|
|
25100
25184
|
return;
|
|
25101
25185
|
}
|
|
25102
|
-
if ((
|
|
25186
|
+
if ((_c = this.socket) == null ? void 0 : _c.connected) {
|
|
25103
25187
|
console.log("[CollabService] Sending operations to the backend", {
|
|
25104
25188
|
changes: stringifiedTuples,
|
|
25105
25189
|
granularChanges: stringifiedGranularTuples,
|