@liveblocks/yjs 1.5.3 → 1.6.0-subdocs2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -27,20 +27,52 @@ declare class Awareness extends Observable<unknown> {
27
27
  setLocalStateField(field: string, value: JsonObject | null): void;
28
28
  getStates(): Map<number, unknown>;
29
29
  }
30
+
31
+ declare class yDocHandler extends Observable<unknown> {
32
+ private unsubscribers;
33
+ private _synced;
34
+ private doc;
35
+ private updateRoomDoc;
36
+ private fetchRoomDoc;
37
+ constructor({ doc, isRoot, updateDoc, fetchDoc, }: {
38
+ doc: Y.Doc;
39
+ isRoot: boolean;
40
+ updateDoc: (update: string, guid?: string) => void;
41
+ fetchDoc: (vector: string, guid?: string) => void;
42
+ });
43
+ handleServerUpdate: ({ update, stateVector, }: {
44
+ update: string;
45
+ stateVector: string | null;
46
+ }) => void;
47
+ syncDoc: () => void;
48
+ get synced(): boolean;
49
+ set synced(state: boolean);
50
+ private updateHandler;
51
+ destroy(): void;
52
+ }
53
+
54
+ declare type ProviderOptions = {
55
+ autoloadSubdocs: boolean;
56
+ };
30
57
  declare class LiveblocksProvider<P extends JsonObject, S extends LsonObject, U extends BaseUserMeta, E extends Json> extends Observable<unknown> {
31
58
  private room;
32
- private doc;
59
+ private rootDoc;
60
+ private options;
33
61
  private unsubscribers;
34
62
  awareness: Awareness;
35
- private _synced;
36
- constructor(room: Room<P, S, U, E>, doc: Y.Doc);
63
+ rootDocHandler: yDocHandler;
64
+ subdocHandlers: Map<string, yDocHandler>;
65
+ constructor(room: Room<P, S, U, E>, doc: Y.Doc, options?: ProviderOptions | undefined);
66
+ private handleSubdocs;
67
+ private updateDoc;
68
+ private fetchDoc;
69
+ private createSubdocHandler;
70
+ loadSubdoc: (guid: string) => boolean;
37
71
  private syncDoc;
38
72
  get synced(): boolean;
39
- set synced(state: boolean);
40
- private updateHandler;
41
73
  destroy(): void;
42
74
  disconnect(): void;
43
75
  connect(): void;
44
76
  }
45
77
 
46
- export { Awareness, LiveblocksProvider as default };
78
+ export { LiveblocksProvider as default };
package/dist/index.d.ts CHANGED
@@ -27,20 +27,52 @@ declare class Awareness extends Observable<unknown> {
27
27
  setLocalStateField(field: string, value: JsonObject | null): void;
28
28
  getStates(): Map<number, unknown>;
29
29
  }
30
+
31
+ declare class yDocHandler extends Observable<unknown> {
32
+ private unsubscribers;
33
+ private _synced;
34
+ private doc;
35
+ private updateRoomDoc;
36
+ private fetchRoomDoc;
37
+ constructor({ doc, isRoot, updateDoc, fetchDoc, }: {
38
+ doc: Y.Doc;
39
+ isRoot: boolean;
40
+ updateDoc: (update: string, guid?: string) => void;
41
+ fetchDoc: (vector: string, guid?: string) => void;
42
+ });
43
+ handleServerUpdate: ({ update, stateVector, }: {
44
+ update: string;
45
+ stateVector: string | null;
46
+ }) => void;
47
+ syncDoc: () => void;
48
+ get synced(): boolean;
49
+ set synced(state: boolean);
50
+ private updateHandler;
51
+ destroy(): void;
52
+ }
53
+
54
+ declare type ProviderOptions = {
55
+ autoloadSubdocs: boolean;
56
+ };
30
57
  declare class LiveblocksProvider<P extends JsonObject, S extends LsonObject, U extends BaseUserMeta, E extends Json> extends Observable<unknown> {
31
58
  private room;
32
- private doc;
59
+ private rootDoc;
60
+ private options;
33
61
  private unsubscribers;
34
62
  awareness: Awareness;
35
- private _synced;
36
- constructor(room: Room<P, S, U, E>, doc: Y.Doc);
63
+ rootDocHandler: yDocHandler;
64
+ subdocHandlers: Map<string, yDocHandler>;
65
+ constructor(room: Room<P, S, U, E>, doc: Y.Doc, options?: ProviderOptions | undefined);
66
+ private handleSubdocs;
67
+ private updateDoc;
68
+ private fetchDoc;
69
+ private createSubdocHandler;
70
+ loadSubdoc: (guid: string) => boolean;
37
71
  private syncDoc;
38
72
  get synced(): boolean;
39
- set synced(state: boolean);
40
- private updateHandler;
41
73
  destroy(): void;
42
74
  disconnect(): void;
43
75
  connect(): void;
44
76
  }
45
77
 
46
- export { Awareness, LiveblocksProvider as default };
78
+ export { LiveblocksProvider as default };
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/index.ts
2
2
  var _core = require('@liveblocks/core');
3
- var _jsbase64 = require('js-base64');
4
3
 
5
4
  // ../../node_modules/lib0/map.js
6
5
  var create = () => /* @__PURE__ */ new Map();
@@ -72,16 +71,7 @@ var Observable = class {
72
71
  }
73
72
  };
74
73
 
75
- // src/index.ts
76
- var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
77
-
78
- // src/version.ts
79
- var PKG_NAME = "@liveblocks/yjs";
80
- var PKG_VERSION = "1.5.3";
81
- var PKG_FORMAT = "cjs";
82
-
83
- // src/index.ts
84
- _core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
74
+ // src/awareness.ts
85
75
  var Y_PRESENCE_KEY = "__yjs";
