@liveblocks/client 0.12.2 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +34 -6
  2. package/lib/cjs/AbstractCrdt.d.ts +61 -0
  3. package/lib/cjs/AbstractCrdt.js +98 -0
  4. package/lib/cjs/LiveList.d.ts +133 -0
  5. package/lib/cjs/LiveList.js +374 -0
  6. package/lib/cjs/LiveMap.d.ts +83 -0
  7. package/lib/cjs/LiveMap.js +272 -0
  8. package/lib/cjs/LiveObject.d.ts +66 -0
  9. package/lib/cjs/LiveObject.js +368 -0
  10. package/lib/cjs/LiveRegister.d.ts +21 -0
  11. package/lib/cjs/LiveRegister.js +69 -0
  12. package/lib/cjs/index.d.ts +3 -1
  13. package/lib/cjs/index.js +7 -5
  14. package/lib/cjs/room.d.ts +50 -9
  15. package/lib/cjs/room.js +476 -85
  16. package/lib/cjs/types.d.ts +220 -40
  17. package/lib/cjs/utils.d.ts +7 -0
  18. package/lib/cjs/utils.js +64 -1
  19. package/lib/esm/AbstractCrdt.d.ts +61 -0
  20. package/lib/esm/AbstractCrdt.js +94 -0
  21. package/lib/esm/LiveList.d.ts +133 -0
  22. package/lib/esm/LiveList.js +370 -0
  23. package/lib/esm/LiveMap.d.ts +83 -0
  24. package/lib/esm/LiveMap.js +268 -0
  25. package/lib/esm/LiveObject.d.ts +66 -0
  26. package/lib/esm/LiveObject.js +364 -0
  27. package/lib/esm/LiveRegister.d.ts +21 -0
  28. package/lib/esm/LiveRegister.js +65 -0
  29. package/lib/esm/index.d.ts +3 -1
  30. package/lib/esm/index.js +3 -1
  31. package/lib/esm/room.d.ts +50 -9
  32. package/lib/esm/room.js +478 -84
  33. package/lib/esm/types.d.ts +220 -40
  34. package/lib/esm/utils.d.ts +7 -0
  35. package/lib/esm/utils.js +58 -0
  36. package/package.json +3 -3
  37. package/lib/cjs/doc.d.ts +0 -347
  38. package/lib/cjs/doc.js +0 -1349
  39. package/lib/cjs/storage.d.ts +0 -21
  40. package/lib/cjs/storage.js +0 -68
  41. package/lib/esm/doc.d.ts +0 -347
  42. package/lib/esm/doc.js +0 -1342
  43. package/lib/esm/storage.d.ts +0 -21
  44. package/lib/esm/storage.js +0 -65
@@ -1,4 +1,6 @@
1
- import { LiveObject } from "./doc";
1
+ import type { LiveList } from "./LiveList";
2
+ import type { LiveMap } from "./LiveMap";
3
+ import type { LiveObject } from "./LiveObject";
2
4
  export declare type MyPresenceCallback<T extends Presence = Presence> = (me: T) => void;
3
5
  export declare type OthersEventCallback<T extends Presence = Presence> = (others: Others<T>, event: OthersEvent<T>) => void;
