@liveblocks/client 0.15.0-alpha.2 → 0.15.0-alpha.3

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.
@@ -9,6 +9,7 @@ export declare type ApplyResult = {
9
9
  export interface Doc {
10
10
  generateId: () => string;
11
11
  generateOpId: () => string;
12
+ getItem: (id: string) => AbstractCrdt | undefined;
12
13
  addItem: (id: string, item: AbstractCrdt) => void;
13
14
  deleteItem: (id: string) => void;
14
15
  dispatch: (ops: Op[], reverseOps: Op[], storageUpdates: Map<string, StorageUpdate>) => void;
@@ -46,7 +47,7 @@ export declare abstract class AbstractCrdt {
46
47
  /**
47
48
  * INTERNAL
48
49
  */
49
- abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
50
+ abstract _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
50
51
  /**
51
52
  * INTERNAL
52
53
  */
@@ -26,7 +26,7 @@ export declare class LiveList<T> extends AbstractCrdt {
26
26
  /**
27
27
  * INTERNAL
28
28
  */
29
- _attachChild(id: string, key: string, child: AbstractCrdt, isLocal: boolean): ApplyResult;
29
+ _attachChild(id: string, key: string, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
30
30
  /**
31
31
  * INTERNAL
32
32
  */
@@ -100,11 +100,14 @@ class LiveList extends AbstractCrdt_1.AbstractCrdt {
100
100
  /**
101
101
  * INTERNAL
102
102
  */
103
- _attachChild(id, key, child, isLocal) {
103
+ _attachChild(id, key, child, opId, isLocal) {
104
104
  var _a;
105
105
  if (this._doc == null) {
106
106
  throw new Error("Can't attach child if doc is not present");
107
107
  }
108
+ if (this._doc.getItem(id) !== undefined) {
109
+ return { modified: false };
110
+ }
108
111
  child._attach(id, this._doc);
109
112
  child._setParentLink(this, key);
110
113
  const index = __classPrivateFieldGet(this, _LiveList_items, "f").findIndex((entry) => entry[1] === key);
@@ -23,7 +23,7 @@ export declare class LiveMap<TKey extends string, TValue> extends AbstractCrdt {
23
23
  /**
24
24
  * INTERNAL
25
25
  */
26
- _attachChild(id: string, key: TKey, child: AbstractCrdt, isLocal: boolean): ApplyResult;
26
+ _attachChild(id: string, key: TKey, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
27
27
  /**
28
28
  * INTERNAL
29
29
  */
@@ -100,10 +100,13 @@ class LiveMap extends AbstractCrdt_1.AbstractCrdt {
100
100
  /**
101
101
  * INTERNAL
102
102
  */
103
- _attachChild(id, key, child, isLocal) {
103
+ _attachChild(id, key, child, opId, isLocal) {
104
104
  if (this._doc == null) {
105
105
  throw new Error("Can't attach child if doc is not present");
106
106
  }
107
+ if (this._doc.getItem(id) !== undefined) {
108
+ return { modified: false };
109
+ }
107
110
  const previousValue = __classPrivateFieldGet(this, _LiveMap_map, "f").get(key);
108
111
  let reverse;
109
112
  if (previousValue) {
@@ -27,7 +27,7 @@ export declare class LiveObject<T extends Record<string, any> = Record<string, a
27
27
  /**
28
28
  * INTERNAL
29
29
  */
30
- _attachChild(id: string, key: keyof T, child: AbstractCrdt, isLocal: boolean): ApplyResult;
30
+ _attachChild(id: string, key: keyof T, child: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
31
31
  /**
32
32
  * INTERNAL
33
33
  */
@@ -106,10 +106,32 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
106
106
  /**
107
107
  * INTERNAL
108
108
  */
109
- _attachChild(id, key, child, isLocal) {
109
+ _attachChild(id, key, child, opId, isLocal) {
110
110
  if (this._doc == null) {
111
111
  throw new Error("Can't attach child if doc is not present");
112
112
  }
113
+ if (this._doc.getItem(id) !== undefined) {
114
+ if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
115
+ // Acknowlegment from local operation
116
+ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
117
+ }
118
+ return { modified: false };
119
+ }
120
+ if (isLocal) {
121
+ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
122
+ }
123
+ else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === undefined) {
124
+ // Remote operation with no local change => apply operation
125
+ }
126
+ else if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) === opId) {
127
+ // Acknowlegment from local operation
128
+ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").delete(key);
129
+ return { modified: false };
130
+ }
131
+ else {
132
+ // Conflict, ignore remote operation
133
+ return { modified: false };
134
+ }
113
135
  const previousValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
114
136
  let reverse;
115
137
  if ((0, utils_1.isCrdt)(previousValue)) {
@@ -314,7 +336,6 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
314
336
  };
315
337
  const updateDelta = {};
316
338
  for (const key in overrides) {
317
- __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
318
339
  const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
319
340
  if (oldValue instanceof AbstractCrdt_1.AbstractCrdt) {
320
341
  reverseOps.push(...oldValue._serialize(this._id, key));
@@ -330,10 +351,16 @@ class LiveObject extends AbstractCrdt_1.AbstractCrdt {
330
351
  if (newValue instanceof AbstractCrdt_1.AbstractCrdt) {
331
352
  newValue._setParentLink(this, key);
332
353
  newValue._attach(this._doc.generateId(), this._doc);
333
- ops.push(...newValue._serialize(this._id, key, this._doc));
354
+ const newAttachChildOps = newValue._serialize(this._id, key, this._doc);
355
+ const createCrdtOp = newAttachChildOps.find((op) => op.parentId === this._id);
356
+ if (createCrdtOp) {
357
+ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, createCrdtOp.opId);
358
+ }
359
+ ops.push(...newAttachChildOps);
334
360
  }
335
361
  else {
336
362
  updatedProps[key] = newValue;
363
+ __classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").set(key, opId);
337
364
  }
338
365
  __classPrivateFieldGet(this, _LiveObject_map, "f").set(key, newValue);
339
366
  updateDelta[key] = { type: "update" };
@@ -426,6 +453,11 @@ _LiveObject_map = new WeakMap(), _LiveObject_propToLastUpdate = new WeakMap(), _
426
453
  if (__classPrivateFieldGet(this, _LiveObject_map, "f").has(key) === false) {
427
454
  return { modified: false };
428
455
  }
456
+ // If a local operation exists on the same key
457
+ // prevent flickering by not applying delete op.
458
+ if (__classPrivateFieldGet(this, _LiveObject_propToLastUpdate, "f").get(key) !== undefined) {
459
+ return { modified: false };
460
+ }
429
461
  const oldValue = __classPrivateFieldGet(this, _LiveObject_map, "f").get(key);
430
462
  let reverse = [];
431
463
  if ((0, utils_1.isCrdt)(oldValue)) {
@@ -19,7 +19,7 @@ export declare class LiveRegister<TValue = any> extends AbstractCrdt {
19
19
  * INTERNAL
20
20
  */
21
21
  _toSerializedCrdt(): SerializedCrdt;
22
- _attachChild(id: string, key: string, crdt: AbstractCrdt, isLocal: boolean): ApplyResult;
22
+ _attachChild(id: string, key: string, crdt: AbstractCrdt, opId: string, isLocal: boolean): ApplyResult;
23
23
  _detachChild(crdt: AbstractCrdt): ApplyResult;
24
24
  _apply(op: Op, isLocal: boolean): ApplyResult;
25
25
  /**
@@ -68,7 +68,7 @@ class LiveRegister extends AbstractCrdt_1.AbstractCrdt {
68
68
  data: this.data,
69
69
  };
70
70
  }
71
- _attachChild(id, key, crdt, isLocal) {
71
+ _attachChild(id, key, crdt, opId, isLocal) {
72
72
  throw new Error("Method not implemented.");
73
73
  }
74
74
  _detachChild(crdt) {
package/lib/cjs/client.js CHANGED
@@ -29,11 +29,7 @@ const room_1 = require("./room");
29
29
  */
30
30
  function createClient(options) {
31
31
  const clientOptions = options;
32
- if (typeof clientOptions.throttle === "number") {
33
- if (clientOptions.throttle < 80 || clientOptions.throttle > 1000) {
34
- throw new Error("Liveblocks client throttle should be between 80 and 1000 ms");
35
- }
36
- }
32
+ const throttleDelay = getThrottleDelayFromOptions(options);
37
33
  const rooms = new Map();
38
34
  function getRoom(roomId) {
39
35
  const internalRoom = rooms.get(roomId);
@@ -44,9 +40,21 @@ function createClient(options) {
44
40
  if (internalRoom) {
45
41
  return internalRoom.room;
46
42
  }
47
- internalRoom = (0, room_1.createRoom)(roomId, Object.assign(Object.assign({}, clientOptions), options));
43
+ internalRoom = (0, room_1.createRoom)({
44
+ defaultPresence: options.defaultPresence,
45
+ defaultStorageRoot: options.defaultStorageRoot,
46
+ }, {
47
+ room: roomId,
48
+ throttleDelay,
49
+ WebSocketPolyfill: clientOptions.WebSocketPolyfill,
50
+ fetchPolyfill: clientOptions.fetchPolyfill,
51
+ liveblocksServer: clientOptions.liveblocksServer || "wss://liveblocks.net/v5",
52
+ authentication: prepareAuthentication(clientOptions),
53
+ });
48
54
  rooms.set(roomId, internalRoom);
49
- internalRoom.connect();
55
+ if (!options.DO_NOT_USE_withoutConnecting) {
56
+ internalRoom.connect();
57
+ }
50
58
  return internalRoom.room;
51
59
  }
52
60
  function leave(roomId) {
@@ -78,3 +86,38 @@ function createClient(options) {
78
86
  };
79
87
  }
80
88
  exports.createClient = createClient;
89
+ function getThrottleDelayFromOptions(options) {
90
+ if (options.throttle === undefined) {
91
+ return 100;
92
+ }
93
+ if (typeof options.throttle !== "number" ||
94
+ options.throttle < 80 ||
95
+ options.throttle > 1000) {
96
+ throw new Error("throttle should be a number between 80 and 1000.");
97
+ }
98
+ return options.throttle;
99
+ }
100
+ function prepareAuthentication(clientOptions) {
101
+ // TODO: throw descriptive errors for invalid options
102
+ if (typeof clientOptions.publicApiKey === "string") {
103
+ return {
104
+ type: "public",
105
+ publicApiKey: clientOptions.publicApiKey,
106
+ url: clientOptions.publicAuthorizeEndpoint ||
107
+ "https://liveblocks.io/api/public/authorize",
108
+ };
109
+ }
110
+ else if (typeof clientOptions.authEndpoint === "string") {
111
+ return {
112
+ type: "private",
113
+ url: clientOptions.authEndpoint,
114
+ };
115
+ }
116
+ else if (typeof clientOptions.authEndpoint === "function") {
117
+ return {
118
+ type: "custom",
119
+ callback: clientOptions.authEndpoint,
120
+ };
121
+ }
122
+ throw new Error("Invalid Liveblocks client options. For more information: https://liveblocks.io/docs/api-reference/liveblocks-client#createClient");
123
+ }
@@ -5,6 +5,7 @@ const LiveList_1 = require("./LiveList");
5
5
  const LiveMap_1 = require("./LiveMap");
6
6
  const LiveObject_1 = require("./LiveObject");
7
7
  const LiveRegister_1 = require("./LiveRegister");
8
+ const utils_1 = require("./utils");
8
9
  function liveObjectToJson(liveObject) {
9
10
  const result = {};
10
11
  const obj = liveObject.toObject();
@@ -140,6 +141,13 @@ function patchLiveList(liveList, prev, next) {
140
141
  }
141
142
  exports.patchLiveList = patchLiveList;
142
143
  function patchLiveObjectKey(liveObject, key, prev, next) {
144
+ if (process.env.NODE_ENV !== "production") {
145
+ const nonSerializableValue = (0, utils_1.findNonSerializableValue)(next);
146
+ if (nonSerializableValue) {
147
+ console.error(`New state path: '${nonSerializableValue.path}' value: '${nonSerializableValue.value}' is not serializable.\nOnly serializable value can be synced with Liveblocks.`);
148
+ return;
149
+ }
150
+ }
143
151
  const value = liveObject.get(key);
144
152
  if (next === undefined) {
145
153
  liveObject.delete(key);
package/lib/cjs/room.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Others, Presence, ClientOptions, Room, MyPresenceCallback, OthersEventCallback, AuthEndpoint, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate, BroadcastOptions } from "./types";
1
+ import { Others, Presence, Room, MyPresenceCallback, OthersEventCallback, EventCallback, User, Connection, ErrorCallback, AuthenticationToken, ConnectionCallback, StorageCallback, StorageUpdate, BroadcastOptions, AuthorizeResponse, Authentication } from "./types";
2
2
  import { ClientMessage, Op } from "./live";
3
3
  import { LiveMap } from "./LiveMap";
4
4
  import { LiveObject } from "./LiveObject";
@@ -66,7 +66,7 @@ export declare type State = {
66
66
  offlineOperations: Map<string, Op>;
67
67
  };
68
68
  export declare type Effects = {
69
- authenticate(): void;
69
+ authenticate(auth: (room: string) => Promise<AuthorizeResponse>, createWebSocket: (token: string) => WebSocket): void;
70
70
  send(messages: ClientMessage[]): void;
71
71
  delayFlush(delay: number): number;
72
72
  startHeartbeatInterval(): number;
@@ -75,13 +75,13 @@ export declare type Effects = {
75
75
  };
76
76
  declare type Context = {
77
77
  room: string;
78
- authEndpoint: AuthEndpoint;
79
- liveblocksServer: string;
80
78
  throttleDelay: number;
81
- publicApiKey?: string;
79
+ fetchPolyfill?: typeof fetch;
80
+ WebSocketPolyfill?: typeof WebSocket;
81
+ authentication: Authentication;
82
+ liveblocksServer: string;
82
83
  };
83
84
  export declare function makeStateMachine(state: State, context: Context, mockedEffects?: Effects): {
84
- onOpen: () => void;
85
85
  onClose: (event: {
86
86
  code: number;
87
87
  wasClean: boolean;
@@ -152,8 +152,8 @@ export declare type InternalRoom = {
152
152
  onNavigatorOnline: () => void;
153
153
  onVisibilityChange: (visibilityState: VisibilityState) => void;
154
154
  };
155
- export declare function createRoom(name: string, options: ClientOptions & {
155
+ export declare function createRoom(options: {
156
156
  defaultPresence?: Presence;
157
157
  defaultStorageRoot?: Record<string, any>;
158
- }): InternalRoom;
158
+ }, context: Context): InternalRoom;
159
159
  export {};
package/lib/cjs/room.js CHANGED
@@ -1,23 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
22
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
23
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -30,7 +11,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
30
11
  Object.defineProperty(exports, "__esModule", { value: true });
31
12
  exports.createRoom = exports.defaultState = exports.makeStateMachine = void 0;
32
13
  const utils_1 = require("./utils");
33
- const authentication_1 = __importStar(require("./authentication"));
34
14
  const live_1 = require("./live");
35
15
  const LiveMap_1 = require("./LiveMap");
36
16
  const LiveObject_1 = require("./LiveObject");
@@ -75,16 +55,12 @@ function log(...params) {
75
55
  }
76
56
  function makeStateMachine(state, context, mockedEffects) {
77
57
  const effects = mockedEffects || {
78
- authenticate() {
58
+ authenticate(auth, createWebSocket) {
79
59
  return __awaiter(this, void 0, void 0, function* () {
80
60
  try {
81
- const token = yield (0, authentication_1.default)(context.authEndpoint, context.room, context.publicApiKey);
82
- const parsedToken = (0, authentication_1.parseToken)(token);
83
- const socket = new WebSocket(`${context.liveblocksServer}/?token=${token}`);
84
- socket.addEventListener("message", onMessage);
85
- socket.addEventListener("open", onOpen);
86
- socket.addEventListener("close", onClose);
87
- socket.addEventListener("error", onError);
61
+ const { token } = yield auth(context.room);
62
+ const parsedToken = parseToken(token);
63
+ const socket = createWebSocket(token);
88
64
  authenticationSuccess(parsedToken, socket);
89
65
  }
90
66
  catch (er) {
@@ -187,6 +163,7 @@ function makeStateMachine(state, context, mockedEffects) {
187
163
  function load(items) {
188
164
  const [root, parentToChildren] = buildRootAndParentToChildren(items);
189
165
  return LiveObject_1.LiveObject._deserialize(root, parentToChildren, {
166
+ getItem,
190
167
  addItem,
191
168
  deleteItem,
192
169
  generateId,
@@ -341,31 +318,31 @@ function makeStateMachine(state, context, mockedEffects) {
341
318
  }
342
319
  case live_1.OpType.CreateObject: {
343
320
  const parent = state.items.get(op.parentId);
344
- if (parent == null || getItem(op.id) != null) {
321
+ if (parent == null) {
345
322
  return { modified: false };
346
323
  }
347
- return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), isLocal);
324
+ return parent._attachChild(op.id, op.parentKey, new LiveObject_1.LiveObject(op.data), op.opId, isLocal);
348
325
  }
349
326
  case live_1.OpType.CreateList: {
350
327
  const parent = state.items.get(op.parentId);
351
- if (parent == null || getItem(op.id) != null) {
328
+ if (parent == null) {
352
329
  return { modified: false };
353
330
  }
354
- return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), isLocal);
331
+ return parent._attachChild(op.id, op.parentKey, new LiveList_1.LiveList(), op.opId, isLocal);
355
332
  }
356
333
  case live_1.OpType.CreateRegister: {
357
334
  const parent = state.items.get(op.parentId);
358
- if (parent == null || getItem(op.id) != null) {
335
+ if (parent == null) {
359
336
  return { modified: false };
360
337
  }
361
- return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), isLocal);
338
+ return parent._attachChild(op.id, op.parentKey, new LiveRegister_1.LiveRegister(op.data), op.opId, isLocal);
362
339
  }
363
340
  case live_1.OpType.CreateMap: {
364
341
  const parent = state.items.get(op.parentId);
365
- if (parent == null || getItem(op.id) != null) {
342
+ if (parent == null) {
366
343
  return { modified: false };
367
344
  }
368
- return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), isLocal);
345
+ return parent._attachChild(op.id, op.parentKey, new LiveMap_1.LiveMap(), op.opId, isLocal);
369
346
  }
370
347
  }
371
348
  return { modified: false };
@@ -412,15 +389,14 @@ See v0.13 release notes for more information.
412
389
  : null;
413
390
  }
414
391
  function connect() {
415
- if (typeof window === "undefined") {
416
- return;
417
- }
418
392
  if (state.connection.state !== "closed" &&
419
393
  state.connection.state !== "unavailable") {
420
394
  return null;
421
395
  }
396
+ const auth = prepareAuthEndpoint(context.authentication, context.fetchPolyfill);
397
+ const createWebSocket = prepareCreateWebSocket(context.liveblocksServer, context.WebSocketPolyfill);
422
398
  updateConnection({ state: "authenticating" });
423
- effects.authenticate();
399
+ effects.authenticate(auth, createWebSocket);
424
400
  }
425
401
  function updatePresence(overrides, options) {
426
402
  const oldValues = {};
@@ -447,6 +423,10 @@ See v0.13 release notes for more information.
447
423
  }
448
424
  }
449
425
  function authenticationSuccess(token, socket) {
426
+ socket.addEventListener("message", onMessage);
427
+ socket.addEventListener("open", onOpen);
428
+ socket.addEventListener("close", onClose);
429
+ socket.addEventListener("error", onError);
450
430
  updateConnection({
451
431
  state: "connecting",
452
432
  id: token.actor,
@@ -680,7 +660,7 @@ See v0.13 release notes for more information.
680
660
  }
681
661
  clearTimeout(state.timeoutHandles.pongTimeout);
682
662
  state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
683
- if (state.socket.readyState === WebSocket.OPEN) {
663
+ if (state.socket.readyState === state.socket.OPEN) {
684
664
  state.socket.send("ping");
685
665
  }
686
666
  }
@@ -727,7 +707,7 @@ See v0.13 release notes for more information.
727
707
  state.offlineOperations.set(op.opId, op);
728
708
  });
729
709
  }
730
- if (state.socket == null || state.socket.readyState !== WebSocket.OPEN) {
710
+ if (state.socket == null || state.socket.readyState !== state.socket.OPEN) {
731
711
  state.buffer.storageOperations = [];
732
712
  return;
733
713
  }
@@ -934,7 +914,6 @@ See v0.13 release notes for more information.
934
914
  }
935
915
  return {
936
916
  // Internal
937
- onOpen,
938
917
  onClose,
939
918
  onMessage,
940
919
  authenticationSuccess,
@@ -1028,26 +1007,9 @@ function defaultState(me, defaultStorageRoot) {
1028
1007
  };
1029
1008
  }
1030
1009
  exports.defaultState = defaultState;
1031
- function createRoom(name, options) {
1032
- const throttleDelay = options.throttle || 100;
1033
- const liveblocksServer = options.liveblocksServer || "wss://liveblocks.net/v5";
1034
- let authEndpoint;
1035
- if (options.authEndpoint) {
1036
- authEndpoint = options.authEndpoint;
1037
- }
1038
- else {
1039
- const publicAuthorizeEndpoint = options.publicAuthorizeEndpoint ||
1040
- "https://liveblocks.io/api/public/authorize";
1041
- authEndpoint = publicAuthorizeEndpoint;
1042
- }
1010
+ function createRoom(options, context) {
1043
1011
  const state = defaultState(options.defaultPresence, options.defaultStorageRoot);
1044
- const machine = makeStateMachine(state, {
1045
- throttleDelay,
1046
- liveblocksServer,
1047
- authEndpoint,
1048
- room: name,
1049
- publicApiKey: options.publicApiKey,
1050
- });
1012
+ const machine = makeStateMachine(state, context);
1051
1013
  const room = {
1052
1014
  /////////////
1053
1015
  // Core //
@@ -1092,3 +1054,76 @@ class LiveblocksError extends Error {
1092
1054
  this.code = code;
1093
1055
  }
1094
1056
  }
1057
+ function parseToken(token) {
1058
+ const tokenParts = token.split(".");
1059
+ if (tokenParts.length !== 3) {
1060
+ throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
1061
+ }
1062
+ const data = JSON.parse(atob(tokenParts[1]));
1063
+ if (typeof data.actor !== "number") {
1064
+ throw new Error(`Authentication error. Liveblocks could not parse the response of your authentication endpoint`);
1065
+ }
1066
+ return data;
1067
+ }
1068
+ function prepareCreateWebSocket(liveblocksServer, WebSocketPolyfill) {
1069
+ if (typeof window === "undefined" && WebSocketPolyfill == null) {
1070
+ throw new Error("To use Liveblocks client in a non-dom environment, you need to provide a WebSocket polyfill.");
1071
+ }
1072
+ const ws = WebSocketPolyfill || WebSocket;
1073
+ return (token) => {
1074
+ return new ws(`${liveblocksServer}/?token=${token}`);
1075
+ };
1076
+ }
1077
+ function prepareAuthEndpoint(authentication, fetchPolyfill) {
1078
+ if (authentication.type === "public") {
1079
+ if (typeof window === "undefined" && fetchPolyfill == null) {
1080
+ throw new Error("To use Liveblocks client in a non-dom environment with a publicApiKey, you need to provide a fetch polyfill.");
1081
+ }
1082
+ return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
1083
+ room,
1084
+ publicApiKey: authentication.publicApiKey,
1085
+ });
1086
+ }
1087
+ if (authentication.type === "private") {
1088
+ if (typeof window === "undefined" && fetchPolyfill == null) {
1089
+ throw new Error("To use Liveblocks client in a non-dom environment with a url as auth endpoint, you need to provide a fetch polyfill.");
1090
+ }
1091
+ return (room) => fetchAuthEndpoint(fetchPolyfill || fetch, authentication.url, {
1092
+ room,
1093
+ });
1094
+ }
1095
+ if (authentication.type === "custom") {
1096
+ return authentication.callback;
1097
+ }
1098
+ throw new Error("Internal error. Unexpected authentication type");
1099
+ }
1100
+ function fetchAuthEndpoint(fetch, endpoint, body) {
1101
+ return __awaiter(this, void 0, void 0, function* () {
1102
+ const res = yield fetch(endpoint, {
1103
+ method: "POST",
1104
+ headers: {
1105
+ "Content-Type": "application/json",
1106
+ },
1107
+ body: JSON.stringify(body),
1108
+ });
1109
+ if (!res.ok) {
1110
+ throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
1111
+ }
1112
+ let authResponse = null;
1113
+ try {
1114
+ authResponse = yield res.json();
1115
+ }
1116
+ catch (er) {
1117
+ throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
1118
+ }
1119
+ if (typeof authResponse.token !== "string") {
1120
+ throw new AuthenticationError(`Authentication error. Liveblocks could not parse the response of your authentication "${endpoint}"`);
1121
+ }
1122
+ return authResponse;
1123
+ });
1124
+ }
1125
+ class AuthenticationError extends Error {
1126
+ constructor(message) {
1127
+ super(message);
1128
+ }
1129
+ }
@@ -146,6 +146,8 @@ export declare type AuthEndpoint = string | AuthEndpointCallback;
146
146
  */
147
147
  export declare type ClientOptions = {
148
148
  throttle?: number;
149
+ fetchPolyfill?: any;
150
+ WebSocketPolyfill?: any;
149
151
  } & ({
150
152
  publicApiKey: string;
151
153
  authEndpoint?: never;
@@ -156,6 +158,17 @@ export declare type ClientOptions = {
156
158
  export declare type AuthorizeResponse = {
157
159
  token: string;
158
160
  };
161
+ export declare type Authentication = {
162
+ type: "public";
163
+ publicApiKey: string;
164
+ url: string;
165
+ } | {
166
+ type: "private";
167
+ url: string;
168
+ } | {
169
+ type: "custom";
170
+ callback: (room: string) => Promise<AuthorizeResponse>;
171
+ };
159
172
  declare type ConnectionState = "closed" | "authenticating" | "unavailable" | "failed" | "open" | "connecting";
160
173
  export declare type Connection = {
161
174
  state: "closed" | "authenticating" | "unavailable" | "failed";
@@ -9,3 +9,7 @@ export declare function selfOrRegisterValue(obj: AbstractCrdt): any;
9
9
  export declare function selfOrRegister(obj: any): AbstractCrdt;
10
10
  export declare function getTreesDiffOperations(currentItems: Map<string, SerializedCrdt>, newItems: Map<string, SerializedCrdt>): Op[];
11
11
  export declare function mergeStorageUpdates(first: StorageUpdate | undefined, second: StorageUpdate): StorageUpdate;
12
+ export declare function findNonSerializableValue(value: any, path?: string): {
13
+ path: string;
14
+ value: any;
15
+ } | false;