@liveblocks/client 0.12.3 → 0.13.2

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 (48) 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/immutable/index.d.ts +7 -0
  13. package/lib/cjs/immutable/index.js +214 -0
  14. package/lib/cjs/index.d.ts +3 -1
  15. package/lib/cjs/index.js +7 -5
  16. package/lib/cjs/room.d.ts +50 -9
  17. package/lib/cjs/room.js +477 -85
  18. package/lib/cjs/types.d.ts +220 -40
  19. package/lib/cjs/utils.d.ts +7 -0
  20. package/lib/cjs/utils.js +64 -1
  21. package/lib/esm/AbstractCrdt.d.ts +61 -0
  22. package/lib/esm/AbstractCrdt.js +94 -0
  23. package/lib/esm/LiveList.d.ts +133 -0
  24. package/lib/esm/LiveList.js +370 -0
  25. package/lib/esm/LiveMap.d.ts +83 -0
  26. package/lib/esm/LiveMap.js +268 -0
  27. package/lib/esm/LiveObject.d.ts +66 -0
  28. package/lib/esm/LiveObject.js +364 -0
  29. package/lib/esm/LiveRegister.d.ts +21 -0
  30. package/lib/esm/LiveRegister.js +65 -0
  31. package/lib/esm/immutable/index.d.ts +7 -0
  32. package/lib/esm/immutable/index.js +207 -0
  33. package/lib/esm/index.d.ts +3 -1
  34. package/lib/esm/index.js +3 -1
  35. package/lib/esm/room.d.ts +50 -9
  36. package/lib/esm/room.js +479 -84
  37. package/lib/esm/types.d.ts +220 -40
  38. package/lib/esm/utils.d.ts +7 -0
  39. package/lib/esm/utils.js +58 -0
  40. package/package.json +3 -3
  41. package/lib/cjs/doc.d.ts +0 -347
  42. package/lib/cjs/doc.js +0 -1349
  43. package/lib/cjs/storage.d.ts +0 -21
  44. package/lib/cjs/storage.js +0 -68
  45. package/lib/esm/doc.d.ts +0 -347
  46. package/lib/esm/doc.js +0 -1342
  47. package/lib/esm/storage.d.ts +0 -21
  48. package/lib/esm/storage.js +0 -65