4
6
  export declare type EventCallback = ({ connectionId, event, }: {
@@ -14,17 +16,31 @@ export declare type RoomEventCallbackMap = {
14
16
  error: ErrorCallback;
15
17
  connection: ConnectionCallback;
16
18
  };
19
+ export declare type LiveMapUpdates<TKey extends string = string, TValue = any> = {
20
+ type: "LiveMap";
21
+ node: LiveMap<TKey, TValue>;
22
+ };
23
+ export declare type LiveObjectUpdates<TData = any> = {
24
+ type: "LiveObject";
25
+ node: LiveObject<TData>;
26
+ };
27
+ export declare type LiveListUpdates<TItem = any> = {
28
+ type: "LiveList";
29
+ node: LiveList<TItem>;
30
+ };
31
+ export declare type StorageUpdate = LiveMapUpdates | LiveObjectUpdates | LiveListUpdates;
32
+ export declare type StorageCallback = (updates: StorageUpdate[]) => void;
17
33
  export declare type Client = {
18
34
  /**
19
35
  * Gets a room. Returns null if {@link Client.enter} has not been called previously.
20
36
  *
21
- * @param roomId - The id of the room
37
+ * @param roomId The id of the room
22
38
  */
23
39
  getRoom(roomId: string): Room | null;
24
40
  /**
25
41
  * Enters a room and returns it.
26
- * @param roomId - The id of the room
27
- * @param defaultPresence - Optional. Should be serializable to JSON. If omitted, an empty object will be used.
42
+ * @param roomId The id of the room
43
+ * @param defaultPresence Optional. Should be serializable to JSON. If omitted, an empty object will be used.
28
44
  */
29
45
  enter<TStorageRoot extends Record<string, any> = Record<string, any>>(roomId: string, options?: {
30
46
  defaultPresence?: Presence;
@@ -32,7 +48,7 @@ export declare type Client = {
32
48
  }): Room;
33
49
  /**
34
50
  * Leaves a room.
35
- * @param roomId - The id of the room
51
+ * @param roomId The id of the room
36
52
  */
37
53
  leave(roomId: string): void;
38
54
  };
@@ -131,85 +147,224 @@ export declare type Room = {
131
147
  /**
132
148
  * Subscribe to the current user presence updates.
133
149
  *
134
- * @param listener - the callback that is called every time the current user presence is updated with {@link Room.updatePresence}.
150
+ * @param listener the callback that is called every time the current user presence is updated with {@link Room.updatePresence}.
135
151
  *
136
152
  * @example
137
153
  * room.subscribe("my-presence", (presence) => {
138
154
  * // Do something
139
155
  * });
140
156
  */
141
- <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): void;
157
+ <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): () => void;
142
158
  /**
143
159
  * Subscribe to the other users updates.
144
160
  *
145
- * @param listener - the callback that is called when a user enters or leaves the room or when a user update its presence.
161
+ * @param listener the callback that is called when a user enters or leaves the room or when a user update its presence.
146
162
  *
147
163
  * @example
148
164
  * room.subscribe("others", (others) => {
149
165
  * // Do something
150
166
  * });
151
167
  */
152
- <T extends Presence>(type: "others", listener: OthersEventCallback<T>): void;
168
+ <T extends Presence>(type: "others", listener: OthersEventCallback<T>): () => void;
153
169
  /**
154
170
  * Subscribe to events broadcasted by {@link Room.broadcastEvent}
155
171
  *
156
- * @param listener - the callback that is called when a user calls {@link Room.broadcastEvent}
172
+ * @param listener the callback that is called when a user calls {@link Room.broadcastEvent}
157
173
  *
158
174
  * @example
159
175
  * room.subscribe("event", ({ event, connectionId }) => {
160
176
  * // Do something
161
177
  * });
162
178
  */
163
- (type: "event", listener: EventCallback): void;
179
+ (type: "event", listener: EventCallback): () => void;
164
180
  /**
165
181
  * Subscribe to errors thrown in the room.
166
182
  */
167
- (type: "error", listener: ErrorCallback): void;
183
+ (type: "error", listener: ErrorCallback): () => void;
168
184
  /**
169
185
  * Subscribe to connection state updates.
170
186
  */
171
- (type: "connection", listener: ConnectionCallback): void;
172
- };
173
- unsubscribe: {
187
+ (type: "connection", listener: ConnectionCallback): () => void;
174
188
  /**
175
- * Unsubscribe to the current user presence updates.
189
+ * Subscribes to changes made on a {@link LiveMap}. Returns an unsubscribe function.
190
+ * In a future version, we will also expose what exactly changed in the {@link LiveMap}.
176
191
  *
177
- * @param listener - the callback that has been used with {@link Room.subscribe}("my-presence").
192
+ * @param listener the callback this called when the {@link LiveMap} changes.
193
+ *
194
+ * @returns Unsubscribe function.
178
195
  *
179
196
  * @example
180
- * const onPresenceChange = (presence) => { };
181
- * room.subscribe("my-presence", onPresenceChange);
182
- * room.unsubscribe("my-presence", onPresenceChange);
197
+ * const liveMap = new LiveMap();
198
+ * const unsubscribe = room.subscribe(liveMap, (liveMap) => { });
199
+ * unsubscribe();
183
200
  */
184
- <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): void;
201
+ <TKey extends string, TValue>(liveMap: LiveMap<TKey, TValue>, listener: (liveMap: LiveMap<TKey, TValue>) => void): () => void;
185
202
  /**
186
- * Unsubscribe to the other users updates.
203
+ * Subscribes to changes made on a {@link LiveObject}. Returns an unsubscribe function.
204
+ * In a future version, we will also expose what exactly changed in the {@link LiveObject}.
205
+ *
206
+ * @param listener the callback this called when the {@link LiveObject} changes.
187
207
  *
188
- * @param listener - the callback that has been used with {@link Room.subscribe}("others").
208
+ * @returns Unsubscribe function.
189
209
  *
190
210
  * @example
191
- * const onOthersChange = (presence) => { };
192
- * room.subscribe("others", onOthersChange);
193
- * room.unsubscribe("others", onOthersChange);
211
+ * const liveObject = new LiveObject();
212
+ * const unsubscribe = room.subscribe(liveObject, (liveObject) => { });
213
+ * unsubscribe();
194
214
  */
195
- <T extends Presence>(type: "others", listener: OthersEventCallback<T>): void;
215
+ <TData>(liveObject: LiveObject<TData>, callback: (liveObject: LiveObject<TData>) => void): () => void;
216
+ /**
217
+ * Subscribes to changes made on a {@link LiveList}. Returns an unsubscribe function.
218
+ * In a future version, we will also expose what exactly changed in the {@link LiveList}.
219
+ *
220
+ * @param listener the callback this called when the {@link LiveList} changes.
221
+ *
222
+ * @returns Unsubscribe function.
223
+ *
224
+ * @example
225
+ * const liveList = new LiveList();
226
+ * const unsubscribe = room.subscribe(liveList, (liveList) => { });
227
+ * unsubscribe();
228
+ */
229
+ <TItem>(liveList: LiveList<TItem>, callback: (liveList: LiveList<TItem>) => void): () => void;
230
+ /**
231
+ * Subscribes to changes made on a {@link LiveMap} and all the nested data structures. Returns an unsubscribe function.
232
+ * In a future version, we will also expose what exactly changed in the {@link LiveMap}.
233
+ *
234
+ * @param listener the callback this called when the {@link LiveMap} changes.
235
+ *
236
+ * @returns Unsubscribe function.
237
+ *
238
+ * @example
239
+ * const liveMap = new LiveMap();
240
+ * const unsubscribe = room.subscribe(liveMap, (liveMap) => { }, { isDeep: true });
241
+ * unsubscribe();
242
+ */
243
+ <TKey extends string, TValue>(liveMap: LiveMap<TKey, TValue>, callback: (updates: StorageUpdate[]) => void, options: {
244
+ isDeep: true;
245
+ }): () => void;
196
246
  /**
197
- * Unsubscribe to events broadcasted by {@link Room.broadcastEvent}
247
+ * Subscribes to changes made on a {@link LiveObject} and all the nested data structures. Returns an unsubscribe function.
248
+ * In a future version, we will also expose what exactly changed in the {@link LiveObject}.
249
+ *
250
+ * @param listener the callback this called when the {@link LiveObject} changes.
198
251
  *
199
- * @param listener - the callback that has been used with {@link Room.unsubscribe}("event").
252
+ * @returns Unsubscribe function.
200
253
  *
201
254
  * @example
202
- * const onEvent = ({ event, connectionId }) => { };
203
- * room.subscribe("event", onEvent);
204
- * room.unsubscribe("event", onEvent);
255
+ * const liveObject = new LiveObject();
256
+ * const unsubscribe = room.subscribe(liveObject, (liveObject) => { }, { isDeep: true });
257
+ * unsubscribe();
258
+ */
259
+ <TData>(liveObject: LiveObject<TData>, callback: (updates: StorageUpdate[]) => void, options: {
260
+ isDeep: true;
261
+ }): () => void;
262
+ /**
263
+ * Subscribes to changes made on a {@link LiveList} and all the nested data structures. Returns an unsubscribe function.
264
+ * In a future version, we will also expose what exactly changed in the {@link LiveList}.
265
+ *
266
+ * @param listener the callback this called when the {@link LiveList} changes.
267
+ *
268
+ * @returns Unsubscribe function.
269
+ *
270
+ * @example
271
+ * const liveList = new LiveList();
272
+ * const unsubscribe = room.subscribe(liveList, (liveList) => { }, { isDeep: true });
273
+ * unsubscribe();
274
+ */
275
+ <TItem>(liveList: LiveList<TItem>, callback: (updates: StorageUpdate[]) => void, options: {
276
+ isDeep: true;
277
+ }): () => void;
278
+ };
279
+ /**
280
+ * Room's history contains functions that let you undo and redo operation made on by the current client on the presence and storage.
281
+ */
282
+ history: {
283
+ /**
284
+ * Undoes the last operation executed by the current client.
285
+ * It does not impact operations made by other clients.
286
+ *
287
+ * @example
288
+ * room.updatePresence({ selectedId: "xxx" }, { addToHistory: true });
289
+ * room.updatePresence({ selectedId: "yyy" }, { addToHistory: true });
290
+ * room.history.undo();
291
+ * // room.getPresence() equals { selectedId: "xxx" }
292
+ */
293
+ undo: () => void;
294
+ /**
295
+ * Redoes the last operation executed by the current client.
296
+ * It does not impact operations made by other clients.
297
+ *
298
+ * @example
299
+ * room.updatePresence({ selectedId: "xxx" }, { addToHistory: true });
300
+ * room.updatePresence({ selectedId: "yyy" }, { addToHistory: true });
301
+ * room.history.undo();
302
+ * // room.getPresence() equals { selectedId: "xxx" }
303
+ * room.history.redo();
304
+ * // room.getPresence() equals { selectedId: "yyy" }
305
+ */
306
+ redo: () => void;
307
+ /**
308
+ * All future modifications made on the Room will be merged together to create a single history item until resume is called.
309
+ *
310
+ * @example
311
+ * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
312
+ * room.history.pause();
313
+ * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
314
+ * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
315
+ * room.history.resume();
316
+ * room.history.undo();
317
+ * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
318
+ */
319
+ pause: () => void;
320
+ /**
321
+ * Resumes history. Modifications made on the Room are not merged into a single history item anymore.
322
+ *
323
+ * @example
324
+ * room.updatePresence({ cursor: { x: 0, y: 0 } }, { addToHistory: true });
325
+ * room.history.pause();
326
+ * room.updatePresence({ cursor: { x: 1, y: 1 } }, { addToHistory: true });
327
+ * room.updatePresence({ cursor: { x: 2, y: 2 } }, { addToHistory: true });
328
+ * room.history.resume();
329
+ * room.history.undo();
330
+ * // room.getPresence() equals { cursor: { x: 0, y: 0 } }
331
+ */
332
+ resume: () => void;
333
+ };
334
+ /**
335
+ * @deprecated use the callback returned by subscribe instead.
336
+ * See v0.13 release notes for more information.
337
+ * Will be removed in a future version.
338
+ */
339
+ unsubscribe: {
340
+ /**
341
+ * @deprecated use the callback returned by subscribe instead.
342
+ * See v0.13 release notes for more information.
343
+ * Will be removed in a future version.
344
+ */
345
+ <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): void;
346
+ /**
347
+ * @deprecated use the callback returned by subscribe instead.
348
+ * See v0.13 release notes for more information.
349
+ * Will be removed in a future version.
350
+ */
351
+ <T extends Presence>(type: "others", listener: OthersEventCallback<T>): void;
352
+ /**
353
+ * @deprecated use the callback returned by subscribe instead.
354
+ * See v0.13 release notes for more information.
355
+ * Will be removed in a future version.
205
356
  */
