Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@liveblocks/react

Package Overview
Dependencies
Maintainers
2
Versions
419
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@liveblocks/react - npm Package Compare versions

Comparing version 0.6.0-beta.5 to 0.7.0

131

lib/index.d.ts

@@ -7,9 +7,122 @@ import { Client, RecordData, Others, Presence, Record, InitialStorageFactory, Room } from "@liveblocks/client";

};
export declare function LiveblocksProvider({ client, children, }: LiveblocksProviderProps): JSX.Element;
export declare function useClient(): Client;
export declare function useMyPresence<T extends Presence>(room: string, initPresence: () => T): [T, (overrides: Partial<T>) => void];
export declare function useUpdateMyPresence<T extends Presence>(room: string, initPresence: () => T): (overrides: Partial<T>) => void;
export declare function useOthersPresence<T extends Presence>(room: string): Others<T>;
export declare function useBroadcastEvent(room: string): (event: any) => void;
export declare function useEventListener<TEvent>(room: string, callback: ({ connectionId, event, }: {
/**
* Makes the Liveblocks client available in the component hierarchy below.
*/
export declare function LiveblocksProvider(props: LiveblocksProviderProps): JSX.Element;
declare type RoomProviderProps = {
/**
* The id of the room you want to connect to
*/
id: string;
/**
* A callback that let you initialize the default presence when entering the room.
* If ommited, the default presence will be an empty object
*/
defaultPresence?: () => Presence;
children: React.ReactNode;
};
/**
* Makes a Room available in the component hierarchy below.
* When this component is unmounted, the current user leave the room.
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
*/
export declare function RoomProvider({ id, children, defaultPresence, }: RoomProviderProps): JSX.Element;
/**
* Returns the presence of the current user of the current room, and a function to update it.
* It is different from the setState function returned by the useState hook from React.
* You don't need to pass the full presence object to update it.
*
* ### Example
* ``` typescript
* import { useMyPresence } from "@liveblocks/react";
*
* const [myPresence, updateMyPresence] = useMyPresence();
* updateMyPresence({ x: 0 });
* updateMyPresence({ y: 0 });
*
* // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }"
* ```
*/
export declare function useMyPresence<T extends Presence>(): [
T,
(overrides: Partial<T>) => void
];
/**
* useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
* If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.
*
* ### Example
* ``` typescript
* import { useUpdateMyPresence } from "@liveblocks/react";
*
* const updateMyPresence = useUpdateMyPresence();
* updateMyPresence({ x: 0 });
* updateMyPresence({ y: 0 });
*
* // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
* ```
*/
export declare function useUpdateMyPresence<T extends Presence>(): (overrides: Partial<T>) => void;
/**
* Returns an object that lets you get information about all the the users currently connected in the room.
*
* ### Example
* ``` typescript
* import { useOthers } from "@liveblocks/react";
*
* const others = useOthers();
*
* // Example to map all cursors in jsx
* {
* others.map(({ connectionId, presence }) => {
* if(presence == null || presence.cursor == null) {
* return null;
* }
* return <Cursor key={connectionId} cursor={presence.cursor} />
* })
* }
* ```
*/
export declare function useOthers<T extends Presence>(): Others<T>;
/**
* Returns a callback that lets you broadcast custom events to other users in the room
*
* ### Example
* ``` typescript
* import { useBroadcastEvent } from "@liveblocks/react";
*
* const broadcast = useBroadcastEvent();
*
* broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } });
* ```
*/
export declare function useBroadcastEvent(): (event: any) => void;
/**
* useErrorListener is a react hook that lets you react to potential room connection errors.
*
* ### Example
* ``` typescript
* import { useErrorListener } from "@liveblocks/react";
*
* useErrorListener(er => {
* console.error(er);
* })
* ```
*/
export declare function useErrorListener(callback: (er: Error) => void): void;
/**
* useEventListener is a react hook that lets you react to event broadcasted by other users in the room.
*
* ### Example
* ``` typescript
* import { useEventListener } from "@liveblocks/react";
*
* useEventListener(({ connectionId, event }) => {
* if (event.type === "CUSTOM_EVENT") {
* // Do something
* }
* });
* ```
*/
export declare function useEventListener<TEvent>(callback: ({ connectionId, event, }: {
connectionId: number;

@@ -26,5 +139,5 @@ event: TEvent;

};
export declare function useStorage<TRoot extends RecordData>(room: string, initialStorage: InitialStorageFactory<TRoot>): [root: Record<TRoot> | null, actions: StorageActions];
export declare function useStorageActions(room: string): StorageActions;
export declare function useStorage<TRoot extends RecordData>(initialStorage: InitialStorageFactory<TRoot>): [root: Record<TRoot> | null, actions: StorageActions];
export declare function useStorageActions(): StorageActions;
export { createClient } from "@liveblocks/client";
export type { Record, Client, List } from "@liveblocks/client";

450

lib/index.js

@@ -44,2 +44,3 @@ Object.defineProperty(exports, '__esModule', { value: true });

WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP"] = 4004] = "MAX_NUMBER_OF_MESSAGES_PER_DAY_PER_APP";
WebsocketCloseCodes[WebsocketCloseCodes["MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM"] = 4005] = "MAX_NUMBER_OF_CONCURRENT_CONNECTIONS_PER_ROOM";
})(WebsocketCloseCodes || (WebsocketCloseCodes = {}));

@@ -641,13 +642,2 @@

};
var __rest = (undefined && undefined.__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;
};
const BACKOFF_RETRY_DELAYS = [250, 500, 1000, 2000, 4000, 8000, 10000];

@@ -660,4 +650,5 @@ const HEARTBEAT_INTERVAL = 30000;

value === "my-presence" ||
value === "others-presence" ||
value === "event");
value === "others" ||
value === "event" ||
value === "error");
}