@@ -0,0 +1,21 @@
1
+ import { AbstractCrdt, Doc, ApplyResult } from "./AbstractCrdt";
2
+ import { SerializedCrdtWithId, Op } from "./live";
3
+ /**
4
+ * INTERNAL
5
+ */
6
+ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
7
+ #private;
8
+ constructor(data: TValue);
9
+ get data(): TValue;
10
+ /**
11
+ * INTERNAL
12
+ */
13
+ static _deserialize([id, item]: SerializedCrdtWithId, parentToChildren: Map<string, SerializedCrdtWithId[]>, doc: Doc): LiveRegister<any>;
14
+ /**
15
+ * INTERNAL
16
+ */
17
+ _serialize(parentId: string, parentKey: string): Op[];
18
+ _attachChild(id: string, key: string, crdt: AbstractCrdt): ApplyResult;
19
+ _detachChild(crdt: AbstractCrdt): void;
20
+ _apply(op: Op): ApplyResult;
21
+ }
@@ -0,0 +1,65 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _LiveRegister_data;
13
+ import { AbstractCrdt } from "./AbstractCrdt";
14
+ import { CrdtType, OpType } from "./live";
15
+ /**
16
+ * INTERNAL
17
+ */
18
+ export class LiveRegister extends AbstractCrdt {
19
+ constructor(data) {
20
+ super();
21
+ _LiveRegister_data.set(this, void 0);
22
+ __classPrivateFieldSet(this, _LiveRegister_data, data, "f");
23
+ }
24
+ get data() {
25
+ return __classPrivateFieldGet(this, _LiveRegister_data, "f");
26
+ }
27
+ /**
28
+ * INTERNAL
29
+ */
30
+ static _deserialize([id, item], parentToChildren, doc) {
31
+ if (item.type !== CrdtType.Register) {
32
+ throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
33
+ }
34
+ const register = new LiveRegister(item.data);
35
+ register._attach(id, doc);
36
+ return register;
37
+ }
38
+ /**
39
+ * INTERNAL
40
+ */
41
+ _serialize(parentId, parentKey) {
42
+ if (this._id == null || parentId == null || parentKey == null) {
43
+ throw new Error("Cannot serialize register if parentId or parentKey is undefined");
44
+ }
45
+ return [
46
+ {
47
+ type: OpType.CreateRegister,
48
+ id: this._id,
49
+ parentId,
50
+ parentKey,
51
+ data: this.data,
52
+ },
53
+ ];
54
+ }
55
+ _attachChild(id, key, crdt) {
56
+ throw new Error("Method not implemented.");
57
+ }
58
+ _detachChild(crdt) {
59
+ throw new Error("Method not implemented.");
60
+ }
61
+ _apply(op) {
62
+ return super._apply(op);
63
+ }
64
+ }
65
+ _LiveRegister_data = new WeakMap();
@@ -0,0 +1,7 @@
1
+ import { LiveList } from "../LiveList";
2
+ import { LiveObject } from "../LiveObject";
3
+ import { StorageUpdate } from "../types";
4
+ export declare function liveObjectToJson(liveObject: LiveObject<any>): any;
5
+ export declare function patchLiveList<T>(liveList: LiveList<T>, prev: Array<T>, next: Array<T>): void;
6
+ export declare function patchLiveObject<T extends Record<string, any>>(root: LiveObject<T>, prev: T, next: T): void;
7
+ export declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
@@ -0,0 +1,207 @@
1
+ import { LiveList } from "../LiveList";
2
+ import { LiveMap } from "../LiveMap";
3
+ import { LiveObject } from "../LiveObject";
4
+ export function liveObjectToJson(liveObject) {
5
+ const result = {};
6
+ const obj = liveObject.toObject();
7
+ for (const key in obj) {
8
+ result[key] = liveNodeToJson(obj[key]);
9
+ }
10
+ return result;
11
+ }
12
+ function liveMapToJson(map) {
13
+ const result = {};
14
+ const obj = Object.fromEntries(map);
15
+ for (const key in obj) {
16
+ result[key] = liveNodeToJson(obj[key]);
17
+ }
18
+ return result;
19
+ }
20
+ function liveListToJson(value) {
21
+ return value.toArray().map(liveNodeToJson);
22
+ }
23
+ function liveNodeToJson(value) {
24
+ if (value instanceof LiveObject) {
25
+ return liveObjectToJson(value);
26
+ }
27
+ else if (value instanceof LiveList) {
28
+ return liveListToJson(value);
29
+ }
30
+ else if (value instanceof LiveMap) {
31
+ return liveMapToJson(value);
32
+ }
33
+ return value;
34
+ }
35
+ function isPlainObject(obj) {
36
+ return Object.prototype.toString.call(obj) === "[object Object]";
37
+ }
38
+ function anyToCrdt(obj) {
39
+ if (obj == null) {
40
+ return obj;
41
+ }
42
+ if (Array.isArray(obj)) {
43
+ return new LiveList(obj.map(anyToCrdt));
44
+ }
45
+ if (isPlainObject(obj)) {
46
+ const init = {};
47
+ for (const key in obj) {
48
+ init[key] = anyToCrdt(obj[key]);
49
+ }
50
+ return new LiveObject(init);
51
+ }
52
+ return obj;
53
+ }
54
+ export function patchLiveList(liveList, prev, next) {
55
+ let i = 0;
56
+ let prevEnd = prev.length - 1;
57
+ let nextEnd = next.length - 1;
58
+ let prevNode = prev[0];
59
+ let nextNode = next[0];
60
+ /**
61
+ * For A,B,C => A,B,C,D
62
+ * i = 3, prevEnd = 2, nextEnd = 3
63
+ *
64
+ * For A,B,C => B,C
65
+ * i = 2, prevEnd = 2, nextEnd = 1
66
+ *
67
+ * For B,C => A,B,C
68
+ * i = 0, pre
69
+ */
70
+ outer: {
71
+ while (prevNode === nextNode) {
72
+ ++i;
73
+ if (i > prevEnd || i > nextEnd) {
74
+ break outer;
75
+ }
76
+ prevNode = prev[i];
77
+ nextNode = next[i];
78
+ }
79
+ prevNode = prev[prevEnd];
80
+ nextNode = next[nextEnd];
81
+ while (prevNode === nextNode) {
82
+ prevEnd--;
83
+ nextEnd--;
84
+ if (i > prevEnd || i > nextEnd) {
85
+ break outer;
86
+ }
87
+ prevNode = prev[prevEnd];
88
+ nextNode = next[nextEnd];
89
+ }
90
+ }
91
+ if (i > prevEnd) {
92
+ if (i <= nextEnd) {
93
+ while (i <= nextEnd) {
94
+ liveList.insert(anyToCrdt(next[i]), i);
95
+ i++;
96
+ }
97
+ }
98
+ }
99
+ else if (i > nextEnd) {
100
+ while (i <= prevEnd) {
101
+ liveList.delete(i++);
102
+ }
103
+ }
104
+ else {
105
+ while (i <= prevEnd && i <= nextEnd) {
106
+ prevNode = prev[i];
107
+ nextNode = next[i];
108
+ const liveListNode = liveList.get(i);
109
+ if (liveListNode instanceof LiveObject &&
110
+ isPlainObject(prevNode) &&
111
+ isPlainObject(nextNode)) {
112
+ patchLiveObject(liveListNode, prevNode, nextNode);
113
+ }
114
+ else {
115
+ liveList.delete(i);
116
+ liveList.insert(anyToCrdt(nextNode), i);
117
+ }
118
+ i++;
119
+ }
120
+ while (i <= nextEnd) {
121
+ liveList.insert(anyToCrdt(next[i]), i);
122
+ i++;
123
+ }
124
+ while (i <= prevEnd) {
125
+ liveList.delete(i);
126
+ i++;
127
+ }
128
+ }
129
+ }
130
+ export function patchLiveObject(root, prev, next) {
131
+ const updates = {};
132
+ for (const key in next) {
133
+ if (prev[key] === next[key]) {
134
+ continue;
135
+ }
136
+ else if (Array.isArray(prev[key]) && Array.isArray(next[key])) {
137
+ patchLiveList(root.get(key), prev[key], next[key]);
138
+ }
139
+ else if (isPlainObject(prev[key]) && isPlainObject(next[key])) {
140
+ patchLiveObject(root.get(key), prev[key], next[key]);
141
+ }
142
+ else {
143
+ updates[key] = anyToCrdt(next[key]);
144
+ }
145
+ }
146
+ for (const key in prev) {
147
+ if (next[key] === undefined) {
148
+ root.delete(key);
149
+ }
150
+ }
151
+ if (Object.keys(updates).length > 0) {
152
+ root.update(updates);
153
+ }
154
+ }
155
+ function getParentsPath(node) {
156
+ const path = [];
157
+ while (node._parentKey != null && node._parent != null) {
158
+ if (node._parent instanceof LiveList) {
159
+ path.push(node._parent._indexOfPosition(node._parentKey));
160
+ }
161
+ else {
162
+ path.push(node._parentKey);
163
+ }
164
+ node = node._parent;
165
+ }
166
+ return path;
167
+ }
168
+ export function patchImmutableObject(state, updates) {
169
+ return updates.reduce((state, update) => patchImmutableObjectWithUpdate(state, update), state);
170
+ }
171
+ function patchImmutableObjectWithUpdate(state, update) {
172
+ const path = getParentsPath(update.node);
173
+ return patchImmutableNode(state, path, update);
174
+ }
175
+ function patchImmutableNode(state, path, update) {
176
+ const pathItem = path.pop();
177
+ if (pathItem === undefined) {
178
+ switch (update.type) {
179
+ case "LiveObject": {
180
+ if (typeof state !== "object") {
181
+ throw new Error("Internal: received update on LiveObject but state was not an object");
182
+ }
183
+ return liveObjectToJson(update.node);
184
+ }
185
+ case "LiveList": {
186
+ if (Array.isArray(state) === false) {
187
+ throw new Error("Internal: received update on LiveList but state was not an array");
188
+ }
189
+ return liveListToJson(update.node);
190
+ }
191
+ case "LiveMap": {
192
+ if (typeof state !== "object") {
193
+ throw new Error("Internal: received update on LiveMap but state was not an object");
194
+ }
195
+ return liveMapToJson(update.node);
196
+ }
197
+ }
198
+ }
199
+ if (Array.isArray(state)) {
200
+ const newArray = [...state];
201
+ newArray[pathItem] = patchImmutableNode(state[pathItem], path, update);
202
+ return newArray;
203
+ }
204
+ else {
205
+ return Object.assign(Object.assign({}, state), { [pathItem]: patchImmutableNode(state[pathItem], path, update) });
206
+ }
207
+ }
@@ -1,3 +1,5 @@
1
- export { LiveObject, LiveList, LiveMap } from "./doc";
1
+ export { LiveObject } from "./LiveObject";
2
+ export { LiveMap } from "./LiveMap";
3
+ export { LiveList } from "./LiveList";
2
4
  export type { Others, Presence, Room, Client, User } from "./types";