206
357
  (type: "event", listener: EventCallback): void;
207
358
  /**
208
- * Unsubscribe to errors thrown in the room.
359
+ * @deprecated use the callback returned by subscribe instead.
360
+ * See v0.13 release notes for more information.
361
+ * Will be removed in a future version.
209
362
  */
210
363
  (type: "error", listener: ErrorCallback): void;
211
364
  /**
212
- * Unsubscribe to connection state updates.
365
+ * @deprecated use the callback returned by subscribe instead.
366
+ * See v0.13 release notes for more information.
367
+ * Will be removed in a future version.
213
368
  */
214
369
  (type: "connection", listener: ConnectionCallback): void;
215
370
  };
@@ -237,7 +392,8 @@ export declare type Room = {
237
392
  getOthers: <T extends Presence>() => Others<T>;
238
393
  /**
239
394
  * Updates the presence of the current user. Only pass the properties you want to update. No need to send the full presence.
240
- * @param {Partial<T>} overrides - A partial object that contains the properties you want to update.
395
+ * @param overrides A partial object that contains the properties you want to update.
396
+ * @param overrides Optional object to configure the behavior of updatePresence.
241
397
  *
242
398
  * @example
243
399
  * room.updatePresence({ x: 0 });
@@ -246,10 +402,15 @@ export declare type Room = {
246
402
  * const presence = room.getPresence();
247
403
  * // presence is equivalent to { x: 0, y: 0 }
248
404
  */
249
- updatePresence: <T extends Presence>(overrides: Partial<T>) => void;
405
+ updatePresence: <T extends Presence>(overrides: Partial<T>, options?: {
406
+ /**
407
+ * Whether or not the presence should have an impact on the undo/redo history.
408
+ */
409
+ addToHistory: boolean;
410
+ }) => void;
250
411
  /**
251
- * Broadcast an event to other users in the room. Event broadcasted to the room can be listened with {@link Room.subscribe}("event").
252
- * @param {any} event - the event to broadcast. Should be serializable to JSON
412
+ * Broadcasts an event to other users in the room. Event broadcasted to the room can be listened with {@link Room.subscribe}("event").
413
+ * @param {any} event the event to broadcast. Should be serializable to JSON
253
414
  *
254
415
  * @example
255
416
  * // On client A
@@ -263,10 +424,29 @@ export declare type Room = {
263
424
  * });
264
425
  */
265
426
  broadcastEvent: (event: any) => void;
427
+ /**
428
+ * Get the room's storage asynchronously.
429
+ * The storage's root is a {@link LiveObject}.
430
+ *
431
+ * @example
432
+ * const { root } = await room.getStorage();
433
+ */
266
434
  getStorage: <TRoot>() => Promise<{
267
435
  root: LiveObject<TRoot>;
268
436
  }>;
269
- undo: () => void;
270
- redo: () => void;
437
+ /**
438
+ * Batches modifications made during the given function.
439
+ * All the modifications are sent to other clients in a single message.
440
+ * All the subscribers are called only after the batch is over.
441
+ * All the modifications are merged in a single history item (undo/redo).
442
+ *
443
+ * @example
444
+ * const { root } = await room.getStorage();
445
+ * room.batch(() => {
446
+ * root.set("x", 0);
447
+ * room.updatePresence({ cursor: { x: 100, y: 100 }});
448
+ * });
449
+ */
450
+ batch: (fn: () => void) => void;
271
451
  };
