@liveblocks/yjs 1.1.0-yjs5 → 1.1.1-yjs2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  # `@liveblocks/yjs`
11
11
 
12
- Provides YJS integration to effortlessly back your YJS apps with Liveblocks
12
+ Provides Yjs integration to effortlessly back your Yjs apps with Liveblocks
13
13
 
14
14
  ## Installation
15
15
 
@@ -0,0 +1,42 @@
1
+ import { Room, JsonObject, LsonObject, BaseUserMeta, Json } from '@liveblocks/client';
2
+ import { Observable } from 'lib0/observable';
3
+ import * as Y from 'yjs';
4
+
5
+ declare type MetaClientState = {
6
+ clock: number;
7
+ lastUpdated: number;
8
+ };
9
+ /**
10
+ * This class will store Yjs awareness in Liveblock's presence under the __yjs key
11
+ * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users
12
+ * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,
13
+ * we simply set the clientId of the doc to the connectionId. Then no further mapping is required
14
+ */
15
+ declare class Awareness extends Observable<unknown> {
16
+ private room;
17
+ doc: Y.Doc;
18
+ clientID: number;
19
+ states: Map<number, unknown>;
20
+ meta: Map<number, MetaClientState>;
21
+ _checkInterval: number;
22
+ private othersUnsub;
23
+ constructor(doc: Y.Doc, room: Room<JsonObject, LsonObject, BaseUserMeta, Json>);
24
+ destroy(): void;
25
+ getLocalState(): JsonObject | null;
26
+ setLocalState(state: Partial<JsonObject> | null): void;
27
+ setLocalStateField(field: string, value: JsonObject | null): void;
28
+ getStates(): Map<number, unknown>;
29
+ }
30
+ declare class LiveblocksProvider<P extends JsonObject, S extends LsonObject, U extends BaseUserMeta, E extends Json> {
31
+ private room;
32
+ private httpEndpoint?;
33
+ private doc;
34
+ private unsubscribers;
35
+ awareness: Awareness;
36
+ constructor(room: Room<P, S, U, E>, doc: Y.Doc);
37
+ private syncDoc;
38
+ private updateHandler;
39
+ destroy(): void;
40
+ }
41
+
42
+ export { Awareness, LiveblocksProvider as default };
package/dist/index.d.ts CHANGED
@@ -2,18 +2,21 @@ import { Room, JsonObject, LsonObject, BaseUserMeta, Json } from '@liveblocks/cl
2
2
  import { Observable } from 'lib0/observable';
3
3
  import * as Y from 'yjs';
4
4
 
5
- declare type LiveblocksYjsOptions = {
6
- httpEndpoint?: string;
7
- };
8
5
  declare type MetaClientState = {
9
6
  clock: number;
10
7
  lastUpdated: number;
11
8
  };
