@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,147 @@
|
|
|
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
|
+
* End-to-end encryption (spec §14, v1.0).
|
|
6
|
+
*
|
|
7
|
+
* Optional: clients in a room share a symmetric per-room key; Y.Doc
|
|
8
|
+
* updates are encrypted with AES-GCM-256 before they hit the
|
|
9
|
+
* websocket. The server only routes ciphertext — it cannot read or
|
|
10
|
+
* mutate the document.
|
|
11
|
+
*
|
|
12
|
+
* Trade-off (documented in the spec): server-side IFCX export is
|
|
13
|
+
* unavailable without key escrow, because the server never sees
|
|
14
|
+
* plaintext. Apps that want escrow can ship the key to a controlled
|
|
15
|
+
* snapshot worker.
|
|
16
|
+
*
|
|
17
|
+
* Wire in:
|
|
18
|
+
* - Key derivation: PBKDF2(password, salt) → AES-GCM-256 key.
|
|
19
|
+
* - Frame format: `[1B version][12B IV][N B ciphertext]`. v1 only.
|
|
20
|
+
* - Key rotation: a new key is derived; both peers are notified;
|
|
21
|
+
* old keys are kept around for `gracePeriodMs` so in-flight frames
|
|
22
|
+
* don't fail.
|
|
23
|
+
* - Member-add: a member is rewrapped — existing members re-derive
|
|
24
|
+
* the room key with the new salt and post the new key envelope to
|
|
25
|
+
* the new member out of band (e.g. via app-level invite link).
|
|
26
|
+
*
|
|
27
|
+
* Implemented against the WebCrypto API so it works in the browser
|
|
28
|
+
* and on Node 22+ without pulling in a crypto dep.
|
|
29
|
+
*/
|
|
30
|
+
const VERSION = 1;
|
|
31
|
+
const IV_LEN = 12;
|
|
32
|
+
/** Cross-runtime crypto handle. */
|
|
33
|
+
const subtle = (() => {
|
|
34
|
+
if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {
|
|
35
|
+
return globalThis.crypto.subtle;
|
|
36
|
+
}
|
|
37
|
+
// Node before 19 needs explicit import.
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
39
|
+
const nodeCrypto = globalThis.require?.('node:crypto');
|
|
40
|
+
if (nodeCrypto?.webcrypto?.subtle)
|
|
41
|
+
return nodeCrypto.webcrypto.subtle;
|
|
42
|
+
throw new Error('@ifc-lite/collab: WebCrypto not available in this runtime');
|
|
43
|
+
})();
|
|
44
|
+
const randomBytes = (n) => {
|
|
45
|
+
const out = new Uint8Array(n);
|
|
46
|
+
if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.getRandomValues) {
|
|
47
|
+
globalThis.crypto.getRandomValues(out);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
throw new Error('@ifc-lite/collab: secure RNG not available in this runtime');
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Derive a room key from a shared password + salt. Salt is typically
|
|
54
|
+
* the room ID hashed; never reuse the same `(password, salt)` pair
|
|
55
|
+
* across rooms.
|
|
56
|
+
*/
|
|
57
|
+
export async function deriveRoomKey(password, salt, options = {}) {
|
|
58
|
+
const iterations = options.iterations ?? 200_000;
|
|
59
|
+
const hash = options.hash ?? 'SHA-256';
|
|
60
|
+
const passwordKey = await subtle.importKey('raw', new TextEncoder().encode(password), { name: 'PBKDF2' }, false, ['deriveKey']);
|
|
61
|
+
const key = await subtle.deriveKey({ name: 'PBKDF2', salt: salt, iterations, hash }, passwordKey, { name: 'AES-GCM', length: 256 },
|
|
62
|
+
/* extractable */ true, ['encrypt', 'decrypt']);
|
|
63
|
+
return { version: 1, key, createdAt: Date.now() };
|
|
64
|
+
}
|
|
65
|
+
/** Generate a random AES-GCM-256 room key (no password). */
|
|
66
|
+
export async function generateRoomKey() {
|
|
67
|
+
const key = await subtle.generateKey({ name: 'AES-GCM', length: 256 },
|
|
68
|
+
/* extractable */ true, ['encrypt', 'decrypt']);
|
|
69
|
+
return { version: 1, key, createdAt: Date.now() };
|
|
70
|
+
}
|
|
71
|
+
/** Export the raw key bytes so apps can persist or rewrap them. */
|
|
72
|
+
export async function exportRoomKey(key) {
|
|
73
|
+
const raw = await subtle.exportKey('raw', key.key);
|
|
74
|
+
return { version: key.version, bytes: new Uint8Array(raw) };
|
|
75
|
+
}
|
|
76
|
+
/** Re-import a previously exported key. */
|
|
77
|
+
export async function importRoomKey(version, bytes) {
|
|
78
|
+
const key = await subtle.importKey('raw', bytes, { name: 'AES-GCM' },
|
|
79
|
+
/* extractable */ true, ['encrypt', 'decrypt']);
|
|
80
|
+
return { version, key, createdAt: Date.now() };
|
|
81
|
+
}
|
|
82
|
+
/** Encrypt a plaintext frame. Adds a 13-byte header (`[ver][iv]`). */
|
|
83
|
+
export async function encryptFrame(plaintext, key) {
|
|
84
|
+
const iv = randomBytes(IV_LEN);
|
|
85
|
+
const ct = await subtle.encrypt({ name: 'AES-GCM', iv: iv }, key.key, plaintext);
|
|
86
|
+
const ctBytes = new Uint8Array(ct);
|
|
87
|
+
const frame = new Uint8Array(1 + IV_LEN + ctBytes.byteLength);
|
|
88
|
+
frame[0] = VERSION;
|
|
89
|
+
frame.set(iv, 1);
|
|
90
|
+
frame.set(ctBytes, 1 + IV_LEN);
|
|
91
|
+
return frame;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Decrypt a frame using `keys`. Tries each key in order so callers can
|
|
95
|
+
* pass `[currentKey, ...recentKeys]` to gracefully decode in-flight
|
|
96
|
+
* frames around a rotation.
|
|
97
|
+
*/
|
|
98
|
+
export async function decryptFrame(frame, keys) {
|
|
99
|
+
if (frame.byteLength < 1 + IV_LEN) {
|
|
100
|
+
throw new Error('@ifc-lite/collab: frame too small');
|
|
101
|
+
}
|
|
102
|
+
if (frame[0] !== VERSION) {
|
|
103
|
+
throw new Error(`@ifc-lite/collab: unsupported frame version ${frame[0]}`);
|
|
104
|
+
}
|
|
105
|
+
const iv = frame.slice(1, 1 + IV_LEN);
|
|
106
|
+
const ct = frame.slice(1 + IV_LEN);
|
|
107
|
+
let lastErr;
|
|
108
|
+
for (const key of keys) {
|
|
109
|
+
try {
|
|
110
|
+
const pt = await subtle.decrypt({ name: 'AES-GCM', iv: iv }, key.key, ct);
|
|
111
|
+
return new Uint8Array(pt);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
lastErr = err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
throw new Error(`@ifc-lite/collab: decryption failed against ${keys.length} key(s): ${lastErr instanceof Error ? lastErr.message : String(lastErr)}`);
|
|
118
|
+
}
|
|
119
|
+
export function createKeyRing(initial, options = {}) {
|
|
120
|
+
const grace = options.gracePeriodMs ?? 30_000;
|
|
121
|
+
const now = options.now ?? Date.now;
|
|
122
|
+
let cur = initial;
|
|
123
|
+
const retired = [];
|
|
124
|
+
const prune = () => {
|
|
125
|
+
const cutoff = now() - grace;
|
|
126
|
+
let dropped = 0;
|
|
127
|
+
while (retired.length > 0 && retired[0].retiredAt < cutoff) {
|
|
128
|
+
retired.shift();
|
|
129
|
+
dropped += 1;
|
|
130
|
+
}
|
|
131
|
+
return dropped;
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
current: () => cur,
|
|
135
|
+
rotate(next) {
|
|
136
|
+
retired.push({ key: cur, retiredAt: now() });
|
|
137
|
+
cur = next;
|
|
138
|
+
prune();
|
|
139
|
+
},
|
|
140
|
+
active() {
|
|
141
|
+
prune();
|
|
142
|
+
return [cur, ...retired.map((r) => r.key)];
|
|
143
|
+
},
|
|
144
|
+
prune,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=e2e.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e.js","sourceRoot":"","sources":["../../src/security/e2e.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CollabSession — the public façade documented in spec §16.2.
|
|
3
|
+
*
|
|
4
|
+
* Glues the Y.Doc, providers, presence, undo, and conflict detector into
|
|
5
|
+
* a single object. Callers don't touch the underlying libraries unless
|
|
6
|
+
* they want to.
|
|
7
|
+
*/
|
|
8
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
9
|
+
import * as Y from 'yjs';
|
|
10
|
+
import { type ConflictDetector, type ConflictListener } from './conflicts/detector.js';
|
|
11
|
+
import { type Presence, type UserIdentity } from './awareness/presence.js';
|
|
12
|
+
import { type WebSocketStatus } from './providers/websocket.js';
|
|
13
|
+
import { type SnapshotOptions } from './snapshot/to-ifcx.js';
|
|
14
|
+
import { type IfcxInput, type SeedOptions } from './snapshot/from-ifcx.js';
|
|
15
|
+
import { type UndoController } from './undo.js';
|
|
16
|
+
export type ProviderKind = 'memory' | 'indexeddb' | 'websocket' | 'indexeddb+websocket';
|
|
17
|
+
export interface CollabSessionOptions {
|
|
18
|
+
roomId: string;
|
|
19
|
+
user: UserIdentity;
|
|
20
|
+
/**
|
|
21
|
+
* Choice of network/persistence stack. `'indexeddb+websocket'` runs both
|
|
22
|
+
* (recommended for browser deployments). `'memory'` is for tests and
|
|
23
|
+
* ephemeral rooms.
|
|
24
|
+
*/
|
|
25
|
+
provider?: ProviderKind;
|
|
26
|
+
/** Required when `provider` involves websocket. */
|
|
27
|
+
serverUrl?: string;
|
|
28
|
+
/** Bearer token forwarded to the websocket server. */
|
|
29
|
+
token?: string;
|
|
30
|
+
/** Override the IDB database name. */
|
|
31
|
+
dbName?: string;
|
|
32
|
+
/** Auto-connect the websocket on construction (default true). */
|
|
33
|
+
connect?: boolean;
|
|
34
|
+
/** Existing Y.Doc to bind to. Defaults to a fresh `createCollabDoc()`. */
|
|
35
|
+
doc?: Y.Doc;
|
|
36
|
+
/** Ws polyfill (e.g. `ws` package in Node tests). */
|
|
37
|
+
WebSocketPolyfill?: unknown;
|
|
38
|
+
/**
|
|
39
|
+
* Disable BroadcastChannel intra-browser sync — every edit goes
|
|
40
|
+
* through the websocket. Forwarded to the websocket provider; ignored
|
|
41
|
+
* for memory / indexeddb-only sessions. Default `false`.
|
|
42
|
+
*/
|
|
43
|
+
disableBc?: boolean;
|
|
44
|
+
/** Presence config knobs. */
|
|
45
|
+
presence?: {
|
|
46
|
+
updateRateHz?: number;
|
|
47
|
+
staleAfterMs?: number;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export interface CollabSession {
|
|
51
|
+
readonly roomId: string;
|
|
52
|
+
readonly doc: Y.Doc;
|
|
53
|
+
readonly clientId: number;
|
|
54
|
+
readonly presence: Presence;
|
|
55
|
+
readonly undoController: UndoController;
|
|
56
|
+
readonly conflicts: ConflictDetector;
|
|
57
|
+
readonly provider: ProviderKind;
|
|
58
|
+
/** Resolves once both persistence and (if applicable) websocket sync have completed. */
|
|
59
|
+
readonly whenSynced: Promise<void>;
|
|
60
|
+
status(): WebSocketStatus | 'memory' | 'indexeddb';
|
|
61
|
+
onStatus(listener: (s: WebSocketStatus | 'memory' | 'indexeddb') => void): () => void;
|
|
62
|
+
/** Seed this session's Y.Doc from an IFCX file. */
|
|
63
|
+
seed(input: IfcxInput, options?: SeedOptions): IfcxFile;
|
|
64
|
+
/** Snapshot the current state to an IFCX object. */
|
|
65
|
+
snapshot(options?: SnapshotOptions): IfcxFile;
|
|
66
|
+
/** Capture a baseline state vector for later layer extraction. */
|
|
67
|
+
captureBaseline(): Uint8Array;
|
|
68
|
+
/** Extract a per-user layer (defaults to *this* peer). */
|
|
69
|
+
extractUserLayer(baseline: Uint8Array, clientId?: number, snapshot?: SnapshotOptions): IfcxFile;
|
|
70
|
+
/** Wrap edits in a Yjs transaction tagged with our local origin. */
|
|
71
|
+
transact<T>(fn: () => T): T;
|
|
72
|
+
/** Local-origin undo via Y.UndoManager. */
|
|
73
|
+
undo(): boolean;
|
|
74
|
+
redo(): boolean;
|
|
75
|
+
onConflict(listener: ConflictListener): () => void;
|
|
76
|
+
dispose(): void;
|
|
77
|
+
}
|
|
78
|
+
export declare function createCollabSession(opts: CollabSessionOptions): Promise<CollabSession>;
|
|
79
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
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 { createCollabDoc, LOCAL_ORIGIN } from './doc/schema.js';
|
|
5
|
+
import { createConflictDetector, } from './conflicts/detector.js';
|
|
6
|
+
import { createPresence } from './awareness/presence.js';
|
|
7
|
+
import { createIndexedDbProvider, createMemoryProvider, } from './providers/indexeddb.js';
|
|
8
|
+
import { createWebSocketProvider, } from './providers/websocket.js';
|
|
9
|
+
import { snapshotToIfcx } from './snapshot/to-ifcx.js';
|
|
10
|
+
import { seedFromIfcx } from './snapshot/from-ifcx.js';
|
|
11
|
+
import { captureBaseline as captureBaselineSV, extractUserLayer as extractLayerForClient, } from './snapshot/layers.js';
|
|
12
|
+
import { createUndoManager } from './undo.js';
|
|
13
|
+
export async function createCollabSession(opts) {
|
|
14
|
+
const doc = opts.doc ?? createCollabDoc();
|
|
15
|
+
const presence = createPresence(doc, opts.presence ?? {});
|
|
16
|
+
presence.setUser(opts.user);
|
|
17
|
+
presence.setStatus('active');
|
|
18
|
+
const undoController = createUndoManager(doc);
|
|
19
|
+
const conflicts = createConflictDetector(doc);
|
|
20
|
+
const providerKind = opts.provider ?? 'memory';
|
|
21
|
+
let idb;
|
|
22
|
+
let ws;
|
|
23
|
+
let currentStatus = providerKind === 'memory' ? 'memory' : 'indexeddb';
|
|
24
|
+
const statusListeners = new Set();
|
|
25
|
+
const setStatus = (s) => {
|
|
26
|
+
if (s === currentStatus)
|
|
27
|
+
return;
|
|
28
|
+
currentStatus = s;
|
|
29
|
+
statusListeners.forEach((l) => l(s));
|
|
30
|
+
};
|
|
31
|
+
const synced = [];
|
|
32
|
+
if (providerKind === 'indexeddb' || providerKind === 'indexeddb+websocket') {
|
|
33
|
+
idb = await createIndexedDbProvider(doc, opts.roomId, { dbName: opts.dbName });
|
|
34
|
+
synced.push(idb.whenSynced);
|
|
35
|
+
}
|
|
36
|
+
else if (providerKind === 'memory') {
|
|
37
|
+
idb = createMemoryProvider(doc, opts.roomId);
|
|
38
|
+
synced.push(idb.whenSynced);
|
|
39
|
+
}
|
|
40
|
+
if (providerKind === 'websocket' || providerKind === 'indexeddb+websocket') {
|
|
41
|
+
if (!opts.serverUrl) {
|
|
42
|
+
throw new Error('@ifc-lite/collab: serverUrl is required for websocket providers');
|
|
43
|
+
}
|
|
44
|
+
ws = await createWebSocketProvider(doc, opts.roomId, opts.serverUrl, {
|
|
45
|
+
WebSocketPolyfill: opts.WebSocketPolyfill,
|
|
46
|
+
token: opts.token,
|
|
47
|
+
awareness: presence.awareness,
|
|
48
|
+
connect: opts.connect ?? true,
|
|
49
|
+
disableBc: opts.disableBc,
|
|
50
|
+
});
|
|
51
|
+
ws.onStatus(setStatus);
|
|
52
|
+
synced.push(ws.whenSynced);
|
|
53
|
+
}
|
|
54
|
+
const session = {
|
|
55
|
+
roomId: opts.roomId,
|
|
56
|
+
doc,
|
|
57
|
+
clientId: doc.clientID,
|
|
58
|
+
presence,
|
|
59
|
+
undoController,
|
|
60
|
+
conflicts,
|
|
61
|
+
provider: providerKind,
|
|
62
|
+
whenSynced: Promise.all(synced).then(() => undefined),
|
|
63
|
+
status: () => currentStatus,
|
|
64
|
+
onStatus(listener) {
|
|
65
|
+
statusListeners.add(listener);
|
|
66
|
+
listener(currentStatus);
|
|
67
|
+
return () => statusListeners.delete(listener);
|
|
68
|
+
},
|
|
69
|
+
seed(input, options) {
|
|
70
|
+
return seedFromIfcx(doc, input, options);
|
|
71
|
+
},
|
|
72
|
+
snapshot(options) {
|
|
73
|
+
return snapshotToIfcx(doc, options);
|
|
74
|
+
},
|
|
75
|
+
captureBaseline() {
|
|
76
|
+
return captureBaselineSV(doc);
|
|
77
|
+
},
|
|
78
|
+
extractUserLayer(baseline, clientId, snapshot) {
|
|
79
|
+
return extractLayerForClient(doc, baseline, {
|
|
80
|
+
clientId: clientId ?? doc.clientID,
|
|
81
|
+
snapshot,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
transact(fn) {
|
|
85
|
+
let result;
|
|
86
|
+
doc.transact(() => {
|
|
87
|
+
result = fn();
|
|
88
|
+
}, LOCAL_ORIGIN);
|
|
89
|
+
return result;
|
|
90
|
+
},
|
|
91
|
+
undo() {
|
|
92
|
+
return undoController.undo();
|
|
93
|
+
},
|
|
94
|
+
redo() {
|
|
95
|
+
return undoController.redo();
|
|
96
|
+
},
|
|
97
|
+
onConflict(listener) {
|
|
98
|
+
return conflicts.onConflict(listener);
|
|
99
|
+
},
|
|
100
|
+
dispose() {
|
|
101
|
+
conflicts.destroy();
|
|
102
|
+
undoController.destroy();
|
|
103
|
+
presence.dispose();
|
|
104
|
+
if (ws)
|
|
105
|
+
ws.destroy();
|
|
106
|
+
if (idb)
|
|
107
|
+
idb.destroy();
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
return session;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IFCX → Y.Doc seeding.
|
|
3
|
+
*
|
|
4
|
+
* Idempotent: seeding the same buffer into a fresh Y.Doc twice produces
|
|
5
|
+
* the same state. Used both at session start and when resetting from a
|
|
6
|
+
* snapshot.
|
|
7
|
+
*/
|
|
8
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
9
|
+
import * as Y from 'yjs';
|
|
10
|
+
export interface SeedOptions {
|
|
11
|
+
/** Origin tag for the seeding transaction. Defaults to SEED_ORIGIN. */
|
|
12
|
+
origin?: unknown;
|
|
13
|
+
/** If true, clear any existing top-level state before seeding. */
|
|
14
|
+
reset?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export type IfcxInput = ArrayBuffer | Uint8Array | string | IfcxFile;
|
|
17
|
+
/** Decode whatever the caller hands us into a parsed IfcxFile. */
|
|
18
|
+
export declare function parseIfcxInput(input: IfcxInput): IfcxFile;
|
|
19
|
+
/**
|
|
20
|
+
* Seed `doc` with the contents of an IFCX file. Returns the parsed file
|
|
21
|
+
* for callers that want to inspect headers / schemas.
|
|
22
|
+
*/
|
|
23
|
+
export declare function seedFromIfcx(doc: Y.Doc, input: IfcxInput, opts?: SeedOptions): IfcxFile;
|
|
24
|
+
//# sourceMappingURL=from-ifcx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-ifcx.d.ts","sourceRoot":"","sources":["../../src/snapshot/from-ifcx.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAIzB,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAErE,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAazD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE,WAAgB,GAAG,QAAQ,CAuD3F"}
|
|
@@ -0,0 +1,93 @@
|
|
|
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 { createEntity } from '../doc/entity.js';
|
|
5
|
+
import { SEED_ORIGIN, assertSchemaInvariants, metaMap } from '../doc/schema.js';
|
|
6
|
+
/** Decode whatever the caller hands us into a parsed IfcxFile. */
|
|
7
|
+
export function parseIfcxInput(input) {
|
|
8
|
+
if (typeof input === 'string') {
|
|
9
|
+
return JSON.parse(input);
|
|
10
|
+
}
|
|
11
|
+
if (input instanceof ArrayBuffer) {
|
|
12
|
+
const text = new TextDecoder().decode(new Uint8Array(input));
|
|
13
|
+
return JSON.parse(text);
|
|
14
|
+
}
|
|
15
|
+
if (input instanceof Uint8Array) {
|
|
16
|
+
const text = new TextDecoder().decode(input);
|
|
17
|
+
return JSON.parse(text);
|
|
18
|
+
}
|
|
19
|
+
return input;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Seed `doc` with the contents of an IFCX file. Returns the parsed file
|
|
23
|
+
* for callers that want to inspect headers / schemas.
|
|
24
|
+
*/
|
|
25
|
+
export function seedFromIfcx(doc, input, opts = {}) {
|
|
26
|
+
const file = parseIfcxInput(input);
|
|
27
|
+
assertSchemaInvariants(doc);
|
|
28
|
+
doc.transact(() => {
|
|
29
|
+
if (opts.reset) {
|
|
30
|
+
const ents = doc.getMap('entities');
|
|
31
|
+
const rels = doc.getMap('relationships');
|
|
32
|
+
const geom = doc.getMap('geometry');
|
|
33
|
+
ents.clear();
|
|
34
|
+
rels.clear();
|
|
35
|
+
geom.clear();
|
|
36
|
+
}
|
|
37
|
+
// Stash file-level metadata so we can re-emit it during snapshotting.
|
|
38
|
+
const meta = metaMap(doc);
|
|
39
|
+
if (file.header)
|
|
40
|
+
meta.set('header', file.header);
|
|
41
|
+
if (file.imports)
|
|
42
|
+
meta.set('imports', file.imports);
|
|
43
|
+
if (file.schemas)
|
|
44
|
+
meta.set('schemas', file.schemas);
|
|
45
|
+
for (const node of file.data ?? []) {
|
|
46
|
+
const path = node.path;
|
|
47
|
+
if (!path)
|
|
48
|
+
continue;
|
|
49
|
+
const attributes = node.attributes ? { ...node.attributes } : {};
|
|
50
|
+
const children = {};
|
|
51
|
+
if (node.children) {
|
|
52
|
+
for (const [role, target] of Object.entries(node.children)) {
|
|
53
|
+
if (typeof target === 'string')
|
|
54
|
+
children[role] = target;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const inherits = {};
|
|
58
|
+
if (node.inherits) {
|
|
59
|
+
for (const [role, target] of Object.entries(node.inherits)) {
|
|
60
|
+
if (typeof target === 'string')
|
|
61
|
+
inherits[role] = target;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const ifcClass = readIfcClass(node.attributes);
|
|
65
|
+
createEntity(doc, path, {
|
|
66
|
+
ifcClass,
|
|
67
|
+
attributes,
|
|
68
|
+
children,
|
|
69
|
+
inherits,
|
|
70
|
+
meta: {
|
|
71
|
+
ifcClass,
|
|
72
|
+
schemaVersion: 'ifc5',
|
|
73
|
+
createdAt: file.header?.timestamp ?? new Date().toISOString(),
|
|
74
|
+
createdBy: file.header?.author,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}, opts.origin ?? SEED_ORIGIN);
|
|
79
|
+
return file;
|
|
80
|
+
}
|
|
81
|
+
/** Read the IfcClass code out of the well-known `bsi::ifc::class` attribute. */
|
|
82
|
+
function readIfcClass(attributes) {
|
|
83
|
+
if (!attributes)
|
|
84
|
+
return undefined;
|
|
85
|
+
const cls = attributes['bsi::ifc::class'];
|
|
86
|
+
if (cls && typeof cls === 'object' && 'code' in cls) {
|
|
87
|
+
const code = cls.code;
|
|
88
|
+
if (typeof code === 'string')
|
|
89
|
+
return code;
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=from-ifcx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-ifcx.js","sourceRoot":"","sources":["../../src/snapshot/from-ifcx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { seedFromIfcx, parseIfcxInput, type SeedOptions, type IfcxInput, } from './from-ifcx.js';
|
|
2
|
+
export { snapshotToIfcx, serializeIfcx, type SnapshotOptions } from './to-ifcx.js';
|
|
3
|
+
export { captureBaseline, extractUserLayer, filterUpdateByClient, } from './layers.js';
|
|
4
|
+
export { extractMinimalLayer, type ExtractMinimalLayerOptions, } from './minimal-layer.js';
|
|
5
|
+
export { runSnapshotWorker, type WorkerRequest, type WorkerResponse, type WorkerScopeLike, } from './worker.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,YAAY,EACZ,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
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 { seedFromIfcx, parseIfcxInput, } from './from-ifcx.js';
|
|
5
|
+
export { snapshotToIfcx, serializeIfcx } from './to-ifcx.js';
|
|
6
|
+
export { captureBaseline, extractUserLayer, filterUpdateByClient, } from './layers.js';
|
|
7
|
+
export { extractMinimalLayer, } from './minimal-layer.js';
|
|
8
|
+
export { runSnapshotWorker, } from './worker.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/snapshot/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,OAAO,EACL,YAAY,EACZ,cAAc,GAGf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,aAAa,EAAwB,MAAM,cAAc,CAAC;AACnF,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,mBAAmB,GAEpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,GAIlB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-user layer extraction.
|
|
3
|
+
*
|
|
4
|
+
* Composed with the baseline they fork from, these layers reproduce the
|
|
5
|
+
* full live state — that's the IFCX layer composition contract from spec
|
|
6
|
+
* §2 / §10.
|
|
7
|
+
*
|
|
8
|
+
* v0.1 strategy: "snapshot of current state, scoped to one client" by
|
|
9
|
+
* applying the *full* update history to a fresh replay doc, not just the
|
|
10
|
+
* post-baseline diff. The diff-only approach can't render IFCX nodes for
|
|
11
|
+
* entities created before the baseline (their parent struct isn't in the
|
|
12
|
+
* filtered update). The full-history approach correctly renders any
|
|
13
|
+
* entity the client has touched, with all of that client's writes
|
|
14
|
+
* reflected — at the cost of also including their pre-baseline writes.
|
|
15
|
+
*
|
|
16
|
+
* v0.7 (branching) introduces a proper layer composer that produces
|
|
17
|
+
* minimal-diff layers; the v0.1 implementation is the foundation.
|
|
18
|
+
*/
|
|
19
|
+
import type { IfcxFile } from '@ifc-lite/ifcx';
|
|
20
|
+
import * as Y from 'yjs';
|
|
21
|
+
import { type SnapshotOptions } from './to-ifcx.js';
|
|
22
|
+
export interface LayerExtractionOptions {
|
|
23
|
+
/** clientID to filter to. If omitted, all clients are included. */
|
|
24
|
+
clientId?: number;
|
|
25
|
+
/** Forwarded to `snapshotToIfcx` for header/timestamp control. */
|
|
26
|
+
snapshot?: SnapshotOptions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Capture a baseline state vector. Composed-with-baseline IFCX layer
|
|
30
|
+
* composition is the v0.7 mode; for v0.1 we still expose this so callers
|
|
31
|
+
* can pin a "before" point for downstream tooling.
|
|
32
|
+
*/
|
|
33
|
+
export declare function captureBaseline(doc: Y.Doc): Uint8Array;
|
|
34
|
+
/**
|
|
35
|
+
* Extract a per-user IFCX layer from `doc`.
|
|
36
|
+
*
|
|
37
|
+
* Replays `doc`'s full state filtered by `clientId` onto a fresh doc and
|
|
38
|
+
* snapshots that. The resulting IFCX is a complete description of every
|
|
39
|
+
* entity the chosen client touched, with that client's view of the
|
|
40
|
+
* attributes.
|
|
41
|
+
*
|
|
42
|
+
* `baseline` is currently unused at the per-write level (the v0.1
|
|
43
|
+
* limitation noted above) but kept in the signature so callers don't have
|
|
44
|
+
* to refactor when the v0.7 differential mode lands.
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractUserLayer(doc: Y.Doc, baseline: Uint8Array | undefined, options?: LayerExtractionOptions): IfcxFile;
|
|
47
|
+
/**
|
|
48
|
+
* Filter a Y update so it only contains operations from `clientId`.
|
|
49
|
+
*
|
|
50
|
+
* We use Yjs's diff-against-state-vector machinery: build a state
|
|
51
|
+
* vector that has every client *except* `clientId` advanced past the
|
|
52
|
+
* end of the input update, then `diffUpdate` returns just `clientId`'s
|
|
53
|
+
* structs.
|
|
54
|
+
*/
|
|
55
|
+
export declare function filterUpdateByClient(update: Uint8Array, clientId: number): Uint8Array;
|
|
56
|
+
//# sourceMappingURL=layers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/snapshot/layers.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,UAAU,CAEtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,OAAO,GAAE,sBAA2B,GACnC,QAAQ,CAcV;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAUrF"}
|