272
452
  export {};
@@ -1 +1,8 @@
1
+ import { AbstractCrdt, Doc } from "./AbstractCrdt";
2
+ import { SerializedCrdtWithId } from "./live";
1
3
  export declare function remove<T>(array: T[], item: T): void;
4
+ export declare function isSameNodeOrChildOf(node: AbstractCrdt, parent: AbstractCrdt): boolean;
5
+ export declare function deserialize(entry: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): AbstractCrdt;
6
+ export declare function isCrdt(obj: any): obj is AbstractCrdt;
7
+ export declare function selfOrRegisterValue(obj: AbstractCrdt): any;
8
+ export declare function selfOrRegister(obj: any): AbstractCrdt;
package/lib/esm/utils.js CHANGED
@@ -1,3 +1,8 @@
1
+ import { CrdtType, } from "./live";
2
+ import { LiveList } from "./LiveList";
3
+ import { LiveMap } from "./LiveMap";
4
+ import { LiveObject } from "./LiveObject";
5
+ import { LiveRegister } from "./LiveRegister";
1
6
  export function remove(array, item) {
2
7
  for (let i = 0; i < array.length; i++) {
3
8
  if (array[i] === item) {
@@ -6,3 +11,56 @@ export function remove(array, item) {
6
11
  }
7
12
  }
8
13
  }
14
+ export function isSameNodeOrChildOf(node, parent) {
15
+ if (node === parent) {
16
+ return true;
17
+ }
18
+ if (node._parent) {
19
+ return isSameNodeOrChildOf(node._parent, parent);
20
+ }
21
+ return false;
22
+ }
23
+ export function deserialize(entry, parentToChildren, doc) {
24
+ switch (entry[1].type) {
25
+ case CrdtType.Object: {
26
+ return LiveObject._deserialize(entry, parentToChildren, doc);
27
+ }
28
+ case CrdtType.List: {
29
+ return LiveList._deserialize(entry, parentToChildren, doc);
30
+ }
31
+ case CrdtType.Map: {
32
+ return LiveMap._deserialize(entry, parentToChildren, doc);
33
+ }
34
+ case CrdtType.Register: {
35
+ return LiveRegister._deserialize(entry, parentToChildren, doc);
36
+ }
37
+ default: {
38
+ throw new Error("Unexpected CRDT type");
39
+ }
40
+ }
41
+ }
42
+ export function isCrdt(obj) {
43
+ return (obj instanceof LiveObject ||
44
+ obj instanceof LiveMap ||
45
+ obj instanceof LiveList ||
46
+ obj instanceof LiveRegister);
47
+ }
48
+ export function selfOrRegisterValue(obj) {
49
+ if (obj instanceof LiveRegister) {
50
+ return obj.data;
51
+ }
52
+ return obj;
53
+ }
54
+ export function selfOrRegister(obj) {
55
+ if (obj instanceof LiveObject ||
56
+ obj instanceof LiveMap ||
57
+ obj instanceof LiveList) {
58
+ return obj;
59
+ }
60
+ else if (obj instanceof LiveRegister) {
61
+ throw new Error("Internal error. LiveRegister should not be created from selfOrRegister");
62
+ }
63
+ else {
64
+ return new LiveRegister(obj);
65
+ }
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/client",
3
- "version": "0.12.2",
3
+ "version": "0.13.1",
4
4
  "description": "",
5
5
  "main": "./lib/cjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -19,8 +19,8 @@
19
19
  "scripts": {
20
20
  "build-and-pack": "npm run build && npm pack",
21
21
  "build": "npm run build:esm && npm run build:cjs",
22
- "build:esm": "tsc -p tsconfig.json && rm ./lib/esm/*.test.js && rm ./lib/esm/*.test.d.ts",
23
- "build:cjs": "tsc -p tsconfig-cjs.json && rm ./lib/cjs/*.test.js && rm ./lib/cjs/*.test.d.ts",
22
+ "build:esm": "tsc -p tsconfig-esm.json",
23
+ "build:cjs": "tsc -p tsconfig-cjs.json",
24
24
  "test": "jest --watch"
25
25
  },
26
26
  "license": "Apache-2.0",