@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.
Files changed (219) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +92 -0
  3. package/dist/awareness/agent.d.ts +36 -0
  4. package/dist/awareness/agent.d.ts.map +1 -0
  5. package/dist/awareness/agent.js +39 -0
  6. package/dist/awareness/agent.js.map +1 -0
  7. package/dist/awareness/color.d.ts +31 -0
  8. package/dist/awareness/color.d.ts.map +1 -0
  9. package/dist/awareness/color.js +61 -0
  10. package/dist/awareness/color.js.map +1 -0
  11. package/dist/awareness/index.d.ts +6 -0
  12. package/dist/awareness/index.d.ts.map +1 -0
  13. package/dist/awareness/index.js +9 -0
  14. package/dist/awareness/index.js.map +1 -0
  15. package/dist/awareness/overlay.d.ts +59 -0
  16. package/dist/awareness/overlay.d.ts.map +1 -0
  17. package/dist/awareness/overlay.js +110 -0
  18. package/dist/awareness/overlay.js.map +1 -0
  19. package/dist/awareness/presence.d.ts +95 -0
  20. package/dist/awareness/presence.d.ts.map +1 -0
  21. package/dist/awareness/presence.js +114 -0
  22. package/dist/awareness/presence.js.map +1 -0
  23. package/dist/awareness/render.d.ts +58 -0
  24. package/dist/awareness/render.d.ts.map +1 -0
  25. package/dist/awareness/render.js +66 -0
  26. package/dist/awareness/render.js.map +1 -0
  27. package/dist/branch/branch-tree.d.ts +40 -0
  28. package/dist/branch/branch-tree.d.ts.map +1 -0
  29. package/dist/branch/branch-tree.js +66 -0
  30. package/dist/branch/branch-tree.js.map +1 -0
  31. package/dist/branch/branch.d.ts +44 -0
  32. package/dist/branch/branch.d.ts.map +1 -0
  33. package/dist/branch/branch.js +109 -0
  34. package/dist/branch/branch.js.map +1 -0
  35. package/dist/branch/history-automerge.d.ts +31 -0
  36. package/dist/branch/history-automerge.d.ts.map +1 -0
  37. package/dist/branch/history-automerge.js +237 -0
  38. package/dist/branch/history-automerge.js.map +1 -0
  39. package/dist/branch/history.d.ts +147 -0
  40. package/dist/branch/history.d.ts.map +1 -0
  41. package/dist/branch/history.js +223 -0
  42. package/dist/branch/history.js.map +1 -0
  43. package/dist/branch/index.d.ts +5 -0
  44. package/dist/branch/index.d.ts.map +1 -0
  45. package/dist/branch/index.js +8 -0
  46. package/dist/branch/index.js.map +1 -0
  47. package/dist/conflicts/detector.d.ts +52 -0
  48. package/dist/conflicts/detector.d.ts.map +1 -0
  49. package/dist/conflicts/detector.js +226 -0
  50. package/dist/conflicts/detector.js.map +1 -0
  51. package/dist/conflicts/index.d.ts +3 -0
  52. package/dist/conflicts/index.d.ts.map +1 -0
  53. package/dist/conflicts/index.js +6 -0
  54. package/dist/conflicts/index.js.map +1 -0
  55. package/dist/conflicts/ui-bridge.d.ts +80 -0
  56. package/dist/conflicts/ui-bridge.d.ts.map +1 -0
  57. package/dist/conflicts/ui-bridge.js +126 -0
  58. package/dist/conflicts/ui-bridge.js.map +1 -0
  59. package/dist/doc/entity.d.ts +84 -0
  60. package/dist/doc/entity.d.ts.map +1 -0
  61. package/dist/doc/entity.js +345 -0
  62. package/dist/doc/entity.js.map +1 -0
  63. package/dist/doc/geometry.d.ts +39 -0
  64. package/dist/doc/geometry.d.ts.map +1 -0
  65. package/dist/doc/geometry.js +99 -0
  66. package/dist/doc/geometry.js.map +1 -0
  67. package/dist/doc/index.d.ts +8 -0
  68. package/dist/doc/index.d.ts.map +1 -0
  69. package/dist/doc/index.js +11 -0
  70. package/dist/doc/index.js.map +1 -0
  71. package/dist/doc/migration-ifc4-to-ifc4x3.d.ts +21 -0
  72. package/dist/doc/migration-ifc4-to-ifc4x3.d.ts.map +1 -0
  73. package/dist/doc/migration-ifc4-to-ifc4x3.js +55 -0
  74. package/dist/doc/migration-ifc4-to-ifc4x3.js.map +1 -0
  75. package/dist/doc/relationship.d.ts +27 -0
  76. package/dist/doc/relationship.d.ts.map +1 -0
  77. package/dist/doc/relationship.js +110 -0
  78. package/dist/doc/relationship.js.map +1 -0
  79. package/dist/doc/schema-version.d.ts +47 -0
  80. package/dist/doc/schema-version.d.ts.map +1 -0
  81. package/dist/doc/schema-version.js +41 -0
  82. package/dist/doc/schema-version.js.map +1 -0
  83. package/dist/doc/schema.d.ts +131 -0
  84. package/dist/doc/schema.d.ts.map +1 -0
  85. package/dist/doc/schema.js +117 -0
  86. package/dist/doc/schema.js.map +1 -0
  87. package/dist/doc/units.d.ts +45 -0
  88. package/dist/doc/units.d.ts.map +1 -0
  89. package/dist/doc/units.js +120 -0
  90. package/dist/doc/units.js.map +1 -0
  91. package/dist/federation/bridge.d.ts +34 -0
  92. package/dist/federation/bridge.d.ts.map +1 -0
  93. package/dist/federation/bridge.js +52 -0
  94. package/dist/federation/bridge.js.map +1 -0
  95. package/dist/federation/index.d.ts +4 -0
  96. package/dist/federation/index.d.ts.map +1 -0
  97. package/dist/federation/index.js +7 -0
  98. package/dist/federation/index.js.map +1 -0
  99. package/dist/federation/resolver.d.ts +58 -0
  100. package/dist/federation/resolver.d.ts.map +1 -0
  101. package/dist/federation/resolver.js +43 -0
  102. package/dist/federation/resolver.js.map +1 -0
  103. package/dist/federation/session.d.ts +79 -0
  104. package/dist/federation/session.d.ts.map +1 -0
  105. package/dist/federation/session.js +126 -0
  106. package/dist/federation/session.js.map +1 -0
  107. package/dist/geometry/blob-store.d.ts +106 -0
  108. package/dist/geometry/blob-store.d.ts.map +1 -0
  109. package/dist/geometry/blob-store.js +266 -0
  110. package/dist/geometry/blob-store.js.map +1 -0
  111. package/dist/geometry/csg.d.ts +63 -0
  112. package/dist/geometry/csg.d.ts.map +1 -0
  113. package/dist/geometry/csg.js +101 -0
  114. package/dist/geometry/csg.js.map +1 -0
  115. package/dist/geometry/determinism.d.ts +45 -0
  116. package/dist/geometry/determinism.d.ts.map +1 -0
  117. package/dist/geometry/determinism.js +92 -0
  118. package/dist/geometry/determinism.js.map +1 -0
  119. package/dist/geometry/gc.d.ts +63 -0
  120. package/dist/geometry/gc.d.ts.map +1 -0
  121. package/dist/geometry/gc.js +109 -0
  122. package/dist/geometry/gc.js.map +1 -0
  123. package/dist/geometry/index.d.ts +6 -0
  124. package/dist/geometry/index.d.ts.map +1 -0
  125. package/dist/geometry/index.js +9 -0
  126. package/dist/geometry/index.js.map +1 -0
  127. package/dist/geometry/parametric.d.ts +92 -0
  128. package/dist/geometry/parametric.d.ts.map +1 -0
  129. package/dist/geometry/parametric.js +200 -0
  130. package/dist/geometry/parametric.js.map +1 -0
  131. package/dist/index.d.ts +27 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +46 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/mutations/bind.d.ts +56 -0
  136. package/dist/mutations/bind.d.ts.map +1 -0
  137. package/dist/mutations/bind.js +68 -0
  138. package/dist/mutations/bind.js.map +1 -0
  139. package/dist/mutations/index.d.ts +2 -0
  140. package/dist/mutations/index.d.ts.map +1 -0
  141. package/dist/mutations/index.js +5 -0
  142. package/dist/mutations/index.js.map +1 -0
  143. package/dist/perf/benchmark.d.ts +25 -0
  144. package/dist/perf/benchmark.d.ts.map +1 -0
  145. package/dist/perf/benchmark.js +97 -0
  146. package/dist/perf/benchmark.js.map +1 -0
  147. package/dist/perf/index.d.ts +3 -0
  148. package/dist/perf/index.d.ts.map +1 -0
  149. package/dist/perf/index.js +6 -0
  150. package/dist/perf/index.js.map +1 -0
  151. package/dist/perf/latency.d.ts +39 -0
  152. package/dist/perf/latency.d.ts.map +1 -0
  153. package/dist/perf/latency.js +79 -0
  154. package/dist/perf/latency.js.map +1 -0
  155. package/dist/privacy.d.ts +45 -0
  156. package/dist/privacy.d.ts.map +1 -0
  157. package/dist/privacy.js +66 -0
  158. package/dist/privacy.js.map +1 -0
  159. package/dist/providers/indexeddb.d.ts +37 -0
  160. package/dist/providers/indexeddb.d.ts.map +1 -0
  161. package/dist/providers/indexeddb.js +45 -0
  162. package/dist/providers/indexeddb.js.map +1 -0
  163. package/dist/providers/webrtc.d.ts +40 -0
  164. package/dist/providers/webrtc.d.ts.map +1 -0
  165. package/dist/providers/webrtc.js +81 -0
  166. package/dist/providers/webrtc.js.map +1 -0
  167. package/dist/providers/websocket.d.ts +45 -0
  168. package/dist/providers/websocket.d.ts.map +1 -0
  169. package/dist/providers/websocket.js +56 -0
  170. package/dist/providers/websocket.js.map +1 -0
  171. package/dist/security/e2e.d.ts +54 -0
  172. package/dist/security/e2e.d.ts.map +1 -0
  173. package/dist/security/e2e.js +147 -0
  174. package/dist/security/e2e.js.map +1 -0
  175. package/dist/security/index.d.ts +2 -0
  176. package/dist/security/index.d.ts.map +1 -0
  177. package/dist/security/index.js +5 -0
  178. package/dist/security/index.js.map +1 -0
  179. package/dist/session.d.ts +79 -0
  180. package/dist/session.d.ts.map +1 -0
  181. package/dist/session.js +112 -0
  182. package/dist/session.js.map +1 -0
  183. package/dist/snapshot/from-ifcx.d.ts +24 -0
  184. package/dist/snapshot/from-ifcx.d.ts.map +1 -0
  185. package/dist/snapshot/from-ifcx.js +93 -0
  186. package/dist/snapshot/from-ifcx.js.map +1 -0
  187. package/dist/snapshot/index.d.ts +6 -0
  188. package/dist/snapshot/index.d.ts.map +1 -0
  189. package/dist/snapshot/index.js +9 -0
  190. package/dist/snapshot/index.js.map +1 -0
  191. package/dist/snapshot/layers.d.ts +56 -0
  192. package/dist/snapshot/layers.d.ts.map +1 -0
  193. package/dist/snapshot/layers.js +82 -0
  194. package/dist/snapshot/layers.js.map +1 -0
  195. package/dist/snapshot/minimal-layer.d.ts +40 -0
  196. package/dist/snapshot/minimal-layer.d.ts.map +1 -0
  197. package/dist/snapshot/minimal-layer.js +123 -0
  198. package/dist/snapshot/minimal-layer.js.map +1 -0
  199. package/dist/snapshot/to-ifcx.d.ts +26 -0
  200. package/dist/snapshot/to-ifcx.d.ts.map +1 -0
  201. package/dist/snapshot/to-ifcx.js +54 -0
  202. package/dist/snapshot/to-ifcx.js.map +1 -0
  203. package/dist/snapshot/worker.d.ts +45 -0
  204. package/dist/snapshot/worker.d.ts.map +1 -0
  205. package/dist/snapshot/worker.js +73 -0
  206. package/dist/snapshot/worker.js.map +1 -0
  207. package/dist/sync/room.d.ts +15 -0
  208. package/dist/sync/room.d.ts.map +1 -0
  209. package/dist/sync/room.js +20 -0
  210. package/dist/sync/room.js.map +1 -0
  211. package/dist/undo.d.ts +25 -0
  212. package/dist/undo.d.ts.map +1 -0
  213. package/dist/undo.js +37 -0
  214. package/dist/undo.js.map +1 -0
  215. package/dist/viewer-bridge.d.ts +27 -0
  216. package/dist/viewer-bridge.d.ts.map +1 -0
  217. package/dist/viewer-bridge.js +82 -0
  218. package/dist/viewer-bridge.js.map +1 -0
  219. 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":"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"}
@@ -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
@@ -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"}