This major release marks the maturity of Liveblocks. It contains new products
(@liveblocks/react-lexical
) and clarifications (e.g.
@liveblocks/react-comments
is now called @liveblocks/react-ui
).
Also, we bring major DX improvements by allowing you to specify your types globally now. These types will be typed once and shared across all Liveblocks APIs, which includes your Node backend.
// ❌ Before
export const {
suspense: {
RoomProvider,
useRoom,
// etc
},
} = createRoomContext<Presence, Storage>(client);
// ✅ After
declare global {
interface Liveblocks {
Presence: Presence;
Storage: Storage;
}
}
In @liveblocks/react
, you can now import hooks directly:
// ❌ Before: get hooks exported from your Liveblocks config
import { RoomProvider, useRoom, ... } from "./liveblocks.config";
// ✅ After: import hooks directly
import { RoomProvider, useRoom, ... } from "@liveblocks/react";
import { RoomProvider, useRoom, ... } from "@liveblocks/react/suspense";
// ❌ Before
const client = createClient(/* options */);
// ✅ After
<LiveblocksProvider /* options */>
<App />
</LiveblocksProvider>
For full upgrade instructions and codemods, see the 2.0 upgrade guide.
- Update config generation for Liveblocks 2.0.
- Add
--upgrade
flag to automatically update all Liveblocks package to their latest version.
- DX improvements: type once, globally, benefit everywhere
- DX improvement: import hooks directly
- DX improvement:
<ClientSideSuspense>
no longer needs a function as itschildren
- New provider:
LiveblocksProvider
(replaces the need forcreateClient
) - New hook:
useClient
- Tweak
useMutation
error message to be less confusing. - Allow thread and activity metadata types to contain
undefined
values.
- Rename from
@liveblocks/react-comments
. - Rename
<CommentsConfig />
to<LiveblocksUIConfig />
. - Improve
InboxNotification
props types.
- Initial release.
- Initial release.
LiveblocksProvider
is no longer a default export, it’s nowimport { LiveblocksYjsProvider } from "@liveblocks/yjs"
.
- DX improvements: all Node client methods will pick up the same global types you’re using in your frontend
- Rename
RoomInfo
toRoomData
. - The webhook event
NotificationEvent
’s type can represent multiple kinds of notifications. ("thread"
,"textMention"
, and custom ones (e.g."$myNotification"
))
- Initial release.
- New API reference page for
@liveblocks/react-lexical
. - Added lots of new information to
@liveblocks/react
API reference page. - Information includes details
Suspense
section, new
LiveblocksProvider
props, details on typing, and more. - Added a set of product pages for Notifications, with info on concepts, components, hooks, styling, and email notifications.
- Added product page for Lexical summarising all its features.
- Restructured and updated existing product pages for our new products.
- More information on the
NotificationEvent
webhook, including the newtextMention
kind. - Created new guide on adding users to Liveblocks Notifications.
- Created new guide on adding users to Liveblocks Text Editor.
- Created new get started guides for our new Lexical packages.
- Added product badges to get started guides.
- Updated all get started guides for new type improvements.
- Updated API references for new type improvements.
- Updated various guides for new type improvements.
- Updated images and text on How Liveblocks works page.
- We redesigned our website to represent the Liveblocks product offering more
accurately. Here are some of the key changes:
- New homepage with interactive 3D game in the hero.
- New page product page for Liveblocks Text Editor
- New page product page for Liveblocks Notifications
- New page product page for Liveblocks Realtime APIs
- Improved pricing page
- New navigation
- Added new example:
nextjs-lexical
- Upgraded and adjusted all examples to 2.0
- Webhooks are now available to everyone.
- Show Lexical information in rooms that use the new Lexical plugin.
adigau, ctnicholas, flowflorent, guillaumesalles, jrowny, marcbouchenoire, nimeshnayaju, nvie, ofoucherot, pierrelevaillant, stevenfabre
- Added a brand new project analytics page with graphs that gives you better insights into active users, active rooms, comments, notifications, and data stored.
- Improved the billing and usage view.
- Moved Webhooks notification throttle interval setting to the project settings page
- Fixed a number formatting issue by enforcing US number formatting for all locations
- Ongoing internal refactorings to enable simpler setup for
@liveblocks/react
in the future.
ofoucherot, flowflorent, stevenfabre, guillaumesalles, nvie
- Liveblocks events are now visible in the dashboard.
- New "Events" tab within a project.
- Filter room events by type (e.g.
userEntered
,userLeft
), exactroomId
, and exactuserId
. - Select a date range (with available presets).
- Click on an event to open the event details modal.
- Navigate between events using the previous/next buttons without leaving the modal.
- On the room's detail page, click "View room events" at the top right to access the room events.
- Added a new date picker to the "Overview" and "Events" pages.
- Improved onboarding.
- Making sure the default team name isn't too long and can be submitted.
- Improved form submission performance by only calling the required API endpoints.
- Fixed broken link in one onboarding email.
- Internal refactorings to enable simpler setup for
@liveblocks/react
in the future.
pierrelevaillant, ofoucherot, stevenfabre, nvie
- New changelog section.
- Completely rewritten API reference for
@liveblocks/client
. - New components for showing arguments, returns, properties.
- Refreshed banner components.
- Add webhooks source IP addresses for receiving endpoints behind NAT or firewalls.
- Fixed a typo in query language rooms guide.
- The project quickstart connection status can now be dismissed.
- Improved copy to clarify the difference between production and development projects.
- Improved project overview banner copy for when Liveblocks hasn't yet been set up.
- Made batch processing of webhook and other events more efficient at scale.
ctnicholas, stevenfabre, pierrelevaillant, ofoucherot, flowflorent
- Add support for custom notification kinds.
- Add new
useInboxNotificationThread
hook tocreateLiveblocksContext
, which can be used to retrieve threads within thread notifications for more flexibility. - Add support for
startsWith
operator touseThreads
when filtering based on metadata.
- Add support for custom notification kinds to the
InboxNotification
component via thekinds
prop and theInboxNotification.Custom
component. - Add destructive color tokens. (
--lb-destructive
,--lb-destructive-foreground
, and--lb-destructive-contrast
)
- Add
triggerInboxNotification
method that lets you trigger custom notification kinds. - Enable filtering rooms by room ID in the
getRooms
method. This works viaquery.roomId
,metadata
is deprecated and is nowquery.metadata
. - Add support for our query language when filtering with the
getRooms
andgetThreads
methods. - Add support for an alternative object-based query notation to the
getRooms
andgetThreads
methods, which supports exact matches and thestartsWith
operator.
- Fixes a potential
RangeError: Maximum call stack size exceeded
in applications that produce many operations
- Add missing
updatedAt
property toYDocUpdatedEvent
type. (@alexlande)
- Add support for the updated Starter Kit.
- Fix the composer’s placeholder to appear instantly instead of being initially invisible.
- Fix the default composer’s actions not being disabled when the composer is.
- Fix "
process
is undefined" issue in Vite builds. This issue was already fixed for@liveblocks/core
, but not for@liveblocks/node
yet.
- Improve tree view to visualize Y.js documents and inspect Y.js awareness.
- Add
updateRoomId
method that lets you update the room ID of the specified room. - Add an optional
guid
parameter tosendYjsBinaryUpdate
andgetYjsDocumentAsBinaryUpdate
to point to a Yjs subdocument with the specified guid.
- Add
scrollOnLoad
option touseThreads
: enabled by default, this option controls whether to scroll to a comment on load based on the URL hash. useUser
anduseRoomInfo
no longer support returning nothing. Returningundefined
will now be treated as an error.- Fix bug where
useUser
anduseRoomInfo
returned an extradata
superfluous property. - Fix bug where customizing types on
createLiveblocksContext
would conflict with the providedClient
.
- Add actions to
InboxNotification
with a single action for now: marking as read. - Improve actions hover behavior in
Comment
/Thread
. - Change
Comment
background color when it’s linked to or being edited.
- Fix bundling issue in Vite projects, where
process is not defined
could happen
- Add support for Emoji v15.1 in emoji picker, along two additional locales:
Bengali (
bn
) and Hindi (hi
). - Fix bug where the
showRoomName
prop onInboxNotification.Thread
wasn’t applied to notifications about mentions.
- Fix bug where removing metadata via
useEditThreadMetadata
would result in a brief flash of the old metadata after the metadata was removed optimistically.
- Fix bug where calling
.clone()
immediately after creating a newLiveObject
could throw an error
- Fix bug where the client’s backoff delay would not be respected correctly in a small edge case.
- Fix date localization in
InboxNotification
. - Add vendor prefixes to more CSS properties within the default styles.
- Added error retrying to
useThreads
,useRoomNotificationSettings
, anduseInboxNotifications
during initial fetching.
This release introduces Notifications (and unread indicators) for Comments.
- Add
createLiveblocksContext
and Notifications to--init
. - Move resolver options from
createRoomContext
tocreateClient
and addresolveRoomsInfo
to the list of resolvers.
- Add options to
createClient
:resolveUsers
,resolveMentionSuggestions
(both were previously defined oncreateRoomContext
from@liveblocks/react
), and the newresolveRoomsInfo
.
- Add new
LiveblocksContext
accessible withcreateLiveblocksContext
, similarly tocreateRoomContext
. This context is meant to live at the root since it handles things outside of rooms, like notifications. It containsLiveblocksProvider
,useUser
,useRoomInfo
,useInboxNotifications
,useUnreadInboxNotificationsCount
,useMarkInboxNotificationAsRead
, anduseMarkAllInboxNotificationsAsRead
. - Add new hooks to
createRoomContext
:useMarkThreadAsRead
,useThreadSubscription
,useRoomInfo
,useRoomNotificationSettings
, anduseUpdateRoomNotificationSettings
. - Make some hooks usable interchangeably between
createLiveblocksContext
andcreateRoomContext
:useUser
, anduseRoomInfo
.
- Add new default components:
InboxNotification
andInboxNotificationList
. - Add unread indicators to the default
Thread
component. - Support "@" in mentions. (e.g.
@[email protected]
is now a valid mention and will triggerresolveMentionSuggestions
with"[email protected]"
)
- Add the Notifications REST APIs as fully typed methods. (includes
getInboxNotification
,getRoomNotificationSettings
,updateRoomNotificationSettings
, anddeleteRoomNotificationSettings
methods) - Add notification webhook event:
NotificationEvent
.
- Fix race condition in client that could leave zombie WebSocket connections open indefinitely in a small edge case. (thanks for reporting, @dev-badace)
- Fix type definitions of
useOthersListener
hook. - Fix type definitions of
useErrorListener
hook.
- Emit update events from awareness.
- Fix several awareness bugs.
- Expose new
nextCursor
field in Get Rooms API responses, to make pagination easier to work with - Update TypeScript types for some responses
- Adds a fallback for passing data from Safari to the console.
- Fix certain Next.js sites not building correctly due to improper
useSyncExternalStore
import
- Fix mention suggestions not appearing.
- Fix polling on
useThreads
hook.
- Fix a bug that prevented comments from being used across multiple rooms.
- Fix
getRooms()
not throwingLiveblocksError
when invalid response was received.
- Add
portalContainer
prop toCommentsConfig
to customize where floating elements (e.g. tooltips, dropdowns, etc) are portaled into.
- Fixes the signature and behavior of the
Liveblocks.sendYjsBinaryUpdate()
API. It now takes a Yjs encoded update (Uint8Array
) directly.
- Add the Comments write REST APIs as fully typed methods. (includes
createThread
,editThreadMetadata
,createComment
,editComment
,deleteComment
,addCommentReaction
, andremoveCommentReaction
methods) - Fix the return type of
getActiveUsers
to match the data returned from the endpoint.
- Add
query
option touseThreads
to filter threads based on their metadata.
- Add support for exit animations to
ComposerSuggestions
.
- Improve Comments revalidation when losing network or staying in the background.
- Improve error handling of Comments mutations. (e.g. thread creation, comment creation, etc.)
- Export the
CommentBody
utilities added to@liveblocks/node
in v1.8.0. - Harmonize exports with
@liveblocks/node
. (addedIUserInfo
andPlainLsonObject
)
- Harmonize exports with
@liveblocks/client
. (addedCommentBody
,CommentBodyBlockElement
,CommentBodyElement
,CommentBodyInlineElement
,CommentBodyLink
,CommentBodyMention
,CommentBodyParagraph
,CommentBodyText
,JsonArray
,JsonScalar
,Lson
,LsonObject
, andUser
)
- Fix a bug in
toPlainLson
helper - Fix a bug where pausing history more than once could lead to history loss
This release adds all the REST APIs as fully typed methods, and utilities to
transform comments, to @liveblocks/node
.
- Add all the REST APIs as fully typed methods to
Liveblocks
client. See docs. - Add utilities to work with the
CommentBody
format from Comments:getMentionedIdsFromCommentBody(body)
- Get a list of all mentioned IDs from aCommentBody
. See docs.stringifyCommentBody(body, options)
- Convert aCommentBody
to a string, either as plain text, HTML, or Markdown. It supports resolving mention IDs similarly to@liveblocks/react
and overriding each element to control the formatting. See docs.
- Fix
Composer
focus issues. - Improve relative date formatting for some locales. (e.g. the `"fr"`` locale formatted “1h ago” as “-1 h” instead of “il y a 1 h”)
- Improve default monospace font for inline code blocks.
Liveblocks Comments is now available for everyone as a public beta, learn more about this in the announcement.
- Improve some internal logging.
- Improve Comments-specific error logging.
- Improve default relative date formatting. (e.g. “2 hours ago” → “2h ago”)
- Add
ThreadMetadata
type to--init
command.
- Add support for subdocs.
- Fix return type of
resolveUsers
.
- Fixes a bug in the bounds check of the
backgroundKeepAliveTimeout
option.
Support multiple RoomProviders, or mixing and matching our React package in the same app with a Redux and/or Zustand instance.
At the client level, there is a new API for entering/leaving rooms, which we’re now recommending over the old APIs. (The old APIs remain working exactly how they are today, however.)
// Old APIs we'll no longer be recommending (but that will remain working)
const room = client.enter("my-room", options);
client.getRoom("my-room");
client.leave("my-room");
// New API we'll be recommending instead
const { room, leave } = client.enterRoom("my-room", options);
leave();
- New client config option:
backgroundKeepAliveTimeout
(a numeric value in milliseconds). See docs. - New APIs:
Client.enterRoom(roomId, options)
– enters the room and return both the room and an "unsubscribe function" to leave that room again. This newer API supports entering/leaving the same room multiple times, making it possible to connect to the same room from different parts of your application. See docs.Client.logout()
– Call this on the Liveblocks client when you log out a user in your application. It will purge all auth tokens and force-leave any rooms, if any are still connected. See docs.LiveList.clone()
– see docs.LiveMap.clone()
– see docs.LiveObject.clone()
– see docs.
- Deprecated APIs:
client.enter(roomId, options)
client.leave(roomId)
- Renamed enter option:
shouldInitiallyConnect
→autoConnect
. Its meaning or working did not change. - Fixes a potential
Cannot set parent: node already has a parent
error when initializing storage with Live datastructures that are already tied to a Storage tree.
- Support using multiple
RoomProvider
components in your component tree for the same room ID. - Renamed
RoomProvider
prop:shouldInitiallyConnect
→autoConnect
. Its meaning or working did not change. - New hook:
useOthersListener({ type, user, others })
, see docs
- Breaking: The
leaveRoom()
function no longer accepts aroomId
. It will always leave the currently joined room.
- The
enterRoom()
function will now return a leave callback function. - Breaking: The
leaveRoom()
function no longer accepts aroomId
. It will always leave the currently joined room.
- Add Comments hooks and options to
--init
command.
- Export all
CommentBody
-related types.
- Improve default styles:
- Cap CSS selector specificity to improve overridability.
- Set tokens on
.lb-root
instead of:root
to improve cascading tokens (overriding--lb-accent
onbody
for example, didn't create the expected results), and to work within shadow DOMs.
- Fix reactions and links styles on Safari.
- Fix
userIds
type inResolveUsersArgs
.
- Fix a race condition that could cause a Liveblocks client to hang during loading when using Suspense.
- Fix
useStatus
return value on SSR responses. - Breaking (beta): The
resolveUser
option increateRoomContext
is now calledresolveUsers
and it receives a list of user IDs (via theuserIds
property, replacinguserId
) instead of a single one. Instead of returning user info of a single user ID, this function will now expect a list of users' info matching the provided list of user IDs. - Breaking (beta): The
ResolveUserOptions
andResolveMentionSuggestionsOptions
types were renamed toResolveUsersArgs
andResolveMentionSuggestionsArgs
respectively. resolveUsers
andresolveMentionSuggestions
now accept synchronous functions.resolveUsers
now also provides the current room ID.editThreadMetadata
now correctly allowsnull
to be set on a property. Doing so deletes existing metadata properties.
- Export
ComposerSubmitComment
type from root too, in addition to/primitives
. - Add
onThreadDelete
toThread
. - Add
metadata
toComposer
to attach custom metadata to new threads. - Add support for specifying a custom
ThreadMetadata
type onThread
andComposer
. - Breaking (beta):
Comment
’sonEdit
andonDelete
were renamed toonEditComment
andonDeleteComment
respectively.
- Fix
createThread
not creating valid comment.
- Fix URL encoding bug
- Fix
removeReaction
not removing reactions which led to reactions displaying a count of 0.
- Fix reactions list (and its add button) showing on all comments.
- Improve emoji rendering on Windows.
- Hide country flag emojis when unsupported. (e.g. on Windows)
- Add new Comments hooks to add/remove reactions.
- Fix a bug in
useOthers()
that could lead to the warning "The result of getServerSnapshot should be cached to avoid an infinite loop"
- Add support for reactions. (👍)
- Add keyboard navigation to emoji picker.
- Fix a bug where calculating the insertion position between two existing elements could happen incorrectly in a small edge case
- #1177 Fix an issue with
internal LiveList serialization that could lead to a "ghosting" bug with
@liveblocks/zustand
/@liveblocks/redux
when using tuples.
- Add comment reaction webhook events
CommentReactionAdded
andCommentReactionRemoved
- New Yjs tab: visualize Yjs documents as a diagram, a tree, or as a list of operations, and inspect Awareness at the same time as Presence.
- New Events tab: inspect all custom Events a client receives in an event timeline, for easy testing/debugging.
- Add support for the Liveblocks DevTools.
- Broadcast event messages now include a
user
property to indicate the user that sent the event:room.subscribe("event", ({ event, user }) => { // ^^^^ New! });
- Broadcast event messages now include a
user
property to indicate the user that sent the event:useEventListener(({ event, user }) => { // ^^^^ New! });
- Breaking (beta): Comments' hook
useThreads
now returns an object in its Suspense version. (const threads = useThreads()
becomesconst { threads } = useThreads()
)
- Breaking (beta):
Comment
’sindentBody
andThread
’sindentCommentBody
were renamed toindentContent
andindentCommentContent
respectively.Thread
’sonResolveChange
was renamed toonResolvedChange
. - Add emoji button in
Composer
.
- Support using
@liveblocks/node
in Edge runtimes.
- Support
unstable_fallbackToHTTP
client option when using any auth token type (previously it only worked when using single-room tokens, which we no longer recommend since 1.2)
- Officially mark
useList()
,useMap()
, anduseObject()
as deprecated in JSDoc comments (we stopped recommending them since the release of 0.18) - Deduplicate Comments requests and improve how race conditions are handled during mutations.
- Fix non-Suspense Comments hooks not working properly in some situations.
- Breaking (beta): Replace the render prop API (e.g.
renderMention
,renderLink
, etc) by a singlecomponents
prop. (e.g.components={{ Mention, Link }}
) - Fix overflowing
Composer.Suggestions
. - Reduce the impact of icons on bundle size.
- Fix confusing
Error: "undefined" is not a valid event name
error when using the (deprecated)useMap()
,useObject()
, oruseList()
hooks on uninitialized storage values.
- Fix unescaped room IDs when using Comments.
- Add support for auto-links. (e.g.
"www.liveblocks.io"
)
- The client will disconnect with an error if your
/api/liveblocks-auth
backend returns reused/cached tokens. It’s important that auth tokens are always freshly generated, and never get cached or reused. (The client itself will cache and reuse tokens already, so implementing additional caching in your backend isn’t needed, and could even cause reconnection issues.)
- Actually include the new Clear History API.
- Fix missing dependency declaration.
This release marks the initial release of Liveblocks Comments, which is currently in private beta.
- New history API:
room.history.clear()
allows you to explicitly clear the history, which resets the ability to undo beyond the current state. - Removed long deprecated methods:
others.count
→ Useothers.length
insteadothers.toArray()
→ Useothers
instead (it’s already an array)
- Deprecated the
Others<P, U>
type → Usereadonly User<P, U>[]
instead.
- Add support for Comments.
UserMeta["info"]
can no longer be a scalar value.
- Initial release.
- Add Comments helpers to Client.
- Add Comments webhook events.
- Fixes a bug where sending an empty (or non-string) user ID with
.identifyUser
would confusingly get reported as an HTTP 503.
- Improve configuration error messages to be more user friendly.
- Fix bug where entering a new room could potentially initialize the undo stack incorrectly.
- Fix Suspense option when specifying a framework.
- Add helpful comments by default.
- Add Yjs document change event (
YDocUpdatedEvent
) toWebhookHandler
. - Allow
Header
object to be passed toheaders
inWebhookHandler.verifyRequest()
- Fix session.allow to support path up to 128 characters to meet room id length requirement.
- Support the new and improved Liveblocks authorization.
- Change client logic to stop retrying if room is full. Instead, the client will
now disconnect. To retry, call
room.reconnect()
explicitly.
- Add new APIs for authorization. See our migration guide for tips on how to adopt the new style of authorizing your Liveblocks clients.
- Fix a small TypeScript issue introduced in 1.1.7.
- When initializing the client with a
custom auth callback,
you can now return
{ error: "forbidden", reason: ... }
as the response, which the client will treat as a sign to stop retrying. The client will then disconnect from the room, instead of remaining in"connecting"
status indefinitely.
- Fix a bug with
useSelf()
where it would not correctly re-render after entering an empty room. It’s now consistent again withuseMyPresence()
.
- Fix a bug in the Liveblocks DevTools panel where the "me" view would incorrectly stay empty after entering an empty room.
- Loosen duplicate import detection so it won't throw when used in test runners that deliberately run multiple instances of a module (like Jest or Playwright can do).
- Ship all of our packages as both ESM and CJS modules again (restore the changes that 1.1.3 originally introduced).
- Auto-detect if multiple copies of Liveblocks are included in your production bundle. If so, a help page is presented that will help you resolve this issue.
- Fix a bug where the room internals could become non-functional when used in combination with Immer due to Immer’s excessive auto-freezing, which would break the room’s internals. (This became an issue since Liveblocks 1.1 was released.)
- Undo the changes made in 1.1.3. We’ve got some bug reports where Liveblocks could still be doubly-included in production bundles (in some bundler setups only), with storage data corruptions as a possible result. We’re investigating.
Ship all of our packages as both ESM and CJS modules. By upgrading, your project’s bundler can now perform (better) tree-shaking on the Liveblocks code.
You can expect (at least) the following bundle size reductions:
@liveblocks/client
from 80kB → 70kB@liveblocks/react
from 129kB → 80kB@liveblocks/redux
from 84kB → 38kB@liveblocks/zustand
from 83kB → 37kB@liveblocks/yjs
from 129kB → 74kB
Added Yjs support to open beta through the new @liveblocks/yjs
package
(not stable yet).
- Fixes a missing internal export.
- Fixes a bug where under certain circumstances the Liveblocks client could
incorrectly throw a
Not started yet
error message.
This release improves the client’s internals to ensure a more reliable connection with Liveblocks servers.
- New APIs:
room.getStatus()
: returns the current status of the WebSocket connection:"initial"
,"connecting"
,"connected"
,"reconnecting"
, or"disconnected"
room.subscribe("status")
: subscribe to changes of the connection status.room.subscribe("lost-connection")
: high-level API to get informed when Liveblocks’ automatic reconnection process is taking longer than usual, so you can show a toast message on screen. (See this example for an illustration.)
- New behavior:
- The client will stop retrying to establish a connection in cases where retrying would not help. For example an explicit 403 forbidden response from your backend, or a configuration error.
- The client will more quickly reconnect even after long periods of sleep.
- New APIs:
useStatus()
- React hook version ofroom.getStatus()
useLostConnectionListener()
- React hook version ofroom.subscribe("lost-connection")
(See this example for an illustration.)
- Reconnection would sometimes not work after long periods of sleep. Waking up is now instant.
- React clients using Suspense could sometimes incorrectly bounce back to the Suspense boundary after a successful load. No longer!
- Client could sometimes not load storage after reconnecting. Not anymore!
- Others array will no longer flash during an internal reconnect.
- DevTools now keeps working even when the client goes offline.
These APIs still work, but are replaced by newer APIs. The old APIs will be removed in a future release of Liveblocks.
Old connection status codes are replaced by the new ones:
❌ Old statuses | ✅ New statuses |
---|---|
closed | initial |
authenticating | connecting |
connecting | connecting |
open | connected |
unavailable | reconnecting |
failed | disconnected |
Recommended steps to upgrade:
- ❌
room.getConnectionState()
→ ✅room.getStatus()
- ❌
room.subscribe('connection')
→ ✅room.subscribe('status')
- Old client options:
- ❌
clientOptions.fetchPolyfill
- ❌
clientOptions.WebSocketPolyfill
→ ✅clientOptions.polyfills: { fetch, WebSocket }
- ❌
- Added
export type TypedRoom = Room<...>
to init command for non-React apps.
- Fix a bug where undo/redo on
LiveObject
creates exponentially larger deltas.
- Fix a bug related to proactive token expiration detection.
- Internal refactorings.
- Add unstable_fallbackToHTTP option to the core client to support messages over 1MB.
- Fix incorrect status code when Liveblocks server cannot be reached temporarily.
- Export
LiveListUpdate
,LiveMapUpdate
, andLiveObjectUpdate
types used by the storage update callback. - Export new utility,
toPlainLson
, to assist in calling the initialize storage API. - Internal refactorings.
- Internal refactorings.
- Added
flags
for creating config files with
--init
. (e.g.--framework react
) - Added an error if an incorrect flag is used.
- Slightly changed the format of the default config file.
- Internal refactorings.
- Private API changes only.
- Release
create-liveblocks-app
along with other Liveblocks packages, using the same versioning scheme. - Internal refactorings.
Non-existent.
Non-existent.
Non-existent.
- Fix bug where passing down
shouldInitiallyConnect
connection option would not always work.
- Log stack traces of function calls that resulted in rejected storage mutations to the console in non-production builds to ease debugging.
- Fixes bug where the state of
others
in a room was wrong when:- Client A disconnects improperly (ex: computer goes to sleep)
- Then Client B disconnects (ex: computer goes to sleep)
- Then Client A reconnects: client B still shows in the
others
state
This major release marks the maturity of Liveblocks. For upgrade instructions, see the 1.0 upgrade guide.
authorize
option userId
is now mandatory.
Our new pricing is based on Monthly Active
Users instead of connections. We're using userId
to track MAU associated to a
Liveblocks account.
WebhookHandler
now handlesRoomCreatedEvent
andRoomDeletedEvent
- Allow
createClient
throttle
option to go as low as 16ms.
- Adds a
WebhookHandler
classnew WebhookHandler(secret).verifyRequest({ rawBody, headers })
can be used to verify event requests from Liveblock's webhook functionality. It also provides fully typedWebhookEvents
.- Check out our Webhooks guide for more details
- Fixes a bug where history didn't reliably undo
LiveObject
key set changes if any pending local changes existed on that key. - Fixes a bug where changes performed inside
room.batch
were incorrectly ordered inside the history resulting in unexpected undo behavior in some cases. - Fixes a bug where under some circumstances the Liveblocks client could get stuck in a "synchronizing" state indefinitely
- Expose
JsonArray
andJsonScalar
types publicly
Fix nested storage event handling issue.
Support authentication with cookies.
Export the StorageStatus
type (introduced with 0.19.3).
Fix CORS issue.
In @liveblocks/client:
Get the storage status.
not-loaded
: Initial state when entering the room.loading
: Once the storage has been requested via room.getStorage().synchronizing
: When some local updates have not been acknowledged by Liveblocks servers.synchronized
: Storage is in sync with Liveblocks servers.
Subscribe to storage status changes.
Returns an unsubscribe function.
room.subscribe("storage-status", (status) => {
switch (status) {
case "not-loaded":
break;
case "loading":
break;
case "synchronizing":
break;
case "synchronized":
break;
default:
break;
}
});
Close the room connection and try to reconnect.
- Add support for the upcoming Liveblocks browser extension
Fixes some internal type definitions.
Fixes an issue where import
s from Liveblocks packages could not be resolved
correctly in certain build environments.
This release brings Zustand v4 support. This is a breaking change only if you’re using @liveblocks/zustand.
In @liveblocks/zustand:
- Support Zustand v4 (actually v4.1.3 or higher)
- Drop support for Zustand v3 (also v4.1.2 or lower are not supported)
- Fix bug where some usage pattern could cause the Zustand store to stop synching (#491)
To migrate, make the following code changes:
npm install zustand@latest
npm install @liveblocks/zustand@latest
- Change these imports, if applicable:
and
-import { middleware } from "@liveblocks/zustand"; +import { liveblocks } from "@liveblocks/zustand";
and rename accordingly.-import type { LiveblocksState } from "@liveblocks/zustand"; +import type { WithLiveblocks } from "@liveblocks/zustand";
- Change the pattern:
to the Zustand v4 recommended pattern:
create(liveblocks<MyState, ...>(...))
To be clear:create<WithLiveblocks<MyState, ...>>()(liveblocks(...))
- First, move the type annotation away from the
liveblocks
middleware call, and onto thecreate
call. - Next, wrap your
MyState
type in aWithLiveblocks<...>
wrapper. This will make sure the injectedliveblocks
property on your Zustand state will be correctly typed. - Finally, make sure to add the extra call
()
wrapper, needed by Zustand v4 now:create<WithLiveblocks<MyState, ...>>()(liveblocks(...)) // ^^ Not a typo
- First, move the type annotation away from the
- Remove the second argument to
state.liveblocks.enterRoom()
: it no longer takes an explicit initial state. Instead, it's automatically be populated from your Zustand state.
In @liveblocks/redux:
- The main export has been renamed:
-import { enhancer } from "@liveblocks/redux"; +import { liveblocksEnhancer } from "@liveblocks/redux";
- The second argument to
state.liveblocks.enterRoom()
to send in an explicit initial state is no longer supported. It will use the state in your Redux store, for consistency and ease of use.
Bug fix:
- Fixes a small bug in a type definition,
scopes
was removed fromBaseUserMeta
.
Internal updates:
- Switch the monorepo over to Turborepo.
All packages now provide an isReadOnly
flag on user instances. It is available
when getting self or others. isReadOnly
is true when storage is read-only, see
the
room management guide
for more information.
const me = room.getSelf();
me.isReadOnly; // boolean
const others = room.getOthers();
for (const other of others) {
other.isReadOnly; // boolean
}
In @liveblocks/client:
-
Add a new option
shouldInitiallyConnect
toclient.enter
that let you control whether or not the room connects to Liveblocks servers. Default istrue
.Usually set to false when the client is used from the server to not call the authentication endpoint or connect via WebSocket.
In @liveblocks/react:
-
Add a new property
shouldInitiallyConnect
toRoomProvider
that let you control whether or not the room connects to Liveblocks servers. Default istrue
.By default equals to
typeof window !== "undefined"
, meaning the RoomProvider tries to connect to Liveblocks servers only on the client side. -
Internal package restructurings to increase code sharing. You may notice a new dependency show up in your dependency tree:
@liveblocks/core
. It contains private APIs that aren't intended for direct consumption.
-
In @liveblocks/react:
Fixes the "zombie-child" problem that can occur with React 17 or lower. If you’re on React 18: great, you can ignore this! If you’re using React 17 or lower with Liveblocks, we’ll now start to enforce that you pass the
unstable_batchedUpdates
prop to RoomProvider, so this problem can be circumvented. This small addition may save you hours of debugging time!// ⚠️ Only if you’re using React 17 or lower import { unstable_batchedUpdates } from "react-dom"; // 👈 <RoomProvider id="my-room" initialPresence={...} initialStorage={...} unstable_batchedUpdates={unstable_batchedUpdates} // 👈 > <App /> </RoomProvider>
To read more, see https://liveblocks.io/docs/guides/troubleshooting#stale-props-zombie-child
-
In @liveblocks/zustand:
- Fix a confusing error message
-
In @liveblocks/react:
- Make sure that
useOther
will not rerender if tracked users already left the room, so that child components won't get rerendered before the parent got the chance to unmount them. - Disallow
useOther
without selector
- Make sure that
-
In @liveblocks/react:
- Fix a bug that could cause an error when patching presence during local development. Not an issue in production builds. (#505)
For information, please read our Upgrade Guide for 0.18.
-
In @liveblocks/react:
-
In @liveblocks/client:
- New
.toImmutable()
method onLiveObject
,LiveList
, andLiveMap
lets you work with an immutable representation of the storage objects - Improved core performance
- Reduced bundle size
- Others only become visible in the
others
array if their presence is known
- New
- Remove support for directly importing hooks from @liveblocks/client (e.g.
import { useMyPresence } from '@liveblocks/react'
). If you’re still using these imports, see the Upgrade Guide for 0.17 for instructions. - Remove
ClientProvider
anduseClient
hook - Remove
defaultPresence
anddefaultStorageRoot
arguments. (Just useinitialPresence
andinitialStorage
arguments now.) - Remove second argument to
useMap()
,useList()
, anduseObject()
. - Remove
new LiveMap(null)
support. (Just usenew LiveMap()
ornew LiveMap([])
.)
General:
- Fix a packaging bug
In @liveblocks/react:
- Deprecate an undocumented API
- Fix bug that could cause duplicate copies of @liveblocks/client to end up in final bundle, for certain bundler configurations.
- Fix bug where in some conditions the initial presence for a new connection would not come through to all existing clients in the room
- Various internal changes
-
In @liveblocks/client:
- Add
canUndo()
andcanRedo()
utilities toroom.history
- Add
"history"
event type toroom.subscribe()
to subscribe to the current user's history changes
- Add
-
In @liveblocks/react:
- Add
useCanUndo()
anduseCanRedo()
hooks
- Add
-
In @liveblocks/zustand:
- Simplify zustand middleware integration with Typescript.
TPresence
,TStorage
,TUserMeta
, andTRoomEvent
are now optional.
- Simplify zustand middleware integration with Typescript.
Note that @liveblocks/zustand
does not work with zustand > v4 because v3 and
v4 have completely different type definitions. As soon as zustand v4 is out of
the RC phase, we will consider updating our middleware to work with the latest
version.
Let's take a look at our To-do list example. Without our middleware, the store would look like this:
import create from "zustand";
type State = {
draft: string;
isTyping: boolean;
todos: Todo[];
setDraft: (draft: string) => void;
addTodo: () => void;
deleteTodo: (index: number) => void;
};
create<State>(/* ... */);
With our middleware, you simply need to move the State
param at the middleware
level:
import create from "zustand";
import { createClient } from "@liveblocks/client";
import { middleware } from "@liveblocks/zustand";
const client = createClient({ /*...*/ });
type State = {
draft: string;
isTyping: boolean;
todos: Todo[];
setDraft: (draft: string) => void;
addTodo: () => void;
deleteTodo: (index: number) => void;
};
create(
middleware<State>(/* ... */, {
client,
presenceMapping: { isTyping: true },
storageMapping: { todos: true }
})
);
If you want to type others
presence, you can use the TPresence
generic
argument on the middleware.
type Presence = {
isTyping: true;
}
const useStore = create(
middleware<State, Presence>(/* ... */, {
client,
presenceMapping: { isTyping: true },
storageMapping: { todos: true }
})
);
// In your component
useStore(state => state.liveblocks.others[0].presence?.isTyping)
-
In @liveblocks/react:
- Expose
RoomContext
in the return value ofcreateRoomContext()
- Expose
-
In @liveblocks/react:
- Fix bug where changing the
key
argument ofuseMap()
,useList()
,useObject()
did not resubscribe to updates correctly - Ignore changes to the
RoomProvider
's initial presence/storage props on subsequent renders. This makes it behave closer touseState(initialState)
- Fix bug where changing the
Fix missing documentation for hooks created via createRoomContext()
.
Fix @liveblocks/nodes
packaging.
For information, please read our Upgrade Guide.
This release contains major TypeScript improvements. The recommended setup now is that you define your own Presence and Storage types at the highest level (i.e. where you set up the room). After that initial one-time setup, you will no longer need to provide any extra type annotations anywhere for your Liveblocks code! 🙌
To learn how to set that up, follow the instructions in our Upgrade Guide.
- No more
any
types used (in@liveblocks/client
and@liveblocks/react
) - All APIs that work with Presence data will now require it to be JSON-serializable
- All APIs that work with Storage data will now require it to be LSON (= JSON + Live structures)
- All Live structures now take mandatory type params for their payloads, just
like the built-in array, object, and map types do:
LiveMap<K, V>
(likeMap<K, V>
)LiveObject<{ a: number, b: string }>
(like, for example,{ a: number, b: string }
)LiveList<T>
(likeArray<T>
)
We now support React Native! To learn how to use Liveblocks in your React Native projects, see our API reference. It's surprisingly simple!
-
In @liveblocks/react:
createRoomContext()
is now the preferred way to initialize hooks.
-
In the API:
- New endpoint to Get Users in a Room
- New endpoint to Get a list of all Rooms
- Improved conflict resolution on LiveList
- Various minor internal bug fixes
-
In @liveblocks/client:
- Removed old
Room.unsubscribe()
API
- Removed old
-
In @liveblocks/client:
- The
defaultPresence
option toclient.enter()
will get renamed toinitialPresence
- The
defaultStorageRoot
option toclient.enter()
will get renamed toinitialStorage
- Calling
new LiveMap(null)
will stop working. Please usenew LiveMap()
, ornew LiveMap([])
- The
-
In @liveblocks/react:
- Importing the React hooks directly is deprecated, instead use the new
createRoomContext()
helper. For help, read the Recommended Upgrade Steps section within our Upgrade Guide - The second argument to
useList()
,useObject()
, anduseMap()
is deprecated - The RoomProvider's
defaultPresence
is renamed toinitialPresence
- The RoomProvider's
defaultStorageRoot
is renamed toinitialStorage
- Importing the React hooks directly is deprecated, instead use the new
Fix bug in internal code where some legal authentication tokens would be considered invalid.
Internals only.
Internals only.
Fix an issue where the current user's info would not properly display accented characters.
(Unpublished.)
Internals only.
Expose helper type to help users adopt to using Live structures with interfaces they don't own.
Restructures a few more internals.
Restructures a few internals.
Fix bug in private/internal code.
Fix bug in private/internal code.
Fix bug in example code suggested in deprecation warning.
- Various internal refactorings
-
In @liveblocks/client:
- If you're using
@liveblocks/client
in a ES2015 context, you no longer have to polyfillObject.fromEntries()
.
- If you're using
- Improve our generated bundles. They are now even more tree-shakable, and smaller!
- Some APIs are being deprecation and will show warnings in the dev console when used
-
In @liveblocks/client:
- Fix bug where internal presence state could not get restored correctly after undo/redo in certain circumstances.
-
In @liveblocks/zustand and @liveblocks/redux:
-
Fixes an issue when initializing an array with items would result in having duplicated items in other clients. Example:
- Client A updates state :
{ list: [0] }
- Client B states is updated to :
{ list: [0, 0] }
- Client A updates state :
-
-
In @liveblocks/client:
- Fix small bug related to new
JsonObject
type, which would reject some values that were legal JSON objects.
- Fix small bug related to new
-
In @liveblocks/react:
- Fix issue with React 18 and StrictMode.
Set one element at a specified index.
const list = new LiveList(["🦁", "🦊", "🐵"]);
list.set(0, "🐺");
list.toArray(); // equals ["🐺", "🦊", "🐵"]
liveblocks#147 for more information
LiveList.set
, you need to make sure that all connected
clients are using 0.16.0
. If a client is connected to a room with version
< 0.16
, LiveList.set
might lead to slightly unexpected behavior.
@nvie improved our typescript definitions! They are more precise and restrictive
(for your own good :)). If typescript errors appears after upgrading to 0.16.0
and they are not clear, please create a Github issue and we'll help you.
More information here: liveblocks#150