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.3 to 0.6.0-beta.4

773

lib/index.js

@@ -44,3 +44,2 @@ 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["INTERNAL_ERROR"] = 4005] = "INTERNAL_ERROR";
})(WebsocketCloseCodes || (WebsocketCloseCodes = {}));

@@ -559,9 +558,2 @@

})(LiveStorageState || (LiveStorageState = {}));
var RoomState;
(function (RoomState) {
RoomState[RoomState["Default"] = 0] = "Default";
RoomState[RoomState["Connecting"] = 1] = "Connecting";
RoomState[RoomState["Connected"] = 2] = "Connected";
RoomState[RoomState["Error"] = 3] = "Error";
})(RoomState || (RoomState = {}));

@@ -661,21 +653,11 @@ function remove(array, item) {

};
const BACKOFF_RETRY_DELAYS = [
250,
500,
1000,
2000,
4000,
8000,
10000,
10000,
10000,
10000,
];
const BACKOFF_RETRY_DELAYS = [250, 500, 1000, 2000, 4000, 8000, 10000];
const HEARTBEAT_INTERVAL = 30000;
// const WAKE_UP_CHECK_INTERVAL = 2000;
const PONG_TIMEOUT = 2000;
function isValidRoomEventType(value) {
return (value === "open" ||
value === "storage" ||
return (value === "storage" ||
value === "my-presence" ||
value === "others-presence" ||
value === "event" ||
value === "close");
value === "event");
}

