Socket
Socket
Sign inDemoInstall

@liveblocks/client

Package Overview
Dependencies
Maintainers
2
Versions
379
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@liveblocks/client - npm Package Compare versions

Comparing version 0.1.3 to 0.2.0

lib/cjs/room.d.ts

56

lib/cjs/client.d.ts

@@ -1,54 +0,2 @@

import { Record, List, RecordData } from "./doc";
export declare type Users<T extends UserState = UserState> = {
[id: string]: T | null;
};
declare type OnMyPresenceChange = (me: UserState) => void;
declare type OnOthersPresenceChange = (others: Users) => void;
export declare type Client = ReturnType<typeof createClient>;
declare type Options = {
authEndpoint: string;
liveblocksServer?: string;
};
declare type CreateRecord = Room["createRecord"];
declare type CreateList = Room["createList"];
export declare type InitialRootFactory<TRoot = RecordData> = (factories: {
createRecord: CreateRecord;
createList: CreateList;
}) => TRoot;
export declare function createClient(options: Options): {
createRecord<T extends RecordData>(room: string, data: any): Record<T>;
createList<T_1 extends List<any> | Record<any>>(room: string): List<T_1>;
updateRecord<T_2 extends RecordData>(room: string, record: Record<T_2>, overrides: Partial<T_2>): void;
pushItem<T_3 extends List<any> | Record<any>>(room: string, list: List<T_3>, item: T_3): void;
deleteItem<T_4 extends List<any> | Record<any>>(room: string, list: List<T_4>, index: number): void;
moveItem<T_5 extends List<any> | Record<any>>(room: string, list: List<T_5>, index: number, targetIndex: number): void;
observeStorage: <TRoot extends RecordData>(room: string, callback: (root: Record<TRoot> | null) => void, initialDocumentState: InitialRootFactory<TRoot>) => void;
unobserveStorage: <TRoot_1 extends RecordData>(room: string, callback: (root: Record<TRoot_1> | null) => void) => void;
getPresence: <TUser extends UserState>(room: string) => TUser | null;
setPresence: (room: string, overrides: Partial<UserState>) => void;
observeMyPresence: (room: string, callback: OnMyPresenceChange) => void;
unobserveMyPresence: (room: string, callback: OnMyPresenceChange) => void;
observeOthersPresence: (room: string, callback: OnOthersPresenceChange) => void;
unobserveOthersPresence: (room: string, callback: OnOthersPresenceChange) => void;
};
export declare type Room = ReturnType<typeof createRoom>;
declare function createRoom(name: string, options: Options): {
createRecord: <T extends RecordData>(data: any) => Record<T>;
createList: <T_1 extends List<any> | Record<any>>() => List<T_1>;
updateRecord<T_2 extends RecordData>(record: Record<T_2>, overrides: Partial<T_2>): void;
pushItem<T_3 extends List<any> | Record<any>>(list: List<T_3>, item: T_3): void;
deleteItem<T_4 extends List<any> | Record<any>>(list: List<T_4>, index: number): void;
moveItem<T_5 extends List<any> | Record<any>>(list: List<T_5>, index: number, targetIndex: number): void;
observeStorage: <TRoot extends RecordData>(callback: (root: Record<TRoot> | null) => void, initialDocumentState: InitialRootFactory<TRoot>) => void;
unobserveStorage: <TRoot_1 extends RecordData>(callback: (root: Record<TRoot_1> | null) => void) => void;
getPresence: <TUser extends UserState>() => TUser | null;
setPresence: <TUser_1 extends UserState>(overrides: Partial<TUser_1>) => void;
observeMyPresence: <TUser_2 extends UserState>(callback: (presence: TUser_2) => void) => void;
unobserveMyPresence: <TUser_3 extends UserState>(callback: (presence: TUser_3) => void) => void;
observeOthersPresence: <TUser_4 extends UserState>(callback: (users: Users<TUser_4>) => void) => void;
unobserveOthersPresence: <TUser_5 extends UserState>(callback: (users: Users<TUser_5>) => void) => void;
};
export declare type UserState = {
[key: string]: boolean | string | number;
};
export {};
import { ClientOptions, Client } from "./types";
export declare function createClient(options: ClientOptions): Client;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createClient = void 0;
const doc_1 = require("./doc");
const WAIT = 100;
function makeIdFactory(actor) {
let count = 0;
return () => `${actor}:${count++}`;
}
function remove(array, item) {
for (let i = 0; i < array.length; i++) {
if (array[i] === item) {
array.splice(i, 1);
break;
const room_1 = require("./room");
const utils_1 = require("./utils");
function createClient(options) {
const rooms = new Map();
const _listeners = {
error: [],
};
function onError(error) {
for (const listener of _listeners.error) {
listener(error);
}
}
}
function authorize(endpoint, room) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
room,
}),
});
if (!res.ok) {
console.error("FAIL");
}
const authResponse = yield res.json();
return {
token: authResponse.token,
appId: authResponse.appId,
actor: authResponse.actor,
};
});
}
function createClient(options) {
const rooms = new Map();
function getRoomOrInit(name) {
let room = rooms.get(name);
if (room == null) {
room = createRoom(name, options);
room = room_1.createRoom(name, Object.assign(Object.assign({}, options), { onError }));
rooms.set(name, room);

@@ -70,338 +24,23 @@ }

}
return {
/////////////
// Storage //
/////////////
createRecord(room, data) {
return getRoomOrInit(room).createRecord(data);
},
createList(room) {
return getRoomOrInit(room).createList();
},
updateRecord(room, record, overrides) {
getRoomOrInit(room).updateRecord(record, overrides);
},
pushItem(room, list, item) {
getRoomOrInit(room).pushItem(list, item);
},
deleteItem(room, list, index) {
getRoomOrInit(room).deleteItem(list, index);
},
moveItem(room, list, index, targetIndex) {
getRoomOrInit(room).moveItem(list, index, targetIndex);
},
observeStorage: (room, callback, initialDocumentState) => {
getRoomOrInit(room).observeStorage(callback, initialDocumentState);
},
unobserveStorage: (room, callback) => {
getRoomOrInit(room).unobserveStorage(callback);
},
//////////////
// Presence //
//////////////
getPresence: (room) => {
return getRoomOrInit(room).getPresence();
},
setPresence: (room, overrides) => {
return getRoomOrInit(room).setPresence(overrides);
},
observeMyPresence: (room, callback) => {
return getRoomOrInit(room).observeMyPresence(callback);
},
unobserveMyPresence: (room, callback) => {
return getRoomOrInit(room).unobserveMyPresence(callback);
},
observeOthersPresence: (room, callback) => {
return getRoomOrInit(room).observeOthersPresence(callback);
},
unobserveOthersPresence: (room, callback) => {
return getRoomOrInit(room).unobserveOthersPresence(callback);
},
};
}
exports.createClient = createClient;
var RoomState;
(function (RoomState) {
RoomState[RoomState["Default"] = 0] = "Default";
RoomState[RoomState["Connecting"] = 1] = "Connecting";
RoomState[RoomState["Connected"] = 2] = "Connected";
})(RoomState || (RoomState = {}));
function createRoom(name, options) {
const liveblocksServer = options.liveblocksServer;
const authEndpoint = options.authEndpoint;
let _listeners = {
onRootChange: [],
onOthersPresenceChange: [],
onPresenceChange: [],
};
let _idFactory = null;
let _socket = null;
let _doc = null;
let toFlush = [];
let _lastEmit = 0;
let _timeout = null;
let _initialRootFactory = null;
let _me = null;
let _users = {};
let state = RoomState.Default;
let _toSend = null;
let _presenceTimeout = null;
let _lastPresenceEmit = 0;
let onSocketOpenCallbacks = [];
function send(clientMessage) {
if (_socket == null) {
throw new Error("Can't send message if socket is not ready");
}
_socket.send(JSON.stringify(clientMessage));
function getRoom(room) {
return getRoomOrInit(room);
}
function makeId() {
if (_idFactory == null) {
throw new Error("Can't generate id. Id factory is missing.");
function addEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
}
return _idFactory();
_listeners.error.push(listener);
}
function updateUsers(users) {
_users = users;
for (const listener of _listeners.onOthersPresenceChange) {
listener(users);
function removeEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
}
utils_1.remove(_listeners.error, listener);
}
function dispatch(op) {
toFlush.push(op);
const now = Date.now();
if (now - _lastEmit > WAIT) {
send({
type: ClientMessageType.UpdateDocument,
ops: toFlush,
});
toFlush = [];
_lastEmit = now;
return;
}
if (_timeout) {
clearTimeout(_timeout);
_timeout = null;
}
_timeout = setTimeout(() => {
send({
type: ClientMessageType.UpdateDocument,
ops: toFlush,
});
toFlush = [];
_lastEmit = Date.now();
}, WAIT - (now - _lastEmit));
}
function updateDoc(doc) {
_doc = doc;
if (doc) {
for (const listener of _listeners.onRootChange) {
listener(doc.root);
}
}
}
function createRecord(data) {
return doc_1.createRecord(makeId(), data);
}
function createList() {
return doc_1.createList(makeId());
}
function updatePresence(me) {
_me = me;
for (const listener of _listeners.onPresenceChange) {
listener(_me);
}
}
function onGetDocument(message) {
if (message.root == null) {
const rootId = makeId();
_doc = doc_1.Doc.empty(rootId, (op) => dispatch(op));
updateDoc(_doc.updateRecord(rootId, _initialRootFactory({
createRecord: (data) => createRecord(data),
createList: () => createList(),
})));
}
else {
updateDoc(doc_1.Doc.load(message.root, (op) => dispatch(op)));
}
}
function onDocumentUpdates(message) {
if (_doc == null) {
// TODO: Cache updates in case they are coming while root is queried
return;
}
updateDoc(message.ops.reduce((doc, op) => doc.dispatch(op), _doc));
}
function connect(onSocketOpen = () => { }) {
return __awaiter(this, void 0, void 0, function* () {
if (state === RoomState.Connected) {
onSocketOpen();
return;
}
if (state === RoomState.Connecting) {
onSocketOpenCallbacks.push(onSocketOpen);
// Already connected to this room
return;
}
onSocketOpenCallbacks.push(onSocketOpen);
state = RoomState.Connecting;
const { token, actor } = yield authorize(authEndpoint, name);
_idFactory = makeIdFactory(actor);
_socket = new WebSocket(`${liveblocksServer}/?token=${token}`);
_socket.addEventListener("message", function (event) {
onMessage(JSON.parse(event.data));
});
_socket.addEventListener("open", () => {
console.log("on open");
for (const callback of onSocketOpenCallbacks) {
callback();
}
state = RoomState.Connected;
onSocketOpenCallbacks = [];
});
});
}
function disconnect() {
// TODO
}
const onMessage = (message) => {
switch (message.type) {
case ServerMessageType.InitialDocumentState: {
onGetDocument(message);
break;
}
case ServerMessageType.DocumentOperations: {
onDocumentUpdates(message);
break;
}
case ServerMessageType.UserJoined: {
// Send current presence to new user
send({
type: ClientMessageType.UpdateUserState,
data: _me,
targetActor: message.actor,
});
break;
}
case ServerMessageType.UpdateUserState: {
const currentUser = _users[message.actor];
updateUsers(Object.assign(Object.assign({}, _users), { [message.actor]: currentUser
? Object.assign(Object.assign({}, currentUser), message.data) : message.data }));
break;
}
case ServerMessageType.UserLeft: {
const userLeftMessage = message;
const _a = _users, _b = userLeftMessage.actor, notUsed = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
updateUsers(rest);
break;
}
}
};
//////////////
// Presence //
//////////////
function getPresence() {
return _me;
}
function setPresence(overrides) {
updatePresence(Object.assign(Object.assign({}, _me), overrides));
if (state !== RoomState.Connected) {
onSocketOpenCallbacks.push(() => send({
type: ClientMessageType.UpdateUserState,
data: _me,
}));
return;
}
const now = Date.now();
if (now - _lastPresenceEmit > WAIT) {
send({
type: ClientMessageType.UpdateUserState,
data: Object.assign(Object.assign({}, _toSend), overrides),
});
_toSend = {};
_lastPresenceEmit = now;
return;
}
_toSend = Object.assign(Object.assign({}, _toSend), overrides);
if (_presenceTimeout) {
clearTimeout(_presenceTimeout);
_presenceTimeout = null;
}
_presenceTimeout = setTimeout(() => {
send({
type: ClientMessageType.UpdateUserState,
data: _toSend,
});
_toSend = {};
_lastPresenceEmit = Date.now();
}, WAIT - (now - _lastPresenceEmit));
}
function observeMyPresence(callback) {
_listeners.onPresenceChange.push(callback);
connect();
}
function unobserveMyPresence(callback) {
remove(_listeners.onPresenceChange, callback);
disconnect();
}
function observeOthersPresence(callback) {
_listeners.onOthersPresenceChange.push(callback);
connect();
}
function unobserveOthersPresence(callback) {
remove(_listeners.onOthersPresenceChange, callback);
disconnect();
}
return {
/////////////
// Storage //
/////////////
createRecord,
createList,
updateRecord(record, overrides) {
updateDoc(_doc.updateRecord(record.id, overrides));
},
pushItem(list, item) {
updateDoc(_doc.pushItem(list.id, item));
},
deleteItem(list, index) {
updateDoc(_doc.deleteItem(list.id, index));
},
moveItem(list, index, targetIndex) {
updateDoc(_doc.moveItem(list.id, index, targetIndex));
},
observeStorage: (callback, initialDocumentState) => {
connect(() => {
_initialRootFactory = initialDocumentState;
send({ type: ClientMessageType.GetDocument });
});
_listeners.onRootChange.push(callback);
},
unobserveStorage: (callback) => {
remove(_listeners.onRootChange, callback);
disconnect();
},
//////////////
// Presence //
//////////////
getPresence,
setPresence,
observeMyPresence,
unobserveMyPresence,
observeOthersPresence,
unobserveOthersPresence,
addEventListener,
removeEventListener,
getRoom,
};
}
var ServerMessageType;
(function (ServerMessageType) {
ServerMessageType[ServerMessageType["UpdateUserState"] = 100] = "UpdateUserState";
ServerMessageType[ServerMessageType["UserJoined"] = 101] = "UserJoined";
ServerMessageType[ServerMessageType["UserLeft"] = 102] = "UserLeft";
ServerMessageType[ServerMessageType["InitialDocumentState"] = 200] = "InitialDocumentState";
ServerMessageType[ServerMessageType["DocumentOperations"] = 201] = "DocumentOperations";
})(ServerMessageType || (ServerMessageType = {}));
var ClientMessageType;
(function (ClientMessageType) {
ClientMessageType[ClientMessageType["UpdateUserState"] = 100] = "UpdateUserState";
ClientMessageType[ClientMessageType["GetDocument"] = 200] = "GetDocument";
ClientMessageType[ClientMessageType["UpdateDocument"] = 201] = "UpdateDocument";
})(ClientMessageType || (ClientMessageType = {}));
exports.createClient = createClient;

@@ -384,3 +384,4 @@ "use strict";

if (key !== "id" && key !== "type") {
serializedData[key] = serialize(record[key]);
const value = record[key]; // TODO: Find out why typescript does not like that
serializedData[key] = serialize(value);
}

@@ -387,0 +388,0 @@ }

