@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 +1 -1
- package/dist/index.d.mts +42 -0
- package/dist/index.d.ts +10 -9
- package/dist/index.js +12 -40
- package/dist/index.mjs +12 -40
- package/package.json +13 -7
package/README.md
CHANGED
package/dist/index.d.mts
ADDED
|
@@ -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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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(
|
|
156
|
+
if (Object.keys(presence).length === 0 || typeof presence[Y_PRESENCE_KEY] === "undefined") {
|
|
156
157
|
return null;
|
|
157
158
|
}
|
|
158
|
-
return presence[
|
|
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[
|
|
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[
|
|
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[
|
|
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
|
|
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.
|
|
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.
|
|
224
|
-
if (
|
|
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.
|
|
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
|
|
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(
|
|
156
|
+
if (Object.keys(presence).length === 0 || typeof presence[Y_PRESENCE_KEY] === "undefined") {
|
|
156
157
|
return null;
|
|
157
158
|
}
|
|
158
|
-
return presence[
|
|
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[
|
|
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[
|
|
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[
|
|
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
|
|
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.
|
|
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.
|
|
224
|
-
if (
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
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.
|
|
30
|
-
"@liveblocks/core": "1.1.
|
|
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": {
|