86
76
  var Awareness = class extends Observable {
87
77
  constructor(doc, room) {
@@ -131,13 +121,13 @@ var Awareness = class extends Observable {
131
121
  return presence[Y_PRESENCE_KEY];
132
122
  }
133
123
  setLocalState(state) {
134
- const presence = _optionalChain([this, 'access', _ => _.room, 'access', _2 => _2.getSelf, 'call', _3 => _3(), 'optionalAccess', _4 => _4.presence, 'access', _5 => _5[Y_PRESENCE_KEY]]);
124
+ const presence = _optionalChain([this, 'access', _2 => _2.room, 'access', _3 => _3.getSelf, 'call', _4 => _4(), 'optionalAccess', _5 => _5.presence, 'access', _6 => _6[Y_PRESENCE_KEY]]);
135
125
  this.room.updatePresence({
136
126
  __yjs: { ...presence || {}, ...state || {} }
137
127
  });
138
128
  }
139
129
  setLocalStateField(field, value) {
140
- const presence = _optionalChain([this, 'access', _6 => _6.room, 'access', _7 => _7.getSelf, 'call', _8 => _8(), 'optionalAccess', _9 => _9.presence, 'access', _10 => _10[Y_PRESENCE_KEY]]);
130
+ const presence = _optionalChain([this, 'access', _7 => _7.room, 'access', _8 => _8.getSelf, 'call', _9 => _9(), 'optionalAccess', _10 => _10.presence, 'access', _11 => _11[Y_PRESENCE_KEY]]);
141
131
  const update = { [field]: value };
142
132
  this.room.updatePresence({
143
133
  __yjs: { ...presence || {}, ...update }
@@ -158,80 +148,211 @@ var Awareness = class extends Observable {
158
148
  return states;
159
149
  }
160
150
  };
161
- var LiveblocksProvider = class extends Observable {
162
- constructor(room, doc) {
151
+
152
+ // src/doc.ts
153
+ var _jsbase64 = require('js-base64');
154
+ var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
155
+ var yDocHandler = class extends Observable {
156
+ constructor({
157
+ doc,
158
+ isRoot,
159
+ updateDoc,
160
+ fetchDoc
161
+ }) {
163
162
  super();
164
163
  this.unsubscribers = [];
165
164
  this._synced = false;
165
+ this.handleServerUpdate = ({
166
+ update,
167
+ stateVector
168
+ }) => {
169
+ Y.applyUpdate(this.doc, _jsbase64.Base64.toUint8Array(update), "backend");
170
+ if (stateVector) {
171
+ try {
172
+ const localUpdate = Y.encodeStateAsUpdate(
173
+ this.doc,
174
+ _jsbase64.Base64.toUint8Array(stateVector)
175
+ );
176
+ this.updateRoomDoc(_jsbase64.Base64.fromUint8Array(localUpdate));
177
+ } catch (e) {
178
+ console.warn(e);
179
+ }
180
+ this.synced = true;
181
+ }
182
+ };
166
183
  this.syncDoc = () => {
167
184
  this.synced = false;
168
- this.doc.clientID = _optionalChain([this, 'access', _11 => _11.room, 'access', _12 => _12.getSelf, 'call', _13 => _13(), 'optionalAccess', _14 => _14.connectionId]) || this.doc.clientID;
169
- this.awareness.clientID = this.doc.clientID;
170
185
  const encodedVector = _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(this.doc));
171
- this.room.fetchYDoc(encodedVector);
186
+ this.fetchRoomDoc(encodedVector);
172
187
  };
173
188
  this.updateHandler = (update, origin) => {
174
189
  if (origin !== "backend") {
175
190
  const encodedUpdate = _jsbase64.Base64.fromUint8Array(update);
176
- this.room.updateYDoc(encodedUpdate);
191
+ this.updateRoomDoc(encodedUpdate);
177
192
  }
178
193
  };
179
194
  this.doc = doc;
195
+ this.doc.on("update", this.updateHandler);
196
+ this.updateRoomDoc = (update) => {
197
+ updateDoc(update, isRoot ? void 0 : this.doc.guid);
198
+ };
199
+ this.fetchRoomDoc = (vector) => {
200
+ fetchDoc(vector, isRoot ? void 0 : this.doc.guid);
201
+ };
202
+ this.syncDoc();
203
+ }
204
+ // The sync'd property is required by some provider implementations
205
+ get synced() {
206
+ return this._synced;
207
+ }
208
+ set synced(state) {
209
+ if (this._synced !== state) {
210
+ this._synced = state;
211
+ this.emit("synced", [state]);
212
+ this.emit("sync", [state]);
213
+ }
214
+ }
215
+ destroy() {
216
+ this.doc.off("update", this.updateHandler);
217
+ this.unsubscribers.forEach((unsub) => unsub());
218
+ this._observers = /* @__PURE__ */ new Map();
219
+ this.doc.destroy();
220
+ }
221
+ };
222
+
223
+ // src/version.ts
224
+ var PKG_NAME = "@liveblocks/yjs";
225
+ var PKG_VERSION = "1.6.0-subdocs2";
226
+ var PKG_FORMAT = "cjs";
227
+
228
+ // src/index.ts
229
+ _core.detectDupes.call(void 0, PKG_NAME, PKG_VERSION, PKG_FORMAT);
230
+ var DefaultOptions = {
231
+ autoloadSubdocs: false
232
+ };
233
+ var LiveblocksProvider = class extends Observable {
234
+ constructor(room, doc, options = DefaultOptions) {
235
+ super();
236
+ this.unsubscribers = [];
237
+ this.subdocHandlers = /* @__PURE__ */ new Map();
238
+ this.handleSubdocs = ({
239
+ loaded,
240
+ removed,
241
+ added
242
+ }) => {
243
+ loaded.forEach(this.createSubdocHandler);
244
+ if (this.options.autoloadSubdocs) {
245
+ for (const subdoc of added) {
246
+ if (!this.subdocHandlers.has(subdoc.guid)) {
247
+ subdoc.load();
248
+ }
249
+ }
250
+ }
251
+ for (const subdoc of removed) {
252
+ if (this.subdocHandlers.has(subdoc.guid)) {
253
+ _optionalChain([this, 'access', _12 => _12.subdocHandlers, 'access', _13 => _13.get, 'call', _14 => _14(subdoc.guid), 'optionalAccess', _15 => _15.destroy, 'call', _16 => _16()]);
254
+ this.subdocHandlers.delete(subdoc.guid);
255
+ }
256
+ }
257
+ };
258
+ this.updateDoc = (update, guid) => {
259
+ this.room.updateYDoc(update, guid);
260
+ };
261
+ this.fetchDoc = (vector, guid) => {
262
+ this.room.fetchYDoc(vector, guid);
263
+ };
264
+ this.createSubdocHandler = (subdoc) => {
265
+ if (this.subdocHandlers.has(subdoc.guid)) {
266
+ _optionalChain([this, 'access', _17 => _17.subdocHandlers, 'access', _18 => _18.get, 'call', _19 => _19(subdoc.guid), 'optionalAccess', _20 => _20.syncDoc, 'call', _21 => _21()]);
267
+ return;
268
+ }
269
+ const handler = new yDocHandler({
270
+ doc: subdoc,
271
+ isRoot: false,
272
+ updateDoc: this.updateDoc,
273
+ fetchDoc: this.fetchDoc
274
+ });
275
+ this.subdocHandlers.set(subdoc.guid, handler);
276
+ };
277
+ // attempt to load a subdoc of a given guid
278
+ this.loadSubdoc = (guid) => {
279
+ for (const subdoc of this.rootDoc.subdocs) {
280
+ if (subdoc.guid === guid) {
281
+ subdoc.load();
282
+ return true;
283
+ }
284
+ }
285
+ return false;
286
+ };
287
+ this.syncDoc = () => {
288
+ this.rootDoc.clientID = _optionalChain([this, 'access', _22 => _22.room, 'access', _23 => _23.getSelf, 'call', _24 => _24(), 'optionalAccess', _25 => _25.connectionId]) || this.rootDoc.clientID;
289
+ this.awareness.clientID = this.rootDoc.clientID;
290
+ this.rootDocHandler.syncDoc();
291
+ for (const [_, handler] of this.subdocHandlers) {
292
+ handler.syncDoc();
293
+ }
294
+ };
295
+ this.rootDoc = doc;
180
296
  this.room = room;
181
- const connectionId = _optionalChain([this, 'access', _15 => _15.room, 'access', _16 => _16.getSelf, 'call', _17 => _17(), 'optionalAccess', _18 => _18.connectionId]);
297
+ this.options = options;
298
+ this.rootDocHandler = new yDocHandler({
299
+ doc,
300
+ isRoot: true,
301
+ updateDoc: this.updateDoc,
302
+ fetchDoc: this.fetchDoc
303
+ });
304
+ const connectionId = _optionalChain([this, 'access', _26 => _26.room, 'access', _27 => _27.getSelf, 'call', _28 => _28(), 'optionalAccess', _29 => _29.connectionId]);
182
305
  if (connectionId) {
183
- this.doc.clientID = connectionId;
306
+ this.rootDoc.clientID = connectionId;
184
307
  }
185
- this.awareness = new Awareness(this.doc, this.room);
186
- this.doc.on("update", this.updateHandler);
308
+ this.awareness = new Awareness(this.rootDoc, this.room);
187
309
  this.unsubscribers.push(
188
310
  this.room.events.status.subscribe((status) => {
189
311
  if (status === "connected") {
190
- this.syncDoc();
312
+ this.rootDocHandler.syncDoc();
191
313
  } else {
192
- this.synced = false;
314
+ this.rootDocHandler.synced = false;
193
315
  }
194
316
  })
195
317
  );
196
318
  this.unsubscribers.push(
197
319
  this.room.events.ydoc.subscribe((message) => {
198
- const { type, update } = message;
320
+ const { type } = message;
199
321
  if (type === _core.ClientMsgCode.UPDATE_YDOC) {
200
322
  return;
201
323
  }
202
- Y.applyUpdate(this.doc, _jsbase64.Base64.toUint8Array(update), "backend");
203
- const { stateVector } = message;
204
- if (stateVector) {
205
- try {
206
- const localUpdate = Y.encodeStateAsUpdate(
207
- this.doc,
208
- _jsbase64.Base64.toUint8Array(stateVector)
209
- );
210
- this.room.updateYDoc(_jsbase64.Base64.fromUint8Array(localUpdate));
211
- } catch (e) {
212
- console.warn(e);
213
- }
214
- this.synced = true;
324
+ const { stateVector, update, guid } = message;
325
+ if (guid !== void 0) {
326
+ _optionalChain([this, 'access', _30 => _30.subdocHandlers, 'access', _31 => _31.get, 'call', _32 => _32(guid), 'optionalAccess', _33 => _33.handleServerUpdate, 'call', _34 => _34({ update, stateVector })]);
327
+ } else {
328
+ this.rootDocHandler.handleServerUpdate({ update, stateVector });
215
329
  }
216
330
  })
217
331
  );
332
+ this.rootDocHandler.on("synced", () => {
333
+ const state = this.rootDocHandler.synced;
334
+ for (const [_, handler] of this.subdocHandlers) {
335
+ handler.syncDoc();
336
+ }
337
+ this.emit("synced", [state]);
338
+ this.emit("sync", [state]);
339
+ });
340
+ this.rootDoc.on("subdocs", this.handleSubdocs);
218
341
  this.syncDoc();
219
342
  }
220
343
  // The sync'd property is required by some provider implementations
221
344
  get synced() {
222
- return this._synced;
223
- }
224
- set synced(state) {
225
- if (this._synced !== state) {
226
- this._synced = state;
227
- this.emit("synced", [state]);
228
- this.emit("sync", [state]);
229
- }
345
+ return this.rootDocHandler.synced;
230
346
  }
231
347
  destroy() {
232
- this.doc.off("update", this.updateHandler);
233
348
  this.unsubscribers.forEach((unsub) => unsub());
234
349
  this.awareness.destroy();
350
+ this.rootDocHandler.destroy();
351
+ this._observers = /* @__PURE__ */ new Map();
352
+ for (const [_, handler] of this.subdocHandlers) {
353
+ handler.destroy();
354
+ }
355
+ this.subdocHandlers.clear();
235
356
  super.destroy();
236
357
  }
237
358
  // Some provider implementations expect to be able to call connect/disconnect, implement as noop
@@ -242,6 +363,5 @@ var LiveblocksProvider = class extends Observable {
242
363
  };
243
364
 
244
365
 
245
-
246
- exports.Awareness = Awareness; exports.default = LiveblocksProvider;
366
+ exports.default = LiveblocksProvider;
247
367
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../../node_modules/lib0/map.js","../../../node_modules/lib0/set.js","../../../node_modules/lib0/array.js","../../../node_modules/lib0/observable.js","../src/version.ts"],"names":["create"],"mappings":"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","sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { ClientMsgCode, detectDupes } from \"@liveblocks/core\";\nimport { Base64 } from \"js-base64\";\nimport { Observable } from \"lib0/observable\";\nimport * as Y from \"yjs\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n2;\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nconst Y_PRESENCE_KEY = \"__yjs\";\n\ntype MetaClientState = {\n clock: number;\n lastUpdated: number;\n};\n\n/**\n * This class will store Yjs awareness in Liveblock's presence under the __yjs key\n * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users\n * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,\n * we simply set the clientId of the doc to the connectionId. Then no further mapping is required\n */\nexport class Awareness extends Observable<unknown> {\n private room: Room<JsonObject, LsonObject, BaseUserMeta, Json>;\n public doc: Y.Doc;\n public clientID: number;\n public states: Map<number, unknown> = new Map();\n // Meta is used to keep track and timeout users who disconnect. Liveblocks provides this for us, so we don't need to\n // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.\n public meta: Map<number, MetaClientState> = new Map();\n // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this\n // unfortunately it's typed by various integrations\n public _checkInterval: number = 0;\n\n private othersUnsub: () => void;\n constructor(\n doc: Y.Doc,\n room: Room<JsonObject, LsonObject, BaseUserMeta, Json>\n ) {\n super();\n this.doc = doc;\n this.room = room;\n this.clientID = doc.clientID;\n this.othersUnsub = this.room.events.others.subscribe((event) => {\n // When others are changed, we emit an event that contains arrays added/updated/removed.\n if (event.type === \"leave\") {\n // REMOVED\n this.emit(\"change\", [\n { added: [], updated: [], removed: [event.user.connectionId] },\n \"local\",\n ]);\n }\n\n if (event.type === \"enter\") {\n // ADDED\n this.emit(\"change\", [\n { added: [event.user.connectionId], updated: [], removed: [] },\n \"local\",\n ]);\n }\n\n if (event.type === \"update\") {\n // UPDATED\n this.emit(\"change\", [\n { added: [], updated: [event.user.connectionId], removed: [] },\n \"local\",\n ]);\n }\n });\n }\n\n destroy(): void {\n this.emit(\"destroy\", [this]);\n this.othersUnsub();\n this.setLocalState(null);\n super.destroy();\n }\n\n getLocalState(): JsonObject | null {\n const presence = this.room.getPresence();\n if (\n Object.keys(presence).length === 0 ||\n typeof presence[Y_PRESENCE_KEY] === \"undefined\"\n ) {\n return null;\n }\n return presence[Y_PRESENCE_KEY] as JsonObject | null;\n }\n\n setLocalState(state: Partial<JsonObject> | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...(state || {}) },\n });\n }\n\n setLocalStateField(field: string, value: JsonObject | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n const update = { [field]: value } as Partial<JsonObject>;\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...update },\n });\n }\n\n // Translate liveblocks presence to yjs awareness\n getStates(): Map<number, unknown> {\n const others = this.room.getOthers();\n const states = others.reduce((acc: Map<number, unknown>, currentValue) => {\n if (currentValue.connectionId) {\n // connectionId == actorId == yjs.clientId\n acc.set(\n currentValue.connectionId,\n currentValue.presence[Y_PRESENCE_KEY] || {}\n );\n }\n return acc;\n }, new Map());\n return states;\n }\n}\n\nexport default class LiveblocksProvider<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n> extends Observable<unknown> {\n private room: Room<P, S, U, E>;\n private doc: Y.Doc;\n\n private unsubscribers: Array<() => void> = [];\n\n public awareness: Awareness;\n\n private _synced = false;\n\n constructor(room: Room<P, S, U, E>, doc: Y.Doc) {\n super();\n this.doc = doc;\n this.room = room;\n\n // if we have a connectionId already during construction, use that\n const connectionId = this.room.getSelf()?.connectionId;\n if (connectionId) {\n this.doc.clientID = connectionId;\n }\n this.awareness = new Awareness(this.doc, this.room);\n this.doc.on(\"update\", this.updateHandler);\n\n this.unsubscribers.push(\n this.room.events.status.subscribe((status) => {\n if (status === \"connected\") {\n this.syncDoc();\n } else {\n this.synced = false;\n }\n })\n );\n\n this.unsubscribers.push(\n this.room.events.ydoc.subscribe((message) => {\n const { type, update } = message;\n if (type === ClientMsgCode.UPDATE_YDOC) {\n // don't apply updates that came from the client\n return;\n }\n // apply update from the server\n Y.applyUpdate(this.doc, Base64.toUint8Array(update), \"backend\");\n const { stateVector } = message;\n // if this update is the result of a fetch, the state vector is included\n if (stateVector) {\n // Use server state to calculate a diff and send it\n try {\n const localUpdate = Y.encodeStateAsUpdate(\n this.doc,\n Base64.toUint8Array(stateVector)\n );\n this.room.updateYDoc(Base64.fromUint8Array(localUpdate));\n } catch (e) {\n // something went wrong encoding local state to send to the server\n console.warn(e);\n }\n // now that we've sent our local and received from server, we're in sync\n // calling `syncDoc` again will sync up the documents\n this.synced = true;\n }\n })\n );\n this.syncDoc();\n }\n\n private syncDoc = () => {\n this.synced = false;\n /**\n * If the connection changes, set the new id, this is used by awareness.\n * yjs' only requirement for clientID is that it's truly unique and a number.\n * Liveblock's connectionID satisfies those constraints\n * */\n this.doc.clientID = this.room.getSelf()?.connectionId || this.doc.clientID;\n this.awareness.clientID = this.doc.clientID; // tell our awareness provider the new ID\n\n // The state vector is sent to the server so it knows what to send back\n // if you don't send it, it returns everything\n const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));\n this.room.fetchYDoc(encodedVector);\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this._synced;\n }\n\n set synced(state: boolean) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n private updateHandler = (update: Uint8Array, origin: string) => {\n if (origin !== \"backend\") {\n const encodedUpdate = Base64.fromUint8Array(update);\n this.room.updateYDoc(encodedUpdate);\n }\n };\n\n destroy(): void {\n this.doc.off(\"update\", this.updateHandler);\n this.unsubscribers.forEach((unsub) => unsub());\n this.awareness.destroy();\n super.destroy();\n }\n\n // Some provider implementations expect to be able to call connect/disconnect, implement as noop\n disconnect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n\n connect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n}\n","/**\n * Utility module to work with key-value stores.\n *\n * @module map\n */\n\n/**\n * Creates a new Map instance.\n *\n * @function\n * @return {Map<any, any>}\n *\n * @function\n */\nexport const create = () => new Map()\n\n/**\n * Copy a Map object into a fresh Map object.\n *\n * @function\n * @template X,Y\n * @param {Map<X,Y>} m\n * @return {Map<X,Y>}\n */\nexport const copy = m => {\n const r = create()\n m.forEach((v, k) => { r.set(k, v) })\n return r\n}\n\n/**\n * Get map property. Create T if property is undefined and set T on map.\n *\n * ```js\n * const listeners = map.setIfUndefined(events, 'eventName', set.create)\n * listeners.add(listener)\n * ```\n *\n * @function\n * @template V,K\n * @template {Map<K,V>} MAP\n * @param {MAP} map\n * @param {K} key\n * @param {function():V} createT\n * @return {V}\n */\nexport const setIfUndefined = (map, key, createT) => {\n let set = map.get(key)\n if (set === undefined) {\n map.set(key, set = createT())\n }\n return set\n}\n\n/**\n * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.\n *\n * @function\n * @template K\n * @template V\n * @template R\n * @param {Map<K,V>} m\n * @param {function(V,K):R} f\n * @return {Array<R>}\n */\nexport const map = (m, f) => {\n const res = []\n for (const [key, value] of m) {\n res.push(f(value, key))\n }\n return res\n}\n\n/**\n * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @todo should rename to some - similarly to Array.some\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const any = (m, f) => {\n for (const [key, value] of m) {\n if (f(value, key)) {\n return true\n }\n }\n return false\n}\n\n/**\n * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const all = (m, f) => {\n for (const [key, value] of m) {\n if (!f(value, key)) {\n return false\n }\n }\n return true\n}\n","/**\n * Utility module to work with sets.\n *\n * @module set\n */\n\nexport const create = () => new Set()\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {Array<T>}\n */\nexport const toArray = set => Array.from(set)\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {T}\n */\nexport const first = set =>\n set.values().next().value || undefined\n\n/**\n * @template T\n * @param {Iterable<T>} entries\n * @return {Set<T>}\n */\nexport const from = entries => new Set(entries)\n","/**\n * Utility module to work with Arrays.\n *\n * @module array\n */\n\nimport * as set from './set.js'\n\n/**\n * Return the last element of an array. The element must exist\n *\n * @template L\n * @param {ArrayLike<L>} arr\n * @return {L}\n */\nexport const last = arr => arr[arr.length - 1]\n\n/**\n * @template C\n * @return {Array<C>}\n */\nexport const create = () => /** @type {Array<C>} */ ([])\n\n/**\n * @template D\n * @param {Array<D>} a\n * @return {Array<D>}\n */\nexport const copy = a => /** @type {Array<D>} */ (a.slice())\n\n/**\n * Append elements from src to dest\n *\n * @template M\n * @param {Array<M>} dest\n * @param {Array<M>} src\n */\nexport const appendTo = (dest, src) => {\n for (let i = 0; i < src.length; i++) {\n dest.push(src[i])\n }\n}\n\n/**\n * Transforms something array-like to an actual Array.\n *\n * @function\n * @template T\n * @param {ArrayLike<T>|Iterable<T>} arraylike\n * @return {T}\n */\nexport const from = Array.from\n\n/**\n * True iff condition holds on every element in the Array.\n *\n * @function\n * @template ITEM\n * @template {ArrayLike<ITEM>} ARR\n *\n * @param {ARR} arr\n * @param {function(ITEM, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const every = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (!f(arr[i], i, arr)) {\n return false\n }\n }\n return true\n}\n\n/**\n * True iff condition holds on some element in the Array.\n *\n * @function\n * @template S\n * @template {ArrayLike<S>} ARR\n * @param {ARR} arr\n * @param {function(S, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const some = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (f(arr[i], i, arr)) {\n return true\n }\n }\n return false\n}\n\n/**\n * @template ELEM\n *\n * @param {ArrayLike<ELEM>} a\n * @param {ArrayLike<ELEM>} b\n * @return {boolean}\n */\nexport const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])\n\n/**\n * @template ELEM\n * @param {Array<Array<ELEM>>} arr\n * @return {Array<ELEM>}\n */\nexport const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))\n\n/**\n * @template T\n * @param {number} len\n * @param {function(number, Array<T>):T} f\n * @return {Array<T>}\n */\nexport const unfold = (len, f) => {\n const array = new Array(len)\n for (let i = 0; i < len; i++) {\n array[i] = f(i, array)\n }\n return array\n}\n\n/**\n * @template T\n * @template RESULT\n * @param {Array<T>} arr\n * @param {RESULT} seed\n * @param {function(RESULT, T, number):RESULT} folder\n */\nexport const fold = (arr, seed, folder) => arr.reduce(folder, seed)\n\nexport const isArray = Array.isArray\n\n/**\n * @template T\n * @param {Array<T>} arr\n * @return {Array<T>}\n */\nexport const unique = arr => from(set.from(arr))\n\n/**\n * @template T\n * @template M\n * @param {ArrayLike<T>} arr\n * @param {function(T):M} mapper\n * @return {Array<T>}\n */\nexport const uniqueBy = (arr, mapper) => {\n /**\n * @type {Set<M>}\n */\n const happened = set.create()\n /**\n * @type {Array<T>}\n */\n const result = []\n for (let i = 0; i < arr.length; i++) {\n const el = arr[i]\n const mapped = mapper(el)\n if (!happened.has(mapped)) {\n happened.add(mapped)\n result.push(el)\n }\n }\n return result\n}\n","/**\n * Observable class prototype.\n *\n * @module observable\n */\n\nimport * as map from './map.js'\nimport * as set from './set.js'\nimport * as array from './array.js'\n\n/**\n * Handles named events.\n *\n * @template N\n */\nexport class Observable {\n constructor () {\n /**\n * Some desc.\n * @type {Map<N, any>}\n */\n this._observers = map.create()\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n on (name, f) {\n map.setIfUndefined(this._observers, name, set.create).add(f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n once (name, f) {\n /**\n * @param {...any} args\n */\n const _f = (...args) => {\n this.off(name, _f)\n f(...args)\n }\n this.on(name, _f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n off (name, f) {\n const observers = this._observers.get(name)\n if (observers !== undefined) {\n observers.delete(f)\n if (observers.size === 0) {\n this._observers.delete(name)\n }\n }\n }\n\n /**\n * Emit a named event. All registered event listeners that listen to the\n * specified name will receive the event.\n *\n * @todo This should catch exceptions\n *\n * @param {N} name The event name.\n * @param {Array<any>} args The arguments that are applied to the event listener.\n */\n emit (name, args) {\n // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.\n return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))\n }\n\n destroy () {\n this._observers = map.create()\n }\n}\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/yjs\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../../../node_modules/lib0/map.js","../../../node_modules/lib0/set.js","../../../node_modules/lib0/array.js","../../../node_modules/lib0/observable.js","../src/awareness.ts","../src/doc.ts","../src/version.ts"],"names":["create"],"mappings":";AAOA,SAAS,eAAe,mBAAmB;;;ACOpC,IAAM,SAAS,MAAM,oBAAI,IAAI;AAgC7B,IAAM,iBAAiB,CAAC,KAAK,KAAK,YAAY;AACnD,MAAI,MAAM,IAAI,IAAI,GAAG;AACrB,MAAI,QAAQ,QAAW;AACrB,QAAI,IAAI,KAAK,MAAM,QAAQ,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;;;AC9CO,IAAMA,UAAS,MAAM,oBAAI,IAAI;;;AC6C7B,IAAM,OAAO,MAAM;AAgFnB,IAAM,UAAU,MAAM;;;ACpHtB,IAAM,aAAN,MAAiB;AAAA,EACtB,cAAe;AAKb,SAAK,aAAiB,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,GAAI,MAAM,GAAG;AACX,IAAI,eAAe,KAAK,YAAY,MAAUA,OAAM,EAAE,IAAI,CAAC;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAM,MAAM,GAAG;AAIb,UAAM,KAAK,IAAI,SAAS;AACtB,WAAK,IAAI,MAAM,EAAE;AACjB,QAAE,GAAG,IAAI;AAAA,IACX;AACA,SAAK,GAAG,MAAM,EAAE;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAK,MAAM,GAAG;AACZ,UAAM,YAAY,KAAK,WAAW,IAAI,IAAI;AAC1C,QAAI,cAAc,QAAW;AAC3B,gBAAU,OAAO,CAAC;AAClB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,WAAW,OAAO,IAAI;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,KAAM,MAAM,MAAM;AAEhB,WAAa,MAAM,KAAK,WAAW,IAAI,IAAI,KAAS,OAAO,GAAG,OAAO,CAAC,EAAE,QAAQ,OAAK,EAAE,GAAG,IAAI,CAAC;AAAA,EACjG;AAAA,EAEA,UAAW;AACT,SAAK,aAAiB,OAAO;AAAA,EAC/B;AACF;;;AChEA,IAAM,iBAAiB;AAahB,IAAM,YAAN,cAAwB,WAAoB;AAAA,EAajD,YACE,KACA,MACA;AACA,UAAM;AAbR,SAAO,SAA+B,oBAAI,IAAI;AAG9C;AAAA;AAAA,SAAO,OAAqC,oBAAI,IAAI;AAGpD;AAAA;AAAA,SAAO,iBAAyB;AAQ9B,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK,WAAW,IAAI;AACpB,SAAK,cAAc,KAAK,KAAK,OAAO,OAAO,UAAU,CAAC,UAAU;AAE9D,UAAI,MAAM,SAAS,SAAS;AAE1B,aAAK,KAAK,UAAU;AAAA,UAClB,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,MAAM,KAAK,YAAY,EAAE;AAAA,UAC7D;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI,MAAM,SAAS,SAAS;AAE1B,aAAK,KAAK,UAAU;AAAA,UAClB,EAAE,OAAO,CAAC,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,UAC7D;AAAA,QACF,CAAC;AAAA,MACH;AAEA,UAAI,MAAM,SAAS,UAAU;AAE3B,aAAK,KAAK,UAAU;AAAA,UAClB,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC,EAAE;AAAA,UAC7D;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK,WAAW,CAAC,IAAI,CAAC;AAC3B,SAAK,YAAY;AACjB,SAAK,cAAc,IAAI;AACvB,UAAM,QAAQ;AAAA,EAChB;AAAA,EAEA,gBAAmC;AACjC,UAAM,WAAW,KAAK,KAAK,YAAY;AACvC,QACE,OAAO,KAAK,QAAQ,EAAE,WAAW,KACjC,OAAO,SAAS,cAAc,MAAM,aACpC;AACA,aAAO;AAAA,IACT;AACA,WAAO,SAAS,cAAc;AAAA,EAChC;AAAA,EAEA,cAAc,OAAyC;AACrD,UAAM,WAAW,KAAK,KAAK,QAAQ,GAAG,SAAS,cAAc;AAC7D,SAAK,KAAK,eAAe;AAAA,MACvB,OAAO,EAAE,GAAK,YAA2B,CAAC,GAAI,GAAI,SAAS,CAAC,EAAG;AAAA,IACjE,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB,OAAe,OAAgC;AAChE,UAAM,WAAW,KAAK,KAAK,QAAQ,GAAG,SAAS,cAAc;AAC7D,UAAM,SAAS,EAAE,CAAC,KAAK,GAAG,MAAM;AAChC,SAAK,KAAK,eAAe;AAAA,MACvB,OAAO,EAAE,GAAK,YAA2B,CAAC,GAAI,GAAG,OAAO;AAAA,IAC1D,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,YAAkC;AAChC,UAAM,SAAS,KAAK,KAAK,UAAU;AACnC,UAAM,SAAS,OAAO,OAAO,CAAC,KAA2B,iBAAiB;AACxE,UAAI,aAAa,cAAc;AAE7B,YAAI;AAAA,UACF,aAAa;AAAA,UACb,aAAa,SAAS,cAAc,KAAK,CAAC;AAAA,QAC5C;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAAG,oBAAI,IAAI,CAAC;AACZ,WAAO;AAAA,EACT;AACF;;;AC5HA,SAAS,cAAc;AAEvB,YAAY,OAAO;AAEnB,IAAqB,cAArB,cAAyC,WAAoB;AAAA,EAQ3D,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAKG;AACD,UAAM;AAlBR,SAAQ,gBAAmC,CAAC;AAE5C,SAAQ,UAAU;AA8BlB,SAAO,qBAAqB,CAAC;AAAA,MAC3B;AAAA,MACA;AAAA,IACF,MAGY;AAEV,MAAE,cAAY,KAAK,KAAK,OAAO,aAAa,MAAM,GAAG,SAAS;AAE9D,UAAI,aAAa;AAEf,YAAI;AACF,gBAAM,cAAgB;AAAA,YACpB,KAAK;AAAA,YACL,OAAO,aAAa,WAAW;AAAA,UACjC;AACA,eAAK,cAAc,OAAO,eAAe,WAAW,CAAC;AAAA,QACvD,SAAS,GAAP;AAEA,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAGA,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAEA,SAAO,UAAU,MAAY;AAC3B,WAAK,SAAS;AAId,YAAM,gBAAgB,OAAO,eAAiB,oBAAkB,KAAK,GAAG,CAAC;AACzE,WAAK,aAAa,aAAa;AAAA,IACjC;AAeA,SAAQ,gBAAgB,CAAC,QAAoB,WAAmB;AAC9D,UAAI,WAAW,WAAW;AACxB,cAAM,gBAAgB,OAAO,eAAe,MAAM;AAClD,aAAK,cAAc,aAAa;AAAA,MAClC;AAAA,IACF;AApEE,SAAK,MAAM;AAEX,SAAK,IAAI,GAAG,UAAU,KAAK,aAAa;AACxC,SAAK,gBAAgB,CAAC,WAAmB;AACvC,gBAAU,QAAQ,SAAS,SAAY,KAAK,IAAI,IAAI;AAAA,IACtD;AACA,SAAK,eAAe,CAAC,WAAmB;AACtC,eAAS,QAAQ,SAAS,SAAY,KAAK,IAAI,IAAI;AAAA,IACrD;AAEA,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAwCA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,OAAO,OAAgB;AACzB,QAAI,KAAK,YAAY,OAAO;AAC1B,WAAK,UAAU;AACf,WAAK,KAAK,UAAU,CAAC,KAAK,CAAC;AAC3B,WAAK,KAAK,QAAQ,CAAC,KAAK,CAAC;AAAA,IAC3B;AAAA,EACF;AAAA,EASA,UAAgB;AACd,SAAK,IAAI,IAAI,UAAU,KAAK,aAAa;AACzC,SAAK,cAAc,QAAQ,CAAC,UAAU,MAAM,CAAC;AAC7C,SAAK,aAAa,oBAAI,IAAI;AAC1B,SAAK,IAAI,QAAQ;AAAA,EACnB;AACF;;;ACjGO,IAAM,WAAW;AACjB,IAAM,cAAiD;AACvD,IAAM,aAAgD;;;APW7D,YAAY,UAAU,aAAa,UAAU;AAM7C,IAAM,iBAAkC;AAAA,EACtC,iBAAiB;AACnB;AAEA,IAAqB,qBAArB,cAKU,WAAoB;AAAA,EAY5B,YACE,MACA,KACA,UAAuC,gBACvC;AACA,UAAM;AAZR,SAAQ,gBAAmC,CAAC;AAK5C,SAAO,iBAA2C,oBAAI,IAAI;AAiE1D,SAAQ,gBAAgB,CAAC;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAIM;AACJ,aAAO,QAAQ,KAAK,mBAAmB;AACvC,UAAI,KAAK,QAAQ,iBAAiB;AAChC,mBAAW,UAAU,OAAO;AAC1B,cAAI,CAAC,KAAK,eAAe,IAAI,OAAO,IAAI,GAAG;AACzC,mBAAO,KAAK;AAAA,UACd;AAAA,QACF;AAAA,MACF;AACA,iBAAW,UAAU,SAAS;AAC5B,YAAI,KAAK,eAAe,IAAI,OAAO,IAAI,GAAG;AACxC,eAAK,eAAe,IAAI,OAAO,IAAI,GAAG,QAAQ;AAC9C,eAAK,eAAe,OAAO,OAAO,IAAI;AAAA,QACxC;AAAA,MACF;AAAA,IACF;AAEA,SAAQ,YAAY,CAAC,QAAgB,SAAkB;AACrD,WAAK,KAAK,WAAW,QAAQ,IAAI;AAAA,IACnC;AAEA,SAAQ,WAAW,CAAC,QAAgB,SAAkB;AACpD,WAAK,KAAK,UAAU,QAAQ,IAAI;AAAA,IAClC;AAEA,SAAQ,sBAAsB,CAAC,WAAwB;AACrD,UAAI,KAAK,eAAe,IAAI,OAAO,IAAI,GAAG;AAExC,aAAK,eAAe,IAAI,OAAO,IAAI,GAAG,QAAQ;AAC9C;AAAA,MACF;AACA,YAAM,UAAU,IAAI,YAAY;AAAA,QAC9B,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,WAAW,KAAK;AAAA,QAChB,UAAU,KAAK;AAAA,MACjB,CAAC;AACD,WAAK,eAAe,IAAI,OAAO,MAAM,OAAO;AAAA,IAC9C;AAGA;AAAA,SAAO,aAAa,CAAC,SAA0B;AAC7C,iBAAW,UAAU,KAAK,QAAQ,SAAS;AACzC,YAAI,OAAO,SAAS,MAAM;AACxB,iBAAO,KAAK;AACZ,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAEA,SAAQ,UAAU,MAAM;AAMtB,WAAK,QAAQ,WACX,KAAK,KAAK,QAAQ,GAAG,gBAAgB,KAAK,QAAQ;AACpD,WAAK,UAAU,WAAW,KAAK,QAAQ;AAEvC,WAAK,eAAe,QAAQ;AAC5B,iBAAW,CAAC,GAAG,OAAO,KAAK,KAAK,gBAAgB;AAC9C,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF;AAnIE,SAAK,UAAU;AACf,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,iBAAiB,IAAI,YAAY;AAAA,MACpC;AAAA,MACA,QAAQ;AAAA,MACR,WAAW,KAAK;AAAA,MAChB,UAAU,KAAK;AAAA,IACjB,CAAC;AAED,UAAM,eAAe,KAAK,KAAK,QAAQ,GAAG;AAC1C,QAAI,cAAc;AAChB,WAAK,QAAQ,WAAW;AAAA,IAC1B;AACA,SAAK,YAAY,IAAI,UAAU,KAAK,SAAS,KAAK,IAAI;AAEtD,SAAK,cAAc;AAAA,MACjB,KAAK,KAAK,OAAO,OAAO,UAAU,CAAC,WAAW;AAC5C,YAAI,WAAW,aAAa;AAC1B,eAAK,eAAe,QAAQ;AAAA,QAC9B,OAAO;AACL,eAAK,eAAe,SAAS;AAAA,QAC/B;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,cAAc;AAAA,MACjB,KAAK,KAAK,OAAO,KAAK,UAAU,CAAC,YAAY;AAC3C,cAAM,EAAE,KAAK,IAAI;AACjB,YAAI,SAAS,cAAc,aAAa;AAEtC;AAAA,QACF;AACA,cAAM,EAAE,aAAa,QAAQ,KAAK,IAAI;AAEtC,YAAI,SAAS,QAAW;AACtB,eAAK,eACF,IAAI,IAAI,GACP,mBAAmB,EAAE,QAAQ,YAAY,CAAC;AAAA,QAChD,OAAO;AACL,eAAK,eAAe,mBAAmB,EAAE,QAAQ,YAAY,CAAC;AAAA,QAChE;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,eAAe,GAAG,UAAU,MAAM;AACrC,YAAM,QAAQ,KAAK,eAAe;AAClC,iBAAW,CAAC,GAAG,OAAO,KAAK,KAAK,gBAAgB;AAC9C,gBAAQ,QAAQ;AAAA,MAClB;AACA,WAAK,KAAK,UAAU,CAAC,KAAK,CAAC;AAC3B,WAAK,KAAK,QAAQ,CAAC,KAAK,CAAC;AAAA,IAC3B,CAAC;AACD,SAAK,QAAQ,GAAG,WAAW,KAAK,aAAa;AAC7C,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EA+EA,IAAI,SAAkB;AACpB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,UAAgB;AACd,SAAK,cAAc,QAAQ,CAAC,UAAU,MAAM,CAAC;AAC7C,SAAK,UAAU,QAAQ;AACvB,SAAK,eAAe,QAAQ;AAC5B,SAAK,aAAa,oBAAI,IAAI;AAC1B,eAAW,CAAC,GAAG,OAAO,KAAK,KAAK,gBAAgB;AAC9C,cAAQ,QAAQ;AAAA,IAClB;AACA,SAAK,eAAe,MAAM;AAC1B,UAAM,QAAQ;AAAA,EAChB;AAAA;AAAA,EAGA,aAAmB;AAAA,EAEnB;AAAA,EAEA,UAAgB;AAAA,EAEhB;AACF","sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { ClientMsgCode, detectDupes } from \"@liveblocks/core\";\nimport { Observable } from \"lib0/observable\";\nimport type * as Y from \"yjs\";\n\nimport { Awareness } from \"./awareness\";\nimport yDocHandler from \"./doc\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n2;\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\ntype ProviderOptions = {\n autoloadSubdocs: boolean;\n};\n\nconst DefaultOptions: ProviderOptions = {\n autoloadSubdocs: false,\n};\n\nexport default class LiveblocksProvider<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n> extends Observable<unknown> {\n private room: Room<P, S, U, E>;\n private rootDoc: Y.Doc;\n private options: ProviderOptions;\n\n private unsubscribers: Array<() => void> = [];\n\n public awareness: Awareness;\n\n public rootDocHandler: yDocHandler;\n public subdocHandlers: Map<string, yDocHandler> = new Map();\n\n constructor(\n room: Room<P, S, U, E>,\n doc: Y.Doc,\n options: ProviderOptions | undefined = DefaultOptions\n ) {\n super();\n this.rootDoc = doc;\n this.room = room;\n this.options = options;\n this.rootDocHandler = new yDocHandler({\n doc,\n isRoot: true,\n updateDoc: this.updateDoc,\n fetchDoc: this.fetchDoc,\n });\n // if we have a connectionId already during construction, use that\n const connectionId = this.room.getSelf()?.connectionId;\n if (connectionId) {\n this.rootDoc.clientID = connectionId;\n }\n this.awareness = new Awareness(this.rootDoc, this.room);\n\n this.unsubscribers.push(\n this.room.events.status.subscribe((status) => {\n if (status === \"connected\") {\n this.rootDocHandler.syncDoc();\n } else {\n this.rootDocHandler.synced = false;\n }\n })\n );\n\n this.unsubscribers.push(\n this.room.events.ydoc.subscribe((message) => {\n const { type } = message;\n if (type === ClientMsgCode.UPDATE_YDOC) {\n // don't apply updates that came from the client\n return;\n }\n const { stateVector, update, guid } = message;\n // find the right doc and update\n if (guid !== undefined) {\n this.subdocHandlers\n .get(guid)\n ?.handleServerUpdate({ update, stateVector });\n } else {\n this.rootDocHandler.handleServerUpdate({ update, stateVector });\n }\n })\n );\n\n this.rootDocHandler.on(\"synced\", () => {\n const state = this.rootDocHandler.synced;\n for (const [_, handler] of this.subdocHandlers) {\n handler.syncDoc();\n }\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n });\n this.rootDoc.on(\"subdocs\", this.handleSubdocs);\n this.syncDoc();\n }\n\n private handleSubdocs = ({\n loaded,\n removed,\n added,\n }: {\n loaded: Y.Doc[];\n removed: Y.Doc[];\n added: Y.Doc[];\n }) => {\n loaded.forEach(this.createSubdocHandler);\n if (this.options.autoloadSubdocs) {\n for (const subdoc of added) {\n if (!this.subdocHandlers.has(subdoc.guid)) {\n subdoc.load();\n }\n }\n }\n for (const subdoc of removed) {\n if (this.subdocHandlers.has(subdoc.guid)) {\n this.subdocHandlers.get(subdoc.guid)?.destroy();\n this.subdocHandlers.delete(subdoc.guid);\n }\n }\n };\n\n private updateDoc = (update: string, guid?: string) => {\n this.room.updateYDoc(update, guid);\n };\n\n private fetchDoc = (vector: string, guid?: string) => {\n this.room.fetchYDoc(vector, guid);\n };\n\n private createSubdocHandler = (subdoc: Y.Doc): void => {\n if (this.subdocHandlers.has(subdoc.guid)) {\n // if we already handle this subdoc, just fetch it again\n this.subdocHandlers.get(subdoc.guid)?.syncDoc();\n return;\n }\n const handler = new yDocHandler({\n doc: subdoc,\n isRoot: false,\n updateDoc: this.updateDoc,\n fetchDoc: this.fetchDoc,\n });\n this.subdocHandlers.set(subdoc.guid, handler);\n };\n\n // attempt to load a subdoc of a given guid\n public loadSubdoc = (guid: string): boolean => {\n for (const subdoc of this.rootDoc.subdocs) {\n if (subdoc.guid === guid) {\n subdoc.load();\n return true;\n }\n }\n // should we throw instead?\n return false;\n };\n\n private syncDoc = () => {\n /**\n * If the connection changes, set the new id, this is used by awareness.\n * yjs' only requirement for clientID is that it's truly unique and a number.\n * Liveblock's connectionID satisfies those constraints\n * */\n this.rootDoc.clientID =\n this.room.getSelf()?.connectionId || this.rootDoc.clientID;\n this.awareness.clientID = this.rootDoc.clientID; // tell our awareness provider the new ID\n\n this.rootDocHandler.syncDoc();\n for (const [_, handler] of this.subdocHandlers) {\n handler.syncDoc();\n }\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this.rootDocHandler.synced;\n }\n\n destroy(): void {\n this.unsubscribers.forEach((unsub) => unsub());\n this.awareness.destroy();\n this.rootDocHandler.destroy();\n this._observers = new Map();\n for (const [_, handler] of this.subdocHandlers) {\n handler.destroy();\n }\n this.subdocHandlers.clear();\n super.destroy();\n }\n\n // Some provider implementations expect to be able to call connect/disconnect, implement as noop\n disconnect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n\n connect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n}\n","/**\n * Utility module to work with key-value stores.\n *\n * @module map\n */\n\n/**\n * Creates a new Map instance.\n *\n * @function\n * @return {Map<any, any>}\n *\n * @function\n */\nexport const create = () => new Map()\n\n/**\n * Copy a Map object into a fresh Map object.\n *\n * @function\n * @template X,Y\n * @param {Map<X,Y>} m\n * @return {Map<X,Y>}\n */\nexport const copy = m => {\n const r = create()\n m.forEach((v, k) => { r.set(k, v) })\n return r\n}\n\n/**\n * Get map property. Create T if property is undefined and set T on map.\n *\n * ```js\n * const listeners = map.setIfUndefined(events, 'eventName', set.create)\n * listeners.add(listener)\n * ```\n *\n * @function\n * @template V,K\n * @template {Map<K,V>} MAP\n * @param {MAP} map\n * @param {K} key\n * @param {function():V} createT\n * @return {V}\n */\nexport const setIfUndefined = (map, key, createT) => {\n let set = map.get(key)\n if (set === undefined) {\n map.set(key, set = createT())\n }\n return set\n}\n\n/**\n * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.\n *\n * @function\n * @template K\n * @template V\n * @template R\n * @param {Map<K,V>} m\n * @param {function(V,K):R} f\n * @return {Array<R>}\n */\nexport const map = (m, f) => {\n const res = []\n for (const [key, value] of m) {\n res.push(f(value, key))\n }\n return res\n}\n\n/**\n * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @todo should rename to some - similarly to Array.some\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const any = (m, f) => {\n for (const [key, value] of m) {\n if (f(value, key)) {\n return true\n }\n }\n return false\n}\n\n/**\n * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const all = (m, f) => {\n for (const [key, value] of m) {\n if (!f(value, key)) {\n return false\n }\n }\n return true\n}\n","/**\n * Utility module to work with sets.\n *\n * @module set\n */\n\nexport const create = () => new Set()\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {Array<T>}\n */\nexport const toArray = set => Array.from(set)\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {T}\n */\nexport const first = set =>\n set.values().next().value || undefined\n\n/**\n * @template T\n * @param {Iterable<T>} entries\n * @return {Set<T>}\n */\nexport const from = entries => new Set(entries)\n","/**\n * Utility module to work with Arrays.\n *\n * @module array\n */\n\nimport * as set from './set.js'\n\n/**\n * Return the last element of an array. The element must exist\n *\n * @template L\n * @param {ArrayLike<L>} arr\n * @return {L}\n */\nexport const last = arr => arr[arr.length - 1]\n\n/**\n * @template C\n * @return {Array<C>}\n */\nexport const create = () => /** @type {Array<C>} */ ([])\n\n/**\n * @template D\n * @param {Array<D>} a\n * @return {Array<D>}\n */\nexport const copy = a => /** @type {Array<D>} */ (a.slice())\n\n/**\n * Append elements from src to dest\n *\n * @template M\n * @param {Array<M>} dest\n * @param {Array<M>} src\n */\nexport const appendTo = (dest, src) => {\n for (let i = 0; i < src.length; i++) {\n dest.push(src[i])\n }\n}\n\n/**\n * Transforms something array-like to an actual Array.\n *\n * @function\n * @template T\n * @param {ArrayLike<T>|Iterable<T>} arraylike\n * @return {T}\n */\nexport const from = Array.from\n\n/**\n * True iff condition holds on every element in the Array.\n *\n * @function\n * @template ITEM\n * @template {ArrayLike<ITEM>} ARR\n *\n * @param {ARR} arr\n * @param {function(ITEM, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const every = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (!f(arr[i], i, arr)) {\n return false\n }\n }\n return true\n}\n\n/**\n * True iff condition holds on some element in the Array.\n *\n * @function\n * @template S\n * @template {ArrayLike<S>} ARR\n * @param {ARR} arr\n * @param {function(S, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const some = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (f(arr[i], i, arr)) {\n return true\n }\n }\n return false\n}\n\n/**\n * @template ELEM\n *\n * @param {ArrayLike<ELEM>} a\n * @param {ArrayLike<ELEM>} b\n * @return {boolean}\n */\nexport const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])\n\n/**\n * @template ELEM\n * @param {Array<Array<ELEM>>} arr\n * @return {Array<ELEM>}\n */\nexport const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))\n\n/**\n * @template T\n * @param {number} len\n * @param {function(number, Array<T>):T} f\n * @return {Array<T>}\n */\nexport const unfold = (len, f) => {\n const array = new Array(len)\n for (let i = 0; i < len; i++) {\n array[i] = f(i, array)\n }\n return array\n}\n\n/**\n * @template T\n * @template RESULT\n * @param {Array<T>} arr\n * @param {RESULT} seed\n * @param {function(RESULT, T, number):RESULT} folder\n */\nexport const fold = (arr, seed, folder) => arr.reduce(folder, seed)\n\nexport const isArray = Array.isArray\n\n/**\n * @template T\n * @param {Array<T>} arr\n * @return {Array<T>}\n */\nexport const unique = arr => from(set.from(arr))\n\n/**\n * @template T\n * @template M\n * @param {ArrayLike<T>} arr\n * @param {function(T):M} mapper\n * @return {Array<T>}\n */\nexport const uniqueBy = (arr, mapper) => {\n /**\n * @type {Set<M>}\n */\n const happened = set.create()\n /**\n * @type {Array<T>}\n */\n const result = []\n for (let i = 0; i < arr.length; i++) {\n const el = arr[i]\n const mapped = mapper(el)\n if (!happened.has(mapped)) {\n happened.add(mapped)\n result.push(el)\n }\n }\n return result\n}\n","/**\n * Observable class prototype.\n *\n * @module observable\n */\n\nimport * as map from './map.js'\nimport * as set from './set.js'\nimport * as array from './array.js'\n\n/**\n * Handles named events.\n *\n * @template N\n */\nexport class Observable {\n constructor () {\n /**\n * Some desc.\n * @type {Map<N, any>}\n */\n this._observers = map.create()\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n on (name, f) {\n map.setIfUndefined(this._observers, name, set.create).add(f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n once (name, f) {\n /**\n * @param {...any} args\n */\n const _f = (...args) => {\n this.off(name, _f)\n f(...args)\n }\n this.on(name, _f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n off (name, f) {\n const observers = this._observers.get(name)\n if (observers !== undefined) {\n observers.delete(f)\n if (observers.size === 0) {\n this._observers.delete(name)\n }\n }\n }\n\n /**\n * Emit a named event. All registered event listeners that listen to the\n * specified name will receive the event.\n *\n * @todo This should catch exceptions\n *\n * @param {N} name The event name.\n * @param {Array<any>} args The arguments that are applied to the event listener.\n */\n emit (name, args) {\n // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.\n return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))\n }\n\n destroy () {\n this._observers = map.create()\n }\n}\n","// TODO: apparently Yjs is full of anys or something, see if we can fix this\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { Observable } from \"lib0/observable\";\nimport type * as Y from \"yjs\";\n\nconst Y_PRESENCE_KEY = \"__yjs\";\n\ntype MetaClientState = {\n clock: number;\n lastUpdated: number;\n};\n\n/**\n * This class will store Yjs awareness in Liveblock's presence under the __yjs key\n * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users\n * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,\n * we simply set the clientId of the doc to the connectionId. Then no further mapping is required\n */\nexport class Awareness extends Observable<unknown> {\n private room: Room<JsonObject, LsonObject, BaseUserMeta, Json>;\n public doc: Y.Doc;\n public clientID: number;\n public states: Map<number, unknown> = new Map();\n // Meta is used to keep track and timeout users who disconnect. Liveblocks provides this for us, so we don't need to\n // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.\n public meta: Map<number, MetaClientState> = new Map();\n // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this\n // unfortunately it's typed by various integrations\n public _checkInterval: number = 0;\n\n private othersUnsub: () => void;\n constructor(\n doc: Y.Doc,\n room: Room<JsonObject, LsonObject, BaseUserMeta, Json>\n ) {\n super();\n this.doc = doc;\n this.room = room;\n this.clientID = doc.clientID;\n this.othersUnsub = this.room.events.others.subscribe((event) => {\n // When others are changed, we emit an event that contains arrays added/updated/removed.\n if (event.type === \"leave\") {\n // REMOVED\n this.emit(\"change\", [\n { added: [], updated: [], removed: [event.user.connectionId] },\n \"local\",\n ]);\n }\n\n if (event.type === \"enter\") {\n // ADDED\n this.emit(\"change\", [\n { added: [event.user.connectionId], updated: [], removed: [] },\n \"local\",\n ]);\n }\n\n if (event.type === \"update\") {\n // UPDATED\n this.emit(\"change\", [\n { added: [], updated: [event.user.connectionId], removed: [] },\n \"local\",\n ]);\n }\n });\n }\n\n destroy(): void {\n this.emit(\"destroy\", [this]);\n this.othersUnsub();\n this.setLocalState(null);\n super.destroy();\n }\n\n getLocalState(): JsonObject | null {\n const presence = this.room.getPresence();\n if (\n Object.keys(presence).length === 0 ||\n typeof presence[Y_PRESENCE_KEY] === \"undefined\"\n ) {\n return null;\n }\n return presence[Y_PRESENCE_KEY] as JsonObject | null;\n }\n\n setLocalState(state: Partial<JsonObject> | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...(state || {}) },\n });\n }\n\n setLocalStateField(field: string, value: JsonObject | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n const update = { [field]: value } as Partial<JsonObject>;\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...update },\n });\n }\n\n // Translate liveblocks presence to yjs awareness\n getStates(): Map<number, unknown> {\n const others = this.room.getOthers();\n const states = others.reduce((acc: Map<number, unknown>, currentValue) => {\n if (currentValue.connectionId) {\n // connectionId == actorId == yjs.clientId\n acc.set(\n currentValue.connectionId,\n currentValue.presence[Y_PRESENCE_KEY] || {}\n );\n }\n return acc;\n }, new Map());\n return states;\n }\n}\n","import { Base64 } from \"js-base64\";\nimport { Observable } from \"lib0/observable\";\nimport * as Y from \"yjs\";\n\nexport default class yDocHandler extends Observable<unknown> {\n private unsubscribers: Array<() => void> = [];\n\n private _synced = false;\n private doc: Y.Doc;\n private updateRoomDoc: (update: string) => void;\n private fetchRoomDoc: (vector: string) => void;\n\n constructor({\n doc,\n isRoot,\n updateDoc,\n fetchDoc,\n }: {\n doc: Y.Doc;\n isRoot: boolean;\n updateDoc: (update: string, guid?: string) => void;\n fetchDoc: (vector: string, guid?: string) => void;\n }) {\n super();\n this.doc = doc;\n // this.doc.load(); // this just emits a load event, it doesn't actually load anything\n this.doc.on(\"update\", this.updateHandler);\n this.updateRoomDoc = (update: string) => {\n updateDoc(update, isRoot ? undefined : this.doc.guid);\n };\n this.fetchRoomDoc = (vector: string) => {\n fetchDoc(vector, isRoot ? undefined : this.doc.guid);\n };\n\n this.syncDoc();\n }\n\n public handleServerUpdate = ({\n update,\n stateVector,\n }: {\n update: string;\n stateVector: string | null;\n }): void => {\n // apply update from the server\n Y.applyUpdate(this.doc, Base64.toUint8Array(update), \"backend\");\n // if this update is the result of a fetch, the state vector is included\n if (stateVector) {\n // Use server state to calculate a diff and send it\n try {\n const localUpdate = Y.encodeStateAsUpdate(\n this.doc,\n Base64.toUint8Array(stateVector)\n );\n this.updateRoomDoc(Base64.fromUint8Array(localUpdate));\n } catch (e) {\n // something went wrong encoding local state to send to the server\n console.warn(e);\n }\n // now that we've sent our local and received from server, we're in sync\n // calling `syncDoc` again will sync up the documents\n this.synced = true;\n }\n };\n\n public syncDoc = (): void => {\n this.synced = false;\n\n // The state vector is sent to the server so it knows what to send back\n // if you don't send it, it returns everything\n const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));\n this.fetchRoomDoc(encodedVector);\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this._synced;\n }\n\n set synced(state: boolean) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n private updateHandler = (update: Uint8Array, origin: string) => {\n if (origin !== \"backend\") {\n const encodedUpdate = Base64.fromUint8Array(update);\n this.updateRoomDoc(encodedUpdate);\n }\n };\n\n destroy(): void {\n this.doc.off(\"update\", this.updateHandler);\n this.unsubscribers.forEach((unsub) => unsub());\n this._observers = new Map();\n this.doc.destroy();\n }\n}\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/yjs\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"]}
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  // src/index.ts
2
2
  import { ClientMsgCode, detectDupes } from "@liveblocks/core";
3
- import { Base64 } from "js-base64";
4
3
 
5
4
  // ../../node_modules/lib0/map.js
6
5
  var create = () => /* @__PURE__ */ new Map();
@@ -72,16 +71,7 @@ var Observable = class {
72
71
  }
73
72
  };
74
73
 
75
- // src/index.ts
76
- import * as Y from "yjs";
77
-
78
- // src/version.ts
79
- var PKG_NAME = "@liveblocks/yjs";
80
- var PKG_VERSION = "1.5.3";
81
- var PKG_FORMAT = "esm";
82
-
83
- // src/index.ts
84
- detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
74
+ // src/awareness.ts
85
75
  var Y_PRESENCE_KEY = "__yjs";
86
76
  var Awareness = class extends Observable {
87
77
  constructor(doc, room) {
@@ -158,80 +148,211 @@ var Awareness = class extends Observable {
158
148
  return states;
159
149
  }
160
150
  };
161
- var LiveblocksProvider = class extends Observable {
162
- constructor(room, doc) {
151
+
152
+ // src/doc.ts
153
+ import { Base64 } from "js-base64";
154
+ import * as Y from "yjs";
155
+ var yDocHandler = class extends Observable {
156
+ constructor({
157
+ doc,
158
+ isRoot,
159
+ updateDoc,
160
+ fetchDoc
161
+ }) {
163
162
  super();
164
163
  this.unsubscribers = [];
165
164
  this._synced = false;
165
+ this.handleServerUpdate = ({
166
+ update,
167
+ stateVector
168
+ }) => {
169
+ Y.applyUpdate(this.doc, Base64.toUint8Array(update), "backend");
170
+ if (stateVector) {
171
+ try {
172
+ const localUpdate = Y.encodeStateAsUpdate(
173
+ this.doc,
174
+ Base64.toUint8Array(stateVector)
175
+ );
176
+ this.updateRoomDoc(Base64.fromUint8Array(localUpdate));
177
+ } catch (e) {
178
+ console.warn(e);
179
+ }
180
+ this.synced = true;
181
+ }
182
+ };
166
183
  this.syncDoc = () => {
167
184
  this.synced = false;
168
- this.doc.clientID = this.room.getSelf()?.connectionId || this.doc.clientID;
169
- this.awareness.clientID = this.doc.clientID;
170
185
  const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));
171
- this.room.fetchYDoc(encodedVector);
186
+ this.fetchRoomDoc(encodedVector);
172
187
  };
173
188
  this.updateHandler = (update, origin) => {
174
189
  if (origin !== "backend") {
175
190
  const encodedUpdate = Base64.fromUint8Array(update);
176
- this.room.updateYDoc(encodedUpdate);
191
+ this.updateRoomDoc(encodedUpdate);
177
192
  }
178
193
  };
179
194
  this.doc = doc;
195
+ this.doc.on("update", this.updateHandler);
196
+ this.updateRoomDoc = (update) => {
197
+ updateDoc(update, isRoot ? void 0 : this.doc.guid);
198
+ };
199
+ this.fetchRoomDoc = (vector) => {
200
+ fetchDoc(vector, isRoot ? void 0 : this.doc.guid);
201
+ };
202
+ this.syncDoc();
203
+ }
204
+ // The sync'd property is required by some provider implementations
205
+ get synced() {
206
+ return this._synced;
207
+ }
208
+ set synced(state) {
209
+ if (this._synced !== state) {
210
+ this._synced = state;
211
+ this.emit("synced", [state]);
212
+ this.emit("sync", [state]);
213
+ }
214
+ }
215
+ destroy() {
216
+ this.doc.off("update", this.updateHandler);
217
+ this.unsubscribers.forEach((unsub) => unsub());
218
+ this._observers = /* @__PURE__ */ new Map();
219
+ this.doc.destroy();
220
+ }
221
+ };
222
+
223
+ // src/version.ts
224
+ var PKG_NAME = "@liveblocks/yjs";
225
+ var PKG_VERSION = "1.6.0-subdocs2";
226
+ var PKG_FORMAT = "esm";
227
+
228
+ // src/index.ts
229
+ detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
230
+ var DefaultOptions = {
231
+ autoloadSubdocs: false
232
+ };
233
+ var LiveblocksProvider = class extends Observable {
234
+ constructor(room, doc, options = DefaultOptions) {
235
+ super();
236
+ this.unsubscribers = [];
237
+ this.subdocHandlers = /* @__PURE__ */ new Map();
238
+ this.handleSubdocs = ({
239
+ loaded,
240
+ removed,
241
+ added
242
+ }) => {
243
+ loaded.forEach(this.createSubdocHandler);
244
+ if (this.options.autoloadSubdocs) {
245
+ for (const subdoc of added) {
246
+ if (!this.subdocHandlers.has(subdoc.guid)) {
247
+ subdoc.load();
248
+ }
249
+ }
250
+ }
251
+ for (const subdoc of removed) {
252
+ if (this.subdocHandlers.has(subdoc.guid)) {
253
+ this.subdocHandlers.get(subdoc.guid)?.destroy();
254
+ this.subdocHandlers.delete(subdoc.guid);
255
+ }
256
+ }
257
+ };
258
+ this.updateDoc = (update, guid) => {
259
+ this.room.updateYDoc(update, guid);
260
+ };
261
+ this.fetchDoc = (vector, guid) => {
262
+ this.room.fetchYDoc(vector, guid);
263
+ };
264
+ this.createSubdocHandler = (subdoc) => {
265
+ if (this.subdocHandlers.has(subdoc.guid)) {
266
+ this.subdocHandlers.get(subdoc.guid)?.syncDoc();
267
+ return;
268
+ }
269
+ const handler = new yDocHandler({
270
+ doc: subdoc,
271
+ isRoot: false,
272
+ updateDoc: this.updateDoc,
273
+ fetchDoc: this.fetchDoc
274
+ });
275
+ this.subdocHandlers.set(subdoc.guid, handler);
276
+ };
277
+ // attempt to load a subdoc of a given guid
278
+ this.loadSubdoc = (guid) => {
279
+ for (const subdoc of this.rootDoc.subdocs) {
280
+ if (subdoc.guid === guid) {
281
+ subdoc.load();
282
+ return true;
283
+ }
284
+ }
285
+ return false;
286
+ };
287
+ this.syncDoc = () => {
288
+ this.rootDoc.clientID = this.room.getSelf()?.connectionId || this.rootDoc.clientID;
289
+ this.awareness.clientID = this.rootDoc.clientID;
290
+ this.rootDocHandler.syncDoc();
291
+ for (const [_, handler] of this.subdocHandlers) {
292
+ handler.syncDoc();
293
+ }
294
+ };
295
+ this.rootDoc = doc;
180
296
  this.room = room;
297
+ this.options = options;
298
+ this.rootDocHandler = new yDocHandler({
299
+ doc,
300
+ isRoot: true,
301
+ updateDoc: this.updateDoc,
302
+ fetchDoc: this.fetchDoc
303
+ });
181
304
  const connectionId = this.room.getSelf()?.connectionId;
182
305
  if (connectionId) {
183
- this.doc.clientID = connectionId;
306
+ this.rootDoc.clientID = connectionId;
184
307
  }
185
- this.awareness = new Awareness(this.doc, this.room);
186
- this.doc.on("update", this.updateHandler);
308
+ this.awareness = new Awareness(this.rootDoc, this.room);
187
309
  this.unsubscribers.push(
188
310
  this.room.events.status.subscribe((status) => {
189
311
  if (status === "connected") {
190
- this.syncDoc();
312
+ this.rootDocHandler.syncDoc();
191
313
  } else {
192
- this.synced = false;
314
+ this.rootDocHandler.synced = false;
193
315
  }
194
316
  })
195
317
  );
196
318
  this.unsubscribers.push(
197
319
  this.room.events.ydoc.subscribe((message) => {
198
- const { type, update } = message;
320
+ const { type } = message;
199
321
  if (type === ClientMsgCode.UPDATE_YDOC) {
200
322
  return;
201
323
  }
202
- Y.applyUpdate(this.doc, Base64.toUint8Array(update), "backend");
203
- const { stateVector } = message;
204
- if (stateVector) {
205
- try {
206
- const localUpdate = Y.encodeStateAsUpdate(
207
- this.doc,
208
- Base64.toUint8Array(stateVector)
209
- );
210
- this.room.updateYDoc(Base64.fromUint8Array(localUpdate));
211
- } catch (e) {
212
- console.warn(e);
213
- }
214
- this.synced = true;
324
+ const { stateVector, update, guid } = message;
325
+ if (guid !== void 0) {
326
+ this.subdocHandlers.get(guid)?.handleServerUpdate({ update, stateVector });
327
+ } else {
328
+ this.rootDocHandler.handleServerUpdate({ update, stateVector });
215
329
  }
216
330
  })
217
331
  );
332
+ this.rootDocHandler.on("synced", () => {
333
+ const state = this.rootDocHandler.synced;
334
+ for (const [_, handler] of this.subdocHandlers) {
335
+ handler.syncDoc();
336
+ }
337
+ this.emit("synced", [state]);
338
+ this.emit("sync", [state]);
339
+ });
340
+ this.rootDoc.on("subdocs", this.handleSubdocs);
218
341
  this.syncDoc();
219
342
  }
220
343
  // The sync'd property is required by some provider implementations
221
344
  get synced() {
222
- return this._synced;
223
- }
224
- set synced(state) {
225
- if (this._synced !== state) {
226
- this._synced = state;
227
- this.emit("synced", [state]);
228
- this.emit("sync", [state]);
229
- }
345
+ return this.rootDocHandler.synced;
230
346
  }
231
347
  destroy() {
232
- this.doc.off("update", this.updateHandler);
233
348
  this.unsubscribers.forEach((unsub) => unsub());
234
349
  this.awareness.destroy();
350
+ this.rootDocHandler.destroy();
351
+ this._observers = /* @__PURE__ */ new Map();
352
+ for (const [_, handler] of this.subdocHandlers) {
353
+ handler.destroy();
354
+ }
355
+ this.subdocHandlers.clear();
235
356
  super.destroy();
236
357
  }
237
358
  // Some provider implementations expect to be able to call connect/disconnect, implement as noop
@@ -241,7 +362,6 @@ var LiveblocksProvider = class extends Observable {
241
362
  }
242
363
  };
243
364
  export {
244
- Awareness,
245
365
  LiveblocksProvider as default
246
366
  };
247
367
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../../../node_modules/lib0/map.js","../../../node_modules/lib0/set.js","../../../node_modules/lib0/array.js","../../../node_modules/lib0/observable.js","../src/version.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { ClientMsgCode, detectDupes } from \"@liveblocks/core\";\nimport { Base64 } from \"js-base64\";\nimport { Observable } from \"lib0/observable\";\nimport * as Y from \"yjs\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n2;\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nconst Y_PRESENCE_KEY = \"__yjs\";\n\ntype MetaClientState = {\n clock: number;\n lastUpdated: number;\n};\n\n/**\n * This class will store Yjs awareness in Liveblock's presence under the __yjs key\n * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users\n * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,\n * we simply set the clientId of the doc to the connectionId. Then no further mapping is required\n */\nexport class Awareness extends Observable<unknown> {\n private room: Room<JsonObject, LsonObject, BaseUserMeta, Json>;\n public doc: Y.Doc;\n public clientID: number;\n public states: Map<number, unknown> = new Map();\n // Meta is used to keep track and timeout users who disconnect. Liveblocks provides this for us, so we don't need to\n // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.\n public meta: Map<number, MetaClientState> = new Map();\n // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this\n // unfortunately it's typed by various integrations\n public _checkInterval: number = 0;\n\n private othersUnsub: () => void;\n constructor(\n doc: Y.Doc,\n room: Room<JsonObject, LsonObject, BaseUserMeta, Json>\n ) {\n super();\n this.doc = doc;\n this.room = room;\n this.clientID = doc.clientID;\n this.othersUnsub = this.room.events.others.subscribe((event) => {\n // When others are changed, we emit an event that contains arrays added/updated/removed.\n if (event.type === \"leave\") {\n // REMOVED\n this.emit(\"change\", [\n { added: [], updated: [], removed: [event.user.connectionId] },\n \"local\",\n ]);\n }\n\n if (event.type === \"enter\") {\n // ADDED\n this.emit(\"change\", [\n { added: [event.user.connectionId], updated: [], removed: [] },\n \"local\",\n ]);\n }\n\n if (event.type === \"update\") {\n // UPDATED\n this.emit(\"change\", [\n { added: [], updated: [event.user.connectionId], removed: [] },\n \"local\",\n ]);\n }\n });\n }\n\n destroy(): void {\n this.emit(\"destroy\", [this]);\n this.othersUnsub();\n this.setLocalState(null);\n super.destroy();\n }\n\n getLocalState(): JsonObject | null {\n const presence = this.room.getPresence();\n if (\n Object.keys(presence).length === 0 ||\n typeof presence[Y_PRESENCE_KEY] === \"undefined\"\n ) {\n return null;\n }\n return presence[Y_PRESENCE_KEY] as JsonObject | null;\n }\n\n setLocalState(state: Partial<JsonObject> | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...(state || {}) },\n });\n }\n\n setLocalStateField(field: string, value: JsonObject | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n const update = { [field]: value } as Partial<JsonObject>;\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...update },\n });\n }\n\n // Translate liveblocks presence to yjs awareness\n getStates(): Map<number, unknown> {\n const others = this.room.getOthers();\n const states = others.reduce((acc: Map<number, unknown>, currentValue) => {\n if (currentValue.connectionId) {\n // connectionId == actorId == yjs.clientId\n acc.set(\n currentValue.connectionId,\n currentValue.presence[Y_PRESENCE_KEY] || {}\n );\n }\n return acc;\n }, new Map());\n return states;\n }\n}\n\nexport default class LiveblocksProvider<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n> extends Observable<unknown> {\n private room: Room<P, S, U, E>;\n private doc: Y.Doc;\n\n private unsubscribers: Array<() => void> = [];\n\n public awareness: Awareness;\n\n private _synced = false;\n\n constructor(room: Room<P, S, U, E>, doc: Y.Doc) {\n super();\n this.doc = doc;\n this.room = room;\n\n // if we have a connectionId already during construction, use that\n const connectionId = this.room.getSelf()?.connectionId;\n if (connectionId) {\n this.doc.clientID = connectionId;\n }\n this.awareness = new Awareness(this.doc, this.room);\n this.doc.on(\"update\", this.updateHandler);\n\n this.unsubscribers.push(\n this.room.events.status.subscribe((status) => {\n if (status === \"connected\") {\n this.syncDoc();\n } else {\n this.synced = false;\n }\n })\n );\n\n this.unsubscribers.push(\n this.room.events.ydoc.subscribe((message) => {\n const { type, update } = message;\n if (type === ClientMsgCode.UPDATE_YDOC) {\n // don't apply updates that came from the client\n return;\n }\n // apply update from the server\n Y.applyUpdate(this.doc, Base64.toUint8Array(update), \"backend\");\n const { stateVector } = message;\n // if this update is the result of a fetch, the state vector is included\n if (stateVector) {\n // Use server state to calculate a diff and send it\n try {\n const localUpdate = Y.encodeStateAsUpdate(\n this.doc,\n Base64.toUint8Array(stateVector)\n );\n this.room.updateYDoc(Base64.fromUint8Array(localUpdate));\n } catch (e) {\n // something went wrong encoding local state to send to the server\n console.warn(e);\n }\n // now that we've sent our local and received from server, we're in sync\n // calling `syncDoc` again will sync up the documents\n this.synced = true;\n }\n })\n );\n this.syncDoc();\n }\n\n private syncDoc = () => {\n this.synced = false;\n /**\n * If the connection changes, set the new id, this is used by awareness.\n * yjs' only requirement for clientID is that it's truly unique and a number.\n * Liveblock's connectionID satisfies those constraints\n * */\n this.doc.clientID = this.room.getSelf()?.connectionId || this.doc.clientID;\n this.awareness.clientID = this.doc.clientID; // tell our awareness provider the new ID\n\n // The state vector is sent to the server so it knows what to send back\n // if you don't send it, it returns everything\n const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));\n this.room.fetchYDoc(encodedVector);\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this._synced;\n }\n\n set synced(state: boolean) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n private updateHandler = (update: Uint8Array, origin: string) => {\n if (origin !== \"backend\") {\n const encodedUpdate = Base64.fromUint8Array(update);\n this.room.updateYDoc(encodedUpdate);\n }\n };\n\n destroy(): void {\n this.doc.off(\"update\", this.updateHandler);\n this.unsubscribers.forEach((unsub) => unsub());\n this.awareness.destroy();\n super.destroy();\n }\n\n // Some provider implementations expect to be able to call connect/disconnect, implement as noop\n disconnect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n\n connect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n}\n","/**\n * Utility module to work with key-value stores.\n *\n * @module map\n */\n\n/**\n * Creates a new Map instance.\n *\n * @function\n * @return {Map<any, any>}\n *\n * @function\n */\nexport const create = () => new Map()\n\n/**\n * Copy a Map object into a fresh Map object.\n *\n * @function\n * @template X,Y\n * @param {Map<X,Y>} m\n * @return {Map<X,Y>}\n */\nexport const copy = m => {\n const r = create()\n m.forEach((v, k) => { r.set(k, v) })\n return r\n}\n\n/**\n * Get map property. Create T if property is undefined and set T on map.\n *\n * ```js\n * const listeners = map.setIfUndefined(events, 'eventName', set.create)\n * listeners.add(listener)\n * ```\n *\n * @function\n * @template V,K\n * @template {Map<K,V>} MAP\n * @param {MAP} map\n * @param {K} key\n * @param {function():V} createT\n * @return {V}\n */\nexport const setIfUndefined = (map, key, createT) => {\n let set = map.get(key)\n if (set === undefined) {\n map.set(key, set = createT())\n }\n return set\n}\n\n/**\n * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.\n *\n * @function\n * @template K\n * @template V\n * @template R\n * @param {Map<K,V>} m\n * @param {function(V,K):R} f\n * @return {Array<R>}\n */\nexport const map = (m, f) => {\n const res = []\n for (const [key, value] of m) {\n res.push(f(value, key))\n }\n return res\n}\n\n/**\n * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @todo should rename to some - similarly to Array.some\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const any = (m, f) => {\n for (const [key, value] of m) {\n if (f(value, key)) {\n return true\n }\n }\n return false\n}\n\n/**\n * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const all = (m, f) => {\n for (const [key, value] of m) {\n if (!f(value, key)) {\n return false\n }\n }\n return true\n}\n","/**\n * Utility module to work with sets.\n *\n * @module set\n */\n\nexport const create = () => new Set()\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {Array<T>}\n */\nexport const toArray = set => Array.from(set)\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {T}\n */\nexport const first = set =>\n set.values().next().value || undefined\n\n/**\n * @template T\n * @param {Iterable<T>} entries\n * @return {Set<T>}\n */\nexport const from = entries => new Set(entries)\n","/**\n * Utility module to work with Arrays.\n *\n * @module array\n */\n\nimport * as set from './set.js'\n\n/**\n * Return the last element of an array. The element must exist\n *\n * @template L\n * @param {ArrayLike<L>} arr\n * @return {L}\n */\nexport const last = arr => arr[arr.length - 1]\n\n/**\n * @template C\n * @return {Array<C>}\n */\nexport const create = () => /** @type {Array<C>} */ ([])\n\n/**\n * @template D\n * @param {Array<D>} a\n * @return {Array<D>}\n */\nexport const copy = a => /** @type {Array<D>} */ (a.slice())\n\n/**\n * Append elements from src to dest\n *\n * @template M\n * @param {Array<M>} dest\n * @param {Array<M>} src\n */\nexport const appendTo = (dest, src) => {\n for (let i = 0; i < src.length; i++) {\n dest.push(src[i])\n }\n}\n\n/**\n * Transforms something array-like to an actual Array.\n *\n * @function\n * @template T\n * @param {ArrayLike<T>|Iterable<T>} arraylike\n * @return {T}\n */\nexport const from = Array.from\n\n/**\n * True iff condition holds on every element in the Array.\n *\n * @function\n * @template ITEM\n * @template {ArrayLike<ITEM>} ARR\n *\n * @param {ARR} arr\n * @param {function(ITEM, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const every = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (!f(arr[i], i, arr)) {\n return false\n }\n }\n return true\n}\n\n/**\n * True iff condition holds on some element in the Array.\n *\n * @function\n * @template S\n * @template {ArrayLike<S>} ARR\n * @param {ARR} arr\n * @param {function(S, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const some = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (f(arr[i], i, arr)) {\n return true\n }\n }\n return false\n}\n\n/**\n * @template ELEM\n *\n * @param {ArrayLike<ELEM>} a\n * @param {ArrayLike<ELEM>} b\n * @return {boolean}\n */\nexport const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])\n\n/**\n * @template ELEM\n * @param {Array<Array<ELEM>>} arr\n * @return {Array<ELEM>}\n */\nexport const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))\n\n/**\n * @template T\n * @param {number} len\n * @param {function(number, Array<T>):T} f\n * @return {Array<T>}\n */\nexport const unfold = (len, f) => {\n const array = new Array(len)\n for (let i = 0; i < len; i++) {\n array[i] = f(i, array)\n }\n return array\n}\n\n/**\n * @template T\n * @template RESULT\n * @param {Array<T>} arr\n * @param {RESULT} seed\n * @param {function(RESULT, T, number):RESULT} folder\n */\nexport const fold = (arr, seed, folder) => arr.reduce(folder, seed)\n\nexport const isArray = Array.isArray\n\n/**\n * @template T\n * @param {Array<T>} arr\n * @return {Array<T>}\n */\nexport const unique = arr => from(set.from(arr))\n\n/**\n * @template T\n * @template M\n * @param {ArrayLike<T>} arr\n * @param {function(T):M} mapper\n * @return {Array<T>}\n */\nexport const uniqueBy = (arr, mapper) => {\n /**\n * @type {Set<M>}\n */\n const happened = set.create()\n /**\n * @type {Array<T>}\n */\n const result = []\n for (let i = 0; i < arr.length; i++) {\n const el = arr[i]\n const mapped = mapper(el)\n if (!happened.has(mapped)) {\n happened.add(mapped)\n result.push(el)\n }\n }\n return result\n}\n","/**\n * Observable class prototype.\n *\n * @module observable\n */\n\nimport * as map from './map.js'\nimport * as set from './set.js'\nimport * as array from './array.js'\n\n/**\n * Handles named events.\n *\n * @template N\n */\nexport class Observable {\n constructor () {\n /**\n * Some desc.\n * @type {Map<N, any>}\n */\n this._observers = map.create()\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n on (name, f) {\n map.setIfUndefined(this._observers, name, set.create).add(f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n once (name, f) {\n /**\n * @param {...any} args\n */\n const _f = (...args) => {\n this.off(name, _f)\n f(...args)\n }\n this.on(name, _f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n off (name, f) {\n const observers = this._observers.get(name)\n if (observers !== undefined) {\n observers.delete(f)\n if (observers.size === 0) {\n this._observers.delete(name)\n }\n }\n }\n\n /**\n * Emit a named event. All registered event listeners that listen to the\n * specified name will receive the event.\n *\n * @todo This should catch exceptions\n *\n * @param {N} name The event name.\n * @param {Array<any>} args The arguments that are applied to the event listener.\n */\n emit (name, args) {\n // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.\n return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))\n }\n\n destroy () {\n this._observers = map.create()\n }\n}\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/yjs\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"mappings":"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","names":["create","create"]}
1
+ {"version":3,"sources":["../src/index.ts","../../../node_modules/lib0/map.js","../../../node_modules/lib0/set.js","../../../node_modules/lib0/array.js","../../../node_modules/lib0/observable.js","../src/awareness.ts","../src/doc.ts","../src/version.ts"],"sourcesContent":["import type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { ClientMsgCode, detectDupes } from \"@liveblocks/core\";\nimport { Observable } from \"lib0/observable\";\nimport type * as Y from \"yjs\";\n\nimport { Awareness } from \"./awareness\";\nimport yDocHandler from \"./doc\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n2;\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\ntype ProviderOptions = {\n autoloadSubdocs: boolean;\n};\n\nconst DefaultOptions: ProviderOptions = {\n autoloadSubdocs: false,\n};\n\nexport default class LiveblocksProvider<\n P extends JsonObject,\n S extends LsonObject,\n U extends BaseUserMeta,\n E extends Json,\n> extends Observable<unknown> {\n private room: Room<P, S, U, E>;\n private rootDoc: Y.Doc;\n private options: ProviderOptions;\n\n private unsubscribers: Array<() => void> = [];\n\n public awareness: Awareness;\n\n public rootDocHandler: yDocHandler;\n public subdocHandlers: Map<string, yDocHandler> = new Map();\n\n constructor(\n room: Room<P, S, U, E>,\n doc: Y.Doc,\n options: ProviderOptions | undefined = DefaultOptions\n ) {\n super();\n this.rootDoc = doc;\n this.room = room;\n this.options = options;\n this.rootDocHandler = new yDocHandler({\n doc,\n isRoot: true,\n updateDoc: this.updateDoc,\n fetchDoc: this.fetchDoc,\n });\n // if we have a connectionId already during construction, use that\n const connectionId = this.room.getSelf()?.connectionId;\n if (connectionId) {\n this.rootDoc.clientID = connectionId;\n }\n this.awareness = new Awareness(this.rootDoc, this.room);\n\n this.unsubscribers.push(\n this.room.events.status.subscribe((status) => {\n if (status === \"connected\") {\n this.rootDocHandler.syncDoc();\n } else {\n this.rootDocHandler.synced = false;\n }\n })\n );\n\n this.unsubscribers.push(\n this.room.events.ydoc.subscribe((message) => {\n const { type } = message;\n if (type === ClientMsgCode.UPDATE_YDOC) {\n // don't apply updates that came from the client\n return;\n }\n const { stateVector, update, guid } = message;\n // find the right doc and update\n if (guid !== undefined) {\n this.subdocHandlers\n .get(guid)\n ?.handleServerUpdate({ update, stateVector });\n } else {\n this.rootDocHandler.handleServerUpdate({ update, stateVector });\n }\n })\n );\n\n this.rootDocHandler.on(\"synced\", () => {\n const state = this.rootDocHandler.synced;\n for (const [_, handler] of this.subdocHandlers) {\n handler.syncDoc();\n }\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n });\n this.rootDoc.on(\"subdocs\", this.handleSubdocs);\n this.syncDoc();\n }\n\n private handleSubdocs = ({\n loaded,\n removed,\n added,\n }: {\n loaded: Y.Doc[];\n removed: Y.Doc[];\n added: Y.Doc[];\n }) => {\n loaded.forEach(this.createSubdocHandler);\n if (this.options.autoloadSubdocs) {\n for (const subdoc of added) {\n if (!this.subdocHandlers.has(subdoc.guid)) {\n subdoc.load();\n }\n }\n }\n for (const subdoc of removed) {\n if (this.subdocHandlers.has(subdoc.guid)) {\n this.subdocHandlers.get(subdoc.guid)?.destroy();\n this.subdocHandlers.delete(subdoc.guid);\n }\n }\n };\n\n private updateDoc = (update: string, guid?: string) => {\n this.room.updateYDoc(update, guid);\n };\n\n private fetchDoc = (vector: string, guid?: string) => {\n this.room.fetchYDoc(vector, guid);\n };\n\n private createSubdocHandler = (subdoc: Y.Doc): void => {\n if (this.subdocHandlers.has(subdoc.guid)) {\n // if we already handle this subdoc, just fetch it again\n this.subdocHandlers.get(subdoc.guid)?.syncDoc();\n return;\n }\n const handler = new yDocHandler({\n doc: subdoc,\n isRoot: false,\n updateDoc: this.updateDoc,\n fetchDoc: this.fetchDoc,\n });\n this.subdocHandlers.set(subdoc.guid, handler);\n };\n\n // attempt to load a subdoc of a given guid\n public loadSubdoc = (guid: string): boolean => {\n for (const subdoc of this.rootDoc.subdocs) {\n if (subdoc.guid === guid) {\n subdoc.load();\n return true;\n }\n }\n // should we throw instead?\n return false;\n };\n\n private syncDoc = () => {\n /**\n * If the connection changes, set the new id, this is used by awareness.\n * yjs' only requirement for clientID is that it's truly unique and a number.\n * Liveblock's connectionID satisfies those constraints\n * */\n this.rootDoc.clientID =\n this.room.getSelf()?.connectionId || this.rootDoc.clientID;\n this.awareness.clientID = this.rootDoc.clientID; // tell our awareness provider the new ID\n\n this.rootDocHandler.syncDoc();\n for (const [_, handler] of this.subdocHandlers) {\n handler.syncDoc();\n }\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this.rootDocHandler.synced;\n }\n\n destroy(): void {\n this.unsubscribers.forEach((unsub) => unsub());\n this.awareness.destroy();\n this.rootDocHandler.destroy();\n this._observers = new Map();\n for (const [_, handler] of this.subdocHandlers) {\n handler.destroy();\n }\n this.subdocHandlers.clear();\n super.destroy();\n }\n\n // Some provider implementations expect to be able to call connect/disconnect, implement as noop\n disconnect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n\n connect(): void {\n // This is a noop for liveblocks as connections are managed by the room\n }\n}\n","/**\n * Utility module to work with key-value stores.\n *\n * @module map\n */\n\n/**\n * Creates a new Map instance.\n *\n * @function\n * @return {Map<any, any>}\n *\n * @function\n */\nexport const create = () => new Map()\n\n/**\n * Copy a Map object into a fresh Map object.\n *\n * @function\n * @template X,Y\n * @param {Map<X,Y>} m\n * @return {Map<X,Y>}\n */\nexport const copy = m => {\n const r = create()\n m.forEach((v, k) => { r.set(k, v) })\n return r\n}\n\n/**\n * Get map property. Create T if property is undefined and set T on map.\n *\n * ```js\n * const listeners = map.setIfUndefined(events, 'eventName', set.create)\n * listeners.add(listener)\n * ```\n *\n * @function\n * @template V,K\n * @template {Map<K,V>} MAP\n * @param {MAP} map\n * @param {K} key\n * @param {function():V} createT\n * @return {V}\n */\nexport const setIfUndefined = (map, key, createT) => {\n let set = map.get(key)\n if (set === undefined) {\n map.set(key, set = createT())\n }\n return set\n}\n\n/**\n * Creates an Array and populates it with the content of all key-value pairs using the `f(value, key)` function.\n *\n * @function\n * @template K\n * @template V\n * @template R\n * @param {Map<K,V>} m\n * @param {function(V,K):R} f\n * @return {Array<R>}\n */\nexport const map = (m, f) => {\n const res = []\n for (const [key, value] of m) {\n res.push(f(value, key))\n }\n return res\n}\n\n/**\n * Tests whether any key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @todo should rename to some - similarly to Array.some\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const any = (m, f) => {\n for (const [key, value] of m) {\n if (f(value, key)) {\n return true\n }\n }\n return false\n}\n\n/**\n * Tests whether all key-value pairs pass the test implemented by `f(value, key)`.\n *\n * @function\n * @template K\n * @template V\n * @param {Map<K,V>} m\n * @param {function(V,K):boolean} f\n * @return {boolean}\n */\nexport const all = (m, f) => {\n for (const [key, value] of m) {\n if (!f(value, key)) {\n return false\n }\n }\n return true\n}\n","/**\n * Utility module to work with sets.\n *\n * @module set\n */\n\nexport const create = () => new Set()\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {Array<T>}\n */\nexport const toArray = set => Array.from(set)\n\n/**\n * @template T\n * @param {Set<T>} set\n * @return {T}\n */\nexport const first = set =>\n set.values().next().value || undefined\n\n/**\n * @template T\n * @param {Iterable<T>} entries\n * @return {Set<T>}\n */\nexport const from = entries => new Set(entries)\n","/**\n * Utility module to work with Arrays.\n *\n * @module array\n */\n\nimport * as set from './set.js'\n\n/**\n * Return the last element of an array. The element must exist\n *\n * @template L\n * @param {ArrayLike<L>} arr\n * @return {L}\n */\nexport const last = arr => arr[arr.length - 1]\n\n/**\n * @template C\n * @return {Array<C>}\n */\nexport const create = () => /** @type {Array<C>} */ ([])\n\n/**\n * @template D\n * @param {Array<D>} a\n * @return {Array<D>}\n */\nexport const copy = a => /** @type {Array<D>} */ (a.slice())\n\n/**\n * Append elements from src to dest\n *\n * @template M\n * @param {Array<M>} dest\n * @param {Array<M>} src\n */\nexport const appendTo = (dest, src) => {\n for (let i = 0; i < src.length; i++) {\n dest.push(src[i])\n }\n}\n\n/**\n * Transforms something array-like to an actual Array.\n *\n * @function\n * @template T\n * @param {ArrayLike<T>|Iterable<T>} arraylike\n * @return {T}\n */\nexport const from = Array.from\n\n/**\n * True iff condition holds on every element in the Array.\n *\n * @function\n * @template ITEM\n * @template {ArrayLike<ITEM>} ARR\n *\n * @param {ARR} arr\n * @param {function(ITEM, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const every = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (!f(arr[i], i, arr)) {\n return false\n }\n }\n return true\n}\n\n/**\n * True iff condition holds on some element in the Array.\n *\n * @function\n * @template S\n * @template {ArrayLike<S>} ARR\n * @param {ARR} arr\n * @param {function(S, number, ARR):boolean} f\n * @return {boolean}\n */\nexport const some = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n if (f(arr[i], i, arr)) {\n return true\n }\n }\n return false\n}\n\n/**\n * @template ELEM\n *\n * @param {ArrayLike<ELEM>} a\n * @param {ArrayLike<ELEM>} b\n * @return {boolean}\n */\nexport const equalFlat = (a, b) => a.length === b.length && every(a, (item, index) => item === b[index])\n\n/**\n * @template ELEM\n * @param {Array<Array<ELEM>>} arr\n * @return {Array<ELEM>}\n */\nexport const flatten = arr => fold(arr, /** @type {Array<ELEM>} */ ([]), (acc, val) => acc.concat(val))\n\n/**\n * @template T\n * @param {number} len\n * @param {function(number, Array<T>):T} f\n * @return {Array<T>}\n */\nexport const unfold = (len, f) => {\n const array = new Array(len)\n for (let i = 0; i < len; i++) {\n array[i] = f(i, array)\n }\n return array\n}\n\n/**\n * @template T\n * @template RESULT\n * @param {Array<T>} arr\n * @param {RESULT} seed\n * @param {function(RESULT, T, number):RESULT} folder\n */\nexport const fold = (arr, seed, folder) => arr.reduce(folder, seed)\n\nexport const isArray = Array.isArray\n\n/**\n * @template T\n * @param {Array<T>} arr\n * @return {Array<T>}\n */\nexport const unique = arr => from(set.from(arr))\n\n/**\n * @template T\n * @template M\n * @param {ArrayLike<T>} arr\n * @param {function(T):M} mapper\n * @return {Array<T>}\n */\nexport const uniqueBy = (arr, mapper) => {\n /**\n * @type {Set<M>}\n */\n const happened = set.create()\n /**\n * @type {Array<T>}\n */\n const result = []\n for (let i = 0; i < arr.length; i++) {\n const el = arr[i]\n const mapped = mapper(el)\n if (!happened.has(mapped)) {\n happened.add(mapped)\n result.push(el)\n }\n }\n return result\n}\n","/**\n * Observable class prototype.\n *\n * @module observable\n */\n\nimport * as map from './map.js'\nimport * as set from './set.js'\nimport * as array from './array.js'\n\n/**\n * Handles named events.\n *\n * @template N\n */\nexport class Observable {\n constructor () {\n /**\n * Some desc.\n * @type {Map<N, any>}\n */\n this._observers = map.create()\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n on (name, f) {\n map.setIfUndefined(this._observers, name, set.create).add(f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n once (name, f) {\n /**\n * @param {...any} args\n */\n const _f = (...args) => {\n this.off(name, _f)\n f(...args)\n }\n this.on(name, _f)\n }\n\n /**\n * @param {N} name\n * @param {function} f\n */\n off (name, f) {\n const observers = this._observers.get(name)\n if (observers !== undefined) {\n observers.delete(f)\n if (observers.size === 0) {\n this._observers.delete(name)\n }\n }\n }\n\n /**\n * Emit a named event. All registered event listeners that listen to the\n * specified name will receive the event.\n *\n * @todo This should catch exceptions\n *\n * @param {N} name The event name.\n * @param {Array<any>} args The arguments that are applied to the event listener.\n */\n emit (name, args) {\n // copy all listeners to an array first to make sure that no event is emitted to listeners that are subscribed while the event handler is called.\n return array.from((this._observers.get(name) || map.create()).values()).forEach(f => f(...args))\n }\n\n destroy () {\n this._observers = map.create()\n }\n}\n","// TODO: apparently Yjs is full of anys or something, see if we can fix this\n/* eslint-disable @typescript-eslint/no-unsafe-call */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport type {\n BaseUserMeta,\n Json,\n JsonObject,\n LsonObject,\n Room,\n} from \"@liveblocks/client\";\nimport { Observable } from \"lib0/observable\";\nimport type * as Y from \"yjs\";\n\nconst Y_PRESENCE_KEY = \"__yjs\";\n\ntype MetaClientState = {\n clock: number;\n lastUpdated: number;\n};\n\n/**\n * This class will store Yjs awareness in Liveblock's presence under the __yjs key\n * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users\n * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,\n * we simply set the clientId of the doc to the connectionId. Then no further mapping is required\n */\nexport class Awareness extends Observable<unknown> {\n private room: Room<JsonObject, LsonObject, BaseUserMeta, Json>;\n public doc: Y.Doc;\n public clientID: number;\n public states: Map<number, unknown> = new Map();\n // Meta is used to keep track and timeout users who disconnect. Liveblocks provides this for us, so we don't need to\n // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.\n public meta: Map<number, MetaClientState> = new Map();\n // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this\n // unfortunately it's typed by various integrations\n public _checkInterval: number = 0;\n\n private othersUnsub: () => void;\n constructor(\n doc: Y.Doc,\n room: Room<JsonObject, LsonObject, BaseUserMeta, Json>\n ) {\n super();\n this.doc = doc;\n this.room = room;\n this.clientID = doc.clientID;\n this.othersUnsub = this.room.events.others.subscribe((event) => {\n // When others are changed, we emit an event that contains arrays added/updated/removed.\n if (event.type === \"leave\") {\n // REMOVED\n this.emit(\"change\", [\n { added: [], updated: [], removed: [event.user.connectionId] },\n \"local\",\n ]);\n }\n\n if (event.type === \"enter\") {\n // ADDED\n this.emit(\"change\", [\n { added: [event.user.connectionId], updated: [], removed: [] },\n \"local\",\n ]);\n }\n\n if (event.type === \"update\") {\n // UPDATED\n this.emit(\"change\", [\n { added: [], updated: [event.user.connectionId], removed: [] },\n \"local\",\n ]);\n }\n });\n }\n\n destroy(): void {\n this.emit(\"destroy\", [this]);\n this.othersUnsub();\n this.setLocalState(null);\n super.destroy();\n }\n\n getLocalState(): JsonObject | null {\n const presence = this.room.getPresence();\n if (\n Object.keys(presence).length === 0 ||\n typeof presence[Y_PRESENCE_KEY] === \"undefined\"\n ) {\n return null;\n }\n return presence[Y_PRESENCE_KEY] as JsonObject | null;\n }\n\n setLocalState(state: Partial<JsonObject> | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...(state || {}) },\n });\n }\n\n setLocalStateField(field: string, value: JsonObject | null): void {\n const presence = this.room.getSelf()?.presence[Y_PRESENCE_KEY];\n const update = { [field]: value } as Partial<JsonObject>;\n this.room.updatePresence({\n __yjs: { ...((presence as JsonObject) || {}), ...update },\n });\n }\n\n // Translate liveblocks presence to yjs awareness\n getStates(): Map<number, unknown> {\n const others = this.room.getOthers();\n const states = others.reduce((acc: Map<number, unknown>, currentValue) => {\n if (currentValue.connectionId) {\n // connectionId == actorId == yjs.clientId\n acc.set(\n currentValue.connectionId,\n currentValue.presence[Y_PRESENCE_KEY] || {}\n );\n }\n return acc;\n }, new Map());\n return states;\n }\n}\n","import { Base64 } from \"js-base64\";\nimport { Observable } from \"lib0/observable\";\nimport * as Y from \"yjs\";\n\nexport default class yDocHandler extends Observable<unknown> {\n private unsubscribers: Array<() => void> = [];\n\n private _synced = false;\n private doc: Y.Doc;\n private updateRoomDoc: (update: string) => void;\n private fetchRoomDoc: (vector: string) => void;\n\n constructor({\n doc,\n isRoot,\n updateDoc,\n fetchDoc,\n }: {\n doc: Y.Doc;\n isRoot: boolean;\n updateDoc: (update: string, guid?: string) => void;\n fetchDoc: (vector: string, guid?: string) => void;\n }) {\n super();\n this.doc = doc;\n // this.doc.load(); // this just emits a load event, it doesn't actually load anything\n this.doc.on(\"update\", this.updateHandler);\n this.updateRoomDoc = (update: string) => {\n updateDoc(update, isRoot ? undefined : this.doc.guid);\n };\n this.fetchRoomDoc = (vector: string) => {\n fetchDoc(vector, isRoot ? undefined : this.doc.guid);\n };\n\n this.syncDoc();\n }\n\n public handleServerUpdate = ({\n update,\n stateVector,\n }: {\n update: string;\n stateVector: string | null;\n }): void => {\n // apply update from the server\n Y.applyUpdate(this.doc, Base64.toUint8Array(update), \"backend\");\n // if this update is the result of a fetch, the state vector is included\n if (stateVector) {\n // Use server state to calculate a diff and send it\n try {\n const localUpdate = Y.encodeStateAsUpdate(\n this.doc,\n Base64.toUint8Array(stateVector)\n );\n this.updateRoomDoc(Base64.fromUint8Array(localUpdate));\n } catch (e) {\n // something went wrong encoding local state to send to the server\n console.warn(e);\n }\n // now that we've sent our local and received from server, we're in sync\n // calling `syncDoc` again will sync up the documents\n this.synced = true;\n }\n };\n\n public syncDoc = (): void => {\n this.synced = false;\n\n // The state vector is sent to the server so it knows what to send back\n // if you don't send it, it returns everything\n const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));\n this.fetchRoomDoc(encodedVector);\n };\n\n // The sync'd property is required by some provider implementations\n get synced(): boolean {\n return this._synced;\n }\n\n set synced(state: boolean) {\n if (this._synced !== state) {\n this._synced = state;\n this.emit(\"synced\", [state]);\n this.emit(\"sync\", [state]);\n }\n }\n\n private updateHandler = (update: Uint8Array, origin: string) => {\n if (origin !== \"backend\") {\n const encodedUpdate = Base64.fromUint8Array(update);\n this.updateRoomDoc(encodedUpdate);\n }\n };\n\n destroy(): void {\n this.doc.off(\"update\", this.updateHandler);\n this.unsubscribers.forEach((unsub) => unsub());\n this._observers = new Map();\n this.doc.destroy();\n }\n}\n","declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/yjs\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"mappings":"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","names":["create","create"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/yjs",
3
- "version": "1.5.3",
3
+ "version": "1.6.0-subdocs2",
4
4
  "description": "An integration with . Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -32,8 +32,8 @@
32
32
  "test:watch": "jest --silent --verbose --color=always --watch"
33
33
  },
34
34
  "dependencies": {
35
- "@liveblocks/client": "1.5.3",
36
- "@liveblocks/core": "1.5.3",
35
+ "@liveblocks/client": "1.6.0-subdocs2",
36
+ "@liveblocks/core": "1.6.0-subdocs2",
37
37
  "js-base64": "^3.7.5"
38
38
  },
39
39
  "peerDependencies": {