export type { Record, RecordData, List } from "./doc";
export type { Users, Client, Room, UserState, InitialRootFactory, } from "./client";
export { createClient } from "./client";
export { RoomState } from "./types";
export type { Others, Presence, Room, InitialStorageFactory, Client, } from "./types";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createClient = void 0;
exports.RoomState = exports.createClient = void 0;
var client_1 = require("./client");
Object.defineProperty(exports, "createClient", { enumerable: true, get: function () { return client_1.createClient; } });
var types_1 = require("./types");
Object.defineProperty(exports, "RoomState", { enumerable: true, get: function () { return types_1.RoomState; } });

@@ -1,54 +0,2 @@

import { Record, List, RecordData } from "./doc";
export declare type Users<T extends UserState = UserState> = {
[id: string]: T | null;
};
declare type OnMyPresenceChange = (me: UserState) => void;
declare type OnOthersPresenceChange = (others: Users) => void;
export declare type Client = ReturnType<typeof createClient>;
declare type Options = {
authEndpoint: string;
liveblocksServer?: string;
};
declare type CreateRecord = Room["createRecord"];
declare type CreateList = Room["createList"];
export declare type InitialRootFactory<TRoot = RecordData> = (factories: {
createRecord: CreateRecord;
createList: CreateList;
}) => TRoot;
export declare function createClient(options: Options): {
createRecord<T extends RecordData>(room: string, data: any): Record<T>;
createList<T_1 extends List<any> | Record<any>>(room: string): List<T_1>;
updateRecord<T_2 extends RecordData>(room: string, record: Record<T_2>, overrides: Partial<T_2>): void;
pushItem<T_3 extends List<any> | Record<any>>(room: string, list: List<T_3>, item: T_3): void;
deleteItem<T_4 extends List<any> | Record<any>>(room: string, list: List<T_4>, index: number): void;
moveItem<T_5 extends List<any> | Record<any>>(room: string, list: List<T_5>, index: number, targetIndex: number): void;
observeStorage: <TRoot extends RecordData>(room: string, callback: (root: Record<TRoot> | null) => void, initialDocumentState: InitialRootFactory<TRoot>) => void;
unobserveStorage: <TRoot_1 extends RecordData>(room: string, callback: (root: Record<TRoot_1> | null) => void) => void;
getPresence: <TUser extends UserState>(room: string) => TUser | null;
setPresence: (room: string, overrides: Partial<UserState>) => void;
observeMyPresence: (room: string, callback: OnMyPresenceChange) => void;
unobserveMyPresence: (room: string, callback: OnMyPresenceChange) => void;
observeOthersPresence: (room: string, callback: OnOthersPresenceChange) => void;
unobserveOthersPresence: (room: string, callback: OnOthersPresenceChange) => void;
};
export declare type Room = ReturnType<typeof createRoom>;
declare function createRoom(name: string, options: Options): {
createRecord: <T extends RecordData>(data: any) => Record<T>;
createList: <T_1 extends List<any> | Record<any>>() => List<T_1>;
updateRecord<T_2 extends RecordData>(record: Record<T_2>, overrides: Partial<T_2>): void;
pushItem<T_3 extends List<any> | Record<any>>(list: List<T_3>, item: T_3): void;
deleteItem<T_4 extends List<any> | Record<any>>(list: List<T_4>, index: number): void;
moveItem<T_5 extends List<any> | Record<any>>(list: List<T_5>, index: number, targetIndex: number): void;
observeStorage: <TRoot extends RecordData>(callback: (root: Record<TRoot> | null) => void, initialDocumentState: InitialRootFactory<TRoot>) => void;
unobserveStorage: <TRoot_1 extends RecordData>(callback: (root: Record<TRoot_1> | null) => void) => void;
getPresence: <TUser extends UserState>() => TUser | null;
setPresence: <TUser_1 extends UserState>(overrides: Partial<TUser_1>) => void;
observeMyPresence: <TUser_2 extends UserState>(callback: (presence: TUser_2) => void) => void;
unobserveMyPresence: <TUser_3 extends UserState>(callback: (presence: TUser_3) => void) => void;
observeOthersPresence: <TUser_4 extends UserState>(callback: (users: Users<TUser_4>) => void) => void;
unobserveOthersPresence: <TUser_5 extends UserState>(callback: (users: Users<TUser_5>) => void) => void;
};
export declare type UserState = {
[key: string]: boolean | string | number;
};
export {};
import { ClientOptions, Client } from "./types";
export declare function createClient(options: ClientOptions): Client;

