@ifc-lite/collab 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/branch/branch.d.ts +11 -0
- package/dist/branch/branch.d.ts.map +1 -1
- package/dist/branch/branch.js +30 -1
- package/dist/branch/branch.js.map +1 -1
- package/dist/conflicts/detector.d.ts +1 -1
- package/dist/conflicts/detector.d.ts.map +1 -1
- package/dist/conflicts/detector.js +19 -6
- package/dist/conflicts/detector.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Real-time collaborative BIM via CRDT on IFCX. Built on [Yjs](https://github.com/
|
|
|
6
6
|
> seed/snapshot round-trip, IndexedDB persistence, undo manager, websocket
|
|
7
7
|
> provider, awareness/presence, conflict detection, per-user layer
|
|
8
8
|
> extraction, branching, federation, and end-to-end encryption helpers. See
|
|
9
|
-
> [
|
|
9
|
+
> [Collaboration architecture](https://github.com/LTplus-AG/ifc-lite/blob/main/docs/architecture/collaboration.md)
|
|
10
10
|
> for the roadmap.
|
|
11
11
|
|
|
12
12
|
## Installation
|
package/dist/branch/branch.d.ts
CHANGED
|
@@ -26,6 +26,17 @@ export interface MergeReport {
|
|
|
26
26
|
bytes: number;
|
|
27
27
|
/** ISO timestamp of when the merge transaction landed on `parent`. */
|
|
28
28
|
mergedAt: string;
|
|
29
|
+
/**
|
|
30
|
+
* Count of entities the `'layer'` strategy could not remove from
|
|
31
|
+
* `parent` even though `branch` deleted them before merge. An IFCX
|
|
32
|
+
* snapshot of the branch (see below) emits only what an entity has, so
|
|
33
|
+
* a branch-side deletion is indistinguishable on the wire from "no
|
|
34
|
+
* opinion" — `applyIfcxOverlay` therefore leaves the parent's copy of
|
|
35
|
+
* that entity untouched. Always `0` for the `'ops'` strategy, which
|
|
36
|
+
* applies the branch's Y update directly and propagates deletions like
|
|
37
|
+
* any other Yjs change.
|
|
38
|
+
*/
|
|
39
|
+
droppedDeletions: number;
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Merge `branch` back into `parent`. Returns a small report.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"AA6BA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,IAAI,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC5C,oCAAoC;IACpC,SAAS,CAAC,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;
|
|
1
|
+
{"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"AA6BA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,IAAI,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACpC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAC5C,oCAAoC;IACpC,SAAS,CAAC,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAgBD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAkCxB;AAED,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,aAAa,CAAC;IACxB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;OASG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,EACrB,QAAQ,GAAE,aAAqB,GAC9B,WAAW,CAwDb;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,GACrB;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAOnE"}
|
package/dist/branch/branch.js
CHANGED
|
@@ -26,12 +26,21 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import * as Y from 'yjs';
|
|
28
28
|
import { createCollabSession, } from '../session.js';
|
|
29
|
-
import { metaMap } from '../doc/schema.js';
|
|
29
|
+
import { entitiesMap, metaMap } from '../doc/schema.js';
|
|
30
30
|
import { snapshotToIfcx } from '../snapshot/to-ifcx.js';
|
|
31
31
|
import { applyIfcxOverlay } from '../snapshot/from-ifcx.js';
|
|
32
32
|
const META_PARENT = 'branch.parentRoomId';
|
|
33
33
|
const META_NAME = 'branch.name';
|
|
34
34
|
const META_FORKED_AT = 'branch.forkedAt';
|
|
35
|
+
/**
|
|
36
|
+
* Entity ids present at fork time, keyed by the branch's Y.Doc. Used by
|
|
37
|
+
* `mergeBranch(..., 'layer')` to tell "the branch deleted this entity"
|
|
38
|
+
* apart from "the parent created this entity after the fork and the
|
|
39
|
+
* branch never had it" — both look like "missing from the branch doc"
|
|
40
|
+
* with no other signal available. A WeakMap keyed on the doc instance so
|
|
41
|
+
* entries are collected once a branch's doc is no longer referenced.
|
|
42
|
+
*/
|
|
43
|
+
const forkEntitySnapshots = new WeakMap();
|
|
35
44
|
export async function forkSession(parent, opts) {
|
|
36
45
|
// 1. Snapshot the parent Y.Doc as a binary update.
|
|
37
46
|
const update = Y.encodeStateAsUpdate(parent.doc);
|
|
@@ -51,6 +60,7 @@ export async function forkSession(parent, opts) {
|
|
|
51
60
|
});
|
|
52
61
|
// 3. Seed the branch doc with the parent state, then stamp branch metadata.
|
|
53
62
|
Y.applyUpdate(branch.doc, update, { source: 'fork', parentRoomId: parent.roomId });
|
|
63
|
+
forkEntitySnapshots.set(branch.doc, new Set(entitiesMap(branch.doc).keys()));
|
|
54
64
|
branch.transact(() => {
|
|
55
65
|
const meta = metaMap(branch.doc);
|
|
56
66
|
meta.set(META_PARENT, parent.roomId);
|
|
@@ -81,6 +91,7 @@ export function mergeBranch(parent, branch, strategy = 'ops') {
|
|
|
81
91
|
strategy,
|
|
82
92
|
bytes: update.byteLength,
|
|
83
93
|
mergedAt: new Date().toISOString(),
|
|
94
|
+
droppedDeletions: 0,
|
|
84
95
|
};
|
|
85
96
|
}
|
|
86
97
|
// 'layer' strategy: snapshot the branch as IFCX, then apply it to the
|
|
@@ -96,6 +107,23 @@ export function mergeBranch(parent, branch, strategy = 'ops') {
|
|
|
96
107
|
// snapshot says nothing about untouched. Deletions made on the branch
|
|
97
108
|
// still do not propagate: an IFCX snapshot emits only what an entity
|
|
98
109
|
// has, so a removal is indistinguishable from "no opinion" on the wire.
|
|
110
|
+
// Diagnostic only (not a fix): count entities the branch deleted that
|
|
111
|
+
// this merge cannot remove from `parent`, so the caller can at least
|
|
112
|
+
// detect the drop. An entity counts only if it existed on the branch
|
|
113
|
+
// at fork time (`forkEntitySnapshots`) — that rules out entities the
|
|
114
|
+
// parent created *after* the fork, which are also absent from the
|
|
115
|
+
// branch doc but were never "deleted" by anything.
|
|
116
|
+
const forkIds = forkEntitySnapshots.get(branch.session.doc);
|
|
117
|
+
const parentEntitiesBefore = entitiesMap(parent.doc);
|
|
118
|
+
const branchEntitiesNow = entitiesMap(branch.session.doc);
|
|
119
|
+
let droppedDeletions = 0;
|
|
120
|
+
if (forkIds) {
|
|
121
|
+
for (const id of forkIds) {
|
|
122
|
+
if (!branchEntitiesNow.has(id) && parentEntitiesBefore.has(id)) {
|
|
123
|
+
droppedDeletions++;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
99
127
|
const ifcx = snapshotToIfcx(branch.session.doc);
|
|
100
128
|
const before = Y.encodeStateAsUpdate(parent.doc);
|
|
101
129
|
applyIfcxOverlay(parent.doc, ifcx);
|
|
@@ -104,6 +132,7 @@ export function mergeBranch(parent, branch, strategy = 'ops') {
|
|
|
104
132
|
strategy,
|
|
105
133
|
bytes: Math.max(0, after.byteLength - before.byteLength),
|
|
106
134
|
mergedAt: new Date().toISOString(),
|
|
135
|
+
droppedDeletions,
|
|
107
136
|
};
|
|
108
137
|
}
|
|
109
138
|
/** Read branch metadata back off a session's Y.Doc. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EACL,mBAAmB,GAGpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"branch.js","sourceRoot":"","sources":["../../src/branch/branch.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EACL,mBAAmB,GAGpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAuB5D,MAAM,WAAW,GAAG,qBAAqB,CAAC;AAC1C,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,IAAI,OAAO,EAA8B,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAqB,EACrB,IAAiB;IAEjB,mDAAmD;IACnD,MAAM,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAEjD,+BAA+B;IAC/B,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,aAAa,IAAI,CAAC,IAAI,EAAE,CAAC;IAC7E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,IAAI,IAAI;QACjE,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;KACf,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;QACvC,MAAM,EAAE,YAAY;QACpB,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ;QAC1C,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;KAC1C,CAAC,CAAC;IAEH,4EAA4E;IAC5E,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACnF,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;QACnB,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,MAAM;QACf,YAAY,EAAE,MAAM,CAAC,MAAM;QAC3B,UAAU,EAAE,IAAI,CAAC,IAAI;KACtB,CAAC;AACJ,CAAC;AAuBD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,MAAqB,EACrB,MAAqB,EACrB,WAA0B,KAAK;IAE/B,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACzD,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE;YAChC,MAAM,EAAE,cAAc;YACtB,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;QACH,OAAO;YACL,QAAQ;YACR,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAClC,gBAAgB,EAAE,CAAC;SACpB,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,qEAAqE;IACrE,uEAAuE;IACvE,oEAAoE;IACpE,mEAAmE;IACnE,uEAAuE;IACvE,8CAA8C;IAC9C,EAAE;IACF,qEAAqE;IACrE,kEAAkE;IAClE,sEAAsE;IACtE,qEAAqE;IACrE,wEAAwE;IACxE,sEAAsE;IACtE,qEAAqE;IACrE,qEAAqE;IACrE,qEAAqE;IACrE,kEAAkE;IAClE,mDAAmD;IACnD,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5D,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,iBAAiB,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC/D,gBAAgB,EAAE,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjD,gBAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,CAAC,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChD,OAAO;QACL,QAAQ;QACR,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACxD,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAClC,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAC5B,OAAsB;IAEtB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAuB;QACzD,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAuB;QACrD,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,cAAc,CAAuB;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* The struct-level view is what we want for the conflict surface.
|
|
18
18
|
*/
|
|
19
19
|
import * as Y from 'yjs';
|
|
20
|
-
export type ConflictKind = 'attribute' | 'pset-property' | 'quantity' | 'hierarchy' | 'geometry-blob' | 'geometry-param' | 'relationship-target' | 'concurrent-delete';
|
|
20
|
+
export type ConflictKind = 'attribute' | 'pset-property' | 'quantity' | 'hierarchy' | 'geometry-blob' | 'geometry-param' | 'relationship-target' | 'concurrent-delete' | 'concurrent-create';
|
|
21
21
|
export interface ConflictEvent {
|
|
22
22
|
kind: ConflictKind;
|
|
23
23
|
/** Entity / relationship / geometry path involved. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/conflicts/detector.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAWzB,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,eAAe,GACf,UAAU,GACV,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,CAAC;AAExB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;IACnD,qEAAqE;IACrE,MAAM,IAAI,aAAa,EAAE,CAAC;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB;AAaD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAyElB"}
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/conflicts/detector.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAWzB,MAAM,MAAM,YAAY,GACpB,WAAW,GACX,eAAe,GACf,UAAU,GACV,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,CAAC;AAExB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;IACnD,qEAAqE;IACrE,MAAM,IAAI,aAAa,EAAE,CAAC;IAC1B,OAAO,IAAI,IAAI,CAAC;CACjB;AAaD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAyElB"}
|
|
@@ -132,12 +132,25 @@ function topLevelKey(type) {
|
|
|
132
132
|
function classify(top, path, key, isDelete) {
|
|
133
133
|
if (top === TOP.ENTITIES) {
|
|
134
134
|
if (path.length === 0) {
|
|
135
|
-
// Entity create OR delete on the top-level entities map.
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
// Entity create OR delete on the top-level entities map.
|
|
136
|
+
//
|
|
137
|
+
// Creates are CRDT-friendly *only* when two peers pick different
|
|
138
|
+
// paths — both entities coexist and no data is lost. When two
|
|
139
|
+
// peers independently create at the SAME path (e.g. each assigns
|
|
140
|
+
// the next sequential id from its own local view), Yjs LWW keeps
|
|
141
|
+
// exactly one peer's entity and silently discards the other's
|
|
142
|
+
// class/attributes/psets. We surface that as `concurrent-create`.
|
|
143
|
+
//
|
|
144
|
+
// This can't false-positive on an ordinary, non-colliding create:
|
|
145
|
+
// `record()` below only flags once >=2 distinct clients write the
|
|
146
|
+
// same `(kind, path)` key within the window, so a create at a
|
|
147
|
+
// unique path never accumulates a second contributor and never
|
|
148
|
+
// fires.
|
|
149
|
+
if (!key)
|
|
150
|
+
return null;
|
|
151
|
+
return isDelete
|
|
152
|
+
? { kind: 'concurrent-delete', path: key }
|
|
153
|
+
: { kind: 'concurrent-create', path: key };
|
|
141
154
|
}
|
|
142
155
|
const entityPath = path[0];
|
|
143
156
|
if (path.length === 1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/conflicts/detector.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAsB/D,OAAO,EACL,UAAU,EAGV,YAAY,EAEZ,gBAAgB,EAChB,GAAG,GACJ,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/conflicts/detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @ifc-lite/collab — Real-time collaborative BIM via CRDT on IFCX.
|
|
3
3
|
*
|
|
4
|
-
* See `docs/architecture/
|
|
4
|
+
* See `docs/architecture/collaboration.md` for the v0.1 → v1.0 roadmap.
|
|
5
5
|
*/
|
|
6
6
|
export * from './doc/schema.js';
|
|
7
7
|
export * from './doc/entity.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* @ifc-lite/collab — Real-time collaborative BIM via CRDT on IFCX.
|
|
6
6
|
*
|
|
7
|
-
* See `docs/architecture/
|
|
7
|
+
* See `docs/architecture/collaboration.md` for the v0.1 → v1.0 roadmap.
|
|
8
8
|
*/
|
|
9
9
|
// Doc model
|
|
10
10
|
export * from './doc/schema.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/collab",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Real-time collaborative BIM via CRDT on IFCX",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"y-protocols": "^1.0.6",
|
|
40
40
|
"y-websocket": "^3.1.0",
|
|
41
41
|
"yjs": "^13.6.32",
|
|
42
|
-
"@ifc-lite/data": "^4.
|
|
43
|
-
"@ifc-lite/
|
|
44
|
-
"@ifc-lite/
|
|
42
|
+
"@ifc-lite/data": "^4.2.0",
|
|
43
|
+
"@ifc-lite/mutations": "^2.2.0",
|
|
44
|
+
"@ifc-lite/ifcx": "^4.1.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"typescript": "^6.0.3",
|