@@ -720,3 +711,3 @@ function makeIdFactory(connectionId) {

};
function addEventListener(type, listener) {
function subscribe(type, listener) {
if (!isValidRoomEventType(type)) {

@@ -727,3 +718,3 @@ throw new Error(`"${type}" is not a valid event name`);

}
function removeEventListener(event, callback) {
function unsubscribe(event, callback) {
if (!isValidRoomEventType(event)) {

@@ -738,9 +729,6 @@ throw new Error(`"${event}" is not a valid event name`);

}
function getListenersCount() {
return (state.listeners["my-presence"].length +
state.listeners["others-presence"].length +
state.listeners.storage.length +
state.listeners.event.length);
}
function connect() {
if (typeof window === "undefined") {
return;
}
if (state.connection.state !== "closed" &&

@@ -787,4 +775,10 @@ state.connection.state !== "unavailable") {

const user = state.users[message.actor];
const newUser = user
? {
if (user == null) {
state.users[message.actor] = {
connectionId: message.actor,
presence: message.data,
};
}
else {
state.users[message.actor] = {
id: user.id,

@@ -794,13 +788,9 @@ info: user.info,

presence: Object.assign(Object.assign({}, user.presence), message.data),
}
: {
connectionId: message.actor,
presence: message.data,
};
updateUsers(Object.assign(Object.assign({}, state.users), { [message.actor]: newUser }));
}
updateUsers();
}
function updateUsers(newUsers) {
state.users = newUsers;
state.others = makeOthers(newUsers);
for (const listener of state.listeners["others-presence"]) {
function updateUsers() {
state.others = makeOthers(state.users);
for (const listener of state.listeners["others"]) {
listener(state.others);

@@ -811,4 +801,4 @@ }

const userLeftMessage = message;
const _a = state.users, _b = userLeftMessage.actor; _a[_b]; const rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
updateUsers(rest);
delete state.users[userLeftMessage.actor];
updateUsers();
}

@@ -826,3 +816,4 @@ function onRoomStateMessage(message) {

}
updateUsers(newUsers);
state.users = newUsers;
updateUsers();
}

@@ -840,7 +831,8 @@ function onNavigatorOnline() {

function onUserJoinedMessage(message) {
updateUsers(Object.assign(Object.assign({}, state.users), { [message.actor]: {
connectionId: message.actor,
info: message.info,
id: message.id,
} }));
state.users[message.actor] = {
connectionId: message.actor,
info: message.info,
id: message.id,
};
updateUsers();
if (state.me) {

@@ -911,6 +903,10 @@ // Send current presence to new user

clearTimeout(state.timeoutHandles.reconnect);
updateUsers({});
state.users = {};
updateUsers();
if (event.code >= 4000 && event.code <= 4100) {
updateConnection({ state: "failed" });
context.onError(new Error(event.reason));
const error = new LiveblocksError(event.reason, event.code);
for (const listener of state.listeners.error) {
listener(error);
}
}

@@ -1032,3 +1028,2 @@ else if (event.wasClean === false) {

updateConnection({ state: "closed" });
state.me = null;
if (state.timeoutHandles.flush) {

@@ -1040,8 +1035,11 @@ clearTimeout(state.timeoutHandles.flush);

clearInterval(state.intervalHandles.heartbeat);
updateUsers({});
state.listeners["my-presence"] = [];
state.listeners["others-presence"] = [];
state.listeners.event = [];
state.listeners.storage = [];
state.users = {};
updateUsers();
clearListeners();
}
function clearListeners() {
for (const key in state.listeners) {
state.listeners[key] = [];
}
}
function getPresence() {

@@ -1153,4 +1151,4 @@ return state.me;

disconnect,
addEventListener,
removeEventListener,
subscribe,
unsubscribe,
// Presence

@@ -1169,3 +1167,2 @@ updatePresence,

// Core
getListenersCount,
getConnectionState,

@@ -1180,3 +1177,3 @@ // Presence

}
function defaultState() {
function defaultState(me) {
return {

@@ -1188,4 +1185,5 @@ connection: { state: "closed" },

event: [],
"others-presence": [],
others: [],
"my-presence": [],
error: [],
},

@@ -1207,3 +1205,3 @@ numberOfRetry: 0,

},
me: null,
me: me == null ? {} : me,
users: {},

@@ -1221,3 +1219,3 @@ others: makeOthers({}),

const authEndpoint = options.authEndpoint;
const state = defaultState();
const state = defaultState(options.initialPresence);
const machine = makeStateMachine(state, {

@@ -1227,3 +1225,2 @@ throttleDelay,

authEndpoint,
onError: options.onError,
room: name,

@@ -1238,5 +1235,4 @@ });

getConnectionState: machine.selectors.getConnectionState,
getListenersCount: machine.selectors.getListenersCount,
addEventListener: machine.addEventListener,
removeEventListener: machine.removeEventListener,
subscribe: machine.subscribe,
unsubscribe: machine.unsubscribe,
/////////////

@@ -1265,2 +1261,8 @@ // Storage //

}
class LiveblocksError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}

@@ -1274,33 +1276,22 @@ function createClient(options) {

const rooms = new Map();
const _listeners = {
error: [],
};
function onError(error) {
for (const listener of _listeners.error) {
listener(error);
}
function getRoom(roomId) {
return rooms.get(roomId) || null;
}
function getRoomOrInit(name) {
let room = rooms.get(name);
if (room == null) {
room = createRoom(name, Object.assign(Object.assign({}, options), { onError }));
rooms.set(name, room);
function enter(roomId, initialPresence) {
let room = rooms.get(roomId);
if (room) {
return room;
}
room = createRoom(roomId, Object.assign(Object.assign({}, options), { initialPresence }));
rooms.set(roomId, room);
room.connect();
return room;
}
function getRoom(room) {
return getRoomOrInit(room);
}
function addEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
function leave(roomId) {
let room = rooms.get(roomId);
if (room) {
room.disconnect();
rooms.delete(roomId);
}
_listeners.error.push(listener);
}
function removeEventListener(type, listener) {
if (type !== "error") {
throw new Error(`"${type}" is not a valid event name`);
}
remove(_listeners.error, listener);
}
if (typeof window !== "undefined") {

@@ -1322,5 +1313,5 @@ // TODO: Expose a way to clear these

return {
addEventListener,
removeEventListener,
getRoom,
enter,
leave,
};

@@ -1330,30 +1321,65 @@ }

var ClientContext = React.createContext(null);
function LiveblocksProvider(_a) {
var client = _a.client, children = _a.children;
var _b = React.useState(null), error = _b[0], setError = _b[1];
if (error) {
throw error;
}
React.useEffect(function () {
function onError(error) {
setError(error);
}
client.addEventListener("error", onError);
return function () {
client.removeEventListener("error", onError);
};
}, [client]);
return (React.createElement(ClientContext.Provider, { value: client }, children));
var RoomContext = React.createContext(null);
/**
* Makes the Liveblocks client available in the component hierarchy below.
*/
function LiveblocksProvider(props) {
return (React.createElement(ClientContext.Provider, { value: props.client }, props.children));
}
/**
* Returns the client of the nearest LiveblocksProvider above in the react component tree
*/
function useClient() {
var client = React.useContext(ClientContext);
if (client == null) {
throw new Error("Missing context");
throw new Error("LiveblocksProvider is missing from the react tree");
}
return client;
}
function useMyPresence(room, initPresence) {
/**
* Makes a Room available in the component hierarchy below.
* When this component is unmounted, the current user leave the room.
* That means that you can't have 2 RoomProvider with the same room id in your react tree.
*/
function RoomProvider(_a) {
var id = _a.id, children = _a.children, defaultPresence = _a.defaultPresence;
var client = useClient();
var _room = client.getRoom(room);
var presence = _room.getPresence() || initPresence();
React.useEffect(function () {
return function () {
client.leave(id);
};
}, [client, id]);
var room = client.getRoom(id) ||
client.enter(id, defaultPresence ? defaultPresence() : undefined);
return React.createElement(RoomContext.Provider, { value: room }, children);
}
/**
* Returns the room of the nearest RoomProvider above in the react component tree
*/
function useRoom() {
var room = React.useContext(RoomContext);
if (room == null) {
throw new Error("RoomProvider is missing from the react tree");
}
return room;
}
/**
* Returns the presence of the current user of the current room, and a function to update it.
* It is different from the setState function returned by the useState hook from React.
* You don't need to pass the full presence object to update it.
*
* ### Example
* ``` typescript
* import { useMyPresence } from "@liveblocks/react";
*
* const [myPresence, updateMyPresence] = useMyPresence();
* updateMyPresence({ x: 0 });
* updateMyPresence({ y: 0 });
*
* // At the next render, "myPresence" will be equal to "{ x: 0, y: 0 }"
* ```
*/
function useMyPresence() {
var room = useRoom();
var presence = room.getPresence();
var _a = React.useState(0), update = _a[1];

@@ -1364,37 +1390,53 @@ React.useEffect(function () {

}
var _room = client.getRoom(room);
_room.connect();
var existingPresence = _room.getPresence();
if (existingPresence == null) {
_room.updatePresence(initPresence());
}
_room.addEventListener("my-presence", onMyPresenceChange);
room.subscribe("my-presence", onMyPresenceChange);
return function () {
_room.removeEventListener("my-presence", onMyPresenceChange);
if (_room.getListenersCount() === 0) {
_room.disconnect();
}
room.unsubscribe("my-presence", onMyPresenceChange);
};
}, [client, room]);
var setPresence = React.useCallback(function (overrides) { return client.getRoom(room).updatePresence(overrides); }, [room, client]);
}, [room]);
var setPresence = React.useCallback(function (overrides) { return room.updatePresence(overrides); }, [room]);
return [presence, setPresence];
}
function useUpdateMyPresence(room, initPresence) {
var client = useClient();
React.useEffect(function () {
var _room = client.getRoom(room);
_room.connect();
var existingPresence = _room.getPresence();
if (existingPresence == null) {
_room.updatePresence(initPresence());
}
}, [client, room]);
/**
* useUpdateMyPresence is similar to useMyPresence but it only returns the function to update the current user presence.
* If you don't use the current user presence in your component, but you need to update it (e.g. live cursor), it's better to use useUpdateMyPresence to avoid unnecessary renders.
*
* ### Example
* ``` typescript
* import { useUpdateMyPresence } from "@liveblocks/react";
*
* const updateMyPresence = useUpdateMyPresence();
* updateMyPresence({ x: 0 });
* updateMyPresence({ y: 0 });
*
* // At the next render, the presence of the current user will be equal to "{ x: 0, y: 0 }"
* ```
*/
function useUpdateMyPresence() {
var room = useRoom();
return React.useCallback(function (overrides) {
var _room = client.getRoom(room);
_room.updatePresence(overrides);
}, [room, client]);
room.updatePresence(overrides);
}, [room]);
}
function useOthersPresence(room) {
var client = useClient();
var _room = client.getRoom(room);
/**
* Returns an object that lets you get information about all the the users currently connected in the room.
*
* ### Example
* ``` typescript
* import { useOthers } from "@liveblocks/react";
*
* const others = useOthers();
*
* // Example to map all cursors in jsx
* {
* others.map(({ connectionId, presence }) => {
* if(presence == null || presence.cursor == null) {
* return null;
* }
* return <Cursor key={connectionId} cursor={presence.cursor} />
* })
* }
* ```
*/
function useOthers() {
var room = useRoom();
var _a = React.useState(0), update = _a[1];

@@ -1405,32 +1447,69 @@ React.useEffect(function () {

}
var _room = client.getRoom(room);
_room.connect();
_room.addEventListener("others-presence", onOthersChange);
room.subscribe("others", onOthersChange);
return function () {
_room.removeEventListener("others-presence", onOthersChange);
if (_room.getListenersCount() === 0) {
_room.disconnect();
}
room.subscribe("others", onOthersChange);
};
}, [client, room]);
return _room.getOthers();
}, [room]);
return room.getOthers();
}
function useBroadcastEvent(room) {
var client = useClient();
/**
* Returns a callback that lets you broadcast custom events to other users in the room
*
* ### Example
* ``` typescript
* import { useBroadcastEvent } from "@liveblocks/react";
*
* const broadcast = useBroadcastEvent();
*
* broadcast({ type: "CUSTOM_EVENT", data: { x: 0, y: 0 } });
* ```
*/
function useBroadcastEvent() {
var room = useRoom();
return React.useCallback(function (event) {
room.broadcastEvent(event);
}, [room]);
}
/**
* useErrorListener is a react hook that lets you react to potential room connection errors.
*
* ### Example
* ``` typescript
* import { useErrorListener } from "@liveblocks/react";
*
* useErrorListener(er => {
* console.error(er);
* })
* ```
*/
function useErrorListener(callback) {
var room = useRoom();
var savedCallback = React.useRef(callback);
React.useEffect(function () {
var _room = client.getRoom(room);
_room.connect();
savedCallback.current = callback;
});
React.useEffect(function () {
var listener = function (e) { return savedCallback.current(e); };
room.subscribe("error", listener);
return function () {
if (_room.getListenersCount() === 0) {
_room.disconnect();
}
room.unsubscribe("error", listener);
};
}, [client, room]);
return React.useCallback(function (event) {
var _room = client.getRoom(room);
_room.broadcastEvent(event);
}, [room, client]);
}, [room]);
}
function useEventListener(room, callback) {
var client = useClient();
/**
* useEventListener is a react hook that lets you react to event broadcasted by other users in the room.
*
* ### Example
* ``` typescript
* import { useEventListener } from "@liveblocks/react";
*
* useEventListener(({ connectionId, event }) => {
* if (event.type === "CUSTOM_EVENT") {
* // Do something
* }
* });
* ```
*/
function useEventListener(callback) {
var room = useRoom();
var savedCallback = React.useRef(callback);

@@ -1441,20 +1520,14 @@ React.useEffect(function () {

React.useEffect(function () {
var _room = client.getRoom(room);
_room.connect();
var listener = function (e) {
return savedCallback.current(e);
};
_room.addEventListener("event", listener);
room.subscribe("event", listener);
return function () {
_room.removeEventListener("event", listener);
if (_room.getListenersCount() === 0) {
_room.disconnect();
}
room.unsubscribe("event", listener);
};
}, [room, client]);
}, [room]);
}
function useStorage(room, initialStorage) {
var client = useClient();
var _room = client.getRoom(room);
var storage = _room.getStorage();
function useStorage(initialStorage) {
var room = useRoom();
var storage = room.getStorage();
var _a = React.useState(0), update = _a[1];

@@ -1465,11 +1538,6 @@ React.useEffect(function () {

}
var _room = client.getRoom(room);
_room.connect();
_room.fetchStorage(initialStorage);
_room.addEventListener("storage", onStorageChange);
room.fetchStorage(initialStorage);
room.subscribe("storage", onStorageChange);
return function () {
_room.removeEventListener("storage", onStorageChange);
if (_room.getListenersCount() === 0) {
_room.disconnect();
}
room.unsubscribe("storage", onStorageChange);
};

@@ -1480,26 +1548,25 @@ }, [room]);

: null;
var actions = useStorageActions(room);
var actions = useStorageActions();
return [root, actions];
}
function useStorageActions(room) {
var client = useClient();
function useStorageActions() {
var room = useRoom();
return React.useMemo(function () {
var _room = client.getRoom(room);
function createRecord(data) {
return _room.createRecord(data);
return room.createRecord(data);
}
function updateRecord(record, overrides) {
return _room.updateRecord(record, overrides);
return room.updateRecord(record, overrides);
}
function createList() {
return _room.createList();
return room.createList();
}
function moveItem(list, index, targetIndex) {
return _room.moveItem(list, index, targetIndex);
return room.moveItem(list, index, targetIndex);
}
function deleteItem(list, index) {
return _room.deleteItem(list, index);
return room.deleteItem(list, index);
}
function pushItem(list, item) {
return _room.pushItem(list, item);
return room.pushItem(list, item);
}

@@ -1514,12 +1581,13 @@ return {

};
}, [client, room]);
}, [room]);
}
exports.LiveblocksProvider = LiveblocksProvider;
exports.RoomProvider = RoomProvider;
exports.createClient = createClient;
exports.useBroadcastEvent = useBroadcastEvent;
exports.useClient = useClient;
exports.useErrorListener = useErrorListener;
exports.useEventListener = useEventListener;
exports.useMyPresence = useMyPresence;
exports.useOthersPresence = useOthersPresence;
exports.useOthers = useOthers;
exports.useStorage = useStorage;

@@ -1526,0 +1594,0 @@ exports.useStorageActions = useStorageActions;

{
"name": "@liveblocks/react",
"version": "0.6.0-beta.5",
"version": "0.7.0",
"description": "",

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

"dependencies": {
"@liveblocks/client": "0.6.0-beta.4"
"@liveblocks/client": "0.7.0"
},

@@ -19,0 +19,0 @@ "peerDependencies": {

Sorry, the diff of this file is not supported yet

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