@@ -1,63 +0,17 @@

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
import { createRoom } from "./room";
import { remove } from "./utils";
export function createClient(options) {
const rooms = new Map();
const _listeners = {
error: [],
};
function onError(error) {
for (const listener of _listeners.error) {
listener(error);
}
return t;
};
import { Doc, createRecord as innerCreateRecord, createList as innerCreateList, } from "./doc";
const WAIT = 100;
function makeIdFactory(actor) {
let count = 0;
return () => `${actor}:${count++}`;
}
function remove(array, item) {
for (let i = 0; i < array.length; i++) {
if (array[i] === item) {
array.splice(i, 1);
break;
}
}
}
function authorize(endpoint, room) {
return __awaiter(this, void 0, void 0, function* () {
const res = yield fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
room,
}),
});
if (!res.ok) {
console.error("FAIL");
}
const authResponse = yield res.json();
return {
token: authResponse.token,
appId: authResponse.appId,
actor: authResponse.actor,
};
});
}
export function createClient(options) {
const rooms = new Map();
function getRoomOrInit(name) {
let room = rooms.get(name);
if (room == null) {
room = createRoom(name, options);
room = createRoom(name, Object.assign(Object.assign({}, options), { onError }));
rooms.set(name, room);

@@ -67,337 +21,22 @@ }

}
return {
/////////////
// Storage //
/////////////
createRecord(room, data) {
return getRoomOrInit(room).createRecord(data);
},
createList(room) {
return getRoomOrInit(room).createList();
},
updateRecord(room, record, overrides) {
getRoomOrInit(room).updateRecord(record, overrides);
},
pushItem(room, list, item) {
getRoomOrInit(room).pushItem(list, item);
},
deleteItem(room, list, index) {
getRoomOrInit(room).deleteItem(list, index);
},
moveItem(room, list, index, targetIndex) {
getRoomOrInit(room).moveItem(list, index, targetIndex);
},
observeStorage: (room, callback, initialDocumentState) => {
getRoomOrInit(room).observeStorage(callback, initialDocumentState);
},
unobserveStorage: (room, callback) => {
getRoomOrInit(room).unobserveStorage(callback);
},
//////////////
// Presence //
//////////////
getPresence: (room) => {
return getRoomOrInit(room).getPresence();
},
setPresence: (room, overrides) => {
return getRoomOrInit(room).setPresence(overrides);
},
observeMyPresence: (room, callback) => {
return getRoomOrInit(room).observeMyPresence(callback);
},
unobserveMyPresence: (room, callback) => {
return getRoomOrInit(room).unobserveMyPresence(callback);
},
observeOthersPresence: (room, callback) => {
return getRoomOrInit(room).observeOthersPresence(callback);
},
unobserveOthersPresence: (room, callback) => {
return getRoomOrInit(room).unobserveOthersPresence(callback);
},
};
}
var RoomState;
(function (RoomState) {
RoomState[RoomState["Default"] = 0] = "Default";
RoomState[RoomState["Connecting"] = 1] = "Connecting";
RoomState[RoomState["Connected"] = 2] = "Connected";
})(RoomState || (RoomState = {}));
function createRoom(name, options) {
const liveblocksServer = options.liveblocksServer;
const authEndpoint = options.authEndpoint;
let _listeners = {
onRootChange: [],
onOthersPresenceChange: [],
onPresenceChange: [],
};
let _idFactory = null;
let _socket = null;
let _doc = null;
let toFlush = [];
let _lastEmit = 0;
let _timeout = null;
let _initialRootFactory = null;
let _me = null;
let _users = {};
let state = RoomState.Default;
let _toSend = null;
let _presenceTimeout = null;
let _lastPresenceEmit = 0;
let onSocketOpenCallbacks = [];
function send(clientMessage) {
if (_socket == null) {
throw new Error("Can't send message if socket is not ready");
}
_socket.send(JSON.stringify(clientMessage));
function getRoom(room) {
return getRoomOrInit(room);
}
function makeId() {
if (_idFactory == null) {
throw new Error("Can't generate id. Id factory is missing.");
function addEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
}
return _idFactory();
_listeners.error.push(listener);
}
function updateUsers(users) {
_users = users;
for (const listener of _listeners.onOthersPresenceChange) {
listener(users);
function removeEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
}
remove(_listeners.error, listener);
}
function dispatch(op) {
toFlush.push(op);
const now = Date.now();
if (now - _lastEmit > WAIT) {
send({
type: ClientMessageType.UpdateDocument,
ops: toFlush,
});
toFlush = [];
_lastEmit = now;
return;
}
if (_timeout) {
clearTimeout(_timeout);
_timeout = null;
}
_timeout = setTimeout(() => {
send({
type: ClientMessageType.UpdateDocument,
ops: toFlush,
});
toFlush = [];
_lastEmit = Date.now();
}, WAIT - (now - _lastEmit));
}
function updateDoc(doc) {
_doc = doc;
if (doc) {
for (const listener of _listeners.onRootChange) {
listener(doc.root);
}
}
}
function createRecord(data) {
return innerCreateRecord(makeId(), data);
}
function createList() {
return innerCreateList(makeId());
}
function updatePresence(me) {
_me = me;
for (const listener of _listeners.onPresenceChange) {
listener(_me);
}
}
function onGetDocument(message) {
if (message.root == null) {
const rootId = makeId();
_doc = Doc.empty(rootId, (op) => dispatch(op));
updateDoc(_doc.updateRecord(rootId, _initialRootFactory({
createRecord: (data) => createRecord(data),
createList: () => createList(),
})));
}
else {
updateDoc(Doc.load(message.root, (op) => dispatch(op)));
}
}
function onDocumentUpdates(message) {
if (_doc == null) {
// TODO: Cache updates in case they are coming while root is queried
return;
}
updateDoc(message.ops.reduce((doc, op) => doc.dispatch(op), _doc));
}
function connect(onSocketOpen = () => { }) {
return __awaiter(this, void 0, void 0, function* () {
if (state === RoomState.Connected) {
onSocketOpen();
return;
}
if (state === RoomState.Connecting) {
onSocketOpenCallbacks.push(onSocketOpen);
// Already connected to this room
return;
}
onSocketOpenCallbacks.push(onSocketOpen);
state = RoomState.Connecting;
const { token, actor } = yield authorize(authEndpoint, name);
_idFactory = makeIdFactory(actor);
_socket = new WebSocket(`${liveblocksServer}/?token=${token}`);
_socket.addEventListener("message", function (event) {
onMessage(JSON.parse(event.data));
});
_socket.addEventListener("open", () => {
console.log("on open");
for (const callback of onSocketOpenCallbacks) {
callback();
}
state = RoomState.Connected;
onSocketOpenCallbacks = [];
});
});
}
function disconnect() {
// TODO
}
const onMessage = (message) => {
switch (message.type) {
case ServerMessageType.InitialDocumentState: {
onGetDocument(message);
break;
}
case ServerMessageType.DocumentOperations: {
onDocumentUpdates(message);
break;
}
case ServerMessageType.UserJoined: {
// Send current presence to new user
send({
type: ClientMessageType.UpdateUserState,
data: _me,
targetActor: message.actor,
});
break;
}
case ServerMessageType.UpdateUserState: {
const currentUser = _users[message.actor];
updateUsers(Object.assign(Object.assign({}, _users), { [message.actor]: currentUser
? Object.assign(Object.assign({}, currentUser), message.data) : message.data }));
break;
}
case ServerMessageType.UserLeft: {
const userLeftMessage = message;
const _a = _users, _b = userLeftMessage.actor, notUsed = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
updateUsers(rest);
break;
}
}
};
//////////////
// Presence //
//////////////
function getPresence() {
return _me;
}
function setPresence(overrides) {
updatePresence(Object.assign(Object.assign({}, _me), overrides));
if (state !== RoomState.Connected) {
onSocketOpenCallbacks.push(() => send({
type: ClientMessageType.UpdateUserState,
data: _me,
}));
return;
}
const now = Date.now();
if (now - _lastPresenceEmit > WAIT) {
send({
type: ClientMessageType.UpdateUserState,
data: Object.assign(Object.assign({}, _toSend), overrides),
});
_toSend = {};
_lastPresenceEmit = now;
return;
}
_toSend = Object.assign(Object.assign({}, _toSend), overrides);
if (_presenceTimeout) {
clearTimeout(_presenceTimeout);
_presenceTimeout = null;
}
_presenceTimeout = setTimeout(() => {
send({
type: ClientMessageType.UpdateUserState,
data: _toSend,
});
_toSend = {};
_lastPresenceEmit = Date.now();
}, WAIT - (now - _lastPresenceEmit));
}
function observeMyPresence(callback) {
_listeners.onPresenceChange.push(callback);
connect();
}
function unobserveMyPresence(callback) {
remove(_listeners.onPresenceChange, callback);
disconnect();
}
function observeOthersPresence(callback) {
_listeners.onOthersPresenceChange.push(callback);
connect();
}
function unobserveOthersPresence(callback) {
remove(_listeners.onOthersPresenceChange, callback);
disconnect();
}
return {
/////////////
// Storage //
/////////////
createRecord,
createList,
updateRecord(record, overrides) {
updateDoc(_doc.updateRecord(record.id, overrides));
},
pushItem(list, item) {
updateDoc(_doc.pushItem(list.id, item));
},
deleteItem(list, index) {
updateDoc(_doc.deleteItem(list.id, index));
},
moveItem(list, index, targetIndex) {
updateDoc(_doc.moveItem(list.id, index, targetIndex));
},
observeStorage: (callback, initialDocumentState) => {
connect(() => {
_initialRootFactory = initialDocumentState;
send({ type: ClientMessageType.GetDocument });
});
_listeners.onRootChange.push(callback);
},
unobserveStorage: (callback) => {
remove(_listeners.onRootChange, callback);
disconnect();
},
//////////////
// Presence //
//////////////
getPresence,
setPresence,
observeMyPresence,
unobserveMyPresence,
observeOthersPresence,
unobserveOthersPresence,
addEventListener,
removeEventListener,
getRoom,
};
}
var ServerMessageType;
(function (ServerMessageType) {
ServerMessageType[ServerMessageType["UpdateUserState"] = 100] = "UpdateUserState";
ServerMessageType[ServerMessageType["UserJoined"] = 101] = "UserJoined";
ServerMessageType[ServerMessageType["UserLeft"] = 102] = "UserLeft";
ServerMessageType[ServerMessageType["InitialDocumentState"] = 200] = "InitialDocumentState";
ServerMessageType[ServerMessageType["DocumentOperations"] = 201] = "DocumentOperations";
})(ServerMessageType || (ServerMessageType = {}));
var ClientMessageType;
(function (ClientMessageType) {
ClientMessageType[ClientMessageType["UpdateUserState"] = 100] = "UpdateUserState";
ClientMessageType[ClientMessageType["GetDocument"] = 200] = "GetDocument";
ClientMessageType[ClientMessageType["UpdateDocument"] = 201] = "UpdateDocument";
})(ClientMessageType || (ClientMessageType = {}));

@@ -378,3 +378,4 @@ import { compare, makePosition } from "./position";

if (key !== "id" && key !== "type") {
serializedData[key] = serialize(record[key]);
const value = record[key]; // TODO: Find out why typescript does not like that
serializedData[key] = serialize(value);
}

@@ -381,0 +382,0 @@ }

export type { Record, RecordData, List } from "./doc";
export type { Users, Client, Room, UserState, InitialRootFactory, } from "./client";
export { createClient } from "./client";
export { RoomState } from "./types";
export type { Others, Presence, Room, InitialStorageFactory, Client, } from "./types";
export { createClient } from "./client";
export { RoomState } from "./types";
{
"name": "@liveblocks/client",
"version": "0.1.3",
"version": "0.2.0",
"description": "",

@@ -22,3 +22,3 @@ "main": "./lib/cjs/index.js",

"@babel/preset-typescript": "^7.12.16",
"@types/jest": "^26.0.20",
"@types/jest": "^26.0.21",
"babel-jest": "^26.6.3",

@@ -25,0 +25,0 @@ "jest": "^26.6.3",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc