@ifc-lite/collab 0.2.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/LICENSE +373 -0
- package/README.md +92 -0
- package/dist/awareness/agent.d.ts +36 -0
- package/dist/awareness/agent.d.ts.map +1 -0
- package/dist/awareness/agent.js +39 -0
- package/dist/awareness/agent.js.map +1 -0
- package/dist/awareness/color.d.ts +31 -0
- package/dist/awareness/color.d.ts.map +1 -0
- package/dist/awareness/color.js +61 -0
- package/dist/awareness/color.js.map +1 -0
- package/dist/awareness/index.d.ts +6 -0
- package/dist/awareness/index.d.ts.map +1 -0
- package/dist/awareness/index.js +9 -0
- package/dist/awareness/index.js.map +1 -0
- package/dist/awareness/overlay.d.ts +59 -0
- package/dist/awareness/overlay.d.ts.map +1 -0
- package/dist/awareness/overlay.js +110 -0
- package/dist/awareness/overlay.js.map +1 -0
- package/dist/awareness/presence.d.ts +95 -0
- package/dist/awareness/presence.d.ts.map +1 -0
- package/dist/awareness/presence.js +114 -0
- package/dist/awareness/presence.js.map +1 -0
- package/dist/awareness/render.d.ts +58 -0
- package/dist/awareness/render.d.ts.map +1 -0
- package/dist/awareness/render.js +66 -0
- package/dist/awareness/render.js.map +1 -0
- package/dist/branch/branch-tree.d.ts +40 -0
- package/dist/branch/branch-tree.d.ts.map +1 -0
- package/dist/branch/branch-tree.js +66 -0
- package/dist/branch/branch-tree.js.map +1 -0
- package/dist/branch/branch.d.ts +44 -0
- package/dist/branch/branch.d.ts.map +1 -0
- package/dist/branch/branch.js +109 -0
- package/dist/branch/branch.js.map +1 -0
- package/dist/branch/history-automerge.d.ts +31 -0
- package/dist/branch/history-automerge.d.ts.map +1 -0
- package/dist/branch/history-automerge.js +237 -0
- package/dist/branch/history-automerge.js.map +1 -0
- package/dist/branch/history.d.ts +147 -0
- package/dist/branch/history.d.ts.map +1 -0
- package/dist/branch/history.js +223 -0
- package/dist/branch/history.js.map +1 -0
- package/dist/branch/index.d.ts +5 -0
- package/dist/branch/index.d.ts.map +1 -0
- package/dist/branch/index.js +8 -0
- package/dist/branch/index.js.map +1 -0
- package/dist/conflicts/detector.d.ts +52 -0
- package/dist/conflicts/detector.d.ts.map +1 -0
- package/dist/conflicts/detector.js +226 -0
- package/dist/conflicts/detector.js.map +1 -0
- package/dist/conflicts/index.d.ts +3 -0
- package/dist/conflicts/index.d.ts.map +1 -0
- package/dist/conflicts/index.js +6 -0
- package/dist/conflicts/index.js.map +1 -0
- package/dist/conflicts/ui-bridge.d.ts +80 -0
- package/dist/conflicts/ui-bridge.d.ts.map +1 -0
- package/dist/conflicts/ui-bridge.js +126 -0
- package/dist/conflicts/ui-bridge.js.map +1 -0
- package/dist/doc/entity.d.ts +84 -0
- package/dist/doc/entity.d.ts.map +1 -0
- package/dist/doc/entity.js +345 -0
- package/dist/doc/entity.js.map +1 -0
- package/dist/doc/geometry.d.ts +39 -0
- package/dist/doc/geometry.d.ts.map +1 -0
- package/dist/doc/geometry.js +99 -0
- package/dist/doc/geometry.js.map +1 -0
- package/dist/doc/index.d.ts +8 -0
- package/dist/doc/index.d.ts.map +1 -0
- package/dist/doc/index.js +11 -0
- package/dist/doc/index.js.map +1 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.d.ts +21 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.d.ts.map +1 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.js +55 -0
- package/dist/doc/migration-ifc4-to-ifc4x3.js.map +1 -0
- package/dist/doc/relationship.d.ts +27 -0
- package/dist/doc/relationship.d.ts.map +1 -0
- package/dist/doc/relationship.js +110 -0
- package/dist/doc/relationship.js.map +1 -0
- package/dist/doc/schema-version.d.ts +47 -0
- package/dist/doc/schema-version.d.ts.map +1 -0
- package/dist/doc/schema-version.js +41 -0
- package/dist/doc/schema-version.js.map +1 -0
- package/dist/doc/schema.d.ts +131 -0
- package/dist/doc/schema.d.ts.map +1 -0
- package/dist/doc/schema.js +117 -0
- package/dist/doc/schema.js.map +1 -0
- package/dist/doc/units.d.ts +45 -0
- package/dist/doc/units.d.ts.map +1 -0
- package/dist/doc/units.js +120 -0
- package/dist/doc/units.js.map +1 -0
- package/dist/federation/bridge.d.ts +34 -0
- package/dist/federation/bridge.d.ts.map +1 -0
- package/dist/federation/bridge.js +52 -0
- package/dist/federation/bridge.js.map +1 -0
- package/dist/federation/index.d.ts +4 -0
- package/dist/federation/index.d.ts.map +1 -0
- package/dist/federation/index.js +7 -0
- package/dist/federation/index.js.map +1 -0
- package/dist/federation/resolver.d.ts +58 -0
- package/dist/federation/resolver.d.ts.map +1 -0
- package/dist/federation/resolver.js +43 -0
- package/dist/federation/resolver.js.map +1 -0
- package/dist/federation/session.d.ts +79 -0
- package/dist/federation/session.d.ts.map +1 -0
- package/dist/federation/session.js +126 -0
- package/dist/federation/session.js.map +1 -0
- package/dist/geometry/blob-store.d.ts +106 -0
- package/dist/geometry/blob-store.d.ts.map +1 -0
- package/dist/geometry/blob-store.js +266 -0
- package/dist/geometry/blob-store.js.map +1 -0
- package/dist/geometry/csg.d.ts +63 -0
- package/dist/geometry/csg.d.ts.map +1 -0
- package/dist/geometry/csg.js +101 -0
- package/dist/geometry/csg.js.map +1 -0
- package/dist/geometry/determinism.d.ts +45 -0
- package/dist/geometry/determinism.d.ts.map +1 -0
- package/dist/geometry/determinism.js +92 -0
- package/dist/geometry/determinism.js.map +1 -0
- package/dist/geometry/gc.d.ts +63 -0
- package/dist/geometry/gc.d.ts.map +1 -0
- package/dist/geometry/gc.js +109 -0
- package/dist/geometry/gc.js.map +1 -0
- package/dist/geometry/index.d.ts +6 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.js +9 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/geometry/parametric.d.ts +92 -0
- package/dist/geometry/parametric.d.ts.map +1 -0
- package/dist/geometry/parametric.js +200 -0
- package/dist/geometry/parametric.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/mutations/bind.d.ts +56 -0
- package/dist/mutations/bind.d.ts.map +1 -0
- package/dist/mutations/bind.js +68 -0
- package/dist/mutations/bind.js.map +1 -0
- package/dist/mutations/index.d.ts +2 -0
- package/dist/mutations/index.d.ts.map +1 -0
- package/dist/mutations/index.js +5 -0
- package/dist/mutations/index.js.map +1 -0
- package/dist/perf/benchmark.d.ts +25 -0
- package/dist/perf/benchmark.d.ts.map +1 -0
- package/dist/perf/benchmark.js +97 -0
- package/dist/perf/benchmark.js.map +1 -0
- package/dist/perf/index.d.ts +3 -0
- package/dist/perf/index.d.ts.map +1 -0
- package/dist/perf/index.js +6 -0
- package/dist/perf/index.js.map +1 -0
- package/dist/perf/latency.d.ts +39 -0
- package/dist/perf/latency.d.ts.map +1 -0
- package/dist/perf/latency.js +79 -0
- package/dist/perf/latency.js.map +1 -0
- package/dist/privacy.d.ts +45 -0
- package/dist/privacy.d.ts.map +1 -0
- package/dist/privacy.js +66 -0
- package/dist/privacy.js.map +1 -0
- package/dist/providers/indexeddb.d.ts +37 -0
- package/dist/providers/indexeddb.d.ts.map +1 -0
- package/dist/providers/indexeddb.js +45 -0
- package/dist/providers/indexeddb.js.map +1 -0
- package/dist/providers/webrtc.d.ts +40 -0
- package/dist/providers/webrtc.d.ts.map +1 -0
- package/dist/providers/webrtc.js +81 -0
- package/dist/providers/webrtc.js.map +1 -0
- package/dist/providers/websocket.d.ts +45 -0
- package/dist/providers/websocket.d.ts.map +1 -0
- package/dist/providers/websocket.js +56 -0
- package/dist/providers/websocket.js.map +1 -0
- package/dist/security/e2e.d.ts +54 -0
- package/dist/security/e2e.d.ts.map +1 -0
- package/dist/security/e2e.js +147 -0
- package/dist/security/e2e.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +5 -0
- package/dist/security/index.js.map +1 -0
- package/dist/session.d.ts +79 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +112 -0
- package/dist/session.js.map +1 -0
- package/dist/snapshot/from-ifcx.d.ts +24 -0
- package/dist/snapshot/from-ifcx.d.ts.map +1 -0
- package/dist/snapshot/from-ifcx.js +93 -0
- package/dist/snapshot/from-ifcx.js.map +1 -0
- package/dist/snapshot/index.d.ts +6 -0
- package/dist/snapshot/index.d.ts.map +1 -0
- package/dist/snapshot/index.js +9 -0
- package/dist/snapshot/index.js.map +1 -0
- package/dist/snapshot/layers.d.ts +56 -0
- package/dist/snapshot/layers.d.ts.map +1 -0
- package/dist/snapshot/layers.js +82 -0
- package/dist/snapshot/layers.js.map +1 -0
- package/dist/snapshot/minimal-layer.d.ts +40 -0
- package/dist/snapshot/minimal-layer.d.ts.map +1 -0
- package/dist/snapshot/minimal-layer.js +123 -0
- package/dist/snapshot/minimal-layer.js.map +1 -0
- package/dist/snapshot/to-ifcx.d.ts +26 -0
- package/dist/snapshot/to-ifcx.d.ts.map +1 -0
- package/dist/snapshot/to-ifcx.js +54 -0
- package/dist/snapshot/to-ifcx.js.map +1 -0
- package/dist/snapshot/worker.d.ts +45 -0
- package/dist/snapshot/worker.d.ts.map +1 -0
- package/dist/snapshot/worker.js +73 -0
- package/dist/snapshot/worker.js.map +1 -0
- package/dist/sync/room.d.ts +15 -0
- package/dist/sync/room.d.ts.map +1 -0
- package/dist/sync/room.js +20 -0
- package/dist/sync/room.js.map +1 -0
- package/dist/undo.d.ts +25 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +37 -0
- package/dist/undo.js.map +1 -0
- package/dist/viewer-bridge.d.ts +27 -0
- package/dist/viewer-bridge.d.ts.map +1 -0
- package/dist/viewer-bridge.js +82 -0
- package/dist/viewer-bridge.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import * as Y from 'yjs';
|
|
5
|
+
import { createCollabDoc } from '../doc/schema.js';
|
|
6
|
+
import { snapshotToIfcx } from './to-ifcx.js';
|
|
7
|
+
/**
|
|
8
|
+
* Capture a baseline state vector. Composed-with-baseline IFCX layer
|
|
9
|
+
* composition is the v0.7 mode; for v0.1 we still expose this so callers
|
|
10
|
+
* can pin a "before" point for downstream tooling.
|
|
11
|
+
*/
|
|
12
|
+
export function captureBaseline(doc) {
|
|
13
|
+
return Y.encodeStateVector(doc);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extract a per-user IFCX layer from `doc`.
|
|
17
|
+
*
|
|
18
|
+
* Replays `doc`'s full state filtered by `clientId` onto a fresh doc and
|
|
19
|
+
* snapshots that. The resulting IFCX is a complete description of every
|
|
20
|
+
* entity the chosen client touched, with that client's view of the
|
|
21
|
+
* attributes.
|
|
22
|
+
*
|
|
23
|
+
* `baseline` is currently unused at the per-write level (the v0.1
|
|
24
|
+
* limitation noted above) but kept in the signature so callers don't have
|
|
25
|
+
* to refactor when the v0.7 differential mode lands.
|
|
26
|
+
*/
|
|
27
|
+
export function extractUserLayer(doc, baseline, options = {}) {
|
|
28
|
+
void baseline;
|
|
29
|
+
const fullUpdate = Y.encodeStateAsUpdate(doc);
|
|
30
|
+
const filtered = options.clientId !== undefined ? filterUpdateByClient(fullUpdate, options.clientId) : fullUpdate;
|
|
31
|
+
const replay = createCollabDoc({ gc: false });
|
|
32
|
+
if (filtered.byteLength > 0) {
|
|
33
|
+
Y.applyUpdate(replay, filtered);
|
|
34
|
+
}
|
|
35
|
+
return snapshotToIfcx(replay, {
|
|
36
|
+
author: options.clientId !== undefined ? `client-${options.clientId}` : undefined,
|
|
37
|
+
...options.snapshot,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Filter a Y update so it only contains operations from `clientId`.
|
|
42
|
+
*
|
|
43
|
+
* We use Yjs's diff-against-state-vector machinery: build a state
|
|
44
|
+
* vector that has every client *except* `clientId` advanced past the
|
|
45
|
+
* end of the input update, then `diffUpdate` returns just `clientId`'s
|
|
46
|
+
* structs.
|
|
47
|
+
*/
|
|
48
|
+
export function filterUpdateByClient(update, clientId) {
|
|
49
|
+
const tmp = createCollabDoc({ gc: false });
|
|
50
|
+
Y.applyUpdate(tmp, update);
|
|
51
|
+
const sv = Y.encodeStateVectorFromUpdate(update);
|
|
52
|
+
const decoded = decodeStateVector(sv);
|
|
53
|
+
// Keep our client at clock 0 so we receive all of its ops; advance
|
|
54
|
+
// every other client to their final clock so they're excluded.
|
|
55
|
+
decoded.delete(clientId);
|
|
56
|
+
const adjusted = encodeStateVector(decoded);
|
|
57
|
+
return Y.encodeStateAsUpdate(tmp, adjusted);
|
|
58
|
+
}
|
|
59
|
+
/* -------------------- minimal SV codec helpers ---------------------- */
|
|
60
|
+
import * as encoding from 'lib0/encoding';
|
|
61
|
+
import * as decoding from 'lib0/decoding';
|
|
62
|
+
function decodeStateVector(buf) {
|
|
63
|
+
const decoder = decoding.createDecoder(buf);
|
|
64
|
+
const ssLen = decoding.readVarUint(decoder);
|
|
65
|
+
const map = new Map();
|
|
66
|
+
for (let i = 0; i < ssLen; i++) {
|
|
67
|
+
const client = decoding.readVarUint(decoder);
|
|
68
|
+
const clock = decoding.readVarUint(decoder);
|
|
69
|
+
map.set(client, clock);
|
|
70
|
+
}
|
|
71
|
+
return map;
|
|
72
|
+
}
|
|
73
|
+
function encodeStateVector(map) {
|
|
74
|
+
const encoder = encoding.createEncoder();
|
|
75
|
+
encoding.writeVarUint(encoder, map.size);
|
|
76
|
+
for (const [client, clock] of map) {
|
|
77
|
+
encoding.writeVarUint(encoder, client);
|
|
78
|
+
encoding.writeVarUint(encoder, clock);
|
|
79
|
+
}
|
|
80
|
+
return encoding.toUint8Array(encoder);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=layers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layers.js","sourceRoot":"","sources":["../../src/snapshot/layers.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAsB/D,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,cAAc,CAAC;AASpE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAU;IACxC,OAAO,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAU,EACV,QAAgC,EAChC,UAAkC,EAAE;IAEpC,KAAK,QAAQ,CAAC;IACd,MAAM,UAAU,GAAG,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,QAAQ,GACZ,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAEnG,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,IAAI,QAAQ,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC5B,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,cAAc,CAAC,MAAM,EAAE;QAC5B,MAAM,EAAE,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS;QACjF,GAAG,OAAO,CAAC,QAAQ;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAkB,EAAE,QAAgB;IACvE,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,CAAC,CAAC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAC;IACtC,mEAAmE;IACnE,+DAA+D;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,CAAC,mBAAmB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,0EAA0E;AAE1E,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,SAAS,iBAAiB,CAAC,GAAe;IACxC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC5C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAwB;IACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC;QAClC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,QAAQ,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Differential layer composer (spec §2 / §10 / §12.4).
|
|
3
|
+
*
|
|
4
|
+
* `extractMinimalLayer(doc, baseline)` produces an IFCX layer that
|
|
5
|
+
* contains *only* what changed since `baseline`:
|
|
6
|
+
* - Entities created since baseline.
|
|
7
|
+
* - Entities whose attributes / children / inherits changed since
|
|
8
|
+
* baseline (only the changed fields appear).
|
|
9
|
+
*
|
|
10
|
+
* Composed with the baseline, the layer reproduces `doc`'s current
|
|
11
|
+
* state — that's the IFCX layer composition contract from §2 (each
|
|
12
|
+
* peer becomes a layer author, layer composition is the merge
|
|
13
|
+
* function).
|
|
14
|
+
*
|
|
15
|
+
* Strategy: reconstruct a "before" Y.Doc from the baseline state,
|
|
16
|
+
* compare entity-by-entity with the live doc, and emit IFCX nodes
|
|
17
|
+
* containing only the diff. We deliberately don't try to express
|
|
18
|
+
* deletions in the layer — IFCX overlay semantics are additive in
|
|
19
|
+
* v0.x, and deletion overlays are spec'd for a future version.
|
|
20
|
+
*/
|
|
21
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
22
|
+
import * as Y from 'yjs';
|
|
23
|
+
import { type SnapshotOptions } from './to-ifcx.js';
|
|
24
|
+
export interface ExtractMinimalLayerOptions {
|
|
25
|
+
/** Forwarded to `snapshotToIfcx` for header / timestamp / id. */
|
|
26
|
+
snapshot?: SnapshotOptions;
|
|
27
|
+
/**
|
|
28
|
+
* If true (default), include attributes that changed value from the
|
|
29
|
+
* baseline as well as new attributes. If false, only include keys
|
|
30
|
+
* that didn't exist in the baseline at all.
|
|
31
|
+
*/
|
|
32
|
+
includeUpdatedValues?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a minimal IFCX layer expressing the diff between `baseline`
|
|
36
|
+
* and `doc`. `baseline` is whatever `Y.encodeStateAsUpdate(doc)`
|
|
37
|
+
* returned at the fork / snapshot point.
|
|
38
|
+
*/
|
|
39
|
+
export declare function extractMinimalLayer(doc: Y.Doc, baseline: Uint8Array, options?: ExtractMinimalLayerOptions): IfcxFile;
|
|
40
|
+
//# sourceMappingURL=minimal-layer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minimal-layer.d.ts","sourceRoot":"","sources":["../../src/snapshot/minimal-layer.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAGzB,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,WAAW,0BAA0B;IACzC,iEAAiE;IACjE,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,QAAQ,EAAE,UAAU,EACpB,OAAO,GAAE,0BAA+B,GACvC,QAAQ,CAsFV"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import * as Y from 'yjs';
|
|
5
|
+
import { createCollabDoc, entitiesMap } from '../doc/schema.js';
|
|
6
|
+
import { entityToJSON } from '../doc/entity.js';
|
|
7
|
+
import { snapshotToIfcx } from './to-ifcx.js';
|
|
8
|
+
/**
|
|
9
|
+
* Build a minimal IFCX layer expressing the diff between `baseline`
|
|
10
|
+
* and `doc`. `baseline` is whatever `Y.encodeStateAsUpdate(doc)`
|
|
11
|
+
* returned at the fork / snapshot point.
|
|
12
|
+
*/
|
|
13
|
+
export function extractMinimalLayer(doc, baseline, options = {}) {
|
|
14
|
+
const includeUpdatedValues = options.includeUpdatedValues ?? true;
|
|
15
|
+
// Reconstruct the "before" state by replaying the baseline update on
|
|
16
|
+
// a fresh doc.
|
|
17
|
+
const before = createCollabDoc({ gc: false });
|
|
18
|
+
if (baseline.byteLength > 0)
|
|
19
|
+
Y.applyUpdate(before, baseline);
|
|
20
|
+
// Snapshot the live doc through the standard writer so we get a
|
|
21
|
+
// header + imports + schemas template, then trim the data array down
|
|
22
|
+
// to the diff.
|
|
23
|
+
const live = snapshotToIfcx(doc, options.snapshot);
|
|
24
|
+
const beforeEnts = entitiesMap(before);
|
|
25
|
+
const liveEnts = entitiesMap(doc);
|
|
26
|
+
const diffNodes = [];
|
|
27
|
+
liveEnts.forEach((entUntyped, path) => {
|
|
28
|
+
const liveJson = entityToJSON(entUntyped);
|
|
29
|
+
const beforeUntyped = beforeEnts.get(path);
|
|
30
|
+
if (!beforeUntyped) {
|
|
31
|
+
// Entity is new — emit it whole (sans empty branches).
|
|
32
|
+
const node = { path };
|
|
33
|
+
if (Object.keys(liveJson.attributes).length > 0)
|
|
34
|
+
node.attributes = { ...liveJson.attributes };
|
|
35
|
+
if (Object.keys(liveJson.children).length > 0)
|
|
36
|
+
node.children = { ...liveJson.children };
|
|
37
|
+
if (Object.keys(liveJson.inherits).length > 0)
|
|
38
|
+
node.inherits = { ...liveJson.inherits };
|
|
39
|
+
diffNodes.push(node);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const beforeJson = entityToJSON(beforeUntyped);
|
|
43
|
+
const node = { path };
|
|
44
|
+
let dirty = false;
|
|
45
|
+
// Attributes: include keys that are new OR (when configured)
|
|
46
|
+
// whose value changed.
|
|
47
|
+
const addedAttrs = {};
|
|
48
|
+
for (const [key, value] of Object.entries(liveJson.attributes)) {
|
|
49
|
+
const wasInBaseline = key in beforeJson.attributes;
|
|
50
|
+
if (!wasInBaseline) {
|
|
51
|
+
addedAttrs[key] = value;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (includeUpdatedValues && !deepEqual(value, beforeJson.attributes[key])) {
|
|
55
|
+
addedAttrs[key] = value;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (Object.keys(addedAttrs).length > 0) {
|
|
59
|
+
node.attributes = addedAttrs;
|
|
60
|
+
dirty = true;
|
|
61
|
+
}
|
|
62
|
+
// Children: same rule.
|
|
63
|
+
const addedChildren = {};
|
|
64
|
+
for (const [role, child] of Object.entries(liveJson.children)) {
|
|
65
|
+
const wasInBaseline = role in beforeJson.children;
|
|
66
|
+
if (!wasInBaseline || (includeUpdatedValues && beforeJson.children[role] !== child)) {
|
|
67
|
+
addedChildren[role] = child;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (Object.keys(addedChildren).length > 0) {
|
|
71
|
+
node.children = addedChildren;
|
|
72
|
+
dirty = true;
|
|
73
|
+
}
|
|
74
|
+
// Inherits: same rule.
|
|
75
|
+
const addedInherits = {};
|
|
76
|
+
for (const [role, inh] of Object.entries(liveJson.inherits)) {
|
|
77
|
+
const wasInBaseline = role in beforeJson.inherits;
|
|
78
|
+
if (!wasInBaseline || (includeUpdatedValues && beforeJson.inherits[role] !== inh)) {
|
|
79
|
+
addedInherits[role] = inh;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (Object.keys(addedInherits).length > 0) {
|
|
83
|
+
node.inherits = addedInherits;
|
|
84
|
+
dirty = true;
|
|
85
|
+
}
|
|
86
|
+
if (dirty)
|
|
87
|
+
diffNodes.push(node);
|
|
88
|
+
});
|
|
89
|
+
before.destroy();
|
|
90
|
+
return {
|
|
91
|
+
...live,
|
|
92
|
+
data: diffNodes,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Heuristic deep-equal: handles primitives, arrays, and plain objects.
|
|
97
|
+
* Sufficient for IFCX values which are JSON-shaped by construction.
|
|
98
|
+
*/
|
|
99
|
+
function deepEqual(a, b) {
|
|
100
|
+
if (a === b)
|
|
101
|
+
return true;
|
|
102
|
+
if (a == null || b == null)
|
|
103
|
+
return false;
|
|
104
|
+
if (typeof a !== typeof b)
|
|
105
|
+
return false;
|
|
106
|
+
if (Array.isArray(a)) {
|
|
107
|
+
if (!Array.isArray(b) || a.length !== b.length)
|
|
108
|
+
return false;
|
|
109
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
110
|
+
}
|
|
111
|
+
if (typeof a === 'object') {
|
|
112
|
+
const ao = a;
|
|
113
|
+
const bo = b;
|
|
114
|
+
const keys = new Set([...Object.keys(ao), ...Object.keys(bo)]);
|
|
115
|
+
for (const k of keys) {
|
|
116
|
+
if (!deepEqual(ao[k], bo[k]))
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=minimal-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minimal-layer.js","sourceRoot":"","sources":["../../src/snapshot/minimal-layer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Y.Doc → IFCX snapshot.
|
|
3
|
+
*
|
|
4
|
+
* Round-trips with `seedFromIfcx`: seeding a doc, snapshotting, then
|
|
5
|
+
* seeding a fresh doc from the snapshot must produce structurally equal
|
|
6
|
+
* Y states (verified by tests).
|
|
7
|
+
*/
|
|
8
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
9
|
+
import * as Y from 'yjs';
|
|
10
|
+
export interface SnapshotOptions {
|
|
11
|
+
author?: string;
|
|
12
|
+
/** Override timestamp; defaults to Date.now(). */
|
|
13
|
+
timestamp?: string;
|
|
14
|
+
/** Override the data version string. */
|
|
15
|
+
dataVersion?: string;
|
|
16
|
+
/** Override the file id. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** Override the IFCX version string. Defaults to whatever was seeded. */
|
|
19
|
+
ifcxVersion?: string;
|
|
20
|
+
/** Stable child-key ordering (defaults to insertion order from the Y.Map). */
|
|
21
|
+
sortChildren?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function snapshotToIfcx(doc: Y.Doc, options?: SnapshotOptions): IfcxFile;
|
|
24
|
+
/** Serialize an IfcxFile to a string. */
|
|
25
|
+
export declare function serializeIfcx(file: IfcxFile, pretty?: boolean): string;
|
|
26
|
+
//# sourceMappingURL=to-ifcx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-ifcx.d.ts","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAIzB,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAiDlF;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAO,GAAG,MAAM,CAEnE"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { entityToJSON, iterEntities } from '../doc/entity.js';
|
|
5
|
+
import { metaMap } from '../doc/schema.js';
|
|
6
|
+
export function snapshotToIfcx(doc, options = {}) {
|
|
7
|
+
const meta = metaMap(doc);
|
|
8
|
+
const seededHeader = meta.get('header') ?? undefined;
|
|
9
|
+
const seededImports = meta.get('imports') ?? [];
|
|
10
|
+
const seededSchemas = meta.get('schemas') ?? {};
|
|
11
|
+
const header = {
|
|
12
|
+
id: options.id ?? seededHeader?.id ?? 'ifc-lite/collab/snapshot',
|
|
13
|
+
ifcxVersion: options.ifcxVersion ?? seededHeader?.ifcxVersion ?? 'ifcx_alpha',
|
|
14
|
+
dataVersion: options.dataVersion ?? seededHeader?.dataVersion ?? '1.0.0',
|
|
15
|
+
author: options.author ?? seededHeader?.author ?? 'ifc-lite/collab',
|
|
16
|
+
timestamp: options.timestamp ?? new Date().toISOString(),
|
|
17
|
+
};
|
|
18
|
+
const data = [];
|
|
19
|
+
for (const [path, entity] of iterEntities(doc)) {
|
|
20
|
+
const json = entityToJSON(entity);
|
|
21
|
+
const node = { path };
|
|
22
|
+
const childrenKeys = options.sortChildren
|
|
23
|
+
? Object.keys(json.children).sort()
|
|
24
|
+
: Object.keys(json.children);
|
|
25
|
+
if (childrenKeys.length > 0) {
|
|
26
|
+
node.children = {};
|
|
27
|
+
for (const k of childrenKeys)
|
|
28
|
+
node.children[k] = json.children[k];
|
|
29
|
+
}
|
|
30
|
+
const inheritsKeys = options.sortChildren
|
|
31
|
+
? Object.keys(json.inherits).sort()
|
|
32
|
+
: Object.keys(json.inherits);
|
|
33
|
+
if (inheritsKeys.length > 0) {
|
|
34
|
+
node.inherits = {};
|
|
35
|
+
for (const k of inheritsKeys)
|
|
36
|
+
node.inherits[k] = json.inherits[k];
|
|
37
|
+
}
|
|
38
|
+
if (Object.keys(json.attributes).length > 0) {
|
|
39
|
+
node.attributes = { ...json.attributes };
|
|
40
|
+
}
|
|
41
|
+
data.push(node);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
header,
|
|
45
|
+
imports: seededImports,
|
|
46
|
+
schemas: seededSchemas,
|
|
47
|
+
data,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Serialize an IfcxFile to a string. */
|
|
51
|
+
export function serializeIfcx(file, pretty = true) {
|
|
52
|
+
return pretty ? JSON.stringify(file, null, 2) : JSON.stringify(file);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=to-ifcx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"to-ifcx.js","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { snapshotToIfcx, type SnapshotOptions } from './to-ifcx.js';
|
|
2
|
+
import { seedFromIfcx, type IfcxInput } from './from-ifcx.js';
|
|
3
|
+
export type WorkerRequest = {
|
|
4
|
+
kind: 'snapshot';
|
|
5
|
+
/** Encoded Y state (e.g. `Y.encodeStateAsUpdate(doc)`) to snapshot. */
|
|
6
|
+
update: Uint8Array;
|
|
7
|
+
options?: SnapshotOptions;
|
|
8
|
+
requestId?: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'seed';
|
|
11
|
+
/** IFCX text or already-decoded `IfcxFile`. */
|
|
12
|
+
source: IfcxInput;
|
|
13
|
+
requestId?: string;
|
|
14
|
+
};
|
|
15
|
+
export type WorkerResponse = {
|
|
16
|
+
kind: 'snapshot:ok';
|
|
17
|
+
requestId?: string;
|
|
18
|
+
ifcx: ReturnType<typeof snapshotToIfcx>;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'seed:ok';
|
|
21
|
+
requestId?: string;
|
|
22
|
+
/** Y update encoded from the seeded doc, ready for `applyUpdate` on the main thread. */
|
|
23
|
+
update: Uint8Array;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'error';
|
|
26
|
+
requestId?: string;
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
/** Minimal subset of `Worker`'s self / DedicatedWorkerGlobalScope. */
|
|
30
|
+
export interface WorkerScopeLike {
|
|
31
|
+
addEventListener(type: 'message', listener: (event: {
|
|
32
|
+
data: WorkerRequest;
|
|
33
|
+
}) => void): void;
|
|
34
|
+
postMessage(data: WorkerResponse, transfer?: Transferable[]): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Mount a `(snapshot|seed)` request handler on a worker scope.
|
|
38
|
+
*
|
|
39
|
+
* The handler creates a fresh Y.Doc per request, applies the supplied
|
|
40
|
+
* update (snapshot path) or seeds from IFCX (seed path), then posts the
|
|
41
|
+
* result back. Memory is bounded to the lifetime of one request.
|
|
42
|
+
*/
|
|
43
|
+
export declare function runSnapshotWorker(scope: WorkerScopeLike): void;
|
|
44
|
+
export { snapshotToIfcx, seedFromIfcx };
|
|
45
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/snapshot/worker.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,YAAY,EAAkB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,MAAM,aAAa,GACrB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,uEAAuE;IACvE,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEN,MAAM,MAAM,cAAc,GACtB;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;CACzC,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,MAAM,EAAE,UAAU,CAAC;CACpB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CACd,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,aAAa,CAAA;KAAE,KAAK,IAAI,GACjD,IAAI,CAAC;IACR,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;CACpE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAsC9D;AAKD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Worker-safe snapshot helpers (spec §16.1 deferred from v0.1).
|
|
6
|
+
*
|
|
7
|
+
* `snapshotToIfcx` and `seedFromIfcx` are pure functions that operate
|
|
8
|
+
* on a Y.Doc — they do not touch the DOM and are therefore safe to
|
|
9
|
+
* call from a Web Worker. This module re-exports them along with a
|
|
10
|
+
* tiny `runSnapshotWorker(self)` adapter that consumers can drop into
|
|
11
|
+
* a worker entry point to get a postMessage-driven snapshot service
|
|
12
|
+
* without writing the boilerplate.
|
|
13
|
+
*
|
|
14
|
+
* Wire from app code:
|
|
15
|
+
* - in `worker.ts`: `import { runSnapshotWorker } from '@ifc-lite/collab/snapshot/worker'; runSnapshotWorker(self);`
|
|
16
|
+
* - in main thread: post `{ kind: 'snapshot', updates }` and await
|
|
17
|
+
* a `{ kind: 'snapshot:ok', ifcx }` reply.
|
|
18
|
+
*/
|
|
19
|
+
import * as Y from 'yjs';
|
|
20
|
+
import { createCollabDoc } from '../doc/schema.js';
|
|
21
|
+
import { snapshotToIfcx } from './to-ifcx.js';
|
|
22
|
+
import { seedFromIfcx, parseIfcxInput } from './from-ifcx.js';
|
|
23
|
+
/**
|
|
24
|
+
* Mount a `(snapshot|seed)` request handler on a worker scope.
|
|
25
|
+
*
|
|
26
|
+
* The handler creates a fresh Y.Doc per request, applies the supplied
|
|
27
|
+
* update (snapshot path) or seeds from IFCX (seed path), then posts the
|
|
28
|
+
* result back. Memory is bounded to the lifetime of one request.
|
|
29
|
+
*/
|
|
30
|
+
export function runSnapshotWorker(scope) {
|
|
31
|
+
scope.addEventListener('message', (event) => {
|
|
32
|
+
const msg = event.data;
|
|
33
|
+
try {
|
|
34
|
+
switch (msg.kind) {
|
|
35
|
+
case 'snapshot': {
|
|
36
|
+
const doc = createCollabDoc({ gc: false });
|
|
37
|
+
if (msg.update.byteLength > 0)
|
|
38
|
+
Y.applyUpdate(doc, msg.update);
|
|
39
|
+
const ifcx = snapshotToIfcx(doc, msg.options);
|
|
40
|
+
scope.postMessage({ kind: 'snapshot:ok', requestId: msg.requestId, ifcx });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
case 'seed': {
|
|
44
|
+
const doc = createCollabDoc({ gc: false });
|
|
45
|
+
// Decode whatever shape the caller hands us.
|
|
46
|
+
parseIfcxInput(msg.source);
|
|
47
|
+
seedFromIfcx(doc, msg.source);
|
|
48
|
+
const update = Y.encodeStateAsUpdate(doc);
|
|
49
|
+
scope.postMessage({ kind: 'seed:ok', requestId: msg.requestId, update },
|
|
50
|
+
// Transfer the buffer so we don't double-copy it.
|
|
51
|
+
[update.buffer]);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
default: {
|
|
55
|
+
const exhaustive = msg;
|
|
56
|
+
throw new Error(`@ifc-lite/collab: unknown worker message kind: ${exhaustive.kind}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
scope.postMessage({
|
|
62
|
+
kind: 'error',
|
|
63
|
+
requestId: msg.requestId,
|
|
64
|
+
message: err instanceof Error ? err.message : String(err),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// Re-export the pure helpers so consumers that don't want the
|
|
70
|
+
// postMessage adapter can still import the worker-safe surface from
|
|
71
|
+
// one entry point.
|
|
72
|
+
export { snapshotToIfcx, seedFromIfcx };
|
|
73
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/snapshot/worker.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAkB,MAAM,gBAAgB,CAAC;AA4C9E;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAsB;IACtD,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;gBACjB,KAAK,UAAU,CAAC,CAAC,CAAC;oBAChB,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,CAAC;wBAAE,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;oBAC9D,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;oBAC9C,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;oBAC3E,OAAO;gBACT,CAAC;gBACD,KAAK,MAAM,CAAC,CAAC,CAAC;oBACZ,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC3C,6CAA6C;oBAC7C,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;oBAC3B,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;oBAC9B,MAAM,MAAM,GAAG,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;oBAC1C,KAAK,CAAC,WAAW,CACf,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE;oBACrD,kDAAkD;oBAClD,CAAC,MAAM,CAAC,MAAM,CAAC,CAChB,CAAC;oBACF,OAAO;gBACT,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,UAAU,GAAU,GAAG,CAAC;oBAC9B,MAAM,IAAI,KAAK,CAAC,kDAAmD,UAAgC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9G,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,CAAC,WAAW,CAAC;gBAChB,IAAI,EAAE,OAAO;gBACb,SAAS,EAAG,GAA8B,CAAC,SAAS;gBACpD,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aAC1D,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8DAA8D;AAC9D,oEAAoE;AACpE,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Room lifecycle helpers.
|
|
3
|
+
*
|
|
4
|
+
* A room is identified by a string key. For a project-wide federated
|
|
5
|
+
* session, room IDs follow the convention `project-id/model-id` plus
|
|
6
|
+
* `project-id/_federation` (spec §10).
|
|
7
|
+
*/
|
|
8
|
+
export interface RoomDescriptor {
|
|
9
|
+
projectId: string;
|
|
10
|
+
modelId: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function roomIdFor(desc: RoomDescriptor): string;
|
|
13
|
+
export declare function federationRoomId(projectId: string): string;
|
|
14
|
+
export declare function parseRoomId(roomId: string): RoomDescriptor;
|
|
15
|
+
//# sourceMappingURL=room.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../src/sync/room.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAS1D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
export function roomIdFor(desc) {
|
|
5
|
+
return `${desc.projectId}/${desc.modelId}`;
|
|
6
|
+
}
|
|
7
|
+
export function federationRoomId(projectId) {
|
|
8
|
+
return `${projectId}/_federation`;
|
|
9
|
+
}
|
|
10
|
+
export function parseRoomId(roomId) {
|
|
11
|
+
const idx = roomId.indexOf('/');
|
|
12
|
+
if (idx < 0) {
|
|
13
|
+
return { projectId: '', modelId: roomId };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
projectId: roomId.slice(0, idx),
|
|
17
|
+
modelId: roomId.slice(idx + 1),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=room.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/sync/room.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAe/D,MAAM,UAAU,SAAS,CAAC,IAAoB;IAC5C,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,GAAG,SAAS,cAAc,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;QACZ,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAC/B,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC;KAC/B,CAAC;AACJ,CAAC"}
|
package/dist/undo.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Undo manager — wraps Y.UndoManager scoped to the local origin so a
|
|
3
|
+
* peer's `undo()` only rolls back their own edits, never their
|
|
4
|
+
* teammates'. Spec §6.1.
|
|
5
|
+
*/
|
|
6
|
+
import * as Y from 'yjs';
|
|
7
|
+
import { UNDO_ORIGIN } from './doc/schema.js';
|
|
8
|
+
export interface UndoOptions {
|
|
9
|
+
/** Origins that count as undoable. Defaults to `[LOCAL_ORIGIN]`. */
|
|
10
|
+
trackedOrigins?: unknown[];
|
|
11
|
+
/** Capture timeout in ms (default 500). */
|
|
12
|
+
captureTimeout?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface UndoController {
|
|
15
|
+
readonly manager: Y.UndoManager;
|
|
16
|
+
undo(): boolean;
|
|
17
|
+
redo(): boolean;
|
|
18
|
+
canUndo(): boolean;
|
|
19
|
+
canRedo(): boolean;
|
|
20
|
+
clear(): void;
|
|
21
|
+
destroy(): void;
|
|
22
|
+
}
|
|
23
|
+
export declare function createUndoManager(doc: Y.Doc, opts?: UndoOptions): UndoController;
|
|
24
|
+
export { UNDO_ORIGIN };
|
|
25
|
+
//# sourceMappingURL=undo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAEL,WAAW,EAIZ,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;IAC3B,2CAA2C;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,WAAW,CAAC;IAChC,IAAI,IAAI,OAAO,CAAC;IAChB,IAAI,IAAI,OAAO,CAAC;IAChB,OAAO,IAAI,OAAO,CAAC;IACnB,OAAO,IAAI,OAAO,CAAC;IACnB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,GAAE,WAAgB,GAAG,cAAc,CA6BpF;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/undo.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
/**
|
|
5
|
+
* Undo manager — wraps Y.UndoManager scoped to the local origin so a
|
|
6
|
+
* peer's `undo()` only rolls back their own edits, never their
|
|
7
|
+
* teammates'. Spec §6.1.
|
|
8
|
+
*/
|
|
9
|
+
import * as Y from 'yjs';
|
|
10
|
+
import { LOCAL_ORIGIN, UNDO_ORIGIN, entitiesMap, geometryMap, relationshipsMap, } from './doc/schema.js';
|
|
11
|
+
export function createUndoManager(doc, opts = {}) {
|
|
12
|
+
const trackedOrigins = new Set(opts.trackedOrigins ?? [LOCAL_ORIGIN]);
|
|
13
|
+
const manager = new Y.UndoManager([entitiesMap(doc), relationshipsMap(doc), geometryMap(doc)], {
|
|
14
|
+
trackedOrigins,
|
|
15
|
+
captureTimeout: opts.captureTimeout ?? 500,
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
manager,
|
|
19
|
+
undo() {
|
|
20
|
+
// Yjs UndoManager.undo returns the StackItem when something was
|
|
21
|
+
// undone, or `null` otherwise. We tag the redo operation with our
|
|
22
|
+
// dedicated origin so observers can distinguish it from human ops.
|
|
23
|
+
const item = manager.undo();
|
|
24
|
+
return item != null;
|
|
25
|
+
},
|
|
26
|
+
redo() {
|
|
27
|
+
const item = manager.redo();
|
|
28
|
+
return item != null;
|
|
29
|
+
},
|
|
30
|
+
canUndo: () => manager.canUndo(),
|
|
31
|
+
canRedo: () => manager.canRedo(),
|
|
32
|
+
clear: () => manager.clear(),
|
|
33
|
+
destroy: () => manager.destroy(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export { UNDO_ORIGIN };
|
|
37
|
+
//# sourceMappingURL=undo.js.map
|
package/dist/undo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../src/undo.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;GAIG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AAmBzB,MAAM,UAAU,iBAAiB,CAAC,GAAU,EAAE,OAAoB,EAAE;IAClE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAU,IAAI,CAAC,cAAc,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAE/E,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,WAAW,CAC/B,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,EAC3D;QACE,cAAc;QACd,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,GAAG;KAC3C,CACF,CAAC;IAEF,OAAO;QACL,OAAO;QACP,IAAI;YACF,gEAAgE;YAChE,kEAAkE;YAClE,mEAAmE;YACnE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,IAAI,IAAI,IAAI,CAAC;QACtB,CAAC;QACD,IAAI;YACF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC5B,OAAO,IAAI,IAAI,IAAI,CAAC;QACtB,CAAC;QACD,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QAChC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QAChC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;QAC5B,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;KACjC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Vec3 } from './awareness/presence.js';
|
|
2
|
+
import type { CollabSession } from './session.js';
|
|
3
|
+
export interface MountPresenceInViewerOptions {
|
|
4
|
+
session: CollabSession;
|
|
5
|
+
container: HTMLElement;
|
|
6
|
+
viewport: string;
|
|
7
|
+
/** Opt out of forwarding mousemove → setCursor* (default: forward). */
|
|
8
|
+
trackLocalCursor?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Host-supplied screen→world raycast. When provided, every mousemove
|
|
11
|
+
* is converted to a 3D world-space point via this callback and
|
|
12
|
+
* broadcast as `cursor3d`. Each peer then reprojects it through
|
|
13
|
+
* THEIR camera, so cursors stay anchored to the same point in the
|
|
14
|
+
* model regardless of camera perspective.
|
|
15
|
+
*
|
|
16
|
+
* When omitted, the bridge falls back to publishing `cursor2d` only
|
|
17
|
+
* (the legacy fixed-projection behaviour — accurate only when every
|
|
18
|
+
* peer shares the same view, e.g. orthographic plan layouts).
|
|
19
|
+
*
|
|
20
|
+
* Return `null` on a ray miss; the bridge will keep the previously
|
|
21
|
+
* published cursor rather than spamming clears.
|
|
22
|
+
*/
|
|
23
|
+
raycastToWorld?: (screenX: number, screenY: number) => Vec3 | null;
|
|
24
|
+
}
|
|
25
|
+
export type Teardown = () => void;
|
|
26
|
+
export declare function mountPresenceInViewer(opts: MountPresenceInViewerOptions): Teardown;
|
|
27
|
+
//# sourceMappingURL=viewer-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer-bridge.d.ts","sourceRoot":"","sources":["../src/viewer-bridge.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAe,IAAI,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CACpE;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;AAElC,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,4BAA4B,GAAG,QAAQ,CAyDlF"}
|