From 375f3404fc3bf78396f853490e54f79e28d01cc5 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 25 Feb 2026 02:52:04 -0800 Subject: [PATCH 1/3] a doc on using presence + storage for agentic workflows (#3101) Co-authored-by: Chris Nicholas --- guides/guides.json | 8 + ...ling-agentic-workflows-with-liveblocks.mdx | 429 ++++++++++++++++++ 2 files changed, 437 insertions(+) create mode 100644 guides/pages/enabling-agentic-workflows-with-liveblocks.mdx diff --git a/guides/guides.json b/guides/guides.json index ee47b460e8..245cf84772 100644 --- a/guides/guides.json +++ b/guides/guides.json @@ -496,5 +496,13 @@ "topics": ["rest-api", "storage"], "technologies": ["storage"], "date": "2026-02-20" + }, + { + "title": "Enabling Agentic Workflows with Liveblocks", + "path": "/enabling-agentic-workflows-with-liveblocks", + "topics": ["rest-api", "ai-copilots", "webhooks"], + "technologies": ["react", "nodejs"], + "date": "2026-02-20", + "featured": true } ] diff --git a/guides/pages/enabling-agentic-workflows-with-liveblocks.mdx b/guides/pages/enabling-agentic-workflows-with-liveblocks.mdx new file mode 100644 index 0000000000..faea4c3a6a --- /dev/null +++ b/guides/pages/enabling-agentic-workflows-with-liveblocks.mdx @@ -0,0 +1,429 @@ +--- +meta: + title: "Enabling Agentic Workflows with Liveblocks" + parentTitle: "Guides" + description: + "Use Liveblocks REST APIs to let AI agents show presence, modify storage, + and participate as collaborators in your rooms." +--- + +AI agents can participate as first-class collaborators inside Liveblocks rooms. +Two REST API capabilities make this possible: + +- **Ephemeral Presence** (`POST /v2/rooms/{roomId}/presence`): Lets an agent + appear in a room with a name, avatar, and custom presence data, with an + auto-expiring TTL. +- **JSON Patch** (`PATCH /v2/rooms/{roomId}/storage/json-patch`): Lets an agent + modify + [Storage](/docs/ready-made-features/multiplayer/sync-engine/liveblocks-storage) + using the RFC 6902 standard, which is well understood by LLMs, making it + straightforward for AI models to generate patch operations directly from + natural language instructions. + +Both are language-agnostic HTTP endpoints, so agents built in Python, +TypeScript, or any other language can use them without a native Liveblocks +client. + +## Making your agent visible with ephemeral presence [#ephemeral-presence] + +The +[`POST /v2/rooms/{roomId}/presence`](/docs/api-reference/rest-api-endpoints#post-rooms-roomId-presence) +endpoint lets your agent set presence in a room just like a connected user +would. The presence expires automatically once the TTL elapses, so the agent +never lingers after it's done. + +```shell title="Endpoint" +POST https://api.liveblocks.io/v2/rooms/{roomId}/presence +``` + +Authenticate with your project's **secret key** in the `Authorization` header. + +```shell +"Authorization: Bearer {{SECRET_KEY}}" +``` + +The request body accepts: + +- `userId`: The agent's stable identifier. +- `data`: Any presence object you want connected clients to see. +- `userInfo`: Optional name, avatar URL, and color for the agent. +- `ttl`: How long (in seconds) the presence should live (minimum: 2, maximum: + 3599). + +```bash +curl -X POST "https://api.liveblocks.io/v2/rooms/my-room/presence" \ + -H "Authorization: Bearer {{SECRET_KEY}}" \ + -H "Content-Type: application/json" \ + -d '{ + "userId": "ai-agent", + "data": { "status": "thinking", "focusedField": "email" }, + "userInfo": { + "name": "AI Agent", + "avatar": "https://example.com/ai-agent-avatar.png", + "color": "#6366f1" + }, + "ttl": 60 + }' +``` + +A `204` response means the presence was set successfully. + +### Rendering the agent as an avatar [#agent-avatar] + +Because the agent's presence is set server-side, it flows to all connected +clients through the normal Liveblocks presence system. The agent appears in +[`useOthers`](/docs/api-reference/liveblocks-react#useOthers) alongside real +users, so existing avatar stack components work without any changes. + +```tsx +import { useOthers, useSelf } from "@liveblocks/react/suspense"; + +function AvatarStack() { + const others = useOthers(); + const self = useSelf(); + + return ( +
+ {others.map(({ connectionId, info }) => ( + {info.name} + ))} + {self && {self.info.name}} +
+ ); +} +``` + +The `userInfo.avatar` you pass to the presence endpoint populates `info.avatar` +here, so the agent shows up with its own avatar. + +### Highlighting form fields [#highlight-fields] + +Presence `data` can carry any shape you choose. A `focusedField` property, for +example, lets the frontend highlight which input the agent is currently working +on, giving users real-time insight into what the agent is doing. + +```tsx +import { useOthers } from "@liveblocks/react/suspense"; + +function FormField({ name, label }: { name: string; label: string }) { + const agentFocus = useOthers((others) => + others.find((o) => o.presence.focusedField === name) + ); + + return ( +
+ + + {agentFocus && ( + + {agentFocus.info.name} is reviewing… + + )} +
+ ); +} +``` + +As the agent moves between fields, call the presence endpoint again with an +updated `focusedField` value. Each call resets the TTL, so the presence stays +alive as long as the agent keeps working. + +## Modifying storage with JSON Patch [#json-patch] + +The +[`PATCH /v2/rooms/{roomId}/storage/json-patch`](/docs/api-reference/rest-api-endpoints#patch-rooms-roomId-storage-json-patch) +endpoint lets an agent write directly to a room's Storage document over HTTP. +The body is a JSON array of operations following the +[RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902) specification. + +```shell title="Endpoint" +PATCH https://api.liveblocks.io/v2/rooms/{roomId}/storage/json-patch +``` + +JSON Patch is a well-established standard that LLMs already understand, which +means you can ask a model to produce the patch operations directly from a +natural language instruction without writing custom tooling or prompt +engineering. + +Supported operations are `add`, `remove`, `replace`, `move`, `copy`, and `test`. +If any operation fails, the whole patch is rejected and the document is left +unchanged. + +For a full reference of all operations and error handling, see the +[Modifying Storage via REST API with JSON Patch](/guides/modifying-storage-via-rest-api-with-json-patch) +guide. + +The example below uses Python, which is common in agentic pipelines: + +```python +import requests + +ROOM_ID = "my-room" +SECRET_KEY = "sk_prod_..." + +operations = [ + {"op": "replace", "path": "/formData/email", "value": "verified@example.com"}, + {"op": "add", "path": "/formData/status", "value": "reviewed"}, +] + +response = requests.patch( + f"https://api.liveblocks.io/v2/rooms/{ROOM_ID}/storage/json-patch", + json=operations, + headers={"Authorization": f"Bearer {SECRET_KEY}"}, +) + +response.raise_for_status() # raises on 4xx / 5xx +``` + +A `200` response means all operations were applied. A `422` response means the +patch failed; the response body includes an `error` code, a human-readable +`message`, and an optional `suggestion`. + +## End-to-end example: agent reviews a form [#end-to-end] + +The following example walks through an agent that reviews a multi-field form. It +uses ephemeral presence to show users what it's doing in real time, and JSON +Patch to commit its changes to Storage. + +```python +import requests + +BASE = "https://api.liveblocks.io/v2" +ROOM = "my-room" +AGENT_ID = "ai-agent" +HEADERS = {"Authorization": "Bearer sk_prod_...", "Content-Type": "application/json"} + +def set_presence(focused_field: str, status: str, ttl: int = 30): + requests.post( + f"{BASE}/rooms/{ROOM}/presence", + json={ + "userId": AGENT_ID, + "data": {"focusedField": focused_field, "status": status}, + "userInfo": { + "name": "AI Agent", + "avatar": "https://example.com/ai-agent-avatar.png", + }, + "ttl": ttl, + }, + headers=HEADERS, + ) + +def patch_storage(ops: list): + requests.patch( + f"{BASE}/rooms/{ROOM}/storage/json-patch", + json=ops, + headers=HEADERS, + ).raise_for_status() + +# Step 1 — signal intent on the "email" field +set_presence("email", "reviewing") + +# Step 2 — validate and update email in Storage +patch_storage([ + {"op": "replace", "path": "/formData/email", "value": "verified@example.com"}, +]) + +# Step 3 — move to the "name" field +set_presence("name", "reviewing") + +patch_storage([ + {"op": "replace", "path": "/formData/name", "value": "Jane Doe"}, +]) + +# Step 4 — mark the review as complete +# Set a short TTL so presence expires soon after we're done +set_presence("", "done", ttl=5) +patch_storage([ + {"op": "add", "path": "/formData/reviewedAt", "value": "2026-02-20T12:00:00Z"}, + {"op": "add", "path": "/formData/reviewedBy", "value": AGENT_ID}, +]) +``` + +On the frontend, the `FormField` component from the +[section above](#highlight-fields) will highlight each field as the agent +focuses on it, and `useStorage` will reflect the patched values as they arrive +in real time, no extra wiring required. + +## Triggering agentic workflows [#triggers] + +There are several natural places to start an agent workflow. Choose the one that +fits your product best, or combine multiple triggers. + +### Comments webhooks—mentioning an AI agent [#comments-webhook] + +Users can invoke an agent by mentioning it in a comment (e.g. +`@AI Agent, please review this form`). The +[`commentCreated`](/docs/platform/webhooks#CommentCreatedEvent) webhook fires +for every new comment, giving you a place to detect the mention and dispatch the +agent. + + + + Register the agent as a mentionable user + + Add the agent's ID to [`resolveUsers`](/docs/api-reference/liveblocks-react#LiveblocksProviderResolveUsers) + and [`resolveMentionSuggestions`](/docs/api-reference/liveblocks-react#LiveblocksProviderResolveMentionSuggestions) + in your [`LiveblocksProvider`](/docs/api-reference/liveblocks-react#LiveblocksProvider) + so it appears in the `@` mention picker alongside real users. + + ```tsx + { + const users = await fetchUsersFromDB(userIds); + return userIds.map((id) => { + if (id === "ai-agent") { + return { name: "AI Agent", avatar: "/ai-agent-avatar.png" }; + } + return users.find((u) => u.id === id); + }); + }} + resolveMentionSuggestions={async ({ text }) => { + const userIds = await searchUsers(text); + // Include the AI agent whenever "ai agent" matches the search text + if ("ai agent".includes(text.toLowerCase())) { + userIds.unshift("ai-agent"); + } + return userIds; + }} + > + {/* ... */} + + ``` + + For more information on `resolveUsers` and `resolveMentionSuggestions`, see + [Users and mentions](/docs/ready-made-features/comments/users-and-mentions). + + + + + + Handle the `commentCreated` webhook + + When a comment is created, the webhook payload contains `roomId`, `threadId`, + and `commentId`. Fetch the full comment using the Liveblocks Node SDK, then use + [`getMentionsFromCommentBody`](/docs/api-reference/liveblocks-node#getMentionsFromCommentBody) + to extract all mentions and check whether the agent's ID is among them. + + ```ts file="app/api/liveblocks-webhook/route.ts" + import { Liveblocks, getMentionsFromCommentBody } from "@liveblocks/node"; + + const liveblocks = new Liveblocks({ secret: process.env.SECRET_KEY! }); + + export async function POST(req: Request) { + const event = await req.json(); + + if (event.type === "commentCreated") { + const { roomId, threadId, commentId } = event.data; + + // Fetch the full comment to inspect its body + const comment = await liveblocks.getComment({ + roomId, + threadId, + commentId, + }); + + // Extract all mentions from the comment body + const mentions = getMentionsFromCommentBody(comment.body); + const mentionsAgent = mentions.some( + (mention) => mention.kind === "user" && mention.id === "ai-agent" + ); + + if (mentionsAgent) { + // Trigger your agent workflow with the relevant context + await triggerAgentWorkflow({ roomId, threadId, commentId }); + } + } + + return new Response(null, { status: 200 }); + } + ``` + + `triggerAgentWorkflow` is where you kick off your agent — call an n8n webhook, + invoke a CrewAI crew, hit an LLM API, or run any other pipeline you've built. + + + + Always verify the webhook signature before processing events. See the + [Webhooks documentation](/docs/platform/webhooks) for verification examples. + + + + + + + +### Storage webhooks [#storage-webhook] + +The `storageUpdated` event fires whenever Storage is written to. This is useful +for agents that react to user edits, for example auto-validation, +auto-summarization, or data enrichment. + +```ts file="app/api/liveblocks-webhook/route.ts" +export async function POST(req: Request) { + const event = await req.json(); + + if (event.type === "storageUpdated") { + const { roomId } = event.data; + await triggerAgentWorkflow({ roomId }); + } + + return new Response(null, { status: 200 }); +} +``` + +### Direct API call or button [#direct-trigger] + +The simplest trigger of all: a user clicks a button in your UI, which calls your +backend endpoint, which runs the agent. This gives you full control over when +and how the agent is invoked. + +```tsx +async function handleReviewClick() { + await fetch("/api/run-agent", { + method: "POST", + body: JSON.stringify({ roomId: "my-room" }), + }); +} +``` + +A scheduled job (CRON) is another variant which can run the agent periodically +to batch process rooms or perform maintenance tasks. + +### Other triggers + +- **Notification webhooks**: Fire when a user receives an inbox notification, + which can be a signal to summarize unread activity or draft a reply. +- **External events**: Slack messages, GitHub PR events, email, Zapier triggers, + or any inbound webhook that carries a `roomId` can start an agent run. +- **Scheduled / CRON jobs**: Poll rooms on a fixed schedule to run quality + checks, generate reports, or clean up stale data. + +## Integrating with agentic frameworks [#frameworks] + +Because both APIs are plain HTTP endpoints, Liveblocks works with any agent +framework that can make HTTP requests. + +- **n8n**: Add an HTTP Request node to call the presence and JSON Patch + endpoints. Use a Liveblocks webhook as the workflow trigger so agents fire + automatically on comment or storage events. +- **CrewAI** :Wrap the REST calls in a custom `Tool` and pass it to your agents. + Agents can then set presence or patch storage as part of a multi-step task. +- **LangChain / LangGraph**: Define Liveblocks tools for function-calling + models. The LLM can generate JSON Patch operations directly — the RFC 6902 + format is part of many models' training data, so no custom schema or special + prompting is needed. +- **Any HTTP-capable framework**: fetch, axios, Python `requests`, Go + `net/http`, cURL—if it can make a `POST` or `PATCH` request it can drive + Liveblocks. + +## Next steps + +- [Modifying Storage via REST API with JSON Patch](/guides/modifying-storage-via-rest-api-with-json-patch): + Full reference for all JSON Patch operations. +- [Webhooks](/docs/platform/webhooks): All available webhook events and + signature verification. +- [REST API reference](/docs/api-reference/rest-api-endpoints): Complete request + and response schemas for all endpoints. +- [Users and mentions](/docs/ready-made-features/comments/users-and-mentions): + Setting up `resolveUsers` and `resolveMentionSuggestions`. From d3a69904709727e21fe39a714a31a5098625a07e Mon Sep 17 00:00:00 2001 From: "devin-ai-integration[bot]" <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 25 Feb 2026 12:01:30 +0100 Subject: [PATCH 2/3] Add "author" field to all published package.json files (LB-3372) (#3114) Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- packages/liveblocks-client/package.json | 1 + packages/liveblocks-core/package.json | 1 + packages/liveblocks-emails/package.json | 1 + packages/liveblocks-node-lexical/package.json | 1 + packages/liveblocks-node-prosemirror/package.json | 1 + packages/liveblocks-node/package.json | 1 + packages/liveblocks-react-blocknote/package.json | 1 + packages/liveblocks-react-lexical/package.json | 1 + packages/liveblocks-react-tiptap/package.json | 1 + packages/liveblocks-react-ui/package.json | 1 + packages/liveblocks-react/package.json | 1 + packages/liveblocks-redux/package.json | 1 + packages/liveblocks-yjs/package.json | 1 + packages/liveblocks-zustand/package.json | 1 + tools/create-liveblocks-app/package.json | 1 + tools/liveblocks-codemod/package.json | 1 + tools/liveblocks-devtools/package.json | 1 + 17 files changed, 17 insertions(+) diff --git a/packages/liveblocks-client/package.json b/packages/liveblocks-client/package.json index 41a5d910ec..92fac05663 100644 --- a/packages/liveblocks-client/package.json +++ b/packages/liveblocks-client/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A client that lets you interact with Liveblocks servers. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-core/package.json b/packages/liveblocks-core/package.json index 19c559f634..dffff217e0 100644 --- a/packages/liveblocks-core/package.json +++ b/packages/liveblocks-core/package.json @@ -47,6 +47,7 @@ "showdeps:high-level": "depcruise src --include-only '^src' --exclude='(^src/index.ts|shallow.ts|__tests__)' --collapse='^src/(refs|lib|compat|types|crdts|protocol)' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg" }, "license": "Apache-2.0", + "author": "Liveblocks Inc.", "devDependencies": { "@liveblocks/eslint-config": "*", "@liveblocks/query-parser": "^0.1.1", diff --git a/packages/liveblocks-emails/package.json b/packages/liveblocks-emails/package.json index 0d964f6eb4..77a5e837fe 100644 --- a/packages/liveblocks-emails/package.json +++ b/packages/liveblocks-emails/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A set of functions and utilities to make sending emails based on Liveblocks notification events easy. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-node-lexical/package.json b/packages/liveblocks-node-lexical/package.json index f063c18622..22846aa70d 100644 --- a/packages/liveblocks-node-lexical/package.json +++ b/packages/liveblocks-node-lexical/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A server-side utility that lets you modify lexical documents hosted in Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-node-prosemirror/package.json b/packages/liveblocks-node-prosemirror/package.json index c265ae6f0b..09a70467c8 100644 --- a/packages/liveblocks-node-prosemirror/package.json +++ b/packages/liveblocks-node-prosemirror/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A server-side utility that lets you modify prosemirror and tiptap documents hosted in Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-node/package.json b/packages/liveblocks-node/package.json index 9fbdb53a8b..8d36871531 100644 --- a/packages/liveblocks-node/package.json +++ b/packages/liveblocks-node/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A server-side utility that lets you set up a Liveblocks authentication endpoint. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-react-blocknote/package.json b/packages/liveblocks-react-blocknote/package.json index 034f64bf88..11e273cb96 100644 --- a/packages/liveblocks-react-blocknote/package.json +++ b/packages/liveblocks-react-blocknote/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "An integration of BlockNote + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-react-lexical/package.json b/packages/liveblocks-react-lexical/package.json index 6d6711cc3f..932508bf9f 100644 --- a/packages/liveblocks-react-lexical/package.json +++ b/packages/liveblocks-react-lexical/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "An integration of Lexical + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-react-tiptap/package.json b/packages/liveblocks-react-tiptap/package.json index 888dbe7327..0bb303cbd3 100644 --- a/packages/liveblocks-react-tiptap/package.json +++ b/packages/liveblocks-react-tiptap/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "An integration of TipTap + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-react-ui/package.json b/packages/liveblocks-react-ui/package.json index 8c9f470d07..5aae47975f 100644 --- a/packages/liveblocks-react-ui/package.json +++ b/packages/liveblocks-react-ui/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-react/package.json b/packages/liveblocks-react/package.json index 4b2f85cd80..ebd2193ff5 100644 --- a/packages/liveblocks-react/package.json +++ b/packages/liveblocks-react/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A set of React hooks and providers to use Liveblocks declaratively. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-redux/package.json b/packages/liveblocks-redux/package.json index 6243928370..5598f39e5c 100644 --- a/packages/liveblocks-redux/package.json +++ b/packages/liveblocks-redux/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A store enhancer to integrate Liveblocks into Redux stores. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-yjs/package.json b/packages/liveblocks-yjs/package.json index dc64b8fc60..ab9edcc15d 100644 --- a/packages/liveblocks-yjs/package.json +++ b/packages/liveblocks-yjs/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "Integrate your existing or new Yjs documents with Liveblocks.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/packages/liveblocks-zustand/package.json b/packages/liveblocks-zustand/package.json index c85e1b88ab..5c53eb3e2e 100644 --- a/packages/liveblocks-zustand/package.json +++ b/packages/liveblocks-zustand/package.json @@ -3,6 +3,7 @@ "version": "3.14.0", "description": "A middleware for Zustand to automatically synchronize your stores with Liveblocks. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", diff --git a/tools/create-liveblocks-app/package.json b/tools/create-liveblocks-app/package.json index 6aa3d1c9ea..ab4ba015de 100644 --- a/tools/create-liveblocks-app/package.json +++ b/tools/create-liveblocks-app/package.json @@ -3,6 +3,7 @@ "version": "2.20240816.0", "description": "An installer for Liveblocks projects, including various examples and a Next.js starter kit. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "bin": "dist/index.cjs", "type": "module", "scripts": { diff --git a/tools/liveblocks-codemod/package.json b/tools/liveblocks-codemod/package.json index 87386d55b8..bd47c06670 100644 --- a/tools/liveblocks-codemod/package.json +++ b/tools/liveblocks-codemod/package.json @@ -3,6 +3,7 @@ "version": "2.20240816.0", "description": "Codemods for updating Liveblocks apps.", "license": "Apache-2.0", + "author": "Liveblocks Inc.", "bin": "dist/bin/liveblocks-codemod.js", "files": [ "dist/**", diff --git a/tools/liveblocks-devtools/package.json b/tools/liveblocks-devtools/package.json index 3b04b48793..870e3b9673 100644 --- a/tools/liveblocks-devtools/package.json +++ b/tools/liveblocks-devtools/package.json @@ -4,6 +4,7 @@ "private": true, "displayName": "Liveblocks DevTools", "description": "A browser extension that lets you inspect Liveblocks real-time collaborative experiences. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.", + "author": "Liveblocks Inc.", "homepage": "https://liveblocks.io", "scripts": { "dev": "plasmo dev --build-path=dist", From 3d0a94e067478d601382c21e3b1f9c70dcbf47ef Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Wed, 25 Feb 2026 11:49:08 +0000 Subject: [PATCH 3/3] Fix starter kit issues (#3113) --- .../components/Inbox/InboxPopover.tsx | 7 ++++++- .../lib/actions/authorizeLiveblocks.ts | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/starter-kits/nextjs-starter-kit/components/Inbox/InboxPopover.tsx b/starter-kits/nextjs-starter-kit/components/Inbox/InboxPopover.tsx index 773b5625be..a602b264ca 100644 --- a/starter-kits/nextjs-starter-kit/components/Inbox/InboxPopover.tsx +++ b/starter-kits/nextjs-starter-kit/components/Inbox/InboxPopover.tsx @@ -24,7 +24,12 @@ export function InboxPopover( content={} {...props} > - diff --git a/starter-kits/nextjs-starter-kit/lib/actions/authorizeLiveblocks.ts b/starter-kits/nextjs-starter-kit/lib/actions/authorizeLiveblocks.ts index aa22c3a144..6fca822123 100644 --- a/starter-kits/nextjs-starter-kit/lib/actions/authorizeLiveblocks.ts +++ b/starter-kits/nextjs-starter-kit/lib/actions/authorizeLiveblocks.ts @@ -1,7 +1,7 @@ "use server"; import { auth } from "@/auth"; -import { ANONYMOUS_USER_ID } from "@/constants"; +import { ANONYMOUS_USER_ID, DEFAULT_ORGANIZATION_ID } from "@/constants"; import { liveblocks } from "@/liveblocks.server.config"; import { User } from "@/types"; @@ -9,7 +9,7 @@ export async function authorizeLiveblocks( /* `undefined` means this call is for a project-level feature, e.g. Notifications */ roomId: string | undefined ) { - // Get current session from NextAuth + // Get current session from NextAuth, and the current room, if provided const [session, room] = await Promise.all([ auth(), roomId ? liveblocks.getRoom(roomId) : null, @@ -36,13 +36,18 @@ export async function authorizeLiveblocks( { userId: id, - // Permissions in this app use groupIds to determine access to rooms - // so we pass the current organizationId if it exists + // Permissions in this app use `groupIds` to determine organization access to + // rooms, so we pass the current `organizationId` if it exists groupIds: currentOrganizationId ? [currentOrganizationId] : [], - // Always pass the organizationId for the current room, otherwise - // anonymous users will not be able to join - organizationId: room?.organizationId ?? undefined, + // Pass the `organizationId` for the current room, otherwise anonymous/other-org + // users will not be able to join. This also means their inbox will + // match the current room's organization. If not inside a room, pass the + // current organization instead, so their inbox matches the current page. + organizationId: + room?.organizationId ?? + currentOrganizationId ?? + DEFAULT_ORGANIZATION_ID, }, { userInfo: { name, color, avatar },