3
5
  export { createClient } from "./client";
package/lib/esm/index.js CHANGED
@@ -1,2 +1,4 @@
1
- export { LiveObject, LiveList, LiveMap } from "./doc";
1
+ export { LiveObject } from "./LiveObject";
2
+ export { LiveMap } from "./LiveMap";
3
+ export { LiveList } from "./LiveList";
2
4
  export { createClient } from "./client";
package/lib/esm/room.d.ts CHANGED
@@ -1,11 +1,19 @@
1
- import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback } from "./types";
1
+ import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate } from "./types";
2
2
  import { ClientMessage, Op } from "./live";
3
+ import { LiveMap } from "./LiveMap";
4
+ import { LiveObject } from "./LiveObject";
5
+ import { LiveList } from "./LiveList";
6
+ import { AbstractCrdt } from "./AbstractCrdt";
7
+ declare type HistoryItem = Array<Op | {
8
+ type: "presence";
9
+ data: Presence;
10
+ }>;
3
11
  declare type IdFactory = () => string;
4
12
  export declare type State = {
5
13
  connection: Connection;
6
14
  socket: WebSocket | null;
7
15
  lastFlushTime: number;
8
- flushData: {
16
+ buffer: {
9
17
  presence: Presence | null;
10
18
  messages: ClientMessage[];
11
19
  storageOperations: Op[];
@@ -24,6 +32,7 @@ export declare type State = {
24
32
  "my-presence": MyPresenceCallback[];
25
33
  error: ErrorCallback[];
26
34
  connection: ConnectionCallback[];
35
+ storage: StorageCallback[];
27
36
  };
28
37
  me: Presence;
29
38
  others: Others;
@@ -35,6 +44,24 @@ export declare type State = {
35
44
  defaultStorageRoot?: {
36
45
  [key: string]: any;
37
46
  };
47
+ clock: number;
48
+ opClock: number;
49
+ items: Map<string, AbstractCrdt>;
50
+ root: LiveObject | undefined;
51
+ undoStack: HistoryItem[];
52
+ redoStack: HistoryItem[];
53
+ isHistoryPaused: boolean;
54
+ pausedHistory: HistoryItem;
55
+ isBatching: boolean;
56
+ batch: {
57
+ ops: Op[];
58
+ reverseOps: HistoryItem;
59
+ updates: {
60
+ others: [];
61
+ presence: boolean;
62
+ nodes: Set<AbstractCrdt>;
63
+ };
64
+ };
38
65
  };
39
66
  export declare type Effects = {
40
67
  authenticate(): void;
@@ -63,14 +90,23 @@ export declare function makeStateMachine(state: State, context: Context, mockedE
63
90
  heartbeat: () => void;
64
91
  onNavigatorOnline: () => void;
65
92
  onVisibilityChange: (visibilityState: VisibilityState) => void;
93
+ getUndoStack: () => HistoryItem[];
94
+ getItemsCount: () => number;
66
95
  connect: () => null | undefined;
67
96
  disconnect: () => void;
68
97
  subscribe: {
69
- <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): void;
70
- <T_1 extends Presence>(type: "others", listener: OthersEventCallback<T_1>): void;
71
- (type: "event", listener: EventCallback): void;
72
- (type: "error", listener: ErrorCallback): void;
73
- (type: "connection", listener: ConnectionCallback): void;
98
+ (callback: (updates: StorageUpdate) => void): () => void;
99
+ <TKey extends string, TValue>(liveMap: LiveMap<TKey, TValue>, callback: (liveMap: LiveMap<TKey, TValue>) => void): () => void;
100
+ <TData>(liveObject: LiveObject<TData>, callback: (liveObject: LiveObject<TData>) => void): () => void;
101
+ <TItem>(liveList: LiveList<TItem>, callback: (liveList: LiveList<TItem>) => void): () => void;
102
+ <TItem_1 extends AbstractCrdt>(node: TItem_1, callback: (updates: StorageUpdate[]) => void, options: {
103
+ isDeep: true;
104
+ }): () => void;
105
+ <T extends Presence>(type: "my-presence", listener: MyPresenceCallback<T>): () => void;
106
+ <T_1 extends Presence>(type: "others", listener: OthersEventCallback<T_1>): () => void;
107
+ (type: "event", listener: EventCallback): () => void;
108
+ (type: "error", listener: ErrorCallback): () => void;
109
+ (type: "connection", listener: ConnectionCallback): () => void;
74
110
  };
75
111
  unsubscribe: {
76
112
  <T_2 extends Presence>(type: "my-presence", listener: MyPresenceCallback<T_2>): void;
@@ -79,12 +115,17 @@ export declare function makeStateMachine(state: State, context: Context, mockedE
79
115
  (type: "error", listener: ErrorCallback): void;
80
116
  (type: "connection", listener: ConnectionCallback): void;
81
117
  };
82
- updatePresence: <T_4 extends Presence>(overrides: Partial<T_4>) => void;
118
+ updatePresence: <T_4 extends Presence>(overrides: Partial<T_4>, options?: {
119
+ addToHistory: boolean;
120
+ } | undefined) => void;
83
121
  broadcastEvent: (event: any) => void;
122
+ batch: (callback: () => void) => void;
84
123
  undo: () => void;
85
124
  redo: () => void;
125
+ pauseHistory: () => void;
126
+ resumeHistory: () => void;
86
127
  getStorage: <TRoot>() => Promise<{
87
- root: import("./doc").LiveObject<TRoot>;
128
+ root: LiveObject<TRoot>;
88
129
  }>;
89
130
  selectors: {
90
131
  getConnectionState: () => "failed" | "closed" | "connecting" | "open" | "authenticating" | "unavailable";