@liveblocks/client 0.16.9 → 0.16.12

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/index.d.ts CHANGED
@@ -28,4 +28,16 @@ export { B as BroadcastOptions, a as Client, H as History, J as Json, d as JsonO
28
28
  */
29
29
  declare function createClient(options: ClientOptions): Client;
30
30
 
31
- export { createClient };
31
+ /**
32
+ * Helper type to help users adopt to Lson types from interface definitions.
33
+ * You should only use this to wrap interfaces you don't control. For more
34
+ * information, see
35
+ * https://liveblocks.io/docs/guides/limits#lson-constraint-and-interfaces
36
+ */
37
+ declare type EnsureJson<T> = [
38
+ unknown
39
+ ] extends [T] ? T : T extends (...args: any[]) => any ? T : {
40
+ [K in keyof T]: EnsureJson<T[K]>;
41
+ };
42
+
43
+ export { EnsureJson, createClient };
package/index.js CHANGED
@@ -78,10 +78,10 @@ function makeStateMachine(state, context, mockedEffects) {
78
78
  })), notify(apply(LiveObject.getTreesDiffOperations(currentItems, new Map(items)), !1).updates);
79
79
  }(message.items) : state.root = (items = message.items, _buildRootAndParentTo = function(items) {
80
80
  for (var _step2, parentToChildren = new Map, root = null, _iterator2 = LiveObject._createForOfIteratorHelperLoose(items); !(_step2 = _iterator2()).done; ) {
81
- var tuple = _step2.value, parentId = tuple[1].parentId;
82
- if (null == parentId) root = tuple; else {
83
- var children = parentToChildren.get(parentId);
84
- null != children ? children.push(tuple) : parentToChildren.set(parentId, [ tuple ]);
81
+ var _step2$value = _step2.value, id = _step2$value[0], crdt = _step2$value[1];
82
+ if (LiveObject.isRootCrdt(crdt)) root = [ id, crdt ]; else {
83
+ var tuple = [ id, crdt ], children = parentToChildren.get(crdt.parentId);
84
+ null != children ? children.push(tuple) : parentToChildren.set(crdt.parentId, [ tuple ]);
85
85
  }
86
86
  }
87
87
  if (null == root) throw new Error("Root can't be null");
@@ -324,7 +324,7 @@ function makeStateMachine(state, context, mockedEffects) {
324
324
  }
325
325
  function onMessage(event) {
326
326
  if ("pong" !== event.data) {
327
- var text, data, messages = (text = event.data, void 0 === (data = LiveObject.parseJson(text)) ? null : LiveObject.isJsonArray(data) ? LiveObject.compact(data.map((function(item) {
327
+ var text, data, messages = (text = event.data, void 0 === (data = LiveObject.tryParseJson(text)) ? null : LiveObject.isJsonArray(data) ? LiveObject.compact(data.map((function(item) {
328
328
  return parseServerMessage(item);
329
329
  }))) : LiveObject.compact([ parseServerMessage(data) ]));
330
330
  if (null !== messages && 0 !== messages.length) {
@@ -758,7 +758,7 @@ var LiveblocksError = function(_Error) {
758
758
  function parseToken(token) {
759
759
  var tokenParts = token.split(".");
760
760
  if (3 !== tokenParts.length) throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
761
- var data = LiveObject.parseJson(atob(tokenParts[1]));
761
+ var data = LiveObject.tryParseJson(atob(tokenParts[1]));
762
762
  if (void 0 !== data && LiveObject.isJsonObject(data) && "number" == typeof data.actor && (void 0 === data.id || "string" == typeof data.id)) return {
763
763
  actor: data.actor,
764
764
  id: data.id,
package/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { A as AbstractCrdt, r as remove, S as ServerMsgCode, m as mergeStorageUpdates, W as WebsocketCloseCodes, C as ClientMsgCode, i as isTokenValid, a as isSameNodeOrChildOf, L as LiveObject, g as getTreesDiffOperations, O as OpCode, b as LiveList, p as parseJson, c as isJsonArray, d as compact, e as isJsonObject, f as deprecateIf } from "./shared.mjs";
1
+ import { A as AbstractCrdt, r as remove, S as ServerMsgCode, m as mergeStorageUpdates, W as WebsocketCloseCodes, C as ClientMsgCode, i as isTokenValid, a as isSameNodeOrChildOf, L as LiveObject, g as getTreesDiffOperations, O as OpCode, b as LiveList, t as tryParseJson, c as isJsonArray, d as compact, e as isJsonObject, f as isRootCrdt, h as deprecateIf } from "./shared.mjs";
2
2
 
3
- export { b as LiveList, h as LiveMap, L as LiveObject } from "./shared.mjs";
3
+ export { b as LiveList, j as LiveMap, L as LiveObject } from "./shared.mjs";
4
4
 
5
5
  const BACKOFF_RETRY_DELAYS = [ 250, 500, 1e3, 2e3, 4e3, 8e3, 1e4 ], BACKOFF_RETRY_DELAYS_SLOW = [ 2e3, 3e4, 6e4, 3e5 ];
6
6
 
@@ -69,12 +69,9 @@ function makeStateMachine(state, context, mockedEffects) {
69
69
  const [root, parentToChildren] = function(items) {
70
70
  const parentToChildren = new Map;
71
71
  let root = null;
72
- for (const tuple of items) {
73
- const parentId = tuple[1].parentId;
74
- if (null == parentId) root = tuple; else {
75
- const children = parentToChildren.get(parentId);
76
- null != children ? children.push(tuple) : parentToChildren.set(parentId, [ tuple ]);
77
- }
72
+ for (const [id, crdt] of items) if (isRootCrdt(crdt)) root = [ id, crdt ]; else {
73
+ const tuple = [ id, crdt ], children = parentToChildren.get(crdt.parentId);
74
+ null != children ? children.push(tuple) : parentToChildren.set(crdt.parentId, [ tuple ]);
78
75
  }
79
76
  if (null == root) throw new Error("Root can't be null");
80
77
  return [ root, parentToChildren ];
@@ -305,7 +302,7 @@ function makeStateMachine(state, context, mockedEffects) {
305
302
  function onMessage(event) {
306
303
  if ("pong" === event.data) return void clearTimeout(state.timeoutHandles.pongTimeout);
307
304
  const messages = function(text) {
308
- const data = parseJson(text);
305
+ const data = tryParseJson(text);
309
306
  return void 0 === data ? null : isJsonArray(data) ? compact(data.map((item => parseServerMessage(item)))) : compact([ parseServerMessage(data) ]);
310
307
  }(event.data);
311
308
  if (null === messages || 0 === messages.length) return;
@@ -713,7 +710,7 @@ class LiveblocksError extends Error {
713
710
  function parseToken(token) {
714
711
  const tokenParts = token.split(".");
715
712
  if (3 !== tokenParts.length) throw new Error("Authentication error. Liveblocks could not parse the response of your authentication endpoint");
716
- const data = parseJson(atob(tokenParts[1]));
713
+ const data = tryParseJson(atob(tokenParts[1]));
717
714
  if (void 0 !== data && isJsonObject(data) && "number" == typeof data.actor && (void 0 === data.id || "string" == typeof data.id)) return {
718
715
  actor: data.actor,
719
716
  id: data.id,
package/internal.d.ts CHANGED
@@ -1,6 +1,18 @@
1
- import { d as JsonObject, J as Json, e as Lson, A as AbstractCrdt, f as LsonObject, L as LiveObject, S as StorageUpdate } from './shared';
1
+ import { d as JsonObject, J as Json, g as Resolve, e as Lson, A as AbstractCrdt, f as LsonObject, L as LiveObject, S as StorageUpdate } from './shared';
2
2
  export { g as Resolve, h as RoomInitializers } from './shared';
3
3
 
4
+ declare type IdTuple<T> = [id: string, value: T];
5
+ /**
6
+ * Lookup table for nodes (= SerializedCrdt values) by their IDs.
7
+ */
8
+ declare type NodeMap = Map<string, // Node ID
9
+ SerializedCrdt>;
10
+ /**
11
+ * Reverse lookup table for all child nodes (= list of SerializedCrdt values)
12
+ * by their parent node's IDs.
13
+ */
14
+ declare type ParentToChildNodeMap = Map<string, // Parent's node ID
15
+ IdTuple<SerializedChild>[]>;
4
16
  /**
5
17
  * Messages that can be sent from the server to the client.
6
18
  */
@@ -100,7 +112,6 @@ declare type BroadcastedEventServerMsg = {
100
112
  */
101
113
  event: Json;
102
114
  };
103
- declare type SerializedCrdtWithId = [id: string, crdt: SerializedCrdt];
104
115
  /**
105
116
  * Sent by the WebSocket server to a single client in response to the client
106
117
  * joining the Room, to provide the initial Storage state of the Room. The
@@ -108,7 +119,7 @@ declare type SerializedCrdtWithId = [id: string, crdt: SerializedCrdt];
108
119
  */
109
120
  declare type InitialDocumentStateServerMsg = {
110
121
  type: ServerMsgCode.INITIAL_STORAGE_STATE;
111
- items: SerializedCrdtWithId[];
122
+ items: IdTuple<SerializedCrdt>[];
112
123
  };
113
124
  /**
114
125
  * Sent by the WebSocket server and broadcasted to all clients to announce that
@@ -121,22 +132,48 @@ declare type UpdateStorageServerMsg = {
121
132
  type: ServerMsgCode.UPDATE_STORAGE;
122
133
  ops: Op[];
123
134
  };
135
+ /**
136
+ * Messages that can be sent from the client to the server.
137
+ */
138
+ declare type ClientMsg<TPresence extends JsonObject> = BroadcastEventClientMsg | UpdatePresenceClientMsg<TPresence> | UpdateStorageClientMsg | FetchStorageClientMsg;
124
139
  declare enum ClientMsgCode {
125
140
  UPDATE_PRESENCE = 100,
126
141
  BROADCAST_EVENT = 103,
127
142
  FETCH_STORAGE = 200,
128
143
  UPDATE_STORAGE = 201
129
144
  }
145
+ declare type BroadcastEventClientMsg = {
146
+ type: ClientMsgCode.BROADCAST_EVENT;
147
+ event: Json;
148
+ };
149
+ declare type UpdatePresenceClientMsg<TPresence extends JsonObject> = {
150
+ type: ClientMsgCode.UPDATE_PRESENCE;
151
+ data: TPresence;
152
+ targetActor?: number;
153
+ };
154
+ declare type UpdateStorageClientMsg = {
155
+ type: ClientMsgCode.UPDATE_STORAGE;
156
+ ops: Op[];
157
+ };
158
+ declare type FetchStorageClientMsg = {
159
+ type: ClientMsgCode.FETCH_STORAGE;
160
+ };
130
161
  declare enum CrdtType {
131
162
  OBJECT = 0,
132
163
  LIST = 1,
133
164
  MAP = 2,
134
165
  REGISTER = 3
135
166
  }
167
+ declare type SerializedRootObject = {
168
+ type: CrdtType.OBJECT;
169
+ data: JsonObject;
170
+ parentId?: never;
171
+ parentKey?: never;
172
+ };
136
173
  declare type SerializedObject = {
137
174
  type: CrdtType.OBJECT;
138
- parentId?: string;
139
- parentKey?: string;
175
+ parentId: string;
176
+ parentKey: string;
140
177
  data: JsonObject;
141
178
  };
142
179
  declare type SerializedList = {
@@ -155,7 +192,10 @@ declare type SerializedRegister = {
155
192
  parentKey: string;
156
193
  data: Json;
157
194
  };
158
- declare type SerializedCrdt = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
195
+ declare type SerializedCrdt = SerializedRootObject | SerializedChild;
196
+ declare type SerializedChild = SerializedObject | SerializedList | SerializedMap | SerializedRegister;
197
+ declare function isRootCrdt(crdt: SerializedCrdt): crdt is SerializedRootObject;
198
+ declare function isChildCrdt(crdt: SerializedCrdt): crdt is SerializedChild;
159
199
  declare enum OpCode {
160
200
  INIT = 0,
161
201
  SET_PARENT_KEY = 1,
@@ -171,7 +211,9 @@ declare enum OpCode {
171
211
  * These operations are the payload for {@link UpdateStorageServerMsg} messages
172
212
  * only.
173
213
  */
174
- declare type Op = CreateObjectOp | UpdateObjectOp | DeleteCrdtOp | CreateListOp | SetParentKeyOp | DeleteObjectKeyOp | CreateMapOp | CreateRegisterOp;
214
+ declare type Op = CreateOp | UpdateObjectOp | DeleteCrdtOp | SetParentKeyOp | DeleteObjectKeyOp;
215
+ declare type CreateOp = CreateRootObjectOp | CreateChildOp;
216
+ declare type CreateChildOp = CreateObjectOp | CreateRegisterOp | CreateMapOp | CreateListOp;
175
217
  declare type UpdateObjectOp = {
176
218
  opId?: string;
177
219
  id: string;
@@ -183,10 +225,14 @@ declare type CreateObjectOp = {
183
225
  id: string;
184
226
  intent?: "set";
185
227
  type: OpCode.CREATE_OBJECT;
186
- parentId?: string;
187
- parentKey?: string;
228
+ parentId: string;
229
+ parentKey: string;
188
230
  data: JsonObject;
189
231
  };
232
+ declare type CreateRootObjectOp = Resolve<Omit<CreateObjectOp, "parentId" | "parentKey"> & {
233
+ parentId?: never;
234
+ parentKey?: never;
235
+ }>;
190
236
  declare type CreateListOp = {
191
237
  opId?: string;
192
238
  id: string;
@@ -278,4 +324,34 @@ declare function patchImmutableObject<T>(state: T, updates: StorageUpdate[]): T;
278
324
  declare function makePosition(before?: string, after?: string): string;
279
325
  declare function comparePosition(posA: string, posB: string): number;
280
326
 
281
- export { ClientMsgCode, CrdtType, CreateListOp, CreateMapOp, CreateObjectOp, CreateRegisterOp, DeleteCrdtOp, DeleteObjectKeyOp, Op, OpCode, RoomStateServerMsg, SerializedCrdt, SerializedCrdtWithId, SerializedList, SerializedMap, SerializedObject, SerializedRegister, ServerMsg, ServerMsgCode, SetParentKeyOp, UpdateObjectOp, UserJoinServerMsg, WebsocketCloseCodes, comparePosition, deprecate, deprecateIf, errorIf, lsonToJson, makePosition, patchImmutableObject, patchLiveObjectKey, throwUsageError };
327
+ /**
328
+ * Helper function that can be used to implement exhaustive switch statements
329
+ * with TypeScript. Example usage:
330
+ *
331
+ * type Fruit = "🍎" | "🍌";
332
+ *
333
+ * switch (fruit) {
334
+ * case "🍎":
335
+ * case "🍌":
336
+ * return doSomething();
337
+ *
338
+ * default:
339
+ * return assertNever(fruit, "Unknown fruit");
340
+ * }
341
+ *
342
+ * If now the Fruit union is extended (i.e. add "🍒"), TypeScript will catch
343
+ * this *statically*, rather than at runtime, and force you to handle the
344
+ * 🍒 case.
345
+ */
346
+ declare function assertNever(_value: never, errmsg: string): never;
347
+ /**
348
+ * Alternative to JSON.parse() that will not throw in production. If the passed
349
+ * string cannot be parsed, this will return `undefined`.
350
+ */
351
+ declare function tryParseJson(rawMessage: string): Json | undefined;
352
+ /**
353
+ * Decode base64 string.
354
+ */
355
+ declare function b64decode(b64value: string): string;
356
+
357
+ export { BroadcastEventClientMsg, ClientMsg, ClientMsgCode, CrdtType, CreateChildOp, CreateListOp, CreateMapOp, CreateObjectOp, CreateRegisterOp, CreateRootObjectOp, DeleteCrdtOp, DeleteObjectKeyOp, FetchStorageClientMsg, IdTuple, InitialDocumentStateServerMsg, NodeMap, Op, OpCode, ParentToChildNodeMap, RoomStateServerMsg, SerializedChild, SerializedCrdt, SerializedList, SerializedMap, SerializedObject, SerializedRegister, SerializedRootObject, ServerMsg, ServerMsgCode, SetParentKeyOp, UpdateObjectOp, UpdatePresenceClientMsg, UpdateStorageClientMsg, UserJoinServerMsg, WebsocketCloseCodes, assertNever, b64decode, comparePosition, deprecate, deprecateIf, errorIf, isChildCrdt, isRootCrdt, lsonToJson, makePosition, patchImmutableObject, patchLiveObjectKey, throwUsageError, tryParseJson };
package/internal.js CHANGED
@@ -165,10 +165,13 @@ Object.defineProperty(exports, "ClientMsgCode", {
165
165
  get: function() {
166
166
  return LiveObject.WebsocketCloseCodes;
167
167
  }
168
- }), exports.comparePosition = LiveObject.comparePosition, exports.deprecate = LiveObject.deprecate,
168
+ }), exports.assertNever = LiveObject.assertNever, exports.b64decode = LiveObject.b64decode,
169
+ exports.comparePosition = LiveObject.comparePosition, exports.deprecate = LiveObject.deprecate,
169
170
  exports.deprecateIf = LiveObject.deprecateIf, exports.errorIf = LiveObject.errorIf,
171
+ exports.isChildCrdt = LiveObject.isChildCrdt, exports.isRootCrdt = LiveObject.isRootCrdt,
170
172
  exports.makePosition = LiveObject.makePosition, exports.throwUsageError = LiveObject.throwUsageError,
171
- exports.lsonToJson = lsonToJson, exports.patchImmutableObject = function(state, updates) {
173
+ exports.tryParseJson = LiveObject.tryParseJson, exports.lsonToJson = lsonToJson,
174
+ exports.patchImmutableObject = function(state, updates) {
172
175
  return updates.reduce((function(state, update) {
173
176
  return function(state, update) {
174
177
  var path = function(node) {
package/internal.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { L as LiveObject, b as LiveList, h as LiveMap, j as LiveRegister, A as AbstractCrdt, k as findNonSerializableValue } from "./shared.mjs";
1
+ import { L as LiveObject, b as LiveList, j as LiveMap, k as LiveRegister, A as AbstractCrdt, l as findNonSerializableValue } from "./shared.mjs";
2
2
 
3
- export { C as ClientMsgCode, o as CrdtType, O as OpCode, S as ServerMsgCode, W as WebsocketCloseCodes, q as comparePosition, l as deprecate, f as deprecateIf, n as errorIf, s as makePosition, t as throwUsageError } from "./shared.mjs";
3
+ export { C as ClientMsgCode, q as CrdtType, O as OpCode, S as ServerMsgCode, W as WebsocketCloseCodes, w as assertNever, x as b64decode, s as comparePosition, n as deprecate, h as deprecateIf, o as errorIf, v as isChildCrdt, f as isRootCrdt, u as makePosition, p as throwUsageError, t as tryParseJson } from "./shared.mjs";
4
4
 
5
5
  function lsonObjectToJson(obj) {
6
6
  const result = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/client",
3
- "version": "0.16.9",
3
+ "version": "0.16.12",
4
4
  "description": "A client that lets you interact with Liveblocks servers.",
5
5
  "main": "./index.js",
6
6
  "module": "./index.mjs",
package/shared.js CHANGED
@@ -124,6 +124,10 @@ function _createForOfIteratorHelperLoose(o, allowArrayLike) {
124
124
 
125
125
  var ServerMsgCode, ClientMsgCode, CrdtType, OpCode, WebsocketCloseCodes;
126
126
 
127
+ function isChildCrdt(crdt) {
128
+ return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
129
+ }
130
+
127
131
  exports.ServerMsgCode = void 0, (ServerMsgCode = exports.ServerMsgCode || (exports.ServerMsgCode = {}))[ServerMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE",
128
132
  ServerMsgCode[ServerMsgCode.USER_JOINED = 101] = "USER_JOINED", ServerMsgCode[ServerMsgCode.USER_LEFT = 102] = "USER_LEFT",
129
133
  ServerMsgCode[ServerMsgCode.BROADCASTED_EVENT = 103] = "BROADCASTED_EVENT", ServerMsgCode[ServerMsgCode.ROOM_STATE = 104] = "ROOM_STATE",
@@ -193,14 +197,6 @@ var AbstractCrdt = function() {
193
197
  } ]), AbstractCrdt;
194
198
  }();
195
199
 
196
- function parseJson(rawMessage) {
197
- try {
198
- return JSON.parse(rawMessage);
199
- } catch (e) {
200
- return;
201
- }
202
- }
203
-
204
200
  function isJsonArray(data) {
205
201
  return Array.isArray(data);
206
202
  }
@@ -216,9 +212,7 @@ var _Symbol$iterator$1, _Symbol$iterator2, LiveRegister = function(_AbstractCrdt
216
212
  _this;
217
213
  }
218
214
  _inheritsLoose(LiveRegister, _AbstractCrdt), LiveRegister._deserialize = function(_ref, _parentToChildren, doc) {
219
- var id = _ref[0], item = _ref[1];
220
- if (item.type !== exports.CrdtType.REGISTER) throw new Error('Tried to deserialize a map but item type is "' + item.type + '"');
221
- var register = new LiveRegister(item.data);
215
+ var id = _ref[0], register = new LiveRegister(_ref[1].data);
222
216
  return register._attach(id, doc), register;
223
217
  };
224
218
  var _proto = LiveRegister.prototype;
@@ -328,8 +322,8 @@ var LiveList = function(_AbstractCrdt) {
328
322
  void 0 === items && (items = []), (_this = _AbstractCrdt.call(this) || this)._items = void 0,
329
323
  _this._items = [];
330
324
  for (var position = void 0, i = 0; i < items.length; i++) {
331
- var newPosition = makePosition(position), _item = selfOrRegister(items[i]);
332
- _this._items.push([ _item, newPosition ]), position = newPosition;
325
+ var newPosition = makePosition(position), item = selfOrRegister(items[i]);
326
+ _this._items.push([ item, newPosition ]), position = newPosition;
333
327
  }
334
328
  return _this;
335
329
  }
@@ -511,8 +505,8 @@ var LiveList = function(_AbstractCrdt) {
511
505
  return entry[1] === position;
512
506
  }));
513
507
  if (this._doc && this._id) {
514
- var _id = this._doc.generateId();
515
- value._attach(_id, this._doc);
508
+ var id = this._doc.generateId();
509
+ value._attach(id, this._doc);
516
510
  var storageUpdates = new Map;
517
511
  storageUpdates.set(this._id, {
518
512
  node: this,
@@ -524,7 +518,7 @@ var LiveList = function(_AbstractCrdt) {
524
518
  } ]
525
519
  }), this._doc.dispatch(value._serialize(this._id, position, this._doc), [ {
526
520
  type: exports.OpCode.DELETE_CRDT,
527
- id: _id
521
+ id: id
528
522
  } ], storageUpdates);
529
523
  }
530
524
  }, _proto.move = function(index, targetIndex) {
@@ -589,14 +583,13 @@ var LiveList = function(_AbstractCrdt) {
589
583
  }, _proto.clear = function() {
590
584
  if (this._doc) {
591
585
  for (var _step5, ops = [], reverseOps = [], updateDelta = [], i = 0, _iterator5 = _createForOfIteratorHelperLoose(this._items); !(_step5 = _iterator5()).done; ) {
592
- var _item3 = _step5.value;
593
- _item3[0]._detach();
594
- var childId = _item3[0]._id;
586
+ var item = _step5.value;
587
+ item[0]._detach();
588
+ var childId = item[0]._id;
595
589
  childId && (ops.push({
596
590
  id: childId,
597
591
  type: exports.OpCode.DELETE_CRDT
598
- }), reverseOps.push.apply(reverseOps, _item3[0]._serialize(this._id, _item3[1])),
599
- updateDelta.push({
592
+ }), reverseOps.push.apply(reverseOps, item[0]._serialize(this._id, item[1])), updateDelta.push({
600
593
  index: i,
601
594
  type: "delete"
602
595
  })), i++;
@@ -620,8 +613,8 @@ var LiveList = function(_AbstractCrdt) {
620
613
  existingItem._detach();
621
614
  var value = selfOrRegister(item);
622
615
  if (value._setParentLink(this, position), this._items[index][0] = value, this._doc && this._id) {
623
- var _id2 = this._doc.generateId();
624
- value._attach(_id2, this._doc);
616
+ var id = this._doc.generateId();
617
+ value._attach(id, this._doc);
625
618
  var storageUpdates = new Map;
626
619
  storageUpdates.set(this._id, {
627
620
  node: this,
@@ -740,8 +733,8 @@ var LiveMap = function(_AbstractCrdt) {
740
733
  }
741
734
  return ops;
742
735
  }, LiveMap._deserialize = function(_ref, parentToChildren, doc) {
743
- var id = _ref[0], item = _ref[1];
744
- if (item.type !== exports.CrdtType.MAP) throw new Error('Tried to deserialize a map but item type is "' + item.type + '"');
736
+ var id = _ref[0];
737
+ _ref[1];
745
738
  var map = new LiveMap;
746
739
  map._attach(id, doc);
747
740
  var children = parentToChildren.get(id);
@@ -911,19 +904,20 @@ function creationOpToLiveStructure(op) {
911
904
  }
912
905
  }
913
906
 
914
- function deserialize(entry, parentToChildren, doc) {
915
- switch (entry[1].type) {
907
+ function deserialize(_ref, parentToChildren, doc) {
908
+ var id = _ref[0], crdt = _ref[1];
909
+ switch (crdt.type) {
916
910
  case exports.CrdtType.OBJECT:
917
- return LiveObject._deserialize(entry, parentToChildren, doc);
911
+ return LiveObject._deserialize([ id, crdt ], parentToChildren, doc);
918
912
 
919
913
  case exports.CrdtType.LIST:
920
- return LiveList._deserialize(entry, parentToChildren, doc);
914
+ return LiveList._deserialize([ id, crdt ], parentToChildren, doc);
921
915
 
922
916
  case exports.CrdtType.MAP:
923
- return LiveMap._deserialize(entry, parentToChildren, doc);
917
+ return LiveMap._deserialize([ id, crdt ], parentToChildren, doc);
924
918
 
925
919
  case exports.CrdtType.REGISTER:
926
- return LiveRegister._deserialize(entry, parentToChildren, doc);
920
+ return LiveRegister._deserialize([ id, crdt ], parentToChildren, doc);
927
921
 
928
922
  default:
929
923
  throw new Error("Unexpected CRDT type");
@@ -960,6 +954,14 @@ function entries(obj) {
960
954
  return Object.entries(obj);
961
955
  }
962
956
 
957
+ function tryParseJson(rawMessage) {
958
+ try {
959
+ return JSON.parse(rawMessage);
960
+ } catch (e) {
961
+ return;
962
+ }
963
+ }
964
+
963
965
  var LiveObject = function(_AbstractCrdt) {
964
966
  function LiveObject(obj) {
965
967
  var _this;
@@ -974,14 +976,20 @@ var LiveObject = function(_AbstractCrdt) {
974
976
  var _proto = LiveObject.prototype;
975
977
  return _proto._serialize = function(parentId, parentKey, doc, intent) {
976
978
  if (null == this._id) throw new Error("Cannot serialize item is not attached");
977
- var ops = [], op = {
979
+ var opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
980
+ type: exports.OpCode.CREATE_OBJECT,
978
981
  id: this._id,
979
- opId: null == doc ? void 0 : doc.generateOpId(),
982
+ opId: opId,
980
983
  intent: intent,
981
- type: exports.OpCode.CREATE_OBJECT,
982
984
  parentId: parentId,
983
985
  parentKey: parentKey,
984
986
  data: {}
987
+ } : {
988
+ type: exports.OpCode.CREATE_OBJECT,
989
+ id: this._id,
990
+ opId: opId,
991
+ intent: intent,
992
+ data: {}
985
993
  };
986
994
  ops.push(op);
987
995
  for (var _step, _iterator = _createForOfIteratorHelperLoose(this._map); !(_step = _iterator()).done; ) {
@@ -990,9 +998,7 @@ var LiveObject = function(_AbstractCrdt) {
990
998
  }
991
999
  return ops;
992
1000
  }, LiveObject._deserialize = function(_ref, parentToChildren, doc) {
993
- var id = _ref[0], item = _ref[1];
994
- if (item.type !== exports.CrdtType.OBJECT) throw new Error('Tried to deserialize a record but item type is "' + item.type + '"');
995
- var liveObj = new LiveObject(item.data);
1001
+ var id = _ref[0], liveObj = new LiveObject(_ref[1].data);
996
1002
  return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
997
1003
  }, LiveObject._deserializeChildren = function(liveObj, parentToChildren, doc) {
998
1004
  var children = parentToChildren.get(liveObj._id);
@@ -1088,11 +1094,14 @@ var LiveObject = function(_AbstractCrdt) {
1088
1094
  var _step7$value = _step7.value, key = _step7$value[0], value = _step7$value[1];
1089
1095
  value instanceof AbstractCrdt == !1 && (data[key] = value);
1090
1096
  }
1091
- return {
1097
+ return void 0 !== (null == (_this$_parent = this._parent) ? void 0 : _this$_parent._id) && void 0 !== this._parentKey ? {
1092
1098
  type: exports.CrdtType.OBJECT,
1093
- parentId: null == (_this$_parent = this._parent) ? void 0 : _this$_parent._id,
1099
+ parentId: this._parent._id,
1094
1100
  parentKey: this._parentKey,
1095
1101
  data: data
1102
+ } : {
1103
+ type: exports.CrdtType.OBJECT,
1104
+ data: data
1096
1105
  };
1097
1106
  }, _proto._applyUpdate = function(op, isLocal) {
1098
1107
  var isModified = !1, reverse = [], reverseUpdate = {
@@ -1260,7 +1269,18 @@ exports._extends = _extends, exports._inheritsLoose = _inheritsLoose, exports._o
1260
1269
  var key, i, target = {}, sourceKeys = Object.keys(source);
1261
1270
  for (i = 0; i < sourceKeys.length; i++) key = sourceKeys[i], excluded.indexOf(key) >= 0 || (target[key] = source[key]);
1262
1271
  return target;
1263
- }, exports._wrapNativeSuper = _wrapNativeSuper, exports.compact = function(items) {
1272
+ }, exports._wrapNativeSuper = _wrapNativeSuper, exports.assertNever = function(_value, errmsg) {
1273
+ throw new Error(errmsg);
1274
+ }, exports.b64decode = function(b64value) {
1275
+ try {
1276
+ var formattedValue = b64value.replace(/-/g, "+").replace(/_/g, "/");
1277
+ return decodeURIComponent(atob(formattedValue).split("").map((function(c) {
1278
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
1279
+ })).join(""));
1280
+ } catch (err) {
1281
+ return atob(b64value);
1282
+ }
1283
+ }, exports.compact = function(items) {
1264
1284
  return items.filter((function(item) {
1265
1285
  return null != item;
1266
1286
  }));
@@ -1294,11 +1314,11 @@ exports.errorIf = function(condition, message) {
1294
1314
  });
1295
1315
  })), newItems.forEach((function(crdt, id) {
1296
1316
  var currentCrdt = currentItems.get(id);
1297
- if (currentCrdt) crdt.type === exports.CrdtType.OBJECT && JSON.stringify(crdt.data) !== JSON.stringify(currentCrdt.data) && ops.push({
1317
+ if (currentCrdt) crdt.type === exports.CrdtType.OBJECT && (currentCrdt.type === exports.CrdtType.OBJECT && JSON.stringify(crdt.data) === JSON.stringify(currentCrdt.data) || ops.push({
1298
1318
  type: exports.OpCode.UPDATE_OBJECT,
1299
1319
  id: id,
1300
1320
  data: crdt.data
1301
- }), crdt.parentKey !== currentCrdt.parentKey && ops.push({
1321
+ })), crdt.parentKey !== currentCrdt.parentKey && ops.push({
1302
1322
  type: exports.OpCode.SET_PARENT_KEY,
1303
1323
  id: id,
1304
1324
  parentKey: crdt.parentKey
@@ -1323,12 +1343,16 @@ exports.errorIf = function(condition, message) {
1323
1343
  break;
1324
1344
 
1325
1345
  case exports.CrdtType.OBJECT:
1326
- ops.push({
1346
+ ops.push(crdt.parentId ? {
1327
1347
  type: exports.OpCode.CREATE_OBJECT,
1328
1348
  id: id,
1329
1349
  parentId: crdt.parentId,
1330
1350
  parentKey: crdt.parentKey,
1331
1351
  data: crdt.data
1352
+ } : {
1353
+ type: exports.OpCode.CREATE_OBJECT,
1354
+ id: id,
1355
+ data: crdt.data
1332
1356
  });
1333
1357
  break;
1334
1358
 
@@ -1341,12 +1365,15 @@ exports.errorIf = function(condition, message) {
1341
1365
  });
1342
1366
  }
1343
1367
  })), ops;
1344
- }, exports.isJsonArray = isJsonArray, exports.isJsonObject = isJsonObject, exports.isSameNodeOrChildOf = function isSameNodeOrChildOf(node, parent) {
1368
+ }, exports.isChildCrdt = isChildCrdt, exports.isJsonArray = isJsonArray, exports.isJsonObject = isJsonObject,
1369
+ exports.isRootCrdt = function(crdt) {
1370
+ return crdt.type === exports.CrdtType.OBJECT && !isChildCrdt(crdt);
1371
+ }, exports.isSameNodeOrChildOf = function isSameNodeOrChildOf(node, parent) {
1345
1372
  return node === parent || !!node._parent && isSameNodeOrChildOf(node._parent, parent);
1346
1373
  }, exports.isTokenValid = function(token) {
1347
1374
  var tokenParts = token.split(".");
1348
1375
  if (3 !== tokenParts.length) return !1;
1349
- var data = parseJson(atob(tokenParts[1]));
1376
+ var data = tryParseJson(atob(tokenParts[1]));
1350
1377
  return !(void 0 === data || !isJsonObject(data) || "number" != typeof data.exp) && !(Date.now() / 1e3 > data.exp - 300);
1351
1378
  }, exports.makePosition = makePosition, exports.mergeStorageUpdates = function(first, second) {
1352
1379
  return first ? "LiveObject" === first.type && "LiveObject" === second.type ? function(first, second) {
@@ -1370,9 +1397,9 @@ exports.errorIf = function(condition, message) {
1370
1397
  updates: first.updates.concat(second.updates)
1371
1398
  });
1372
1399
  }(first, second) : second : second;
1373
- }, exports.parseJson = parseJson, exports.remove = function(array, item) {
1400
+ }, exports.remove = function(array, item) {
1374
1401
  for (var i = 0; i < array.length; i++) if (array[i] === item) {
1375
1402
  array.splice(i, 1);
1376
1403
  break;
1377
1404
  }
1378
- }, exports.throwUsageError = throwUsageError;
1405
+ }, exports.throwUsageError = throwUsageError, exports.tryParseJson = tryParseJson;
package/shared.mjs CHANGED
@@ -1,5 +1,13 @@
1
1
  var ServerMsgCode, ClientMsgCode, CrdtType, OpCode, WebsocketCloseCodes;
2
2
 
3
+ function isRootCrdt(crdt) {
4
+ return crdt.type === CrdtType.OBJECT && !isChildCrdt(crdt);
5
+ }
6
+
7
+ function isChildCrdt(crdt) {
8
+ return void 0 !== crdt.parentId && void 0 !== crdt.parentKey;
9
+ }
10
+
3
11
  !function(ServerMsgCode) {
4
12
  ServerMsgCode[ServerMsgCode.UPDATE_PRESENCE = 100] = "UPDATE_PRESENCE", ServerMsgCode[ServerMsgCode.USER_JOINED = 101] = "USER_JOINED",
5
13
  ServerMsgCode[ServerMsgCode.USER_LEFT = 102] = "USER_LEFT", ServerMsgCode[ServerMsgCode.BROADCASTED_EVENT = 103] = "BROADCASTED_EVENT",
@@ -62,14 +70,6 @@ class AbstractCrdt {
62
70
  }
63
71
  }
64
72
 
65
- function parseJson(rawMessage) {
66
- try {
67
- return JSON.parse(rawMessage);
68
- } catch (e) {
69
- return;
70
- }
71
- }
72
-
73
73
  function isJsonArray(data) {
74
74
  return Array.isArray(data);
75
75
  }
@@ -86,7 +86,6 @@ class LiveRegister extends AbstractCrdt {
86
86
  return this._data;
87
87
  }
88
88
  static _deserialize([id, item], _parentToChildren, doc) {
89
- if (item.type !== CrdtType.REGISTER) throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
90
89
  const register = new LiveRegister(item.data);
91
90
  return register._attach(id, doc), register;
92
91
  }
@@ -587,8 +586,7 @@ class LiveMap extends AbstractCrdt {
587
586
  for (const [key, value] of this._map) ops.push(...value._serialize(this._id, key, doc));
588
587
  return ops;
589
588
  }
590
- static _deserialize([id, item], parentToChildren, doc) {
591
- if (item.type !== CrdtType.MAP) throw new Error(`Tried to deserialize a map but item type is "${item.type}"`);
589
+ static _deserialize([id, _item], parentToChildren, doc) {
592
590
  const map = new LiveMap;
593
591
  map._attach(id, doc);
594
592
  const children = parentToChildren.get(id);
@@ -758,6 +756,10 @@ class LiveMap extends AbstractCrdt {
758
756
  }
759
757
  }
760
758
 
759
+ function assertNever(_value, errmsg) {
760
+ throw new Error(errmsg);
761
+ }
762
+
761
763
  function remove(array, item) {
762
764
  for (let i = 0; i < array.length; i++) if (array[i] === item) {
763
765
  array.splice(i, 1);
@@ -789,19 +791,19 @@ function isSameNodeOrChildOf(node, parent) {
789
791
  return node === parent || !!node._parent && isSameNodeOrChildOf(node._parent, parent);
790
792
  }
791
793
 
792
- function deserialize(entry, parentToChildren, doc) {
793
- switch (entry[1].type) {
794
+ function deserialize([id, crdt], parentToChildren, doc) {
795
+ switch (crdt.type) {
794
796
  case CrdtType.OBJECT:
795
- return LiveObject._deserialize(entry, parentToChildren, doc);
797
+ return LiveObject._deserialize([ id, crdt ], parentToChildren, doc);
796
798
 
797
799
  case CrdtType.LIST:
798
- return LiveList._deserialize(entry, parentToChildren, doc);
800
+ return LiveList._deserialize([ id, crdt ], parentToChildren, doc);
799
801
 
800
802
  case CrdtType.MAP:
801
- return LiveMap._deserialize(entry, parentToChildren, doc);
803
+ return LiveMap._deserialize([ id, crdt ], parentToChildren, doc);
802
804
 
803
805
  case CrdtType.REGISTER:
804
- return LiveRegister._deserialize(entry, parentToChildren, doc);
806
+ return LiveRegister._deserialize([ id, crdt ], parentToChildren, doc);
805
807
 
806
808
  default:
807
809
  throw new Error("Unexpected CRDT type");
@@ -831,11 +833,11 @@ function getTreesDiffOperations(currentItems, newItems) {
831
833
  });
832
834
  })), newItems.forEach(((crdt, id) => {
833
835
  const currentCrdt = currentItems.get(id);
834
- if (currentCrdt) crdt.type === CrdtType.OBJECT && JSON.stringify(crdt.data) !== JSON.stringify(currentCrdt.data) && ops.push({
836
+ if (currentCrdt) crdt.type === CrdtType.OBJECT && (currentCrdt.type === CrdtType.OBJECT && JSON.stringify(crdt.data) === JSON.stringify(currentCrdt.data) || ops.push({
835
837
  type: OpCode.UPDATE_OBJECT,
836
838
  id: id,
837
839
  data: crdt.data
838
- }), crdt.parentKey !== currentCrdt.parentKey && ops.push({
840
+ })), crdt.parentKey !== currentCrdt.parentKey && ops.push({
839
841
  type: OpCode.SET_PARENT_KEY,
840
842
  id: id,
841
843
  parentKey: crdt.parentKey
@@ -860,12 +862,16 @@ function getTreesDiffOperations(currentItems, newItems) {
860
862
  break;
861
863
 
862
864
  case CrdtType.OBJECT:
863
- ops.push({
865
+ ops.push(crdt.parentId ? {
864
866
  type: OpCode.CREATE_OBJECT,
865
867
  id: id,
866
868
  parentId: crdt.parentId,
867
869
  parentKey: crdt.parentKey,
868
870
  data: crdt.data
871
+ } : {
872
+ type: OpCode.CREATE_OBJECT,
873
+ id: id,
874
+ data: crdt.data
869
875
  });
870
876
  break;
871
877
 
@@ -936,7 +942,7 @@ function findNonSerializableValue(value, path = "") {
936
942
  function isTokenValid(token) {
937
943
  const tokenParts = token.split(".");
938
944
  if (3 !== tokenParts.length) return !1;
939
- const data = parseJson(atob(tokenParts[1]));
945
+ const data = tryParseJson(atob(tokenParts[1]));
940
946
  if (void 0 === data || !isJsonObject(data) || "number" != typeof data.exp) return !1;
941
947
  return !(Date.now() / 1e3 > data.exp - 300);
942
948
  }
@@ -945,6 +951,25 @@ function entries(obj) {
945
951
  return Object.entries(obj);
946
952
  }
947
953
 
954
+ function tryParseJson(rawMessage) {
955
+ try {
956
+ return JSON.parse(rawMessage);
957
+ } catch (e) {
958
+ return;
959
+ }
960
+ }
961
+
962
+ function b64decode(b64value) {
963
+ try {
964
+ const formattedValue = b64value.replace(/-/g, "+").replace(/_/g, "/");
965
+ return decodeURIComponent(atob(formattedValue).split("").map((function(c) {
966
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
967
+ })).join(""));
968
+ } catch (err) {
969
+ return atob(b64value);
970
+ }
971
+ }
972
+
948
973
  class LiveObject extends AbstractCrdt {
949
974
  constructor(obj = {}) {
950
975
  super(), this._propToLastUpdate = new Map;
@@ -956,21 +981,26 @@ class LiveObject extends AbstractCrdt {
956
981
  }
957
982
  _serialize(parentId, parentKey, doc, intent) {
958
983
  if (null == this._id) throw new Error("Cannot serialize item is not attached");
959
- const ops = [], op = {
984
+ const opId = null == doc ? void 0 : doc.generateOpId(), ops = [], op = void 0 !== parentId && void 0 !== parentKey ? {
985
+ type: OpCode.CREATE_OBJECT,
960
986
  id: this._id,
961
- opId: null == doc ? void 0 : doc.generateOpId(),
987
+ opId: opId,
962
988
  intent: intent,
963
- type: OpCode.CREATE_OBJECT,
964
989
  parentId: parentId,
965
990
  parentKey: parentKey,
966
991
  data: {}
992
+ } : {
993
+ type: OpCode.CREATE_OBJECT,
994
+ id: this._id,
995
+ opId: opId,
996
+ intent: intent,
997
+ data: {}
967
998
  };
968
999
  ops.push(op);
969
1000
  for (const [key, value] of this._map) value instanceof AbstractCrdt ? ops.push(...value._serialize(this._id, key, doc)) : op.data[key] = value;
970
1001
  return ops;
971
1002
  }
972
1003
  static _deserialize([id, item], parentToChildren, doc) {
973
- if (item.type !== CrdtType.OBJECT) throw new Error(`Tried to deserialize a record but item type is "${item.type}"`);
974
1004
  const liveObj = new LiveObject(item.data);
975
1005
  return liveObj._attach(id, doc), this._deserializeChildren(liveObj, parentToChildren, doc);
976
1006
  }
@@ -1065,11 +1095,14 @@ class LiveObject extends AbstractCrdt {
1065
1095
  var _a;
1066
1096
  const data = {};
1067
1097
  for (const [key, value] of this._map) value instanceof AbstractCrdt == !1 && (data[key] = value);
1068
- return {
1098
+ return void 0 !== (null === (_a = this._parent) || void 0 === _a ? void 0 : _a._id) && void 0 !== this._parentKey ? {
1069
1099
  type: CrdtType.OBJECT,
1070
- parentId: null === (_a = this._parent) || void 0 === _a ? void 0 : _a._id,
1100
+ parentId: this._parent._id,
1071
1101
  parentKey: this._parentKey,
1072
1102
  data: data
1103
+ } : {
1104
+ type: CrdtType.OBJECT,
1105
+ data: data
1073
1106
  };
1074
1107
  }
1075
1108
  _applyUpdate(op, isLocal) {
@@ -1240,4 +1273,4 @@ class LiveObject extends AbstractCrdt {
1240
1273
  }
1241
1274
  }
1242
1275
 
1243
- export { AbstractCrdt as A, ClientMsgCode as C, LiveObject as L, OpCode as O, ServerMsgCode as S, WebsocketCloseCodes as W, isSameNodeOrChildOf as a, LiveList as b, isJsonArray as c, compact as d, isJsonObject as e, deprecateIf as f, getTreesDiffOperations as g, LiveMap as h, isTokenValid as i, LiveRegister as j, findNonSerializableValue as k, deprecate as l, mergeStorageUpdates as m, errorIf as n, CrdtType as o, parseJson as p, comparePosition as q, remove as r, makePosition as s, throwUsageError as t };
1276
+ export { AbstractCrdt as A, ClientMsgCode as C, LiveObject as L, OpCode as O, ServerMsgCode as S, WebsocketCloseCodes as W, isSameNodeOrChildOf as a, LiveList as b, isJsonArray as c, compact as d, isJsonObject as e, isRootCrdt as f, getTreesDiffOperations as g, deprecateIf as h, isTokenValid as i, LiveMap as j, LiveRegister as k, findNonSerializableValue as l, mergeStorageUpdates as m, deprecate as n, errorIf as o, throwUsageError as p, CrdtType as q, remove as r, comparePosition as s, tryParseJson as t, makePosition as u, isChildCrdt as v, assertNever as w, b64decode as x };