@@ -700,137 +682,104 @@ function makeIdFactory(connectionId) {

}
function createRoom(name, options) {
const throttleDelay = options.throttle || 100;
const liveblocksServer = options.liveblocksServer || "wss://live.liveblocks.io";
const authEndpoint = options.authEndpoint;
const _listeners = {
open: [],
storage: [],
event: [],
"others-presence": [],
"my-presence": [],
close: [],
};
let _idFactory = null;
let _doc = null;
let _storageState = LiveStorageState.NotInitialized;
let _initialStorageFactory = null;
const _state = {
me: null,
socket: null,
lastFlushTime: 0,
flushTimeout: null,
flushData: {
presence: null,
messages: [],
storageOperations: [],
function makeStateMachine(state, context, mockedEffects) {
const effects = mockedEffects || {
authenticate() {
return __awaiter$1(this, void 0, void 0, function* () {
try {
const token = yield auth(context.authEndpoint, context.room);
const connectionId = parseToken(token).actor;
const socket = new WebSocket(`${context.liveblocksServer}/?token=${token}`);
socket.addEventListener("message", onMessage);
socket.addEventListener("open", onOpen);
socket.addEventListener("close", onClose);
socket.addEventListener("error", onError);
authenticationSuccess(connectionId, socket);
}
catch (er) {
authenticationFailure(er);
}
});
},
send(messageOrMessages) {
if (state.socket == null) {
throw new Error("Can't send message if socket is null");
}
state.socket.send(JSON.stringify(messageOrMessages));
},
delayFlush(delay) {
return setTimeout(tryFlushing, delay);
},
startHeartbeatInterval() {
return setInterval(heartbeat, HEARTBEAT_INTERVAL);
},
schedulePongTimeout() {
return setTimeout(pongTimeout, PONG_TIMEOUT);
},
scheduleReconnect(delay) {
return setTimeout(connect, delay);
},
};
let _users = {};
let _others = makeOthers(_users);
let state = RoomState.Default;
let numberOfRetry = 0;
let retryTimeoutId = 0;
function send(messageOrMessages) {
if (_state.socket == null) {
throw new Error("Can't send message if socket is null");
function addEventListener(type, listener) {
if (!isValidRoomEventType(type)) {
throw new Error(`"${type}" is not a valid event name`);
}
_state.socket.send(JSON.stringify(messageOrMessages));
state.listeners[type].push(listener);
}
function makeId() {
if (_idFactory == null) {
throw new Error("Can't generate id. Id factory is missing.");
function removeEventListener(event, callback) {
if (!isValidRoomEventType(event)) {
throw new Error(`"${event}" is not a valid event name`);
}
return _idFactory();
const callbacks = state.listeners[event];
remove(callbacks, callback);
}
function updateUsers(newUsers) {
_users = newUsers;
_others = makeOthers(newUsers);
for (const listener of _listeners["others-presence"]) {
listener(_others);
}
function getConnectionState() {
return state.connection;
}
function dispatch(op) {
_state.flushData.storageOperations.push(op);
tryFlushing();
function getListenersCount() {
return (state.listeners["my-presence"].length +
state.listeners["others-presence"].length +
state.listeners.storage.length +
state.listeners.event.length);
}
function getStorage() {
if (_storageState === LiveStorageState.Loaded) {
return {
state: _storageState,
root: _doc.root,
};
function connect() {
if (state.connection.state !== "closed" &&
state.connection.state !== "unavailable") {
return null;
}
return {
state: _storageState,
};
updateConnection({ state: "authenticating" });
effects.authenticate();
}
function fetchStorage(initialStorageFactory) {
_initialStorageFactory = initialStorageFactory;
_storageState = LiveStorageState.Loading;
_state.flushData.messages.push({ type: ClientMessageType.FetchStorage });
tryFlushing();
}
function updateDoc(doc) {
_doc = doc;
if (doc) {
for (const listener of _listeners.storage) {
listener(getStorage());
}
function updatePresence(overrides) {
const newPresence = Object.assign(Object.assign({}, state.me), overrides);
if (state.flushData.presence == null) {
state.flushData.presence = overrides;
}
}
function createRecord$1(data) {
return createRecord(makeId(), data);
}
function createList$1() {
return createList(makeId());
}
function onInitialStorageState(message) {
_storageState = LiveStorageState.Loaded;
if (message.root == null) {
const rootId = makeId();
_doc = Doc.empty(rootId, (op) => dispatch(op));
updateDoc(_doc.updateRecord(rootId, _initialStorageFactory({
createRecord: (data) => createRecord$1(data),
createList: () => createList$1(),
})));
}
else {
updateDoc(Doc.load(message.root, (op) => dispatch(op)));
for (const key in overrides) {
state.flushData.presence[key] = overrides[key];
}
}
}
function onStorageUpdates(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 onOpen() {
state = RoomState.Connected;
numberOfRetry = 0;
state.me = newPresence;
tryFlushing();
for (const callback of _listeners.open) {
callback();
for (const listener of state.listeners["my-presence"]) {
listener(state.me);
}
}
function onEvent(message) {
for (const listener of _listeners.event) {
listener({ connectionId: message.actor, event: message.event });
}
function authenticationSuccess(connectionId, socket) {
updateConnection({ state: "connecting", id: connectionId });
state.idFactory = makeIdFactory(connectionId);
state.socket = socket;
}
function onRoomStateMessage(message) {
const newUsers = {};
for (const key in message.users) {
const connectionId = Number.parseInt(key);
const user = message.users[key];
newUsers[connectionId] = {
connectionId,
info: user.info,
id: user.id,
};
function authenticationFailure(error) {
console.error(error);
updateConnection({ state: "unavailable" });
state.numberOfRetry++;
state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
}
function onVisibilityChange(visibilityState) {
if (visibilityState === "visible" && state.connection.state === "open") {
heartbeat();
}
updateUsers(newUsers);
}
function onUpdatePresenceMessage(message) {
const user = _users[message.actor];
const user = state.users[message.actor];
const newUser = user

@@ -847,11 +796,41 @@ ? {

};
updateUsers(Object.assign(Object.assign({}, _users), { [message.actor]: newUser }));
updateUsers(Object.assign(Object.assign({}, state.users), { [message.actor]: newUser }));
}
function updateUsers(newUsers) {
state.users = newUsers;
state.others = makeOthers(newUsers);
for (const listener of state.listeners["others-presence"]) {
listener(state.others);
}
}
function onUserLeftMessage(message) {
const userLeftMessage = message;
const _a = _users, _b = userLeftMessage.actor; _a[_b]; const rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
const _a = state.users, _b = userLeftMessage.actor; _a[_b]; const rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
updateUsers(rest);
}
function onRoomStateMessage(message) {
const newUsers = {};
for (const key in message.users) {
const connectionId = Number.parseInt(key);
const user = message.users[key];
newUsers[connectionId] = {
connectionId,
info: user.info,
id: user.id,
};
}
updateUsers(newUsers);
}
function onNavigatorOnline() {
if (state.connection.state === "unavailable") {
reconnect();
}
}
function onEvent(message) {
for (const listener of state.listeners.event) {
listener({ connectionId: message.actor, event: message.event });
}
}
function onUserJoinedMessage(message) {
updateUsers(Object.assign(Object.assign({}, _users), { [message.actor]: {
updateUsers(Object.assign(Object.assign({}, state.users), { [message.actor]: {
connectionId: message.actor,

@@ -861,12 +840,18 @@ info: message.info,

} }));
// Send current presence to new user
// TODO: Consider storing it on the backend
_state.flushData.messages.push({
type: ClientMessageType.UpdatePresence,
data: _state.me,
targetActor: message.actor,
});
tryFlushing();
if (state.me) {
// Send current presence to new user
// TODO: Consider storing it on the backend
state.flushData.messages.push({
type: ClientMessageType.UpdatePresence,
data: state.me,
targetActor: message.actor,
});
tryFlushing();
}
}
function onMessage(event) {
if (event.data === "pong") {
clearTimeout(state.timeoutHandles.pongTimeout);
return;
}
const message = JSON.parse(event.data);

@@ -904,88 +889,97 @@ switch (message.type) {

}
// function onWakeUp() {
// // Sometimes, the browser can put the webpage on pause (computer is on sleep mode for example)
// // The client will not know that the server has probably close the connection even if the readyState is Open
// // One way to detect this kind of pause is to ensure that a setInterval is not taking more than the delay it was configured with
// if (state.connection.state === "open") {
// log("Try to reconnect after laptop wake up");
// reconnect();
// }
// }
function onClose(event) {
state.socket = null;
clearTimeout(state.timeoutHandles.pongTimeout);
clearInterval(state.intervalHandles.heartbeat);
if (state.timeoutHandles.flush) {
clearTimeout(state.timeoutHandles.flush);
}
clearTimeout(state.timeoutHandles.reconnect);
updateUsers({});
if (event.code >= 4000 && event.code <= 4100) {
options.onError(new Error(event.reason));
updateConnection({ state: "failed" });
context.onError(new Error(event.reason));
}
for (const listener of _listeners.close) {
listener();
else if (event.wasClean === false) {
updateConnection({ state: "unavailable" });
state.numberOfRetry++;
state.timeoutHandles.reconnect = effects.scheduleReconnect(getRetryDelay());
}
_state.socket = null;
updateUsers({});
if (event.wasClean === false) {
state = RoomState.Default;
numberOfRetry++;
retryTimeoutId = setTimeout(() => connect(), BACKOFF_RETRY_DELAYS[numberOfRetry < BACKOFF_RETRY_DELAYS.length
? numberOfRetry
: BACKOFF_RETRY_DELAYS.length - 1]);
else {
updateConnection({ state: "closed" });
}
}
function onError(event) { }
function connect() {
return __awaiter$1(this, void 0, void 0, function* () {
if (state === RoomState.Connected || state === RoomState.Connecting) {
return;
}
state = RoomState.Connecting;
let token = null;
let actor = null;
try {
token = yield auth(authEndpoint, name);
actor = parseToken(token).actor;
}
catch (er) {
options.onError(er);
state = RoomState.Error;
return;
}
_idFactory = makeIdFactory(actor);
_state.socket = new WebSocket(`${liveblocksServer}/?token=${token}`);
_state.socket.addEventListener("message", onMessage);
_state.socket.addEventListener("open", onOpen);
_state.socket.addEventListener("close", onClose);
_state.socket.addEventListener("error", onError);
});
function updateConnection(connection) {
state.connection = connection;
}
function disconnect() {
if (_state.socket) {
_state.socket.removeEventListener("open", onOpen);
_state.socket.removeEventListener("message", onMessage);
_state.socket.removeEventListener("close", onClose);
_state.socket.removeEventListener("error", onError);
_state.socket.close();
_state.socket = null;
function getRetryDelay() {
return BACKOFF_RETRY_DELAYS[state.numberOfRetry < BACKOFF_RETRY_DELAYS.length
? state.numberOfRetry
: BACKOFF_RETRY_DELAYS.length - 1];
}
function onError() { }
function onOpen() {
clearInterval(state.intervalHandles.heartbeat);
state.intervalHandles.heartbeat = effects.startHeartbeatInterval();
updateConnection({ state: "open", id: state.connection.id });
state.numberOfRetry = 0;
tryFlushing();
}
function heartbeat() {
if (state.socket == null) {
// Should never happen, because we clear the pong timeout when the connection is dropped explictly
return;
}
state = RoomState.Default;
updateUsers({});
clearTimeout(retryTimeoutId);
_listeners.open = [];
_listeners["my-presence"] = [];
_listeners["others-presence"] = [];
_listeners.event = [];
_listeners.storage = [];
_listeners.close = [];
clearTimeout(state.timeoutHandles.pongTimeout);
state.timeoutHandles.pongTimeout = effects.schedulePongTimeout();
if (state.socket.readyState === WebSocket.OPEN) {
state.socket.send("ping");
}
}
//////////////
// Presence //
//////////////
function getPresence() {
return _state.me;
function pongTimeout() {
reconnect();
}
function getOthers() {
return _others;
}
function updatePresence(overrides) {
// Create new local presence right away and call listeners
const newPresence = Object.assign(Object.assign({}, _state.me), overrides);
_state.me = newPresence;
for (const listener of _listeners["my-presence"]) {
listener(_state.me);
function reconnect() {
if (state.socket) {
state.socket.removeEventListener("open", onOpen);
state.socket.removeEventListener("message", onMessage);
state.socket.removeEventListener("close", onClose);
state.socket.removeEventListener("error", onError);
state.socket.close();
state.socket = null;
}
updatePresenceToSend(_state, overrides);
tryFlushing();
updateConnection({ state: "unavailable" });
clearTimeout(state.timeoutHandles.pongTimeout);
if (state.timeoutHandles.flush) {
clearTimeout(state.timeoutHandles.flush);
}
clearTimeout(state.timeoutHandles.reconnect);
clearInterval(state.intervalHandles.heartbeat);
connect();
}
function tryFlushing() {
if (state.socket == null) {
return;
}
if (state.socket.readyState !== WebSocket.OPEN) {
return;
}
const now = Date.now();
if (canSend(now, _state, throttleDelay)) {
send(flushDataToMessages(_state));
_state.flushData = {
const elapsedTime = now - state.lastFlushTime;
if (elapsedTime > context.throttleDelay) {
const messages = flushDataToMessages(state);
if (messages.length === 0) {
return;
}
effects.send(messages);
state.flushData = {
messages: [],

@@ -995,28 +989,64 @@ storageOperations: [],

};
_state.lastFlushTime = Date.now();
state.lastFlushTime = now;
}
else {
if (_state.flushTimeout) {
clearTimeout(_state.flushTimeout);
_state.flushTimeout = null;
if (state.timeoutHandles.flush != null) {
clearTimeout(state.timeoutHandles.flush);
}
_state.flushTimeout = setTimeout(() => {
if (isSocketReady(_state)) {
flushDataToMessages(_state);
send(flushDataToMessages(_state));
_state.flushData = {
messages: [],
storageOperations: [],
presence: null,
};
_state.lastFlushTime = Date.now();
}
}, throttleDelay - (now - _state.lastFlushTime));
state.timeoutHandles.flush = effects.delayFlush(context.throttleDelay - (now - state.lastFlushTime));
}
}
function flushDataToMessages(state) {
const messages = [];
if (state.flushData.presence) {
messages.push({
type: ClientMessageType.UpdatePresence,
data: state.flushData.presence,
});
}
for (const event of state.flushData.messages) {
messages.push(event);
}
if (state.flushData.storageOperations.length > 0) {
messages.push({
type: ClientMessageType.UpdateStorage,
ops: state.flushData.storageOperations,
});
}
return messages;
}
function disconnect() {
if (state.socket) {
state.socket.removeEventListener("open", onOpen);
state.socket.removeEventListener("message", onMessage);
state.socket.removeEventListener("close", onClose);
state.socket.removeEventListener("error", onError);
state.socket.close();
state.socket = null;
}
updateConnection({ state: "closed" });
state.me = null;
if (state.timeoutHandles.flush) {
clearTimeout(state.timeoutHandles.flush);
}
clearTimeout(state.timeoutHandles.reconnect);
clearTimeout(state.timeoutHandles.pongTimeout);
clearInterval(state.intervalHandles.heartbeat);
updateUsers({});
state.listeners["my-presence"] = [];
state.listeners["others-presence"] = [];
state.listeners.event = [];
state.listeners.storage = [];
}
function getPresence() {
return state.me;
}
function getOthers() {
return state.others;
}
function broadcastEvent(event) {
if (!isSocketReady(_state)) {
if (state.socket == null) {
return;
}
_state.flushData.messages.push({
state.flushData.messages.push({
type: ClientMessageType.ClientEvent,

@@ -1027,96 +1057,196 @@ event,

}
function addEventListener(type, listener) {
if (!isValidRoomEventType(type)) {
throw new Error(`"${type}" is not a valid event name`);
/**
* STORAGE
*/
function onStorageUpdates(message) {
if (state.doc == null) {
// TODO: Cache updates in case they are coming while root is queried
return;
}
_listeners[type].push(listener);
updateDoc(message.ops.reduce((doc, op) => doc.dispatch(op), state.doc));
}
function removeEventListener(event, callback) {
if (!isValidRoomEventType(event)) {
throw new Error(`"${event}" is not a valid event name`);
function updateDoc(doc) {
state.doc = doc;
if (doc) {
for (const listener of state.listeners.storage) {
listener(getStorage());
}
}
const callbacks = _listeners[event];
remove(callbacks, callback);
}
function getStorage() {
if (state.storageState === LiveStorageState.Loaded) {
return {
state: state.storageState,
root: state.doc.root,
};
}
return {
state: state.storageState,
};
}
function onInitialStorageState(message) {
state.storageState = LiveStorageState.Loaded;
if (message.root == null) {
const rootId = makeId();
state.doc = Doc.empty(rootId, (op) => dispatch(op));
updateDoc(state.doc.updateRecord(rootId, state.initialStorageFactory({
createRecord: (data) => createRecord$1(data),
createList: () => createList$1(),
})));
}
else {
updateDoc(Doc.load(message.root, (op) => dispatch(op)));
}
}
function makeId() {
if (state.idFactory == null) {
throw new Error("Can't generate id. Id factory is missing.");
}
return state.idFactory();
}
function dispatch(op) {
state.flushData.storageOperations.push(op);
tryFlushing();
}
function createRecord$1(data) {
return createRecord(makeId(), data);
}
function createList$1() {
return createList(makeId());
}
function fetchStorage(initialStorageFactory) {
state.initialStorageFactory = initialStorageFactory;
state.storageState = LiveStorageState.Loading;
state.flushData.messages.push({ type: ClientMessageType.FetchStorage });
tryFlushing();
}
function updateRecord(record, overrides) {
updateDoc(state.doc.updateRecord(record.id, overrides));
}
function pushItem(list, item) {
updateDoc(state.doc.pushItem(list.id, item));
}
function deleteItem(list, index) {
updateDoc(state.doc.deleteItem(list.id, index));
}
function moveItem(list, index, targetIndex) {
updateDoc(state.doc.moveItem(list.id, index, targetIndex));
}
return {
connect() {
connect();
},
// Internal
onOpen,
onClose,
onMessage,
authenticationSuccess,
heartbeat,
onNavigatorOnline,
// onWakeUp,
onVisibilityChange,
// Core
connect,
disconnect,
getListenersCount() {
return (_listeners.open.length +
_listeners["my-presence"].length +
_listeners["others-presence"].length +
_listeners.storage.length +
_listeners.close.length +
_listeners.event.length);
},
getState() {
return state;
},
addEventListener,
removeEventListener,
/////////////
// Storage //
/////////////
getStorage,
// Presence
updatePresence,
broadcastEvent,
// Storage
fetchStorage,
createRecord: createRecord$1,
updateRecord,
createList: createList$1,
updateRecord(record, overrides) {
updateDoc(_doc.updateRecord(record.id, overrides));
pushItem,
deleteItem,
moveItem,
selectors: {
// Core
getListenersCount,
getConnectionState,
// Presence
getPresence,
getOthers,
// Storage
getStorage,
},
pushItem(list, item) {
updateDoc(_doc.pushItem(list.id, item));
};
}
function defaultState() {
return {
connection: { state: "closed" },
socket: null,
listeners: {
storage: [],
event: [],
"others-presence": [],
"my-presence": [],
},
deleteItem(list, index) {
updateDoc(_doc.deleteItem(list.id, index));
numberOfRetry: 0,
lastFlushTime: 0,
timeoutHandles: {
flush: null,
reconnect: 0,
pongTimeout: 0,
},
moveItem(list, index, targetIndex) {
updateDoc(_doc.moveItem(list.id, index, targetIndex));
flushData: {
presence: null,
messages: [],
storageOperations: [],
},
intervalHandles: {
heartbeat: 0,
},
me: null,
users: {},
others: makeOthers({}),
storageState: LiveStorageState.NotInitialized,
initialStorageFactory: null,
doc: null,
idFactory: null,
};
}
function createRoom(name, options) {
const throttleDelay = options.throttle || 100;
const liveblocksServer = options.liveblocksServer || "wss://live.liveblocks.io";
const authEndpoint = options.authEndpoint;
const state = defaultState();
const machine = makeStateMachine(state, {
throttleDelay,
liveblocksServer,
authEndpoint,
onError: options.onError,
room: name,
});
const room = {
/////////////
// Core //
/////////////
connect: machine.connect,
disconnect: machine.disconnect,
getConnectionState: machine.selectors.getConnectionState,
getListenersCount: machine.selectors.getListenersCount,
addEventListener: machine.addEventListener,
removeEventListener: machine.removeEventListener,
/////////////
// Storage //
/////////////
getStorage: machine.selectors.getStorage,
fetchStorage: machine.fetchStorage,
createRecord: machine.createRecord,
createList: machine.createList,
updateRecord: machine.updateRecord,
pushItem: machine.pushItem,
deleteItem: machine.deleteItem,
moveItem: machine.moveItem,
//////////////
// Presence //
//////////////
getPresence,
updatePresence,
getOthers,
broadcastEvent,
getPresence: machine.selectors.getPresence,
updatePresence: machine.updatePresence,
getOthers: machine.selectors.getOthers,
broadcastEvent: machine.broadcastEvent,
};
room._onNavigatorOnline = machine.onNavigatorOnline;
room._onVisibilityChange = machine.onVisibilityChange;
return room;
}
function flushDataToMessages(state) {
const messages = [];
if (state.flushData.presence) {
messages.push({
type: ClientMessageType.UpdatePresence,
data: state.flushData.presence,
});
}
for (const event of state.flushData.messages) {
messages.push(event);
}
if (state.flushData.storageOperations.length > 0) {
messages.push({
type: ClientMessageType.UpdateStorage,
ops: state.flushData.storageOperations,
});
}
return messages;
}
function isSocketReady(state) {
return state.socket !== null && state.socket.readyState === WebSocket.OPEN;
}
function canSend(now, state, wait) {
return isSocketReady(state) && now - state.lastFlushTime > wait;
}
function updatePresenceToSend(state, overrides) {
if (state.flushData.presence == null) {
state.flushData.presence = overrides;
}
else {
for (const key in overrides) {
state.flushData.presence[key] = overrides[key];
}
}
}

@@ -1161,2 +1291,17 @@ function createClient(options) {

}
if (typeof window !== "undefined") {
// TODO: Expose a way to clear these
window.addEventListener("online", () => {
for (const [, room] of rooms) {
room._onNavigatorOnline();
}
});
}
if (typeof document !== "undefined") {
document.addEventListener("visibilitychange", () => {
for (const [, room] of rooms) {
room._onVisibilityChange(document.visibilityState);
}
});
}
return {

@@ -1163,0 +1308,0 @@ addEventListener,

{
"name": "@liveblocks/react",
"version": "0.6.0-beta.3",
"version": "0.6.0-beta.4",
"description": "",

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

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

@@ -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