12
- declare class Awareness extends Observable<any> {
9
+ /**
10
+ * This class will store Yjs awareness in Liveblock's presence under the __yjs key
11
+ * IMPORTANT: The Yjs awareness protocol uses ydoc.clientId to reference users
12
+ * to their respective documents. To avoid mapping Yjs clientIds to liveblock's connectionId,
13
+ * we simply set the clientId of the doc to the connectionId. Then no further mapping is required
14
+ */
15
+ declare class Awareness extends Observable<unknown> {
13
16
  private room;
14
17
  doc: Y.Doc;
15
18
  clientID: number;
16
- states: Map<number, any>;
19
+ states: Map<number, unknown>;
17
20
  meta: Map<number, MetaClientState>;
18
21
  _checkInterval: number;
19
22
  private othersUnsub;
@@ -22,19 +25,17 @@ declare class Awareness extends Observable<any> {
22
25
  getLocalState(): JsonObject | null;
23
26
  setLocalState(state: Partial<JsonObject> | null): void;
24
27
  setLocalStateField(field: string, value: JsonObject | null): void;
25
- getStates(): Map<number, any>;
28
+ getStates(): Map<number, unknown>;
26
29
  }
27
30
  declare class LiveblocksProvider<P extends JsonObject, S extends LsonObject, U extends BaseUserMeta, E extends Json> {
28
31
  private room;
29
32
  private httpEndpoint?;
30
- private lastUpdateDate;
31
33
  private doc;
32
34
  private unsubscribers;
33
35
  awareness: Awareness;
34
- constructor(room: Room<P, S, U, E>, doc: Y.Doc, config?: LiveblocksYjsOptions);
36
+ constructor(room: Room<P, S, U, E>, doc: Y.Doc);
35
37
  private syncDoc;
36
38
  private updateHandler;
37
- private resyncHttp;
38
39
  destroy(): void;
39
40
  }
40
41
 
package/dist/index.js CHANGED
@@ -110,6 +110,7 @@ var Observable = class {
110
110
 
111
111
  // src/index.ts
112
112
  var _yjs = require('yjs'); var Y = _interopRequireWildcard(_yjs);
113
+ var Y_PRESENCE_KEY = "__yjs";
113
114
  var Awareness = class extends Observable {
114
115
  constructor(doc, room) {
115
116
  super();
@@ -118,7 +119,7 @@ var Awareness = class extends Observable {
118
119
  // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.
119
120
  this.meta = /* @__PURE__ */ new Map();
120
121
  // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this
121
- // unfortunately it's expected to exist by various integrations.
122
+ // unfortunately it's typed by various integrations
122
123
  this._checkInterval = 0;
123
124
  this.doc = doc;
124
125
  this.room = room;
@@ -152,21 +153,21 @@ var Awareness = class extends Observable {
152
153
  }
153
154
  getLocalState() {
154
155
  const presence = this.room.getPresence();
155
- if (Object.keys(this.room.getPresence()).length === 0) {
156
+ if (Object.keys(presence).length === 0 || typeof presence[Y_PRESENCE_KEY] === "undefined") {
156
157
  return null;
157
158
  }
158
- return presence["__yjs"];
159
+ return presence[Y_PRESENCE_KEY];
159
160
  }
160
161
  setLocalState(state) {
161
162
  var _a;
162
- const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence["__yjs"];
163
+ const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence[Y_PRESENCE_KEY];
163
164
  this.room.updatePresence({
164
165
  __yjs: __spreadValues(__spreadValues({}, presence || {}), state || {})
165
166
  });
166
167
  }
167
168
  setLocalStateField(field, value) {
168
169
  var _a;
169
- const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence["__yjs"];
170
+ const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence[Y_PRESENCE_KEY];
170
171
  const update = { [field]: value };
171
172
  this.room.updatePresence({
172
173
  __yjs: __spreadValues(__spreadValues({}, presence || {}), update)
@@ -179,7 +180,7 @@ var Awareness = class extends Observable {
179
180
  if (currentValue.connectionId) {
180
181
  acc.set(
181
182
  currentValue.connectionId,
182
- currentValue.presence["__yjs"] || {}
183
+ currentValue.presence[Y_PRESENCE_KEY] || {}
183
184
  );
184
185
  }
185
186
  return acc;
@@ -188,15 +189,14 @@ var Awareness = class extends Observable {
188
189
  }
189
190
  };
190
191
  var LiveblocksProvider = class {
191
- constructor(room, doc, config) {
192
- this.lastUpdateDate = null;
192
+ constructor(room, doc) {
193
193
  this.unsubscribers = [];
194
194
  this.syncDoc = () => {
195
195
  var _a;
196
196
  this.doc.clientID = ((_a = this.room.getSelf()) == null ? void 0 : _a.connectionId) || this.doc.clientID;
197
197
  this.awareness.clientID = this.doc.clientID;
198
198
  const encodedVector = _jsbase64.Base64.fromUint8Array(Y.encodeStateVector(this.doc));
199
- this.room.getYDoc(encodedVector);
199
+ this.room.fetchYDoc(encodedVector);
200
200
  };
201
201
  this.updateHandler = (update, origin) => __async(this, null, function* () {
202
202
  if (origin !== "backend") {
@@ -220,47 +220,19 @@ var LiveblocksProvider = class {
220
220
  this.awareness = new Awareness(this.doc, this.room);
221
221
  this.doc.on("update", this.updateHandler);
222
222
  this.unsubscribers.push(
223
- this.room.events.connection.subscribe((e) => {
224
- if (e === "open") {
223
+ this.room.events.status.subscribe((status) => {
224
+ if (status === "connected") {
225
225
  this.syncDoc();
226
226
  }
227
227
  })
228
228
  );
229
229
  this.unsubscribers.push(
230
- this.room.events.docUpdated.subscribe((update) => {
230
+ this.room.events.ydoc.subscribe((update) => {
231
231
  Y.applyUpdate(this.doc, _jsbase64.Base64.toUint8Array(update), "backend");
232
232
  })
233
233
  );
234
- if (config == null ? void 0 : config.httpEndpoint) {
235
- this.httpEndpoint = config.httpEndpoint + "?room=" + this.room.id;
236
- this.unsubscribers.push(
237
- this.room.events.customEvent.subscribe(({ event }) => {
238
- if ((event == null ? void 0 : event.type) === "REFRESH") {
239
- void this.resyncHttp();
240
- }
241
- })
242
- );
243
- void this.resyncHttp();
244
- }
245
234
  this.syncDoc();
246
235
  }
247
- resyncHttp() {
248
- return __async(this, null, function* () {
249
- if (!this.httpEndpoint) {
250
- return;
251
- }
252
- const response = yield fetch(
253
- `${this.httpEndpoint}${this.lastUpdateDate !== null ? `&after=${this.lastUpdateDate.toISOString()}` : ""}`
254
- );
255
- const { updates, lastUpdate } = yield response.json();
256
- if (updates.length === 0) {
257
- return;
258
- }
259
- this.lastUpdateDate = new Date(lastUpdate);
260
- const update = Y.mergeUpdates(updates.map(_jsbase64.Base64.toUint8Array));
261
- Y.applyUpdate(this.doc, update, "backend");
262
- });
263
- }
264
236
  destroy() {
265
237
  this.doc.off("update", this.updateHandler);
266
238
  this.unsubscribers.forEach((unsub) => unsub());
package/dist/index.mjs CHANGED
@@ -110,6 +110,7 @@ var Observable = class {
110
110
 
111
111
  // src/index.ts
112
112
  import * as Y from "yjs";
113
+ var Y_PRESENCE_KEY = "__yjs";
113
114
  var Awareness = class extends Observable {
114
115
  constructor(doc, room) {
115
116
  super();
@@ -118,7 +119,7 @@ var Awareness = class extends Observable {
118
119
  // manage it here. Unfortunately, it's expected to exist by various integrations, so it's an empty map.
119
120
  this.meta = /* @__PURE__ */ new Map();
120
121
  // _checkInterval this would hold a timer to remove users, but Liveblock's presence already handles this
121
- // unfortunately it's expected to exist by various integrations.
122
+ // unfortunately it's typed by various integrations
122
123
  this._checkInterval = 0;
123
124
  this.doc = doc;
124
125
  this.room = room;
@@ -152,21 +153,21 @@ var Awareness = class extends Observable {
152
153
  }
153
154
  getLocalState() {
154
155
  const presence = this.room.getPresence();
155
- if (Object.keys(this.room.getPresence()).length === 0) {
156
+ if (Object.keys(presence).length === 0 || typeof presence[Y_PRESENCE_KEY] === "undefined") {
156
157
  return null;
157
158
  }
158
- return presence["__yjs"];
159
+ return presence[Y_PRESENCE_KEY];
159
160
  }
160
161
  setLocalState(state) {
161
162
  var _a;
162
- const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence["__yjs"];
163
+ const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence[Y_PRESENCE_KEY];
163
164
  this.room.updatePresence({
164
165
  __yjs: __spreadValues(__spreadValues({}, presence || {}), state || {})
165
166
  });
166
167
  }
167
168
  setLocalStateField(field, value) {
168
169
  var _a;
169
- const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence["__yjs"];
170
+ const presence = (_a = this.room.getSelf()) == null ? void 0 : _a.presence[Y_PRESENCE_KEY];
170
171
  const update = { [field]: value };
171
172
  this.room.updatePresence({
172
173
  __yjs: __spreadValues(__spreadValues({}, presence || {}), update)
@@ -179,7 +180,7 @@ var Awareness = class extends Observable {
179
180
  if (currentValue.connectionId) {
180
181
  acc.set(
181
182
  currentValue.connectionId,
182
- currentValue.presence["__yjs"] || {}
183
+ currentValue.presence[Y_PRESENCE_KEY] || {}
183
184
  );
184
185
  }
185
186
  return acc;
@@ -188,15 +189,14 @@ var Awareness = class extends Observable {
188
189
  }
189
190
  };
190
191
  var LiveblocksProvider = class {
191
- constructor(room, doc, config) {
192
- this.lastUpdateDate = null;
192
+ constructor(room, doc) {
193
193
  this.unsubscribers = [];
194
194
  this.syncDoc = () => {
195
195
  var _a;
196
196
  this.doc.clientID = ((_a = this.room.getSelf()) == null ? void 0 : _a.connectionId) || this.doc.clientID;
197
197
  this.awareness.clientID = this.doc.clientID;
198
198
  const encodedVector = Base64.fromUint8Array(Y.encodeStateVector(this.doc));
199
- this.room.getYDoc(encodedVector);
199
+ this.room.fetchYDoc(encodedVector);
200
200
  };
201
201
  this.updateHandler = (update, origin) => __async(this, null, function* () {
202
202
  if (origin !== "backend") {
@@ -220,47 +220,19 @@ var LiveblocksProvider = class {
220
220
  this.awareness = new Awareness(this.doc, this.room);
221
221
  this.doc.on("update", this.updateHandler);
222
222
  this.unsubscribers.push(
223
- this.room.events.connection.subscribe((e) => {
224
- if (e === "open") {
223
+ this.room.events.status.subscribe((status) => {
224
+ if (status === "connected") {
225
225
  this.syncDoc();
226
226
  }
227
227
  })
228
228
  );
229
229
  this.unsubscribers.push(
230
- this.room.events.docUpdated.subscribe((update) => {
230
+ this.room.events.ydoc.subscribe((update) => {
231
231
  Y.applyUpdate(this.doc, Base64.toUint8Array(update), "backend");
232
232
  })
233
233
  );
234
- if (config == null ? void 0 : config.httpEndpoint) {
235
- this.httpEndpoint = config.httpEndpoint + "?room=" + this.room.id;
236
- this.unsubscribers.push(
237
- this.room.events.customEvent.subscribe(({ event }) => {
238
- if ((event == null ? void 0 : event.type) === "REFRESH") {
239
- void this.resyncHttp();
240
- }
241
- })
242
- );
243
- void this.resyncHttp();
244
- }
245
234
  this.syncDoc();
246
235
  }
247
- resyncHttp() {
248
- return __async(this, null, function* () {
249
- if (!this.httpEndpoint) {
250
- return;
251
- }
252
- const response = yield fetch(
253
- `${this.httpEndpoint}${this.lastUpdateDate !== null ? `&after=${this.lastUpdateDate.toISOString()}` : ""}`
254
- );
255
- const { updates, lastUpdate } = yield response.json();
256
- if (updates.length === 0) {
257
- return;
258
- }
259
- this.lastUpdateDate = new Date(lastUpdate);
260
- const update = Y.mergeUpdates(updates.map(Base64.toUint8Array));
261
- Y.applyUpdate(this.doc, update, "backend");
262
- });
263
- }
264
236
  destroy() {
265
237
  this.doc.off("update", this.updateHandler);
266
238
  this.unsubscribers.forEach((unsub) => unsub());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/yjs",
3
- "version": "1.1.0-yjs5",
3
+ "version": "1.1.1-yjs2",
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",
@@ -11,23 +11,29 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "dev": "tsup --watch",
14
- "build": "tsup --format cjs,esm --dts --clean",
14
+ "build": "tsup && cp dist/index.d.ts dist/index.d.mts",
15
15
  "format": "eslint --fix src/; prettier --write src/",
16
16
  "lint": "eslint src/",
17
+ "lint:package": "publint --strict && attw /tmp/$( npm pack -q --pack-destination /tmp )",
17
18
  "test": "jest --silent --verbose --color=always",
18
19
  "test:types": "tsd",
19
20
  "test:watch": "jest --silent --verbose --color=always --watch"
20
21
  },
21
22
  "exports": {
22
23
  ".": {
23
- "require": "./dist/index.js",
24
- "import": "./dist/index.mjs",
25
- "types": "./dist/index.d.ts"
24
+ "import": {
25
+ "types": "./dist/index.d.mts",
26
+ "default": "./dist/index.mjs"
27
+ },
28
+ "require": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
26
32
  }
27
33
  },
28
34
  "dependencies": {
29
- "@liveblocks/client": "1.1.0-yjs5",
30
- "@liveblocks/core": "1.1.0-yjs5",
35
+ "@liveblocks/client": "1.1.1-yjs2",
36
+ "@liveblocks/core": "1.1.1-yjs2",
31
37
  "js-base64": "^3.7.5"
32
38
  },
33
39
  "peerDependencies": {