Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
## vNEXT (not yet released)

## v3.22.0

### `@liveblocks/react`

This release adds version history support for Storage: a version now snapshots
both the room's Storage and Yjs documents (previously Yjs only).

- Creating a version now also snapshots Storage, not just Yjs, see
[docs](https://liveblocks.io/docs/api-reference/rest-api-endpoints#create-version-history-snapshot).
- `useHistoryVersions()` lists the room's versions. Each has a `vh_xxx` id, see
[docs](https://liveblocks.io/docs/api-reference/liveblocks-react#useHistoryVersions).
- `useHistoryVersionStorageData("vh_xxx")` returns that version's Storage as a
read-only `LiveObject` so you can visualize or diff it manually, see
[docs](https://liveblocks.io/docs/api-reference/liveblocks-react#useHistoryVersionStorageData).
- `useRestoreToStorageVersion("vh_xxx")` restores the room's Storage to that
version, as a single undoable change, see
[docs](https://liveblocks.io/docs/api-reference/liveblocks-react#useRestoreToStorageVersion).
- `useDeleteHistoryVersion()` returns `deleteHistoryVersion("vh_xxx")` to
permanently delete a version, see
[docs](https://liveblocks.io/docs/api-reference/liveblocks-react#useDeleteHistoryVersion).

### `@liveblocks/node` and Python SDK

- Add methods for version history to list room versions, create a version
snapshot, and delete a version.

## v3.21.0

### All packages
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions docs/pages/api-reference/liveblocks-node.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,73 @@ const binaryYjsUpdate = await liveblocks.getYjsDocumentAsBinaryUpdate(
Read the [Yjs documentation](https://docs.yjs.dev/api/document-updates) to learn
more about using binary updates.

### Version History

#### Liveblocks.getVersionHistory [#get-version-history]

Returns a room鈥檚 version history snapshots, sorted by creation date from newest
to oldest. Throws an error if the room isn鈥檛 found. This is a wrapper around the
[Get Version History API](/docs/api-reference/rest-api-endpoints#get-version-history)
and returns the same response.

```ts
const { data: versions, nextCursor } = await liveblocks.getVersionHistory(
"my-room-id",
{
// Optional, defaults to 20
limit: 20,

// Optional, used for pagination
cursor: "eyJjcmVhdGVkQXQi...",
}
);
```

#### Liveblocks.createVersionHistorySnapshot [#create-version-history-snapshot]

Creates a new version history snapshot of a room, capturing both its Storage and
Yjs documents. Throws an error if the room isn鈥檛 found. This is a wrapper around
the
[Create Version History Snapshot API](/docs/api-reference/rest-api-endpoints#create-version-history-snapshot)
and returns the same response.

```ts
const { data } =
await liveblocks.createVersionHistorySnapshot("my-room-id");

// { id: "vh_d75sF3..." }
console.log(data);
```

#### Liveblocks.getYjsVersion [#get-yjs-version]

Returns a specific version of a room鈥檚 Yjs document encoded as a binary Yjs
update. Throws an error if the room or version isn鈥檛 found. This is a wrapper
around the
[Get Yjs Document Version API](/docs/api-reference/rest-api-endpoints#get-yjs-version)
and returns the same response.

```ts
const binaryYjsUpdate = await liveblocks.getYjsVersion({
roomId: "my-room-id",
versionId: "vh_d75sF3...",
});
```

#### Liveblocks.deleteVersion [#delete-version]

Permanently deletes a version from a room鈥檚 history. Throws an error if the room
or version isn鈥檛 found. This is a wrapper around the
[Delete Version API](/docs/api-reference/rest-api-endpoints#delete-version) and
returns no response.

```ts
await liveblocks.deleteVersion({
roomId: "my-room-id",
versionId: "vh_d75sF3...",
});
```

### Attachments

#### Liveblocks.getAttachment [#get-rooms-roomId-attachments-attachmentId]
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/api-reference/liveblocks-react-blocknote.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,8 @@ The `HistoryVersionPreview` component allows you to display a preview of a
specific version of your BlockNote editor鈥檚 content. It also contains a button
and logic for restoring. To render a list of versions, see
[`VersionHistory`](/docs/api-reference/liveblocks-react-ui#Version-History).
Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

#### Usage [#HistoryVersionPreview-usage]

Expand Down
2 changes: 2 additions & 0 deletions docs/pages/api-reference/liveblocks-react-lexical.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,8 @@ specific version of your Lexical editor's content. It also contains a button and
logic for restoring. It must be used inside the `<LiveblocksPlugin>` context. To
render a list of versions, see
[`VersionHistory`](/docs/api-reference/liveblocks-react-ui#Version-History).
Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

#### Usage

Expand Down
2 changes: 2 additions & 0 deletions docs/pages/api-reference/liveblocks-react-tiptap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,8 @@ The `HistoryVersionPreview` component allows you to display a preview of a
specific version of your Tiptap editor鈥檚 content. It also contains a button and
logic for restoring. To render a list of versions, see
[`VersionHistory`](/docs/api-reference/liveblocks-react-ui#Version-History).
Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

#### Usage [#HistoryVersionPreview-usage]

Expand Down
14 changes: 7 additions & 7 deletions docs/pages/api-reference/liveblocks-react-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4117,13 +4117,13 @@ All hooks for Presence are in

## Version History

Version history enables you to track and restore versions of your
[Lexical](https://liveblocks.io/docs/api-reference/liveblocks-react-lexical) or
[Yjs](/docs/api-reference/liveblocks-yjs) document. Versions can be
automatically created when enabled in your project settings, or manually created
using the
[REST API](/docs/api-reference/rest-api-endpoints#create-version-history-snapshot).
These components aid in displaying a list of those versions.
Version history enables you to track and restore versions of your Storage and
Yjs documents. These ready-made components aid in displaying a list of version
information for [Tiptap](/docs/api-reference/liveblocks-react-tiptap),
[BlockNote](/docs/api-reference/liveblocks-react-blocknote), and
[Lexical](/docs/api-reference/liveblocks-react-lexical). Learn how to set this
up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

### Default components [#Version-History-Components]

Expand Down
96 changes: 94 additions & 2 deletions docs/pages/api-reference/liveblocks-react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6418,10 +6418,14 @@ updateSettings({

## Version History

Hooks for listing, previewing, restoring, and deleting versions of a room鈥檚
Storage and Yjs documents. Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

### useHistoryVersions [@badge=RoomProvider]

Returns the versions of the room. See
[Version History Components](/docs/api-reference/liveblocks-react-ui#Version-history-components)
Returns the versions of the room, both Storage and Yjs. See
[Version History Components](/docs/api-reference/liveblocks-react-ui#Version-History)
for more information on how to display versions.

```tsx
Expand All @@ -6436,6 +6440,39 @@ const { versions, error, isLoading } = useHistoryVersions();
</PropertiesListItem>
</PropertiesList>

### useHistoryVersionStorageData [@badge=RoomProvider]

Returns the Storage data for a given version of the room, reconstructed as a
read-only [`LiveObject`][]. Because a historical version may not match your
room's current `Storage` type, its shape is typed as the more permissive
`LsonObject`.

```tsx
import { useHistoryVersionStorageData } from "@liveblocks/react";

const { data, error, isLoading } = useHistoryVersionStorageData(versionId);
```

<PropertiesList title="Arguments">
<PropertiesListItem name="versionId" type="string">
The ID of the version to retrieve. Obtained from the `id` field of a
`HistoryVersion` returned by [`useHistoryVersions`][].
</PropertiesListItem>
</PropertiesList>

<PropertiesList title="Returns">
<PropertiesListItem name="data" type="LiveObject | undefined">
The Storage data for the version as a read-only `LiveObject`, or `undefined`
while loading.
</PropertiesListItem>
<PropertiesListItem name="isLoading" type="boolean">
Whether the version data is currently being loaded.
</PropertiesListItem>
<PropertiesListItem name="error" type="Error | undefined">
Any error that occurred while loading the version data.
</PropertiesListItem>
</PropertiesList>

### useHistoryVersionYjsData [@badge=RoomProvider]

Returns the raw Yjs binary data for a given version of the room, for use with
Expand Down Expand Up @@ -6466,6 +6503,60 @@ const { data, error, isLoading } = useHistoryVersionYjsData(versionId);
</PropertiesListItem>
</PropertiesList>

### useRestoreToStorageVersion [@badge=RoomProvider]

Returns a function that restores the room's Storage to a given version, applied
as a single undoable change. Only the Storage surface is affected; other
surfaces (such as Yjs) are left untouched.

```tsx
import { useRestoreToStorageVersion } from "@liveblocks/react";

const restoreToStorageVersion = useRestoreToStorageVersion(versionId);

// Later, restore the room's Storage to this version
await restoreToStorageVersion();
```

<PropertiesList title="Arguments">
<PropertiesListItem name="versionId" type="string">
The ID of the version to restore to. Obtained from the `id` field of a
`HistoryVersion` returned by [`useHistoryVersions`][].
</PropertiesListItem>
</PropertiesList>

<PropertiesList title="Returns">
<PropertiesListItem name="restoreToStorageVersion" type="() => Promise<void>">
A function that restores the room's Storage to the version. The change is
applied locally as a single undoable operation, then synced to the other
clients in the room.
</PropertiesListItem>
</PropertiesList>

### useDeleteHistoryVersion [@badge=RoomProvider]

Returns a function that permanently deletes a version from the room's history.

```tsx
import { useDeleteHistoryVersion } from "@liveblocks/react";

const deleteHistoryVersion = useDeleteHistoryVersion();

// Later, delete a version by its id
await deleteHistoryVersion(versionId);
```

<PropertiesList title="Returns">
<PropertiesListItem
name="deleteHistoryVersion"
type="(versionId: string) => Promise<void>"
>
A function that deletes the version with the given id. The `versionId` is
obtained from the `id` field of a `HistoryVersion` returned by
[`useHistoryVersions`][].
</PropertiesListItem>
</PropertiesList>

## Miscellaneous

### useUser [@badge=Both]
Expand Down Expand Up @@ -7116,6 +7207,7 @@ And the following timeline:
[`useothersconnectionids`]:
/docs/api-reference/liveblocks-react#useOthersConnectionIds
[`useother`]: /docs/api-reference/liveblocks-react#useOther
[`usehistoryversions`]: /docs/api-reference/liveblocks-react#useHistoryVersions
[`uselostconnectionlistener`]:
/docs/api-reference/liveblocks-react#useLostConnectionListener
[`clientsidesuspense`]: /docs/api-reference/liveblocks-react#ClientSideSuspsnse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,56 @@ function MultiplayerCanvas() {
We also provide [`useRedo`](/docs/api-reference/liveblocks-react#useRedo) and
[`useCanRedo`](/docs/api-reference/liveblocks-react#useCanRedo) to handle redo.

### Version history

Create version snapshots of your Storage document, and let users browse,
preview, and restore them.
[`useHistoryVersions`](/docs/api-reference/liveblocks-react#useHistoryVersions)
lists a room鈥檚 versions, and
[`useRestoreToStorageVersion`](/docs/api-reference/liveblocks-react#useRestoreToStorageVersion)
restores Storage to a version, applied as a single undoable change.

```tsx
import {
useHistoryVersions,
useRestoreToStorageVersion,
} from "@liveblocks/react";

function VersionHistory() {
// +++
const { versions } = useHistoryVersions();
// +++

return (
<div>
// +++
{versions.map((version) => (
<div key={version.id}>
<time>{version.createdAt}</time>
<RestoreButton versionId={version.id} />
</div>
))}
// +++
</div>
);
}

function RestoreButton({ versionId }) {
// +++
const restoreToStorageVersion = useRestoreToStorageVersion(versionId);
// +++

return (
<button onClick={() => restoreToStorageVersion()}>Restore version</button>
);
}
```

You can also preview a version鈥檚 data with
[`useHistoryVersionStorageData`](/docs/api-reference/liveblocks-react#useHistoryVersionStorageData).
Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

## Broadcast

Broadcast realtime events to other clients, helpful for triggering live actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,59 @@ function App() {
}
```

## Version history

Create version snapshots of your Yjs document, and let users browse, preview,
and restore them.
[`useHistoryVersions`](/docs/api-reference/liveblocks-react#useHistoryVersions)
lists a room鈥檚 versions, and
[`useHistoryVersionYjsData`](/docs/api-reference/liveblocks-react#useHistoryVersionYjsData)
returns a version as a binary Yjs update, which you can apply to a fresh `Y.Doc`
to read its contents.

```tsx
import {
useHistoryVersions,
useHistoryVersionYjsData,
} from "@liveblocks/react";
import * as Y from "yjs";

function VersionHistory() {
// +++
const { versions } = useHistoryVersions();
// +++

return (
<div>
// +++
{versions.map((version) => (
<div key={version.id}>
<time>{version.createdAt}</time>
<VersionPreview versionId={version.id} />
</div>
))}
// +++
</div>
}

function VersionPreview({ versionId }) {
// +++
const { data } = useHistoryVersionYjsData(versionId);
// +++

// Apply the version's binary update to an empty Y.Doc
const yDoc = new Y.Doc();
Y.applyUpdate(yDoc, data);

// ...
}
```

If you鈥檙e using our Tiptap, BlockNote, or Lexical plugins, ready-made
[`HistoryVersionPreview`](/docs/api-reference/liveblocks-react-tiptap#HistoryVersionPreview)
components preview and restore versions for you. Learn how to set this up in our
[version history guide](/docs/guides/how-to-add-version-history-to-your-app).

## Text and code editor integrations

Liveblocks Yjs integrates with popular text and code editors such as Slate,
Expand Down
Loading
Loading