From f30181ca4ec850c20879864a2f25bdc2466411c6 Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Wed, 8 Apr 2026 11:34:46 +0200 Subject: [PATCH 1/6] Release 3.18 (#3311) For full upgrade instructions, see the [3.18 upgrade guide](https://liveblocks.io/docs/platform/upgrading/3.18). ### `@liveblocks/client` - **Breaking:** `useStorage` now returns plain objects for `LiveMap` values instead of `Map` instances. Legacy APIs have been removed: `.toImmutable()`, `.toObject()`, `.toArray()`. - New `.toJSON()` on all Live structures, returning a cached JSON-compatible snapshot. `JSON.stringify(root)` now just works. - New `LiveObject.from(obj)` to create a LiveObject from plain JSON, recursively converting nested objects/arrays to Live structures. - New `.reconcile(obj)` to efficiently reconcile a LiveObject tree to match a JSON snapshot, only mutating what changed. - `initialStorage` accepts `LiveObject.from()` result directly. ### `@liveblocks/react-flow/node` - New `mutateFlow()` API for reading and mutating React Flow data from a Node.js backend. Install via `npm i @liveblocks/react-flow`, import from `@liveblocks/react-flow/node`. ### `@liveblocks/react-ui` - Add standalone `Avatar` component to complement `AvatarStack` for more fine-grained customization. - Add `variant` prop to `AvatarStack` to support outlined avatars. ### `@liveblocks/zustand` and `@liveblocks/redux` - Fix: Initial storage seeding no longer creates an undo frame. - Fix: Presence updates are now batched with storage updates. Co-authored-by: Marc Bouchenoire --- CHANGELOG.md | 35 + CLAUDE.md | 14 + .../pages/api-reference/liveblocks-client.mdx | 226 +-- .../api-reference/liveblocks-react-flow.mdx | 324 ++++- .../api-reference/liveblocks-react-ui.mdx | 72 + docs/pages/api-reference/liveblocks-react.mdx | 2 +- docs/pages/upgrading.mdx | 6 + docs/pages/upgrading/3.18.mdx | 152 ++ e2e/next-sandbox/pages/batching.tsx | 8 +- e2e/next-sandbox/pages/storage/map.tsx | 8 +- e2e/next-sandbox/pages/storage/object.tsx | 5 +- .../pages/storage/stress/[roomId]/index.tsx | 24 +- e2e/next-sandbox/test/zustand-kanban.test.ts | 2 +- e2e/next-sandbox/utils/index.tsx | 4 +- e2e/node-sandbox/turbo.json | 2 + .../app/flowchart/agent.ts | 763 +++++----- .../app/flowchart/shared.ts | 42 +- .../nextjs-react-flow-ai/package-lock.json | 68 +- examples/nextjs-react-flow-ai/package.json | 10 +- package-lock.json | 13 + packages/liveblocks-client/src/index.ts | 4 +- .../liveblocks-core/e2e/list-property.test.ts | 4 +- .../liveblocks-core/e2e/list-single.test.ts | 11 +- .../liveblocks-core/e2e/map-single.test.ts | 11 +- packages/liveblocks-core/e2e/map.test.ts | 19 +- packages/liveblocks-core/e2e/utils.ts | 24 +- packages/liveblocks-core/settings.json | 10 +- .../__tests__/_MockWebSocketServer.setup.ts | 17 +- .../src/__tests__/_devserver.ts | 21 +- .../src/__tests__/_updatesUtils.ts | 28 +- .../src/__tests__/immutable.test.ts | 1262 ++--------------- .../src/__tests__/room.devserver.test.ts | 29 +- .../src/__tests__/room.mockserver.test.ts | 29 +- .../src/__tests__/sync-config.test.ts | 45 +- packages/liveblocks-core/src/client.ts | 16 +- .../liveblocks-core/src/crdts/AbstractCrdt.ts | 43 +- .../liveblocks-core/src/crdts/LiveList.ts | 133 +- packages/liveblocks-core/src/crdts/LiveMap.ts | 19 +- .../liveblocks-core/src/crdts/LiveObject.ts | 83 +- .../liveblocks-core/src/crdts/LiveRegister.ts | 5 +- packages/liveblocks-core/src/crdts/Lson.ts | 34 +- .../__tests__/LiveList.devserver.test.ts | 50 +- .../crdts/__tests__/LiveMap.devserver.test.ts | 111 +- .../__tests__/LiveObject.devserver.test.ts | 56 +- .../src/crdts/__tests__/_arbitraries.ts | 30 +- .../src/crdts/__tests__/cloning.test.ts | 6 +- .../src/crdts/__tests__/doc.test.ts | 4 +- .../__tests__/liveblocks-helpers.test.ts | 31 +- .../src/crdts/liveblocks-helpers.ts | 63 - .../liveblocks-core/src/crdts/reconcile.ts | 27 +- packages/liveblocks-core/src/crdts/utils.ts | 57 +- packages/liveblocks-core/src/immutable.ts | 424 +----- packages/liveblocks-core/src/index.ts | 15 +- packages/liveblocks-core/src/lib/Json.ts | 15 + .../liveblocks-core/src/types/Immutable.ts | 2 +- .../src/__tests__/client.test.ts | 4 +- packages/liveblocks-node/src/client.ts | 26 +- .../test-d/no-augmentation.test-d.ts | 4 +- .../check-node-entrypoint.mjs | 54 + packages/liveblocks-react-flow/package.json | 18 + .../liveblocks-react-flow/rollup.config.js | 2 +- .../src/__tests__/flow.test.tsx | 2 +- .../mutate-flow-from-backend.test.ts | 937 ++++++++++++ .../liveblocks-react-flow/src/constants.ts | 41 - packages/liveblocks-react-flow/src/helpers.ts | 67 - packages/liveblocks-react-flow/src/index.ts | 7 +- .../src/{ => lib}/flow.ts | 103 +- .../liveblocks-react-flow/src/lib/shared.ts | 108 ++ .../src/{ => lib}/types.ts | 2 +- .../src/{ => lib}/version.ts | 0 packages/liveblocks-react-flow/src/node.ts | 294 ++++ .../test-d/mutate-flow.test-d.ts | 145 ++ .../src/mentions/mention-plugin.tsx | 7 +- .../src/mentions/MentionsList.tsx | 7 +- .../liveblocks-react-ui/src/_private/index.ts | 2 +- .../src/components/Avatar.tsx | 246 ++++ .../src/components/AvatarStack.tsx | 126 +- .../src/components/Comment.tsx | 6 +- .../src/components/CommentPin.tsx | 4 +- .../src/components/Composer.tsx | 6 +- .../src/components/InboxNotification.tsx | 4 +- .../src/components/internal/Avatar.tsx | 94 -- .../src/components/internal/User.tsx | 51 +- packages/liveblocks-react-ui/src/index.ts | 2 + .../liveblocks-react-ui/src/styles/index.css | 21 + .../src/utils/use-user-or-group-info.ts | 86 -- packages/liveblocks-react/src/room.tsx | 105 +- packages/liveblocks-react/src/types/index.ts | 13 +- .../test-d/factories.test-d.tsx | 6 +- .../src/__tests__/index.test.ts | 17 + packages/liveblocks-redux/src/index.ts | 128 +- .../src/__tests__/index.test.ts | 21 +- packages/liveblocks-zustand/src/index.ts | 130 +- 93 files changed, 4029 insertions(+), 3385 deletions(-) create mode 100644 docs/pages/upgrading/3.18.mdx create mode 100644 packages/liveblocks-react-flow/check-node-entrypoint.mjs create mode 100644 packages/liveblocks-react-flow/src/__tests__/mutate-flow-from-backend.test.ts delete mode 100644 packages/liveblocks-react-flow/src/constants.ts delete mode 100644 packages/liveblocks-react-flow/src/helpers.ts rename packages/liveblocks-react-flow/src/{ => lib}/flow.ts (87%) create mode 100644 packages/liveblocks-react-flow/src/lib/shared.ts rename packages/liveblocks-react-flow/src/{ => lib}/types.ts (98%) rename packages/liveblocks-react-flow/src/{ => lib}/version.ts (100%) create mode 100644 packages/liveblocks-react-flow/src/node.ts create mode 100644 packages/liveblocks-react-flow/test-d/mutate-flow.test-d.ts create mode 100644 packages/liveblocks-react-ui/src/components/Avatar.tsx delete mode 100644 packages/liveblocks-react-ui/src/components/internal/Avatar.tsx delete mode 100644 packages/liveblocks-react-ui/src/utils/use-user-or-group-info.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d0ef322407..0b421a869dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ ## vNEXT (not yet released) +## v3.18.0 + +For full upgrade instructions, see the +[3.18 upgrade guide](https://liveblocks.io/docs/platform/upgrading/3.18). + +### `@liveblocks/client` + +- **Breaking:** `useStorage` now returns plain objects for `LiveMap` values + instead of `Map` instances. Legacy APIs have been removed: `.toImmutable()`, + `.toObject()`, `.toArray()`. +- New `.toJSON()` on all Live structures, returning a cached JSON-compatible + snapshot. `JSON.stringify(root)` now just works. +- New `LiveObject.from(obj)` to create a LiveObject from plain JSON, recursively + converting nested objects/arrays to Live structures. +- New `.reconcile(obj)` to efficiently reconcile a LiveObject tree to match a + JSON snapshot, only mutating what changed. +- `initialStorage` accepts `LiveObject.from()` result directly. + +### `@liveblocks/react-flow/node` + +- New `mutateFlow()` API for reading and mutating React Flow data from a Node.js + backend. Install via `npm i @liveblocks/react-flow`, import from + `@liveblocks/react-flow/node`. + +### `@liveblocks/react-ui` + +- Add standalone `Avatar` component to complement `AvatarStack` for more + fine-grained customization. +- Add `variant` prop to `AvatarStack` to support outlined avatars. + +### `@liveblocks/zustand` and `@liveblocks/redux` + +- Fix: Initial storage seeding no longer creates an undo frame. +- Fix: Presence updates are now batched with storage updates. + ## v3.17.0 ### `@liveblocks/react-flow` diff --git a/CLAUDE.md b/CLAUDE.md index 24c1f976c2b..b7723d4982d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,10 +47,24 @@ When running scripts, use `npx turbo`, not `npm`. Run e2e tests headlessly using Playwright: npx turbo build && env HEADLESS=1 playwright test --retries=5 -- +# Examples + +Examples live in the `examples/` directory but are NOT part of the monorepo +workspace. They depend on the latest _published_ version of Liveblocks packages, +not on the local source. You cannot test examples against local changes. They +need to be updated separately when a new version is published. + # Documentation All documentation lives in the `docs/` directory, as Markdown files. +# Changelog + +CHANGELOG.md entries should use public-facing package names as subheadings (e.g. +``### `@liveblocks/client` `` or ``### `@liveblocks/react` ``), not generic +categories like "Breaking changes" or "New features". Avoid referencing +`@liveblocks/core` — it is not a public-facing package. + # Packages maintained elsewhere The following packages are primarily maintained from our backend monorepo for diff --git a/docs/pages/api-reference/liveblocks-client.mdx b/docs/pages/api-reference/liveblocks-client.mdx index 4817b3b2948..d9c59ab44c8 100644 --- a/docs/pages/api-reference/liveblocks-client.mdx +++ b/docs/pages/api-reference/liveblocks-client.mdx @@ -2558,12 +2558,12 @@ room.batch(() => { }); // { name: "Felix", age: 10 } -pet.toImmutable(); +pet.toJSON(); room.history.undo(); // { name: "Fido", age: 5 } -pet.toImmutable(); +pet.toJSON(); ``` #### Doesn’t work with async functions @@ -4520,6 +4520,41 @@ JSON-serializable data. If multiple clients update the same property simultaneously, the last modification received by the Liveblocks servers is the winner. +### LiveObject.from [#LiveObject.from] + +Creates a new `LiveObject` from a plain JSON object, recursively converting +nested objects to `LiveObject` instances and arrays to `LiveList` instances. + +```ts +const liveObject = LiveObject.from({ + name: "Grace", + hobbies: ["reading", "piano"], + address: { city: "New York", zip: "10001" }, +}); +``` + +This is equivalent to writing: + +```ts +const liveObject = new LiveObject({ + name: "Grace", + hobbies: new LiveList(["reading", "piano"]), + address: new LiveObject({ city: "New York", zip: "10001" }), +}); +``` + + + + A new `LiveObject` with deeply converted children. + + + + + + A plain JSON object to convert into a `LiveObject`. + + + ### new LiveObject [#LiveObject.constructor] Create an empty `LiveObject` @@ -4575,7 +4610,7 @@ const object = new LiveObject({ firstName: "Ada", lastName: "Lovelace" }); object.delete("lastName"); // { firstName: "Ada" } -object.toImmutable(); +object.toJSON(); ``` _Nothing_ @@ -4619,7 +4654,7 @@ const object = new LiveObject({ firstName: "Marie" }); object.set("lastName", "Curie"); // { firstName: "Ada", lastName: "Curie" } -object.toImmutable(); +object.toJSON(); ``` _Nothing_ @@ -4644,7 +4679,7 @@ const object = new LiveObject({ firstName: "Grace" }); object.update({ lastName: "Hopper", job: "Computer Scientist" }); // { firstName: "Grace", lastName: "Hopper", job: "Computer Scientist" } -object.toImmutable(); +object.toJSON(); ``` _Nothing_ @@ -4676,12 +4711,12 @@ root.set("b", obj.clone()); _None_ -### toImmutable [#LiveObject.toImmutable] +### toJSON [#LiveObject.toJSON] -Returns an immutable JavaScript object that is equivalent to the `LiveObject`. -Nested values will also be immutable. Calling this method multiple times has no -performance penalty. It will return the same cached immutable value as long as -its (nested) contents have not changed. +Returns a JSON-compatible snapshot of this `LiveObject` and all its nested +children. `LiveObject` values become plain objects, `LiveList` values become +arrays, and `LiveMap` values also become plain objects (not `Map` instances). +The result is cached and only recomputed when the contents change. ```ts const liveObject = new LiveObject({ @@ -4690,51 +4725,62 @@ const liveObject = new LiveObject({ hobbies: new LiveList(["reading", "piano"]), }); -// { -// firstName: "Grace", -// lastName: "Hopper", -// hobbies: ["reading", "piano"] -// } -liveObject.toImmutable(); +// { firstName: "Grace", lastName: "Hopper", hobbies: ["reading", "piano"] } +liveObject.toJSON(); ``` - - Returns a JavaScript object in the shape of your data structure. - `LiveObject` is converted to an object, `LiveMap` to a map, and `LiveList` - to an array. + + A plain JSON-compatible object. Always serializable — `JSON.stringify()` + works out of the box. _None_ -### toObject [#LiveObject.toObject] +### reconcile [#LiveObject.reconcile] - +Reconciles this `LiveObject` tree to match the given JSON object. Only mutates +keys that actually changed. Keys present on this `LiveObject` but absent from +the input will be deleted. Nested structures are recursively reconciled. -Starting with 0.18, we recommend [`toImmutable`][] instead. It’s faster, cached, -and leads to fewer surprises. +```ts +const liveObject = new LiveObject({ + name: "Grace", + age: 85, + nested: new LiveObject({ x: 1, y: 2 }), +}); + +// Updates nested.y, deletes age (absent from input) +liveObject.reconcile({ name: "Grace", nested: { x: 1, y: 99 } }); +``` + +_Nothing_ + + + + The target state to reconcile towards. Missing keys will be deleted. + + + +### toImmutable [#LiveObject.toImmutable] + + + +This method has been replaced by [`.toJSON()`](#LiveObject.toJSON), which +returns plain objects instead of `Map` instances for `LiveMap` values, making +the result always valid JSON. Please migrate to `.toJSON()`. -Transform the `LiveObject` into a normal JavaScript object. +### toObject [#LiveObject.toObject] -```ts -const liveObject = new LiveObject({ firstName: "Grace", lastName: "Hopper" }); -liveObject.toObject(); -// { firstName: "Grace", lastName: "Hopper" } -``` + -Please note that this method won’t recursively convert Live structures, which -may be surprising: +Use `.toJSON()` instead. It’s faster, cached, and deeply converts all nested +Live structures. -```ts -const liveObject = new LiveObject({ - animals: new LiveList(["🦁", "🦊", "🐵"]), -}); -liveObject.toObject(); -// { animals: } // ❗️ -``` + ## LiveMap @@ -4821,7 +4867,7 @@ const map = new LiveMap([ map.delete("nimesh"); // Map { "pierre" => "designer" } -map.toImmutable(); +map.toJSON(); ``` @@ -4989,7 +5035,7 @@ const map = new LiveMap(); map.set("vincent", "engineer"); // Map { "vincent" => "engineer" } -map.toImmutable(); +map.toJSON(); ``` _Nothing_ @@ -5075,12 +5121,12 @@ root.set("b", map.clone()); _None_ -### toImmutable [#LiveMap.toImmutable] +### toJSON [#LiveMap.toJSON] -Returns an immutable ES6 Map that is equivalent to the `LiveMap`. Nested values -will also be immutable. Calling this method multiple times has no performance -penalty. It will return the same cached immutable value as long as its (nested) -contents have not changed. +Returns a JSON-compatible snapshot of this `LiveMap` and all its nested +children. `LiveObject` values become plain objects, `LiveList` values become +arrays, and `LiveMap` values also become plain objects (not `Map` instances). +The result is cached and only recomputed when the contents change. ```ts const map = new LiveMap([ @@ -5088,23 +5134,28 @@ const map = new LiveMap([ ["marc", new LiveObject({ role: "designer" })], ]); -// Map { -// "florent" => { role: "engineer" }, -// "marc" => { role: "designer" }, -// } -map.toImmutable(); +// { florent: { role: "engineer" }, marc: { role: "designer" } } +map.toJSON(); ``` - - Returns a JavaScript object in the shape of your data structure. `LiveMap` - is converted to a map, `LiveObject` to an object, and `LiveList` to an - array. + + A plain JSON-compatible object with string keys. _None_ +### toImmutable [#LiveMap.toImmutable] + + + +This method has been replaced by [`.toJSON()`](#LiveMap.toJSON), which returns +plain objects instead of `Map` instances, making the result always valid JSON. +Please migrate to `.toJSON()`. + + + ## LiveList The `LiveList` class represents an ordered collection of items that is @@ -5157,7 +5208,7 @@ const list = new LiveList(["adrien", "jonathan"]); list.clear(); // [] -list.toImmutable(); +list.toJSON(); ``` _Nothing_ @@ -5174,7 +5225,7 @@ const list = new LiveList(["adrien", "jonathan"]); list.delete(0); // ["jonathan"] -list.toImmutable(); +list.toJSON(); ``` This operation uses ID-based semantics, not position-based. When called, it @@ -5413,7 +5464,7 @@ const list = new LiveList(["adrien", "jonathan"]); list.insert("chris", 1); // ["adrien", "chris", "jonathan"] -list.toImmutable(); +list.toJSON(); ``` _Nothing_ @@ -5518,7 +5569,7 @@ const list = new LiveList(["adrien", "chris", "jonathan"]); list.move(2, 0); // ["jonathan", "adrien", "chris"] -list.toImmutable(); +list.toJSON(); ``` _Nothing_ @@ -5542,7 +5593,7 @@ const list = new LiveList(["adrien", "jonathan"]); list.push("chris"); // ["adrien", "jonathan", "chris"] -list.toImmutable(); +list.toJSON(); ``` _Nothing_ @@ -5563,7 +5614,7 @@ const list = new LiveList(["adrien", "jonathan"]); list.set(1, "chris"); // equals ["adrien", "chris"] -list.toImmutable(); +list.toJSON(); ``` ### some [#LiveList.some] @@ -5618,12 +5669,12 @@ root.set("b", list.clone()); _None_ -### toImmutable [#LiveList.toImmutable] +### toJSON [#LiveList.toJSON] -Returns an immutable JavaScript array that is equivalent to the `LiveList`. -Nested values will also be immutable. Calling this method multiple times has no -performance penalty. It will return the same cached immutable value as long as -its (nested) contents have not changed. +Returns a JSON-compatible snapshot of this `LiveList` and all its nested +children. `LiveObject` values become plain objects, `LiveList` values become +arrays, and `LiveMap` values also become plain objects (not `Map` instances). +The result is cached and only recomputed when the contents change. ```ts const list = new LiveList([ @@ -5631,49 +5682,37 @@ const list = new LiveList([ new LiveObject({ name: "Vincent" }), ]); -// [ -// { name: "Olivier" }, -// { name: "Vincent" }, -// ] -list.toImmutable(); +// [{ name: "Olivier" }, { name: "Vincent" }] +list.toJSON(); ``` - - Returns a JavaScript object in the shape of your data structure. `ListList` - is converted to an array, `LiveObject` to an object, and `LiveMap` to a map. + + A plain JSON-compatible array. Always serializable — `JSON.stringify()` + works out of the box. _None_ -### toArray [#LiveList.toArray] +### toImmutable [#LiveList.toImmutable] - + -Starting with 0.18, we recommend [`toImmutable`][] instead. It’s faster, cached, -and leads to fewer surprises. +This method has been replaced by [`.toJSON()`](#LiveList.toJSON), which returns +plain objects instead of `Map` instances for `LiveMap` values, making the result +always valid JSON. Please migrate to `.toJSON()`. -Transforms the `LiveList` into a normal JavaScript array. +### toArray [#LiveList.toArray] -```ts -const list = new LiveList(["🦁", "🦊", "🐵"]); -list.toArray(); -// ["🦁", "🦊", "🐵"] -``` + -Please note that this method won’t recursively convert Live structures, which -may be surprising: +Use [`.toJSON()`](#LiveList.toJSON) instead. It’s faster, cached, and deeply +converts all nested Live structures. -```ts -const list = new LiveList([ - new LiveObject({ firstName: "Grace", lastName: "Hopper" }), -]); -list.toArray(); -// [ ] // ❗️ -``` + ## Resolvers @@ -6289,7 +6328,6 @@ const user = room.getSelf(); [`liveobject`]: /docs/api-reference/liveblocks-client#LiveObject [`lostconnectiontimeout`]: /docs/api-reference/liveblocks-client#createClientLostConnectionTimeout -[`toimmutable`]: /docs/api-reference/liveblocks-client#LiveObject.toImmutable [`node-fetch`]: https://npmjs.com/package/node-fetch [`room.broadcastevent`]: /docs/api-reference/liveblocks-client#Room.broadcastEvent diff --git a/docs/pages/api-reference/liveblocks-react-flow.mdx b/docs/pages/api-reference/liveblocks-react-flow.mdx index 53dc30f42e1..bb1d3b87c12 100644 --- a/docs/pages/api-reference/liveblocks-react-flow.mdx +++ b/docs/pages/api-reference/liveblocks-react-flow.mdx @@ -236,8 +236,8 @@ export function App() { config](#sync-config). - The key used to store the diagram in Liveblocks Storage. Defaults to - `"flow"`. See [`storageKey`](#storageKey). + The key used to store the flow in Liveblocks Storage. Defaults to `"flow"`. + See [`storageKey`](#storageKey). When `true`, suspends until the diagram is ready. Learn more about this in @@ -688,3 +688,323 @@ function Flow() { Override the component’s components. + +## Updating your Flow from the server [#server-side] + +To update a React Flow from your Node.js back-end, use `mutateFlow`. + +```tsx +import { Liveblocks } from "@liveblocks/node"; +// +++ +import { mutateFlow } from "@liveblocks/react-flow/node"; +// ~~~~ +// +++ + +const client = new Liveblocks({ + secret: "sk_prod_xxxxxxxxxxxxxxxxxxxxxxxx", +}); + +await mutateFlow( + { client, roomId: "my-room-id" }, + + (flow) => { + flow.addNode({ + id: "1", + position: { x: 0, y: 0 }, + data: { label: "Hello" }, + }); + flow.addNode({ + id: "2", + position: { x: 100, y: 100 }, + data: { label: "World" }, + }); + flow.addEdge({ id: "e1-2", source: "1", target: "2" }); + } +); +``` + +```bash +npm install @liveblocks/node @liveblocks/react-flow +``` + +### mutateFlow [#mutateFlow] + +`mutateFlow` opens a room’s flow for reading and mutating. A "flow" is a +collection of nodes and edges stored in Liveblocks Storage. By default, your +flow gets persisted in the Room’s Storage under the top-level key `"flow"`, but +you can change this with the `storageKey` option. + + + Even though internally `mutateFlow` uses Liveblocks Storage and its primitives + like LiveObjects, LiveLists, and LiveMaps, you don’t need to work with those + directly. You just work with React Flow nodes and edges as you normally would, + and they get intelligently stored and synchronized via Live structures in the + most efficient manner. + + + + + A [Liveblocks Node + client](/docs/api-reference/liveblocks-node#Liveblocks-client) instance. + + + The ID of the room whose flow to mutate. + + + The key used to store the flow in Liveblocks Storage. Defaults to `"flow"`. + Must match the [`storageKey`](#storageKey) used on the client. + + + Per-type sync configuration for node `data` keys. Must match the [sync + config](#sync-config) used on the client. + + + Per-type sync configuration for edge `data` keys. Must match the [sync + config](#sync-config) used on the client. + + + +### Custom node and edge types [#mutateFlow-custom-types] + +Pass your custom `Node` and `Edge` types as type parameters to get full type +safety. + +```ts +import type { Node, Edge } from "@xyflow/react"; +import { mutateFlow } from "@liveblocks/react-flow/node"; + +type TaskNode = Node<{ title: string; priority: number }, "task">; +type CustomEdge = Edge<{ weight: number }, "weighted">; + +// +++ +await mutateFlow( + // +++ + { client: liveblocks, roomId: "my-room-id" }, + (flow) => { + // flow.addNode, flow.updateNodeData, etc. are fully typed + flow.addNode({ + id: "t1", + type: "task", + position: { x: 0, y: 0 }, + data: { title: "Ship it", priority: 1 }, + }); + } +); +``` + +### MutableFlow API [#mutable-flow] + +The callback receives a `MutableFlow` instance. All reads reflect mutations made +earlier in the same callback. + +#### flow.nodes + +Returns the current list of nodes as a readonly array. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + const allNodes = flow.nodes; // readonly Node[] +}); +``` + +#### flow.edges + +Returns the current list of edges as a readonly array. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + const allEdges = flow.edges; // readonly Edge[] +}); +``` + +#### flow.toJSON + +Returns a plain object with `nodes` and `edges` arrays. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + const snapshot = flow.toJSON(); + // { nodes: [...], edges: [...] } +}); +``` + +#### flow.getNode + +Returns a single node by ID, or `undefined` if not found. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + const node = flow.getNode("n1"); +}); +``` + +#### flow.getEdge + +Returns a single edge by ID, or `undefined` if not found. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + const edge = flow.getEdge("e1"); +}); +``` + +#### flow.addNode / flow.addNodes + +Adds one or more nodes. If a node with the same ID already exists, it is +replaced. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "1", + position: { x: 0, y: 0 }, + data: { label: "A" }, + }); + + flow.addNodes([ + { id: "2", position: { x: 100, y: 0 }, data: { label: "B" } }, + { id: "3", position: { x: 200, y: 0 }, data: { label: "C" } }, + ]); +}); +``` + +#### flow.updateNode + +Updates a node by ID. Accepts a partial object to merge, or an updater function. +No-op if the node does not exist. + +When using an updater function, always return a new object. Never mutate the +provided value in-place. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + // With a partial object + flow.updateNode("1", { position: { x: 100, y: 200 } }); + + // With an updater function + flow.updateNode("1", (node) => ({ + ...node, + position: { x: node.position.x + 10, y: node.position.y }, + })); +}); +``` + +#### flow.updateNodeData + +Updates only a node’s `data` by ID. Accepts a partial object to merge, or an +updater function. No-op if the node does not exist. + +When using an updater function, always return a new object. Never mutate the +provided value in-place. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + // Merge partial data + flow.updateNodeData("1", { label: "Updated" }); + + // With an updater function + flow.updateNodeData("1", (data) => ({ + ...data, + color: "red", + })); +}); +``` + +#### flow.removeNode / flow.removeNodes + +Removes one or more nodes by ID. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + flow.removeNode("1"); + flow.removeNodes(["2", "3"]); +}); +``` + +#### flow.addEdge / flow.addEdges + +Adds one or more edges. If an edge with the same ID already exists, it is +replaced. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1-2", source: "1", target: "2" }); + + flow.addEdges([ + { id: "e2-3", source: "2", target: "3" }, + { id: "e3-4", source: "3", target: "4" }, + ]); +}); +``` + +#### flow.updateEdge + +Updates an edge by ID. Accepts a partial object to merge, or an updater +function. No-op if the edge does not exist. + +When using an updater function, always return a new object. Never mutate the +provided value in-place. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + // With a partial object + flow.updateEdge("e1-2", { label: "My edge" }); + + // With an updater function + flow.updateEdge("e1-2", (edge) => ({ + ...edge, + label: "Updated", + })); +}); +``` + +#### flow.updateEdgeData + +Updates only an edge’s `data` by ID. Accepts a partial object to merge, or an +updater function. No-op if the edge does not exist. + +When using an updater function, always return a new object. Never mutate the +provided value in-place. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + // Merge partial data + flow.updateEdgeData("e1-2", { weight: 5 }); + + // With an updater function + flow.updateEdgeData("e1-2", (data) => ({ + ...data, + color: "red", + })); +}); +``` + +#### flow.removeEdge / flow.removeEdges + +Removes one or more edges by ID. + +```ts +await mutateFlow({ client, roomId }, (flow) => { + flow.removeEdge("e1-2"); + flow.removeEdges(["e2-3", "e3-4"]); +}); +``` + +### How mutations are flushed [#mutateFlow-flushing] + +The [`mutateFlow`][] function is built on top of [`Liveblocks.mutateStorage`][], +but rather than giving you access to the Liveblocks Storage root directly, it +gives you a convenient API tailored to React Flow—a `MutableFlow` instance you +can use to read or mutate your nodes and edges directly. + +Under the hood, everything still gets stored and synced efficiently via Live +structures (`LiveObject`, `LiveMap`, etc), but this is an implementation detail. + +Just like with [`Liveblocks.mutateStorage`][], your mutation callback can be +long-running. During its execution, any mutations you make will periodically get +flushed to the server in the background, and when your callback finishes, the +final state will be flushed before the promise returned by `mutateFlow` +resolves. + +[`mutateFlow`]: /docs/api-reference/liveblocks-react-flow#mutateFlow +[`Liveblocks.mutateStorage`]: /docs/api-reference/liveblocks-node#mutate-storage diff --git a/docs/pages/api-reference/liveblocks-react-ui.mdx b/docs/pages/api-reference/liveblocks-react-ui.mdx index 096e45619d9..63f6916796c 100644 --- a/docs/pages/api-reference/liveblocks-react-ui.mdx +++ b/docs/pages/api-reference/liveblocks-react-ui.mdx @@ -3754,6 +3754,64 @@ All hooks for Notifications are in ### Default components [#Presence-Components] +#### Avatar + +Displays a user avatar from an image URL, or falls back to initials. + +```tsx + +``` + +You can also customize fallback content by passing children. This will take +precedence over the default content. + +```tsx +{/* Custom icon */} +``` + +Use `outline` to add an outline around the avatar. + +```tsx + + + + + +``` + +Use `tooltip` to display additional content on hover. + +```tsx +stacy@example.com} /> +``` + +##### Props [#Avatar-props] + + + + The URL of the avatar’s image. + + + The name of the avatar. + + + Whether and how the avatar should have an outline. + + + The content to display in the avatar’s tooltip. + + + Override the avatar’s content. + + + #### AvatarStack Displays a stack of avatars for users currently present in the room. @@ -3792,6 +3850,13 @@ to change the avatars’ size. ``` +You can use the `variant` prop to switch between default and outlined avatars. +The outline color uses the resolved user’s `color` property by default. + +```tsx + +``` + ##### User information `AvatarStack` uses @@ -3838,6 +3903,13 @@ properties. The gap around the avatars. + + Whether the avatars should show an outline. + Override the component’s strings. diff --git a/docs/pages/api-reference/liveblocks-react.mdx b/docs/pages/api-reference/liveblocks-react.mdx index b27d3e66ea1..d21c281d696 100644 --- a/docs/pages/api-reference/liveblocks-react.mdx +++ b/docs/pages/api-reference/liveblocks-react.mdx @@ -3750,7 +3750,7 @@ const myTodos = useStorage( - + A selector function to extract specific data from the storage root. The root is an immutable copy of your entire Liveblocks Storage tree. diff --git a/docs/pages/upgrading.mdx b/docs/pages/upgrading.mdx index d49dbe9c7e6..9c69c1ef942 100644 --- a/docs/pages/upgrading.mdx +++ b/docs/pages/upgrading.mdx @@ -9,6 +9,12 @@ packages should be upgraded to the same version. If a version isn’t mentioned, there are no breaking changes. + 3.18} + /> root.myMap); +``` + +| ❌ Before | ✅ After | +| ----------------------------- | --------------------------- | +| `myMap.get("my-node")` | `myMap["my-node"]` | +| `myMap.has("my-node")` | `"my-node" in myMap` | +| `myMap.size` | `Object.keys(myMap).length` | +| `Array.from(myMap.keys())` | `Object.keys(myMap)` | +| `Array.from(myMap.values())` | `Object.values(myMap)` | +| `Array.from(myMap.entries())` | `Object.entries(myMap)` | + +Of course, if you prefer, you can still convert the plain object back to a `Map` +if your application requires it: + +```tsx +// Still possible, but not recommended +const myMap = useStorage((root) => root.myMap); +const myTrueMap = useMemo(() => new Map(Object.entries(myMap)), [myMap]); +``` + +## Removed .toImmutable() [#removed-toimmutable] + +`.toImmutable()` has been removed from all Live structures (`LiveObject`, +`LiveList`, `LiveMap`). Use `.toJSON()` instead, which returns a cached, +JSON-compatible snapshot. If you aren't using any `LiveMap`s in your +application, the results will be identical. + +```tsx +// ❌ Before +const snapshot = liveObject.toImmutable(); + +// ✅ After +const snapshot = liveObject.toJSON(); +``` + +## Removed .toObject() [#removed-toobject] + +`.toObject()` has been removed from `LiveObject`. Use `.toJSON()` or `.get(key)` +instead: + +```tsx +// ❌ Before +const obj = liveObject.toObject(); + +// ✅ After +const obj = liveObject.toJSON(); +// or access individual keys +const value = liveObject.get("key"); +``` + +## Removed .toArray() [#removed-toarray] + +`.toArray()` has been removed from `LiveList`. Use `.toJSON()` or iterate +directly: + +```tsx +// ❌ Before +const arr = liveList.toArray(); + +// ✅ After +const arr = liveList.toJSON(); +// or iterate directly +for (const item of liveList) { + // ... +} +``` + +## Removed ToImmutable type [#removed-toimmutable-type] + +The `ToImmutable` type has been removed. Use `ToJson` instead: + +```tsx +// ❌ Before +import type { ToImmutable } from "@liveblocks/client"; +type Snapshot = ToImmutable; + +// ✅ After +import type { ToJson } from "@liveblocks/client"; +type Snapshot = ToJson; +``` diff --git a/e2e/next-sandbox/pages/batching.tsx b/e2e/next-sandbox/pages/batching.tsx index a497bef01fa..6b1b058288b 100644 --- a/e2e/next-sandbox/pages/batching.tsx +++ b/e2e/next-sandbox/pages/batching.tsx @@ -106,8 +106,12 @@ function Sandbox() {

Storage

- - + +
diff --git a/e2e/next-sandbox/pages/storage/map.tsx b/e2e/next-sandbox/pages/storage/map.tsx index f27a8003c16..44171a0fe81 100644 --- a/e2e/next-sandbox/pages/storage/map.tsx +++ b/e2e/next-sandbox/pages/storage/map.tsx @@ -68,12 +68,12 @@ function Sandbox() { return
Loading...
; } - const canDelete = map.size > 0; + const keys = Object.keys(map); + const canDelete = keys.length > 0; const nextKey = `key:${randomInt(10)}`; const nextValue = `value:${randomInt(10)}`; - const keys = Array.from(map.keys()); const nextKeyToDelete = canDelete ? keys[randomInt(keys.length)] : ""; return ( @@ -120,8 +120,8 @@ function Sandbox() { name="Sync status (immediate)" value={syncStatus} /> - - + + diff --git a/e2e/next-sandbox/pages/storage/object.tsx b/e2e/next-sandbox/pages/storage/object.tsx index 9a514fa29df..cdcf8c559ce 100644 --- a/e2e/next-sandbox/pages/storage/object.tsx +++ b/e2e/next-sandbox/pages/storage/object.tsx @@ -1,5 +1,4 @@ import { LiveObject } from "@liveblocks/client"; -import { lsonToJson } from "@liveblocks/core"; import { createRoomContext } from "@liveblocks/react"; import { @@ -86,7 +85,7 @@ function Sandbox() { const clear = useMutation(({ storage }) => { const obj = storage.get("object"); - const keys = Object.keys(obj.toObject()); + const keys = Array.from(obj.keys()); let key; while ((key = keys.pop()) !== undefined) { obj.delete(key); @@ -181,7 +180,7 @@ function Sandbox() { name="Sync status (immediate)" value={syncStatus} /> - + diff --git a/e2e/next-sandbox/pages/storage/stress/[roomId]/index.tsx b/e2e/next-sandbox/pages/storage/stress/[roomId]/index.tsx index 2cc097ad8f1..26da41aebc3 100644 --- a/e2e/next-sandbox/pages/storage/stress/[roomId]/index.tsx +++ b/e2e/next-sandbox/pages/storage/stress/[roomId]/index.tsx @@ -29,14 +29,6 @@ const { useUndo, } = createRoomContext(client); -// JSON.stringify replacer to handle Map objects (LiveMap.toImmutable() returns Map) -function mapReplacer(_key: string, value: unknown): unknown { - if (value instanceof Map) { - return Object.fromEntries(value); - } - return value; -} - // Deterministic JSON stringify with sorted keys (for consistent hashing) function stableStringify(obj: unknown): string { return JSON.stringify(obj, (_key, value: unknown) => { @@ -146,7 +138,9 @@ function collectAttachmentPoints( if (value instanceof LiveObject) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment points.push({ type: "object", node: value as LiveObject }); - for (const child of Object.values(value.toObject())) { + for (const key of value.keys()) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const child = value.get(key); visit(child); } } else if (value instanceof LiveList) { @@ -164,7 +158,9 @@ function collectAttachmentPoints( } } - for (const child of Object.values(root.toObject())) { + for (const key of root.keys()) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const child = root.get(key); visit(child); } @@ -263,7 +259,7 @@ function Sandbox({ roomId }: { roomId: string }) { const point = points[randomInt(points.length)]; if (point.type === "object") { - const keys = Object.keys(point.node.toObject()); + const keys = Array.from(point.node.keys()); if (keys.length > 0) { point.node.delete(keys[randomInt(keys.length)]); deleted++; @@ -290,7 +286,7 @@ function Sandbox({ roomId }: { roomId: string }) { const point = points[randomInt(points.length)]; if (point.type === "object") { - const keys = Object.keys(point.node.toObject()); + const keys = Array.from(point.node.keys()); if (keys.length > 0 && Math.random() < 0.5) { // Change existing value to a string const key = keys[randomInt(keys.length)]; @@ -329,7 +325,7 @@ function Sandbox({ roomId }: { roomId: string }) { }, []); const clear = useMutation(({ storage }) => { - for (const key of Object.keys(storage.toObject())) { + for (const key of storage.keys()) { storage.delete(key); } }, []); @@ -519,7 +515,7 @@ function Sandbox({ roomId }: { roomId: string }) { border: "1px solid #ddd", }} > - {JSON.stringify(immutable, mapReplacer, 2)} + {JSON.stringify(immutable, null, 2)} ) : null} diff --git a/e2e/next-sandbox/test/zustand-kanban.test.ts b/e2e/next-sandbox/test/zustand-kanban.test.ts index 4f7eb46d4d1..abade2cba12 100644 --- a/e2e/next-sandbox/test/zustand-kanban.test.ts +++ b/e2e/next-sandbox/test/zustand-kanban.test.ts @@ -301,7 +301,7 @@ test.describe("Zustand Kanban", () => { await waitForJson(pages, "#numCards", 0); }); - test("conflict: both clients move same card to different columns", async () => { + test.skip("conflict: both clients move same card to different columns", async () => { const [page1, page2] = pages; await page1.click("#clear"); diff --git a/e2e/next-sandbox/utils/index.tsx b/e2e/next-sandbox/utils/index.tsx index fcc76a9074c..a059adcde40 100644 --- a/e2e/next-sandbox/utils/index.tsx +++ b/e2e/next-sandbox/utils/index.tsx @@ -1,4 +1,4 @@ -import type { Json } from "@liveblocks/client"; +import type { ReadonlyJson } from "@liveblocks/client"; import { raise } from "@liveblocks/core"; import type { Reducer } from "react"; import { useReducer, useRef } from "react"; @@ -79,7 +79,7 @@ export const styles = { export type RowProps = { readonly id: string; readonly name: string; - readonly value: Readonly | undefined; + readonly value: ReadonlyJson | undefined; readonly style?: Record; }; diff --git a/e2e/node-sandbox/turbo.json b/e2e/node-sandbox/turbo.json index 9ad4363d13f..24cacebe9fb 100644 --- a/e2e/node-sandbox/turbo.json +++ b/e2e/node-sandbox/turbo.json @@ -2,9 +2,11 @@ "extends": ["//"], "tasks": { "test": { + "dependsOn": ["^build"], "cache": false }, "test:ci": { + "dependsOn": ["^build"], "cache": false } } diff --git a/examples/nextjs-react-flow-ai/app/flowchart/agent.ts b/examples/nextjs-react-flow-ai/app/flowchart/agent.ts index 11b1ff654f1..30d36a0e9a1 100644 --- a/examples/nextjs-react-flow-ai/app/flowchart/agent.ts +++ b/examples/nextjs-react-flow-ai/app/flowchart/agent.ts @@ -1,16 +1,12 @@ "use server"; import { openai } from "@ai-sdk/openai"; -import { Liveblocks, LiveMap } from "@liveblocks/node"; +import { Liveblocks } from "@liveblocks/node"; +import { mutateFlow } from "@liveblocks/react-flow/node"; import { generateText, stepCountIs, tool } from "ai"; import dedent from "dedent"; import { nanoid } from "nanoid"; import { z } from "zod"; -import { - LiveblocksNode, - toLiveblocksEdge, - toLiveblocksNode, -} from "@liveblocks/react-flow"; import { createAgentUser } from "../api/database"; import { BLOCK_COLORS, @@ -18,11 +14,12 @@ import { DEFAULT_BLOCK_SIZE, FLOWCHART_EDGE_TYPE, FLOWCHART_STORAGE_KEY, - FlowchartFlow, + FlowchartEdge, FlowchartNode, createFlowchartEdge, createFlowchartNode, easeInOutCubic, + getBoundsFromNodes, getEdgeHandlesForNodes, getMidpoint, getNodeCenter, @@ -31,7 +28,6 @@ import { sleep, type BlockColor, type Bounds, - type Frame, type Point, } from "./shared"; @@ -68,46 +64,6 @@ const edgeDataSchema = z.object({ label: z.string().optional(), }); -function getLiveblocksNodeFrame(node: LiveblocksNode): Frame { - return { - position: node.get("position") as Point, - width: node.get("width") ?? undefined, - height: node.get("height") ?? undefined, - }; -} - -function getLiveblocksNodeSize(node: LiveblocksNode) { - return getNodeSize(getLiveblocksNodeFrame(node)); -} - -function getLiveblocksNodeCenter(node: LiveblocksNode): Point { - return getNodeCenter(getLiveblocksNodeFrame(node)); -} - -function getBoundsFromLiveblocksNodes( - nodes: LiveMap> -): Bounds | null { - let minX = Infinity; - let minY = Infinity; - let maxX = -Infinity; - let maxY = -Infinity; - let hasNodes = false; - - for (const node of nodes.values()) { - const position = node.get("position") as Point; - const { width, height } = getLiveblocksNodeSize(node); - - minX = Math.min(minX, position.x); - minY = Math.min(minY, position.y); - maxX = Math.max(maxX, position.x + width); - maxY = Math.max(maxY, position.y + height); - - hasNodes = true; - } - - return hasNodes ? { minX, minY, maxX, maxY } : null; -} - async function runFlowchartAgent(roomId: string, prompt: string) { const agentUser = createAgentUser(); let lastCursor: Point | null = null; @@ -152,39 +108,36 @@ async function runFlowchartAgent(roomId: string, prompt: string) { return run; }; - await liveblocks.mutateStorage(roomId, async ({ root }) => { - const flow = root.get(FLOWCHART_STORAGE_KEY) as FlowchartFlow | undefined; - - if (!flow) { - return; - } - - const nodes = flow.get("nodes"); - const edges = flow.get("edges"); - - const bounds: Bounds = getBoundsFromLiveblocksNodes(nodes) ?? { - minX: -DEFAULT_BOUNDS_RADIUS, - minY: -DEFAULT_BOUNDS_RADIUS, - maxX: DEFAULT_BOUNDS_RADIUS, - maxY: DEFAULT_BOUNDS_RADIUS, - }; - - await setPresence({ cursor: getRandomPointInBounds(bounds) }); - - let thinkingIntervalId: ReturnType | undefined = - setInterval(() => { - void setPresence({ cursor: getRandomPointInBounds(bounds) }); - }, CURSOR_THINKING_INTERVAL); - - function stopThinkingInterval() { - clearInterval(thinkingIntervalId); - lastThinking = false; - } - - try { - await generateText({ - model: openai("gpt-5.4-nano"), - system: dedent` + await mutateFlow( + { + client: liveblocks, + roomId, + storageKey: FLOWCHART_STORAGE_KEY, + }, + async (flow) => { + const bounds: Bounds = getBoundsFromNodes(flow.nodes) ?? { + minX: -DEFAULT_BOUNDS_RADIUS, + minY: -DEFAULT_BOUNDS_RADIUS, + maxX: DEFAULT_BOUNDS_RADIUS, + maxY: DEFAULT_BOUNDS_RADIUS, + }; + + await setPresence({ cursor: getRandomPointInBounds(bounds) }); + + let thinkingIntervalId: ReturnType | undefined = + setInterval(() => { + void setPresence({ cursor: getRandomPointInBounds(bounds) }); + }, CURSOR_THINKING_INTERVAL); + + function stopThinkingInterval() { + clearInterval(thinkingIntervalId); + lastThinking = false; + } + + try { + await generateText({ + model: openai("gpt-5.4-nano"), + system: dedent` You edit a live collaborative React Flow flowchart. Node shape: { id, position: { x, y }, width, height, data: { label, shape, color } }. @@ -204,417 +157,423 @@ async function runFlowchartAgent(roomId: string, prompt: string) { - When moving a node, attached edges should be updated to reflect the new layout. For example, a "bottom" to "top" edge makes sense for two nodes that are above each other, but if they become side by side, the edge should be updated to a "right" to "left" edge. - Use moveNode to change position, resizeNode to change width/height, and styleNode for label/shape/color — never mix them. `, - prompt: dedent` + prompt: dedent` - ${JSON.stringify( - { - nodes: Object.fromEntries(nodes.toImmutable()), - edges: Object.fromEntries(edges.toImmutable()), - }, - null, - 2 - )} + ${JSON.stringify(flow, null, 2)} ${prompt} `, - providerOptions: { openai: { reasoningEffort: "low" } }, - tools: { - addNode: tool({ - description: "Create one block node.", - inputSchema: z.object({ - ...idSchema.partial().shape, - ...nodeLayoutSchema.shape, - ...nodeDataSchema.partial().shape, - }), - execute: (newNode) => - $(async () => { - const width = newNode.width ?? DEFAULT_BLOCK_SIZE; - const height = newNode.height ?? DEFAULT_BLOCK_SIZE; + providerOptions: { openai: { reasoningEffort: "low" } }, + tools: { + addNode: tool({ + description: "Create one block node.", + inputSchema: z.object({ + ...idSchema.partial().shape, + ...nodeLayoutSchema.shape, + ...nodeDataSchema.partial().shape, + }), + execute: (newNode) => + $(async () => { + const width = newNode.width ?? DEFAULT_BLOCK_SIZE; + const height = newNode.height ?? DEFAULT_BLOCK_SIZE; - await setPresence({ - cursor: { - x: newNode.position.x + width / 2, - y: newNode.position.y + height / 2, - }, - }); + await setPresence({ + cursor: { + x: newNode.position.x + width / 2, + y: newNode.position.y + height / 2, + }, + }); - await pause(); + await pause(); - const id = newNode.id ?? `block-${nanoid()}`; + const id = newNode.id ?? `block-${nanoid()}`; - if (nodes.has(id)) { - return { ok: false, idExists: true, id }; - } + if (flow.getNode(id)) { + return { ok: false, idExists: true, id }; + } - const node = createFlowchartNode({ ...newNode, id }); - nodes.set(id, toLiveblocksNode(node)); + const node = createFlowchartNode({ ...newNode, id }); + flow.addNode(node); - await pause(); + await pause(); - return { ok: true, id }; - }), - }), - moveNode: tool({ - description: "Move one node to a new position.", - inputSchema: z.object({ - id: z.string(), - position: pointSchema, + return { ok: true, id }; + }), }), - execute: (updatedNode) => - $(async () => { - const node = nodes.get(updatedNode.id); - - if (!node) { - return { ok: false, missing: true, id: updatedNode.id }; - } - - await setPresence({ cursor: getLiveblocksNodeCenter(node) }); - - await pause(); - - const currentPosition = node.get("position") as Point; - const position = updatedNode.position; - const { width, height } = getLiveblocksNodeSize(node); - - const distance = Math.hypot( - position.x - currentPosition.x, - position.y - currentPosition.y - ); - - if (distance >= POSITION_ANIMATION_STEP_DISTANCE) { - const steps = Math.min( - POSITION_ANIMATION_MAX_STEPS, - Math.max( - POSITION_ANIMATION_MIN_STEPS, - Math.ceil(distance / POSITION_ANIMATION_STEP_DISTANCE) - ) - ); + moveNode: tool({ + description: "Move one node to a new position.", + inputSchema: z.object({ + id: z.string(), + position: pointSchema, + }), + execute: (updatedNode) => + $(async () => { + const node = flow.getNode(updatedNode.id); - for (let i = 1; i <= steps; i++) { - const progress = easeInOutCubic(i / steps); + if (!node) { + return { ok: false, missing: true, id: updatedNode.id }; + } - node.set("position", { - x: - currentPosition.x + - (position.x - currentPosition.x) * progress, - y: - currentPosition.y + - (position.y - currentPosition.y) * progress, - }); + await setPresence({ cursor: getNodeCenter(node) }); + await pause(); + + const currentPosition = node.position; + const position = updatedNode.position; + const { width, height } = getNodeSize(node); + + const distance = Math.hypot( + position.x - currentPosition.x, + position.y - currentPosition.y + ); + + if (distance >= POSITION_ANIMATION_STEP_DISTANCE) { + const steps = Math.min( + POSITION_ANIMATION_MAX_STEPS, + Math.max( + POSITION_ANIMATION_MIN_STEPS, + Math.ceil(distance / POSITION_ANIMATION_STEP_DISTANCE) + ) + ); + + for (let i = 1; i <= steps; i++) { + const progress = easeInOutCubic(i / steps); + const nextPosition = { + x: + currentPosition.x + + (position.x - currentPosition.x) * progress, + y: + currentPosition.y + + (position.y - currentPosition.y) * progress, + }; + + flow.updateNode(updatedNode.id, { + position: nextPosition, + }); + + await setPresence({ + cursor: { + x: nextPosition.x + width / 2, + y: nextPosition.y + height / 2, + }, + }); + } + + flow.updateNode(updatedNode.id, { position }); + } else { await setPresence({ - cursor: getLiveblocksNodeCenter(node), + cursor: { + x: position.x + width / 2, + y: position.y + height / 2, + }, }); - } - - node.set("position", position); - } else { - await setPresence({ - cursor: { - x: position.x + width / 2, - y: position.y + height / 2, - }, - }); - await pause(); + await pause(); - node.set("position", position); - } + flow.updateNode(updatedNode.id, { position }); + } - await pause(); + await pause(); - return { ok: true, id: updatedNode.id }; - }), - }), - resizeNode: tool({ - description: "Resize one node.", - inputSchema: z.object({ - id: z.string(), - width: sizeSchema.optional(), - height: sizeSchema.optional(), + return { ok: true, id: updatedNode.id }; + }), }), - execute: (updatedNode) => - $(async () => { - const node = nodes.get(updatedNode.id); + resizeNode: tool({ + description: "Resize one node.", + inputSchema: z.object({ + id: z.string(), + width: sizeSchema.optional(), + height: sizeSchema.optional(), + }), + execute: (updatedNode) => + $(async () => { + const node = flow.getNode(updatedNode.id); - if (!node) { - return { ok: false, missing: true, id: updatedNode.id }; - } + if (!node) { + return { ok: false, missing: true, id: updatedNode.id }; + } - const position = node.get("position") as Point; - const { width: currentWidth, height: currentHeight } = - getLiveblocksNodeSize(node); + const { position } = node; + const { width: currentWidth, height: currentHeight } = + getNodeSize(node); - await setPresence({ - cursor: { - x: position.x + currentWidth, - y: position.y + currentHeight, - }, - }); + await setPresence({ + cursor: { + x: position.x + currentWidth, + y: position.y + currentHeight, + }, + }); - await pause(); + await pause(); - if (updatedNode.width !== undefined) { - node.set("width", updatedNode.width); - } + const partial: Partial = {}; + if (updatedNode.width !== undefined) { + partial.width = updatedNode.width; + } + if (updatedNode.height !== undefined) { + partial.height = updatedNode.height; + } - if (updatedNode.height !== undefined) { - node.set("height", updatedNode.height); - } + if (Object.keys(partial).length > 0) { + flow.updateNode(updatedNode.id, partial); + } - const newWidth = updatedNode.width ?? currentWidth; - const newHeight = updatedNode.height ?? currentHeight; + const newWidth = updatedNode.width ?? currentWidth; + const newHeight = updatedNode.height ?? currentHeight; - await setPresence({ - cursor: { - x: position.x + newWidth, - y: position.y + newHeight, - }, - }); + await setPresence({ + cursor: { + x: position.x + newWidth, + y: position.y + newHeight, + }, + }); - await pause(); + await pause(); - return { ok: true, id: updatedNode.id }; - }), - }), - updateNodeData: tool({ - description: "Update one node's data.", - inputSchema: z.object({ - ...idSchema.shape, - ...nodeDataSchema.partial().shape, + return { ok: true, id: updatedNode.id }; + }), }), - execute: (updatedNode) => - $(async () => { - const node = nodes.get(updatedNode.id); + updateNodeData: tool({ + description: "Update one node's data.", + inputSchema: z.object({ + ...idSchema.shape, + ...nodeDataSchema.partial().shape, + }), + execute: (updatedNode) => + $(async () => { + const node = flow.getNode(updatedNode.id); - if (!node) { - return { ok: false, missing: true, id: updatedNode.id }; - } + if (!node) { + return { ok: false, missing: true, id: updatedNode.id }; + } - await setPresence({ cursor: getLiveblocksNodeCenter(node) }); + await setPresence({ cursor: getNodeCenter(node) }); - await pause(); + await pause(); - const data = node.get("data"); + const dataPartial: Partial = {}; - if (updatedNode.label !== undefined) { - data.set("label", updatedNode.label); - } + if (updatedNode.label !== undefined) { + dataPartial.label = updatedNode.label; + } - if (updatedNode.shape !== undefined) { - data.set("shape", updatedNode.shape); - } + if (updatedNode.shape !== undefined) { + dataPartial.shape = updatedNode.shape; + } - if (updatedNode.color !== undefined) { - data.set("color", updatedNode.color); - } + if (updatedNode.color !== undefined) { + dataPartial.color = updatedNode.color; + } - await pause(); + if (Object.keys(dataPartial).length > 0) { + flow.updateNodeData(updatedNode.id, dataPartial); + } - return { ok: true, id: updatedNode.id }; - }), - }), - deleteNode: tool({ - description: "Delete one node.", - inputSchema: idSchema, - execute: ({ id }) => - $(async () => { - const node = nodes.get(id); + await pause(); - if (!node) { - return { ok: false, missing: true, id }; - } + return { ok: true, id: updatedNode.id }; + }), + }), + deleteNode: tool({ + description: "Delete one node.", + inputSchema: idSchema, + execute: ({ id }) => + $(async () => { + const node = flow.getNode(id); + + if (!node) { + return { ok: false, missing: true, id }; + } - await setPresence({ cursor: getLiveblocksNodeCenter(node) }); + await setPresence({ cursor: getNodeCenter(node) }); - await pause(); + await pause(); - nodes.delete(id); + flow.removeNode(id); - await pause(); + await pause(); - return { ok: true, id }; - }), - }), - addEdge: tool({ - description: "Create one edge between two nodes.", - inputSchema: z.object({ - ...idSchema.partial().shape, - ...edgeDataSchema.partial().shape, - source: z.string(), - target: z.string(), + return { ok: true, id }; + }), }), - execute: (newEdge) => - $(async () => { - const sourceNode = nodes.get(newEdge.source); - const targetNode = nodes.get(newEdge.target); - - if (!sourceNode || !targetNode) { - return { - ok: false, - missing: true, - source: newEdge.source, - target: newEdge.target, - }; - } - - const sourceCenter = getLiveblocksNodeCenter(sourceNode); - const targetCenter = getLiveblocksNodeCenter(targetNode); - - await setPresence({ cursor: sourceCenter }); - - await pause(); + addEdge: tool({ + description: "Create one edge between two nodes.", + inputSchema: z.object({ + ...idSchema.partial().shape, + ...edgeDataSchema.partial().shape, + source: z.string(), + target: z.string(), + }), + execute: (newEdge) => + $(async () => { + const sourceNode = flow.getNode(newEdge.source); + const targetNode = flow.getNode(newEdge.target); + + if (!sourceNode || !targetNode) { + return { + ok: false, + missing: true, + source: newEdge.source, + target: newEdge.target, + }; + } - await setPresence({ cursor: targetCenter }); + const sourceCenter = getNodeCenter(sourceNode); + const targetCenter = getNodeCenter(targetNode); - await pause(); + await setPresence({ cursor: sourceCenter }); - const id = - newEdge.id ?? - `e-${newEdge.source}-${newEdge.target}-${nanoid(6)}`; + await pause(); - if (edges.has(id)) { - return { ok: false, idExists: true, id }; - } + await setPresence({ cursor: targetCenter }); - const { sourceHandle, targetHandle } = getEdgeHandlesForNodes( - getLiveblocksNodeFrame(sourceNode), - getLiveblocksNodeFrame(targetNode) - ); + await pause(); - const edge = createFlowchartEdge({ - id, - source: newEdge.source, - target: newEdge.target, - sourceHandle, - targetHandle, - label: "", - }); - edges.set(id, toLiveblocksEdge(edge)); + const id = + newEdge.id ?? + `e-${newEdge.source}-${newEdge.target}-${nanoid(6)}`; - await pause(); + if (flow.getEdge(id)) { + return { ok: false, idExists: true, id }; + } - const label = newEdge.label?.trim(); + const { sourceHandle, targetHandle } = getEdgeHandlesForNodes( + sourceNode, + targetNode + ); - if (label) { - await setPresence({ - cursor: getMidpoint(sourceCenter, targetCenter), + const edge = createFlowchartEdge({ + id, + source: newEdge.source, + target: newEdge.target, + sourceHandle, + targetHandle, + label: "", }); + flow.addEdge(edge); await pause(); - const edge = edges.get(id); + const label = newEdge.label?.trim(); - edge?.get("data")?.set("label", label); - - await pause(); - } + if (label) { + await setPresence({ + cursor: getMidpoint(sourceCenter, targetCenter), + }); - return { ok: true, id }; - }), - }), - updateEdgeData: tool({ - description: "Update one edge's data.", - inputSchema: z.object({ - ...idSchema.shape, - ...edgeDataSchema.partial().shape, - }), - execute: (updatedEdge) => - $(async () => { - const edge = edges.get(updatedEdge.id); + await pause(); - if (!edge) { - return { - ok: false, - missing: true, - id: updatedEdge.id, - }; - } + flow.updateEdgeData(id, { label }); - const sourceId = edge.get("source") as string; - const targetId = edge.get("target") as string; - const sourceNode = nodes.get(sourceId); - const targetNode = nodes.get(targetId); + await pause(); + } - if (!sourceNode || !targetNode) { - return { - ok: false, - missing: true, - id: updatedEdge.id, - }; - } + return { ok: true, id }; + }), + }), + updateEdgeData: tool({ + description: "Update one edge's data.", + inputSchema: z.object({ + ...idSchema.shape, + ...edgeDataSchema.partial().shape, + }), + execute: (updatedEdge) => + $(async () => { + const edge = flow.getEdge(updatedEdge.id); + + if (!edge) { + return { + ok: false, + missing: true, + id: updatedEdge.id, + }; + } - const sourceCenter = getLiveblocksNodeCenter(sourceNode); - const targetCenter = getLiveblocksNodeCenter(targetNode); + const sourceNode = flow.getNode(edge.source); + const targetNode = flow.getNode(edge.target); - await setPresence({ cursor: sourceCenter }); + if (!sourceNode || !targetNode) { + return { + ok: false, + missing: true, + id: updatedEdge.id, + }; + } - await pause(); + const sourceCenter = getNodeCenter(sourceNode); + const targetCenter = getNodeCenter(targetNode); - await setPresence({ cursor: targetCenter }); + await setPresence({ cursor: sourceCenter }); - await pause(); + await pause(); - if (updatedEdge.label !== undefined) { - edge.get("data")?.set("label", updatedEdge.label); + await setPresence({ cursor: targetCenter }); await pause(); - } - return { ok: true, id: updatedEdge.id }; - }), - }), - deleteEdge: tool({ - description: "Delete one edge.", - inputSchema: idSchema, - execute: ({ id }) => - $(async () => { - const edge = edges.get(id); + if (updatedEdge.label !== undefined) { + flow.updateEdgeData(updatedEdge.id, { + label: updatedEdge.label, + }); - if (!edge) { - return { ok: false, missing: true, id }; - } + await pause(); + } - const sourceNode = nodes.get(edge.get("source")); - const targetNode = nodes.get(edge.get("target")); + return { ok: true, id: updatedEdge.id }; + }), + }), + deleteEdge: tool({ + description: "Delete one edge.", + inputSchema: idSchema, + execute: ({ id }) => + $(async () => { + const edge = flow.getEdge(id); + + if (!edge) { + return { ok: false, missing: true, id }; + } - if (!sourceNode || !targetNode) { - return { ok: false, missing: true, id }; - } + const sourceNode = flow.getNode(edge.source); + const targetNode = flow.getNode(edge.target); - await setPresence({ - cursor: getMidpoint( - getLiveblocksNodeCenter(sourceNode), - getLiveblocksNodeCenter(targetNode) - ), - }); + if (!sourceNode || !targetNode) { + return { ok: false, missing: true, id }; + } - await pause(); + await setPresence({ + cursor: getMidpoint( + getNodeCenter(sourceNode), + getNodeCenter(targetNode) + ), + }); - await setPresence({ - cursor: getLiveblocksNodeCenter(sourceNode), - }); + await pause(); - await pause(); + await setPresence({ + cursor: getNodeCenter(sourceNode), + }); - edges.delete(id); + await pause(); - await pause(); + flow.removeEdge(id); - return { ok: true, id }; - }), - }), - }, - stopWhen: stepCountIs(30), - experimental_onToolCallStart: stopThinkingInterval, - }); - } finally { - stopThinkingInterval(); + await pause(); + + return { ok: true, id }; + }), + }), + }, + stopWhen: stepCountIs(30), + experimental_onToolCallStart: stopThinkingInterval, + }); + } finally { + stopThinkingInterval(); + } } - }); + ); await setPresence({ ttl: PRESENCE_DONE_TTL_SECONDS }); } diff --git a/examples/nextjs-react-flow-ai/app/flowchart/shared.ts b/examples/nextjs-react-flow-ai/app/flowchart/shared.ts index a32e430b906..4748bd8795c 100644 --- a/examples/nextjs-react-flow-ai/app/flowchart/shared.ts +++ b/examples/nextjs-react-flow-ai/app/flowchart/shared.ts @@ -27,7 +27,6 @@ export const FLOWCHART_EDGE_TYPE = "smoothstep" as const; export const BLOCK_HANDLE_SIDES = ["top", "right", "bottom", "left"] as const; export type Point = { x: number; y: number }; -export type Frame = { position: Point; width?: number; height?: number }; export type Bounds = { minX: number; minY: number; maxX: number; maxY: number }; export type BlockShape = (typeof BLOCK_SHAPES)[number]; @@ -62,14 +61,14 @@ export function blockTargetHandleId( return `tgt-${side}`; } -export function getNodeSize(node: Pick) { +export function getNodeSize(node: FlowchartNode) { return { width: node.width ?? DEFAULT_BLOCK_SIZE, height: node.height ?? DEFAULT_BLOCK_SIZE, }; } -export function getNodeCenter(node: Frame): Point { +export function getNodeCenter(node: FlowchartNode): Point { const { width, height } = getNodeSize(node); return { @@ -78,8 +77,32 @@ export function getNodeCenter(node: Frame): Point { }; } +export function getBoundsFromNodes( + nodes: readonly FlowchartNode[] +): Bounds | null { + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + let hasNodes = false; + + for (const node of nodes) { + const { position } = node; + const { width, height } = getNodeSize(node); + + minX = Math.min(minX, position.x); + minY = Math.min(minY, position.y); + maxX = Math.max(maxX, position.x + width); + maxY = Math.max(maxY, position.y + height); + + hasNodes = true; + } + + return hasNodes ? { minX, minY, maxX, maxY } : null; +} + export function flowPointToNormalized( - node: Frame, + node: FlowchartNode, flowX: number, flowY: number ): Point { @@ -91,7 +114,10 @@ export function flowPointToNormalized( }; } -export function normalizedToFlowPoint(node: Frame, normalized: Point): Point { +export function normalizedToFlowPoint( + node: FlowchartNode, + normalized: Point +): Point { const { width, height } = getNodeSize(node); return { @@ -101,7 +127,7 @@ export function normalizedToFlowPoint(node: Frame, normalized: Point): Point { } export function getNodeAtFlowPoint( - nodes: FlowchartNode[], + nodes: readonly FlowchartNode[], flow: Point ): FlowchartNode | undefined { return nodes.find((node) => { @@ -130,8 +156,8 @@ export function easeInOutCubic(t: number) { } export function getEdgeHandlesForNodes( - sourceNode: Frame, - targetNode: Frame + sourceNode: FlowchartNode, + targetNode: FlowchartNode ): { sourceHandle: BlockSourceHandleId; targetHandle: BlockTargetHandleId; diff --git a/examples/nextjs-react-flow-ai/package-lock.json b/examples/nextjs-react-flow-ai/package-lock.json index eedd00a0406..f14380794c4 100644 --- a/examples/nextjs-react-flow-ai/package-lock.json +++ b/examples/nextjs-react-flow-ai/package-lock.json @@ -8,11 +8,11 @@ "license": "Apache-2.0", "dependencies": { "@ai-sdk/openai": "^3.0.48", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "3.18.0-rc1", + "@liveblocks/node": "3.18.0-rc1", + "@liveblocks/react": "3.18.0-rc1", + "@liveblocks/react-flow": "3.18.0-rc1", + "@liveblocks/react-ui": "3.18.0-rc1", "@xyflow/react": "^12.10.1", "ai": "^6.0.136", "dedent": "^1.7.2", @@ -582,43 +582,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0-rc1.tgz", + "integrity": "sha512-0vKVmUVI4qmrvXqUWnmNxJIA3TdIBHYKGApbkRWJNZcUpPjCDi6FII6kEix8/HIPkoBLlLwnI1qXBkDzrEX9tQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0-rc1" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0-rc1.tgz", + "integrity": "sha512-f7X0So8GMHUKmLH+Yep9N8qWtvmISiV4cY2orHr/0JgyA23hhIJFylesdRt7lCzyleA0TvY/sBtTPzUNrhDo0Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0-rc1.tgz", + "integrity": "sha512-8eGpKSC2pM+NZw9cF5ZBRk8NIR64kfeLozaq/HuPYd8XoTxmVyTdbCZIKTYoLj/cZQ3eCd7vw2jvqUbkFBIkrQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0-rc1", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0-rc1.tgz", + "integrity": "sha512-+EFMryb+lcIjREUEGLiWTS7VSlaC3PsO/PJbszvKbpC1mJ4lwNqz+En4Aeqg4VCHoD+nIQCq0CRCeZ2x2ZDOow==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0-rc1", + "@liveblocks/core": "3.18.0-rc1" }, "peerDependencies": { "@types/react": "*", @@ -635,15 +635,15 @@ } }, "node_modules/@liveblocks/react-flow": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.17.0.tgz", - "integrity": "sha512-pAuFm827OdvDW8s7i/qMEU+/5E2pJ59m/3h9hkGEEC80XdQt1urWDPwW2TYPnsRvfs7dZXe6n7bp4AdYOyfV4A==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.18.0-rc1.tgz", + "integrity": "sha512-2ZCR+DhrPvQyvDt/5ILxZ7bwjJa6Ci7xaCAvulYTzZuWJLZrQiQpKqMBzSBiQ08wI7sNGDiNv62VsnMBA0t57g==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0" + "@liveblocks/client": "3.18.0-rc1", + "@liveblocks/core": "3.18.0-rc1", + "@liveblocks/react": "3.18.0-rc1", + "@liveblocks/react-ui": "3.18.0-rc1" }, "peerDependencies": { "@xyflow/react": "^12", @@ -660,15 +660,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0-rc1", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0-rc1.tgz", + "integrity": "sha512-uy4aNWlW+yxAi4d1Kof3pxYdDr2Dv8pGeEpy+xDlbrE67y/A6XdBKPjqQxvST4ZpRQ7Kh0Z/JNCd2BZSZyVCRw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0-rc1", + "@liveblocks/core": "3.18.0-rc1", + "@liveblocks/react": "3.18.0-rc1", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-react-flow-ai/package.json b/examples/nextjs-react-flow-ai/package.json index a622e5eb96b..0f656e08711 100644 --- a/examples/nextjs-react-flow-ai/package.json +++ b/examples/nextjs-react-flow-ai/package.json @@ -11,11 +11,11 @@ }, "dependencies": { "@ai-sdk/openai": "^3.0.48", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "3.18.0-rc1", + "@liveblocks/node": "3.18.0-rc1", + "@liveblocks/react": "3.18.0-rc1", + "@liveblocks/react-flow": "3.18.0-rc1", + "@liveblocks/react-ui": "3.18.0-rc1", "@xyflow/react": "^12.10.1", "ai": "^6.0.136", "dedent": "^1.7.2", diff --git a/package-lock.json b/package-lock.json index fa99de77d09..c08c0563bcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24519,6 +24519,18 @@ "node": ">=0.10.0" } }, + "node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/immutable": { "version": "4.1.0", "license": "MIT" @@ -37747,6 +37759,7 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", + "@liveblocks/node": "*", "@liveblocks/rollup-config": "*", "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^6.4.6", diff --git a/packages/liveblocks-client/src/index.ts b/packages/liveblocks-client/src/index.ts index 0807466bbe4..5c8f5bdd2f9 100644 --- a/packages/liveblocks-client/src/index.ts +++ b/packages/liveblocks-client/src/index.ts @@ -60,6 +60,8 @@ export type { NotificationSettings, OthersEvent, PlainLsonObject, + ReadonlyJson, + ReadonlyJsonObject, ResolveGroupsInfoArgs, ResolveMentionSuggestionsArgs, ResolveRoomsInfoArgs, @@ -72,7 +74,7 @@ export type { StringifyCommentBodyElements, StringifyCommentBodyOptions, ThreadData, - ToImmutable, + ToJson, UploadAttachmentOptions, User, } from "@liveblocks/core"; diff --git a/packages/liveblocks-core/e2e/list-property.test.ts b/packages/liveblocks-core/e2e/list-property.test.ts index 9e4683db70b..d9fb81081cb 100644 --- a/packages/liveblocks-core/e2e/list-property.test.ts +++ b/packages/liveblocks-core/e2e/list-property.test.ts @@ -321,8 +321,8 @@ test( await control.flushB(); // Property: both clients should have identical final states - const list1 = root1.get("list").toImmutable(); - const list2 = root2.get("list").toImmutable(); + const list1 = root1.get("list").toJSON(); + const list2 = root2.get("list").toJSON(); ctx.log(`Client A: ${JSON.stringify(list1)}`); ctx.log(`Client B: ${JSON.stringify(list2)}`); ctx.log( diff --git a/packages/liveblocks-core/e2e/list-single.test.ts b/packages/liveblocks-core/e2e/list-single.test.ts index 3a022f668d5..e2347a19237 100644 --- a/packages/liveblocks-core/e2e/list-single.test.ts +++ b/packages/liveblocks-core/e2e/list-single.test.ts @@ -1,8 +1,7 @@ import { expect, test } from "vitest"; import { LiveList } from "../src/crdts/LiveList"; -import { lsonToJson } from "../src/immutable"; -import type { Json } from "../src/lib/Json"; +import type { ReadonlyJson } from "../src/lib/Json"; import { prepareSingleClientTest } from "./utils"; test( @@ -12,8 +11,8 @@ test( list: new LiveList(["a"]), }, async ({ root, flushSocketMessages, room }) => { - const states: Json[] = []; - room.subscribe(root, () => states.push(lsonToJson(root)), { + const states: ReadonlyJson[] = []; + room.subscribe(root, () => states.push(root.toJSON()), { isDeep: true, }); @@ -33,8 +32,8 @@ test( list: null, } as { list: LiveList | null }, async ({ root, flushSocketMessages, room }) => { - const states: Json[] = []; - room.subscribe(root, () => states.push(lsonToJson(root)), { + const states: ReadonlyJson[] = []; + room.subscribe(root, () => states.push(root.toJSON()), { isDeep: true, }); diff --git a/packages/liveblocks-core/e2e/map-single.test.ts b/packages/liveblocks-core/e2e/map-single.test.ts index ec6140efcb5..dd5e1d2162b 100644 --- a/packages/liveblocks-core/e2e/map-single.test.ts +++ b/packages/liveblocks-core/e2e/map-single.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "vitest"; import { LiveMap } from "../src/crdts/LiveMap"; -import type { Immutable } from "../src/types/Immutable"; +import type { ReadonlyJson } from "../src/lib/Json"; import { prepareSingleClientTest } from "./utils"; test( @@ -11,8 +11,8 @@ test( map: new LiveMap(), }, async ({ root, flushSocketMessages, room }) => { - const states: Immutable[] = []; - room.subscribe(root, () => states.push(root.toImmutable()), { + const states: ReadonlyJson[] = []; + room.subscribe(root, () => states.push(root.toJSON()), { isDeep: true, }); @@ -20,10 +20,7 @@ test( root.get("map").set("key", "b"); await flushSocketMessages(); - expect(states).toEqual([ - { map: new Map([["key", "a"]]) }, - { map: new Map([["key", "b"]]) }, - ]); + expect(states).toEqual([{ map: { key: "a" } }, { map: { key: "b" } }]); } ) ); diff --git a/packages/liveblocks-core/e2e/map.test.ts b/packages/liveblocks-core/e2e/map.test.ts index a84d04fc93e..c051c41fcc8 100644 --- a/packages/liveblocks-core/e2e/map.test.ts +++ b/packages/liveblocks-core/e2e/map.test.ts @@ -11,16 +11,13 @@ test( async ({ root1, root2, control, assert }) => { root1.get("map").set("key", "a"); root2.get("map").set("key", "b"); - assert( - { map: new Map([["key", "a"]]) }, - { map: new Map([["key", "b"]]) } - ); + assert({ map: { key: "a" } }, { map: { key: "b" } }); await control.flushA(); - assert({ map: new Map([["key", "a"]]) }); + assert({ map: { key: "a" } }); await control.flushB(); - assert({ map: new Map([["key", "b"]]) }); + assert({ map: { key: "b" } }); } ) ); @@ -34,18 +31,18 @@ test( root1.get("map").delete("key"); root2.get("map").set("key", "b"); assert( - { map: new Map() }, // - { map: new Map([["key", "b"]]) } + { map: {} }, // + { map: { key: "b" } } ); await control.flushA(); assert( - { map: new Map() }, // - { map: new Map([["key", "b"]]) } + { map: {} }, // + { map: { key: "b" } } ); await control.flushB(); - assert({ map: new Map([["key", "b"]]) }); + assert({ map: { key: "b" } }); } ) ); diff --git a/packages/liveblocks-core/e2e/utils.ts b/packages/liveblocks-core/e2e/utils.ts index a6f00bec317..4a6c1aaa66a 100644 --- a/packages/liveblocks-core/e2e/utils.ts +++ b/packages/liveblocks-core/e2e/utils.ts @@ -7,8 +7,7 @@ import { createClient } from "../src/client"; import type { Status } from "../src/connection"; import { isLiveStructure } from "../src/crdts/liveblocks-helpers"; import type { LiveObject } from "../src/crdts/LiveObject"; -import type { LsonObject } from "../src/crdts/Lson"; -import type { ToImmutable } from "../src/crdts/utils"; +import type { LsonObject, ToJson } from "../src/crdts/Lson"; import { controlledPromise } from "../src/lib/controlledPromise"; import type { Json, JsonObject } from "../src/lib/Json"; import { mapValues, wait, withTimeout } from "../src/lib/utils"; @@ -115,7 +114,7 @@ export function prepareTestsConflicts( * rooms' storages are expected to be equal. It also ensures that immutable * states updated with the updates generated from conflicts are equal. */ - assert: (immRoot1: ToImmutable, immRoot2?: ToImmutable) => void; + assert: (immRoot1: ToJson, immRoot2?: ToJson) => void; /** Test utilities to exactly control message passing */ control: { /** @@ -240,10 +239,10 @@ export function prepareTestsConflicts( await Promise.all([control.flushA(), control.flushB()]); const expectedStorage = mapValues(initialStorage, (value) => - isLiveStructure(value) ? value.toImmutable() : value + isLiveStructure(value) ? value.toJSON() : value ); - let immutableStorage1 = root1.toImmutable(); - let immutableStorage2 = root2.toImmutable(); + let immutableStorage1 = root1.toJSON(); + let immutableStorage2 = root2.toJSON(); // Initial storage should be equal at the start of the test expect(immutableStorage1).toEqual(expectedStorage); @@ -252,26 +251,23 @@ export function prepareTestsConflicts( actor1.room.subscribe( root1, () => { - immutableStorage1 = root1.toImmutable(); + immutableStorage1 = root1.toJSON(); }, { isDeep: true } ); actor2.room.subscribe( root2, () => { - immutableStorage2 = root2.toImmutable(); + immutableStorage2 = root2.toJSON(); }, { isDeep: true } ); - function assert( - immRoot1: ToImmutable, - immRoot2: ToImmutable = immRoot1 - ) { + function assert(immRoot1: ToJson, immRoot2: ToJson = immRoot1) { try { - expect({ root1: root1.toImmutable() }).toEqual({ root1: immRoot1 }); + expect({ root1: root1.toJSON() }).toEqual({ root1: immRoot1 }); expect(immutableStorage1).toEqual(immRoot1); - expect({ root2: root2.toImmutable() }).toEqual({ root2: immRoot2 }); + expect({ root2: root2.toJSON() }).toEqual({ root2: immRoot2 }); expect(immutableStorage2).toEqual(immRoot2); } catch (error) { // Better stack trace (point to where assert is called instead) diff --git a/packages/liveblocks-core/settings.json b/packages/liveblocks-core/settings.json index 111730cc7ca..f61e6a08158 100644 --- a/packages/liveblocks-core/settings.json +++ b/packages/liveblocks-core/settings.json @@ -1,6 +1,6 @@ { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, - "editor.tabSize": 2, - "editor.detectIndentation": false -} \ No newline at end of file + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + "editor.tabSize": 2, + "editor.detectIndentation": false +} diff --git a/packages/liveblocks-core/src/__tests__/_MockWebSocketServer.setup.ts b/packages/liveblocks-core/src/__tests__/_MockWebSocketServer.setup.ts index fc3e64c5390..4c6f818dbc1 100644 --- a/packages/liveblocks-core/src/__tests__/_MockWebSocketServer.setup.ts +++ b/packages/liveblocks-core/src/__tests__/_MockWebSocketServer.setup.ts @@ -12,8 +12,7 @@ import { createApiClient } from "../api-client"; import { createAuthManager } from "../auth-manager"; import { DEFAULT_BASE_URL } from "../constants"; import type { LiveObject } from "../crdts/LiveObject"; -import type { LsonObject } from "../crdts/Lson"; -import type { ToImmutable } from "../crdts/utils"; +import type { LsonObject, ToJson } from "../crdts/Lson"; import { kInternal } from "../internal"; import { makeEventSource } from "../lib/EventSource"; import type { Json, JsonObject } from "../lib/Json"; @@ -238,8 +237,8 @@ export async function prepareIsolatedStorageTest( room, wss, - expectStorage: (data: ToImmutable) => - expect(storage.root.toImmutable()).toEqual(data), + expectStorage: (data: ToJson) => + expect(storage.root.toJSON()).toEqual(data), expectMessagesSent: ( messages: (ClientMsg | ClientMsg[])[] @@ -347,17 +346,17 @@ export async function prepareStorageTest< }) ); - const states: ToImmutable[] = []; + const states: ToJson[] = []; - function expectBothClientStoragesToEqual(data: ToImmutable) { - expect(subject.storage.root.toImmutable()).toEqual(data); - expect(ref.storage.root.toImmutable()).toEqual(data); + function expectBothClientStoragesToEqual(data: ToJson) { + expect(subject.storage.root.toJSON()).toEqual(data); + expect(ref.storage.root.toJSON()).toEqual(data); expect(subject.room[kInternal].nodeCount).toBe( ref.room[kInternal].nodeCount ); } - function expectStorage(data: ToImmutable) { + function expectStorage(data: ToJson) { states.push(data); expectBothClientStoragesToEqual(data); } diff --git a/packages/liveblocks-core/src/__tests__/_devserver.ts b/packages/liveblocks-core/src/__tests__/_devserver.ts index 0409662d487..f6c661b1b34 100644 --- a/packages/liveblocks-core/src/__tests__/_devserver.ts +++ b/packages/liveblocks-core/src/__tests__/_devserver.ts @@ -5,8 +5,7 @@ import { expect, onTestFinished, vi } from "vitest"; import { createClient } from "../client"; -import type { LsonObject } from "../crdts/Lson"; -import type { ToImmutable } from "../crdts/utils"; +import type { LsonObject, ToJson } from "../crdts/Lson"; import { kInternal } from "../internal"; import type { JsonObject } from "../lib/Json"; import { nanoid } from "../lib/nanoid"; @@ -184,16 +183,16 @@ export async function prepareStorageTest( // Wait for both clients to have synced initial storage await vi.waitFor(() => { - expect(storageA.root.toImmutable()).toEqual(storageB.root.toImmutable()); + expect(storageA.root.toJSON()).toEqual(storageB.root.toJSON()); }); - const states: ToImmutable[] = []; + const states: ToJson[] = []; - async function expectBothClientStoragesToEqual(data: ToImmutable) { - expect(storageA.root.toImmutable()).toEqual(data); + async function expectBothClientStoragesToEqual(data: ToJson) { + expect(storageA.root.toJSON()).toEqual(data); await vi.waitFor(() => { - expect(storageB.root.toImmutable()).toEqual(data); + expect(storageB.root.toJSON()).toEqual(data); }); expect(clientA.room[kInternal].nodeCount).toBe( @@ -201,7 +200,7 @@ export async function prepareStorageTest( ); } - async function expectStorage(data: ToImmutable) { + async function expectStorage(data: ToJson) { states.push(data); await expectBothClientStoragesToEqual(data); } @@ -271,8 +270,8 @@ export async function prepareIsolatedStorageTest( permissions: opts?.permissions, }); - function expectStorage(data: ToImmutable) { - expect(storage.root.toImmutable()).toEqual(data); + function expectStorage(data: ToJson) { + expect(storage.root.toJSON()).toEqual(data); } return { @@ -306,7 +305,7 @@ export async function prepareStorageUpdateTest( // Wait for both clients to have synced initial storage await vi.waitFor(() => { - expect(storageA.root.toImmutable()).toEqual(storageB.root.toImmutable()); + expect(storageA.root.toJSON()).toEqual(storageB.root.toJSON()); }); const updatesA: JsonStorageUpdate[][] = []; diff --git a/packages/liveblocks-core/src/__tests__/_updatesUtils.ts b/packages/liveblocks-core/src/__tests__/_updatesUtils.ts index a95181859d3..fdc05b13a1d 100644 --- a/packages/liveblocks-core/src/__tests__/_updatesUtils.ts +++ b/packages/liveblocks-core/src/__tests__/_updatesUtils.ts @@ -13,7 +13,7 @@ export type JsonStorageUpdate = export type JsonLiveListUpdate = { type: "LiveList"; - node: Array>; + node: readonly ToJson[]; updates: Array>; }; @@ -57,38 +57,40 @@ export function liveListUpdateToJson( ): JsonLiveListUpdate { return { type: update.type, - node: lsonToJson(update.node) as ToJson[], - // ^^^^^^^^^^^^^^^^^^ FIXME: Manual cast should eventually not be necessary - updates: update.updates.map((delta) => { + node: update.node.toJSON(), + updates: update.updates.map((delta): JsonLiveListUpdateDelta => { switch (delta.type) { case "move": { return { type: delta.type, index: delta.index, previousIndex: delta.previousIndex, - item: lsonToJson(delta.item), + item: lsonToJson(delta.item) as ToJson, }; } case "delete": { - return delta; + return { + type: delta.type, + index: delta.index, + deletedItem: lsonToJson(delta.deletedItem) as ToJson, + }; } case "insert": { return { type: delta.type, index: delta.index, - item: lsonToJson(delta.item), + item: lsonToJson(delta.item) as ToJson, }; } case "set": { return { type: delta.type, index: delta.index, - item: lsonToJson(delta.item), + item: lsonToJson(delta.item) as ToJson, }; } } - }) as any, - // ^^^^^^ FIXME: TypeScript nags about this correctly. Deal with this later. + }), }; } @@ -102,8 +104,7 @@ export function serializeUpdateToJson( if (update.type === "LiveObject") { return { type: update.type, - node: lsonToJson(update.node) as ToJson, - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME: Manual cast should eventually not be necessary + node: update.node.toJSON(), updates: update.updates, }; } @@ -111,8 +112,7 @@ export function serializeUpdateToJson( if (update.type === "LiveMap") { return { type: update.type, - node: lsonToJson(update.node) as { [key: string]: Json }, - // ^^^^^^^^^^^^^^^^^^^^^^^^^^ FIXME: Manual cast should eventually not be necessary + node: update.node.toJSON(), updates: update.updates, }; } diff --git a/packages/liveblocks-core/src/__tests__/immutable.test.ts b/packages/liveblocks-core/src/__tests__/immutable.test.ts index 49540533556..2147c33433c 100644 --- a/packages/liveblocks-core/src/__tests__/immutable.test.ts +++ b/packages/liveblocks-core/src/__tests__/immutable.test.ts @@ -1,29 +1,12 @@ import * as fc from "fast-check"; -import type { MockInstance } from "vitest"; -import { - afterEach, - beforeAll, - describe, - expect, - onTestFinished, - test, - vi, -} from "vitest"; - -import { jsonObject } from "../crdts/__tests__/_arbitraries"; +import { describe, expect, test, vi } from "vitest"; + +import { jsonObject, liveStructure } from "../crdts/__tests__/_arbitraries"; import { LiveList } from "../crdts/LiveList"; import { LiveMap } from "../crdts/LiveMap"; import { LiveObject } from "../crdts/LiveObject"; import type { LsonObject, ToJson } from "../crdts/Lson"; -import type { StorageUpdate } from "../crdts/StorageUpdates"; -import { - legacy_patchImmutableObject, - legacy_patchLiveObject, - legacy_patchLiveObjectKey, - lsonToJson, -} from "../immutable"; import { kInternal } from "../internal"; -import * as console from "../lib/fancy-console"; import type { JsonObject } from "../lib/Json"; import type { PlainLsonObject } from "../types/PlainLson"; import { @@ -36,24 +19,8 @@ import { objectUpdate } from "./_updatesUtils"; /** * Sets up two real clients (A and B) connected to the same room via the dev * server, with storage initialized from `initialStorage`. - * - * Returns: - * - `storage` — client A's storage root (the "active" client that tests - * mutate via `legacy_patchLiveObjectKey` / `legacy_patchLiveObject`) - * - `refStorage` — client B's storage root (the "reference" client that - * passively receives changes via server-mediated sync) - * - `state` — a plain-JSON mirror of client A's storage, shared by reference - * with the caller. Tests mutate this object directly (e.g. - * `state.foo = "bar"`) and then call `legacy_patchLiveObjectKey` to propagate - * the diff into the live CRDT tree. - * - `expectStorageAndState(data, itemsCount?)` — asserts that both clients' - * storage equals `data`, that the CRDT node count matches `itemsCount` - * (if provided), and that the JSON `state` mirror was kept in sync by - * the `storageBatch` subscription. - * - `expectStorage(data)` — lighter variant that only checks storage equality - * across both clients (no node count or state mirror checks). */ -export async function prepareStorageImmutableTest( +async function prepareStorageImmutableTest( initialStorage: PlainLsonObject ) { const roomId = await initRoom(initialStorage); @@ -66,38 +33,29 @@ export async function prepareStorageImmutableTest( const storageA = clientA.storage; const storageB = clientB.storage; - // Wait for both clients to sync initial storage await vi.waitFor(() => { - expect(lsonToJson(storageA.root)).toEqual(lsonToJson(storageB.root)); + expect(storageA.root.toJSON()).toEqual(storageB.root.toJSON()); }); - const state = lsonToJson(storageA.root) as ToJson; - let refState = lsonToJson(storageB.root) as ToJson; - - onTestFinished( - clientB.room.events.storageBatch.subscribe(() => { - refState = lsonToJson(storageB.root) as ToJson; - }) - ); - - async function expectStorageAndState(data: ToJson, itemsCount?: number) { - expect(lsonToJson(storageA.root)).toEqual(data); + async function expectStorageAndState( + data: ToJson, + expectedNodeCount?: number + ) { + expect(storageA.root.toJSON()).toEqual(data); await vi.waitFor(() => { - expect(lsonToJson(storageB.root)).toEqual(data); + expect(storageB.root.toJSON()).toEqual(data); }); - if (itemsCount !== undefined) { - expect(clientA.room[kInternal].nodeCount).toBe(itemsCount); + if (expectedNodeCount !== undefined) { + expect(clientA.room[kInternal].nodeCount).toBe(expectedNodeCount); } - expect(state).toEqual(refState); - expect(state).toEqual(data); } async function expectStorage(data: ToJson) { - expect(lsonToJson(storageA.root)).toEqual(data); + expect(storageA.root.toJSON()).toEqual(data); await vi.waitFor(() => { - expect(lsonToJson(storageB.root)).toEqual(data); + expect(storageB.root.toJSON()).toEqual(data); }); } @@ -106,43 +64,67 @@ export async function prepareStorageImmutableTest( refStorage: storageB, expectStorageAndState, expectStorage, - state, }; } -function applyStateChanges( - state: TState, - applyChanges: () => void -): { oldState: TState; newState: TState } { - const oldState = JSON.parse(JSON.stringify(state)) as TState; - applyChanges(); - const newState = JSON.parse(JSON.stringify(state)) as TState; - return { oldState, newState }; -} - -describe("immutableIs", () => { +describe("hasCache", () => { test("returns true when cached immutable matches the provided value", () => { const liveObj = new LiveObject({ a: 1 }); - const snapshot = liveObj.toImmutable(); - expect(liveObj.immutableIs(snapshot)).toBe(true); + const snapshot = liveObj.toJSON(); + expect(liveObj.hasCache(snapshot)).toBe(true); }); - test("returns false when toImmutable was never called", () => { + test("returns false when toJSON was never called", () => { const liveObj = new LiveObject({ a: 1 }); - expect(liveObj.immutableIs({ a: 1 })).toBe(false); + expect(liveObj.hasCache({ a: 1 })).toBe(false); }); test("returns false after invalidation", () => { const liveObj = new LiveObject({ a: 1 }); - const snapshot = liveObj.toImmutable(); + const snapshot = liveObj.toJSON(); liveObj.set("a", 2); - expect(liveObj.immutableIs(snapshot)).toBe(false); + expect(liveObj.hasCache(snapshot)).toBe(false); }); test("returns false when value does not match", () => { const liveObj = new LiveObject({ a: 1 }); - liveObj.toImmutable(); - expect(liveObj.immutableIs({ a: 999 })).toBe(false); + liveObj.toJSON(); + expect(liveObj.hasCache({ a: 999 })).toBe(false); + }); +}); + +describe("toJSON", () => { + test("property: toJSON() result never contains Map instances", () => { + function containsMap(value: unknown): boolean { + if (value instanceof Map) return true; + if (Array.isArray(value)) return value.some(containsMap); + if (value !== null && typeof value === "object") { + return Object.values(value).some(containsMap); + } + return false; + } + + fc.assert( + fc.property(liveStructure, (live) => { + expect(containsMap(live.toJSON())).toBe(false); + }) + ); + }); + + test("toJSON() is cached (returns same reference on repeated calls)", () => { + const liveObj = new LiveObject({ a: 1, b: new LiveList([2, 3]) }); + const first = liveObj.toJSON(); + const second = liveObj.toJSON(); + expect(first).toBe(second); + }); + + test("toJSON() cache is invalidated after mutation", () => { + const liveObj = new LiveObject({ a: 1 }); + const before = liveObj.toJSON(); + liveObj.set("a", 2); + const after = liveObj.toJSON(); + expect(before).not.toBe(after); + expect(after).toEqual({ a: 2 }); }); }); @@ -150,30 +132,30 @@ describe("reconcileLiveObject", () => { test("updates a changed scalar value", () => { const liveObj = new LiveObject({ a: 1, b: 2 }); liveObj.reconcile({ a: 1, b: 3 }); - expect(liveObj.toImmutable()).toEqual({ a: 1, b: 3 }); + expect(liveObj.toJSON()).toEqual({ a: 1, b: 3 }); }); test("adds a new key", () => { const liveObj = new LiveObject({ a: 1 }); liveObj.reconcile({ a: 1, b: "hello" }); - expect(liveObj.toImmutable()).toEqual({ a: 1, b: "hello" }); + expect(liveObj.toJSON()).toEqual({ a: 1, b: "hello" }); }); test("deletes a removed key", () => { const liveObj = new LiveObject({ a: 1, b: 2 }); liveObj.reconcile({ a: 1 }); - expect(liveObj.toImmutable()).toEqual({ a: 1 }); + expect(liveObj.toJSON()).toEqual({ a: 1 }); }); test("leaves unchanged scalars untouched", () => { const liveObj = new LiveObject({ a: 1, b: 2 }); - const before = liveObj.toImmutable(); + const before = liveObj.toJSON(); liveObj.reconcile({ a: 1, b: 2 }); - expect(liveObj.toImmutable()).toEqual({ a: 1, b: 2 }); + expect(liveObj.toJSON()).toEqual({ a: 1, b: 2 }); // Referentially identical when a no-op - expect(liveObj.toImmutable()).toBe(before); + expect(liveObj.toJSON()).toBe(before); }); test("deep-liveifies a new nested object", () => { @@ -181,7 +163,7 @@ describe("reconcileLiveObject", () => { a: 1, }); liveObj.reconcile({ a: 1, nested: { x: 10 } }); - expect(liveObj.toImmutable()).toEqual({ a: 1, nested: { x: 10 } }); + expect(liveObj.toJSON()).toEqual({ a: 1, nested: { x: 10 } }); expect(liveObj.get("nested")).toBeInstanceOf(LiveObject); }); @@ -191,7 +173,7 @@ describe("reconcileLiveObject", () => { }); const nestedBefore = liveObj.get("nested"); liveObj.reconcile({ nested: { x: 1, y: 99 } }); - expect(liveObj.toImmutable()).toEqual({ nested: { x: 1, y: 99 } }); + expect(liveObj.toJSON()).toEqual({ nested: { x: 1, y: 99 } }); // Same LiveObject instance — reconciled in place, not replaced expect(liveObj.get("nested")).toBe(nestedBefore); }); @@ -201,13 +183,13 @@ describe("reconcileLiveObject", () => { val: new LiveObject({ x: 1 }), }); liveObj.reconcile({ val: 42 }); - expect(liveObj.toImmutable()).toEqual({ val: 42 }); + expect(liveObj.toJSON()).toEqual({ val: 42 }); }); test("deep-liveifies a new array as LiveList", () => { const liveObj = new LiveObject<{ a: number; items?: number[] }>({ a: 1 }); liveObj.reconcile({ a: 1, items: [1, 2, 3] }); - expect(liveObj.toImmutable()).toEqual({ a: 1, items: [1, 2, 3] }); + expect(liveObj.toJSON()).toEqual({ a: 1, items: [1, 2, 3] }); expect(liveObj.get("items")).toBeInstanceOf(LiveList); }); @@ -217,7 +199,7 @@ describe("reconcileLiveObject", () => { }); const listBefore = liveObj.get("items"); liveObj.reconcile({ items: [1, 2, 4] }); - expect(liveObj.toImmutable()).toEqual({ items: [1, 2, 4] }); + expect(liveObj.toJSON()).toEqual({ items: [1, 2, 4] }); // Same LiveList instance expect(liveObj.get("items")).toBe(listBefore); }); @@ -225,9 +207,9 @@ describe("reconcileLiveObject", () => { test("skips subtree when cached immutable matches", () => { const nested = new LiveObject({ x: 1, y: 2 }); const liveObj = new LiveObject({ nested }); - const snapshot = nested.toImmutable(); + const snapshot = nested.toJSON(); liveObj.reconcile({ nested: snapshot }); - expect(liveObj.toImmutable()).toEqual({ nested: { x: 1, y: 2 } }); + expect(liveObj.toJSON()).toEqual({ nested: { x: 1, y: 2 } }); expect(liveObj.get("nested")).toBe(nested); }); @@ -241,7 +223,7 @@ describe("reconcileLiveObject", () => { liveObj.reconcile({ foo: { bar: { qux: 123, other: "keep" } }, }); - expect(liveObj.toImmutable()).toEqual({ + expect(liveObj.toJSON()).toEqual({ foo: { bar: { qux: 123, other: "keep" } }, }); // Same LiveObject instances preserved @@ -253,7 +235,7 @@ describe("reconcileLiveObject", () => { items: new LiveList([new LiveObject({ a: 1 })]), }); liveObj.reconcile({ items: [42] }); - expect(liveObj.toImmutable()).toEqual({ items: [42] }); + expect(liveObj.toJSON()).toEqual({ items: [42] }); }); test("appends elements when new array is longer", () => { @@ -261,7 +243,7 @@ describe("reconcileLiveObject", () => { items: new LiveList([1, 2]), }); liveObj.reconcile({ items: [1, 2, 3, 4] }); - expect(liveObj.toImmutable()).toEqual({ items: [1, 2, 3, 4] }); + expect(liveObj.toJSON()).toEqual({ items: [1, 2, 3, 4] }); }); test("removes elements when new array is shorter", () => { @@ -269,7 +251,7 @@ describe("reconcileLiveObject", () => { items: new LiveList([1, 2, 3, 4]), }); liveObj.reconcile({ items: [1, 2] }); - expect(liveObj.toImmutable()).toEqual({ items: [1, 2] }); + expect(liveObj.toJSON()).toEqual({ items: [1, 2] }); }); test("replaces LiveList with scalar when type changes", () => { @@ -277,20 +259,20 @@ describe("reconcileLiveObject", () => { val: new LiveList([1, 2]), }); liveObj.reconcile({ val: "hello" }); - expect(liveObj.toImmutable()).toEqual({ val: "hello" }); + expect(liveObj.toJSON()).toEqual({ val: "hello" }); }); test("replaces scalar with LiveObject when type changes", () => { const liveObj = new LiveObject({ val: 42 }); liveObj.reconcile({ val: { a: 1 } }); - expect(liveObj.toImmutable()).toEqual({ val: { a: 1 } }); + expect(liveObj.toJSON()).toEqual({ val: { a: 1 } }); expect(liveObj.get("val")).toBeInstanceOf(LiveObject); }); test("replaces scalar with LiveList when type changes", () => { const liveObj = new LiveObject({ val: 42 }); liveObj.reconcile({ val: [1, 2] }); - expect(liveObj.toImmutable()).toEqual({ val: [1, 2] }); + expect(liveObj.toJSON()).toEqual({ val: [1, 2] }); expect(liveObj.get("val")).toBeInstanceOf(LiveList); }); @@ -307,10 +289,10 @@ describe("reconcileLiveObject", () => { fc.assert( fc.property(jsonObject, jsonObject, (initial, target) => { const liveObj = LiveObject.from(initial); - expect(liveObj.toImmutable()).toEqual(initial); + expect(liveObj.toJSON()).toEqual(initial); liveObj.reconcile(target); - expect(liveObj.toImmutable()).toEqual(target); + expect(liveObj.toJSON()).toEqual(target); }) ); }); @@ -382,38 +364,10 @@ describe("reconcileLiveObject", () => { }); }); -describe("legacy_patchLiveObjectKey", () => { - test("should set string", () => { - const liveObject = new LiveObject(); - legacy_patchLiveObjectKey(liveObject, "key", undefined, "value"); - expect(liveObject.get("key")).toBe("value"); - }); - - test("should set number", () => { - const liveObject = new LiveObject(); - legacy_patchLiveObjectKey(liveObject, "key", undefined, 0); - expect(liveObject.get("key")).toBe(0); - }); - - test("should set LiveObject if next is object", () => { - const liveObject = new LiveObject<{ key: LiveObject<{ a: number }> }>(); - legacy_patchLiveObjectKey(liveObject, "key", undefined, { a: 0 }); - const value = liveObject.get("key"); - expect(value instanceof LiveObject).toBe(true); - expect(value.toObject()).toEqual({ a: 0 }); - }); - - test("should delete key if next is undefined", () => { - const liveObject = new LiveObject({ key: "value" }); - legacy_patchLiveObjectKey(liveObject, "key", "value", undefined); - expect(liveObject.toObject()).toEqual({}); - }); -}); - describe("2 ways tests with two clients", () => { describe("Object/LiveObject", () => { test("create object", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncObj: { a: number }; }>({ @@ -421,24 +375,12 @@ describe("2 ways tests with two clients", () => { data: {}, }); - expect(state).toEqual({}); - - const { oldState, newState } = applyStateChanges(state, () => { - state.syncObj = { a: 1 }; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - newState["syncObj"] - ); - + storage.root.reconcilePartially({ syncObj: { a: 1 } } as JsonObject); await expectStorageAndState({ syncObj: { a: 1 } }, 2); }); test("update object", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncObj: { a: number }; }>({ @@ -448,24 +390,12 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ syncObj: { a: 0 } }); - - const { oldState, newState } = applyStateChanges(state, () => { - state.syncObj.a = 1; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - newState["syncObj"] - ); - + storage.root.reconcilePartially({ syncObj: { a: 1 } } as JsonObject); await expectStorageAndState({ syncObj: { a: 1 } }, 2); }); test("add nested object", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncObj: { a: any }; }>({ @@ -475,24 +405,14 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ syncObj: { a: 0 } }); - - const { oldState, newState } = applyStateChanges(state, () => { - state.syncObj.a = { subA: "ok" }; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - newState["syncObj"] - ); - + storage.root.reconcilePartially({ + syncObj: { a: { subA: "ok" } }, + } as JsonObject); await expectStorageAndState({ syncObj: { a: { subA: "ok" } } }, 3); }); test("create LiveList with one LiveRegister item in same batch", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ doc: any; }>({ @@ -502,24 +422,12 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ doc: {} }); - - const { oldState, newState } = applyStateChanges(state, () => { - state.doc = { sub: [0] }; - }); - - legacy_patchLiveObjectKey( - storage.root, - "doc", - oldState["doc"], - newState["doc"] - ); - + storage.root.reconcilePartially({ doc: { sub: [0] } } as JsonObject); await expectStorageAndState({ doc: { sub: [0] } }, 4); }); test("create nested LiveList with one LiveObject item in same batch", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ doc: any; }>({ @@ -529,24 +437,14 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ doc: {} }); - - const { oldState, newState } = applyStateChanges(state, () => { - state.doc = { sub: { subSub: [{ a: 1 }] } }; - }); - - legacy_patchLiveObjectKey( - storage.root, - "doc", - oldState["doc"], - newState["doc"] - ); - + storage.root.reconcilePartially({ + doc: { sub: { subSub: [{ a: 1 }] } }, + } as JsonObject); await expectStorageAndState({ doc: { sub: { subSub: [{ a: 1 }] } } }, 5); }); test("Add nested objects in same batch", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ doc: any; }>({ @@ -556,24 +454,14 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ doc: {} }); - - const { oldState, newState } = applyStateChanges(state, () => { - state.doc = { pos: { a: { b: 1 } } }; - }); - - legacy_patchLiveObjectKey( - storage.root, - "doc", - oldState["doc"], - newState["doc"] - ); - + storage.root.reconcilePartially({ + doc: { pos: { a: { b: 1 } } }, + } as JsonObject); await expectStorageAndState({ doc: { pos: { a: { b: 1 } } } }, 4); }); test("delete object key", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncObj: { a?: number }; }>({ @@ -583,26 +471,14 @@ describe("2 ways tests with two clients", () => { }, }); - expect(state).toEqual({ syncObj: { a: 0 } }); - - const { oldState, newState } = applyStateChanges(state, () => { - delete state.syncObj.a; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - newState["syncObj"] - ); - + storage.root.reconcilePartially({ syncObj: {} } as JsonObject); await expectStorageAndState({ syncObj: {} }, 2); }); }); describe("Array/LiveList", () => { test("replace array of 3 elements to 1 element", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -612,22 +488,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList = [2]; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: [2] } as JsonObject); await expectStorageAndState({ syncList: [2] }); }); test("add item to array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -637,22 +503,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList.push("a"); - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: ["a"] } as JsonObject); await expectStorageAndState({ syncList: ["a"] }, 3); }); test("replace first item in array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ list: LiveList; }>({ @@ -662,17 +518,14 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.list[0] = "D"; - }); - - legacy_patchLiveObject(storage.root, oldState, newState); - + storage.root.reconcilePartially({ + list: ["D", "B", "C"], + } as JsonObject); await expectStorageAndState({ list: ["D", "B", "C"] }, 5); }); test("replace last item in array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ list: LiveList; }>({ @@ -682,17 +535,14 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.list[2] = "D"; - }); - - legacy_patchLiveObject(storage.root, oldState, newState); - + storage.root.reconcilePartially({ + list: ["A", "B", "D"], + } as JsonObject); await expectStorageAndState({ list: ["A", "B", "D"] }, 5); }); test("insert item at beginning of array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -702,22 +552,14 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList.unshift("b"); - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ + syncList: ["b", "a"], + } as JsonObject); await expectStorageAndState({ syncList: ["b", "a"] }, 4); }); test("swap items in array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -730,22 +572,14 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList = ["d", "b", "c", "a"]; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ + syncList: ["d", "b", "c", "a"], + } as JsonObject); await expectStorageAndState({ syncList: ["d", "b", "c", "a"] }, 6); }); test("array of objects", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList>; }>({ @@ -758,22 +592,14 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList[0].a = 2; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ + syncList: [{ a: 2 }], + } as JsonObject); await expectStorageAndState({ syncList: [{ a: 2 }] }, 3); }); test("remove first item from array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -783,22 +609,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList.shift(); - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: ["b"] } as JsonObject); await expectStorageAndState({ syncList: ["b"] }, 3); }); test("remove last item from array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -808,22 +624,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList.pop(); - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: ["a"] } as JsonObject); await expectStorageAndState({ syncList: ["a"] }, 3); }); test("remove all elements of array except first", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -836,22 +642,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList = ["a"]; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: ["a"] } as JsonObject); await expectStorageAndState({ syncList: ["a"] }, 3); }); test("remove all elements of array except last", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -864,22 +660,12 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList = ["c"]; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: ["c"] } as JsonObject); await expectStorageAndState({ syncList: ["c"] }, 3); }); test("remove all elements of array", async () => { - const { storage, state, expectStorageAndState } = + const { storage, expectStorageAndState } = await prepareStorageImmutableTest<{ syncList: LiveList; }>({ @@ -892,786 +678,8 @@ describe("2 ways tests with two clients", () => { }, }); - const { oldState, newState } = applyStateChanges(state, () => { - state.syncList = []; - }); - - legacy_patchLiveObjectKey( - storage.root, - "syncList", - oldState["syncList"], - newState["syncList"] - ); - + storage.root.reconcilePartially({ syncList: [] } as JsonObject); await expectStorageAndState({ syncList: [] }, 2); }); }); - - describe("unsupported types", () => { - let originalEnv: NodeJS.ProcessEnv; - let consoleErrorSpy: MockInstance; - - beforeAll(() => { - originalEnv = process.env; - consoleErrorSpy = vi.spyOn(console, "error"); - }); - - afterEach(() => { - process.env = originalEnv; - consoleErrorSpy.mockRestore(); - }); - - test("new state contains a function", async () => { - const { storage, state, expectStorage } = - await prepareStorageImmutableTest<{ syncObj: { a: any } }>({ - liveblocksType: "LiveObject", - data: { - syncObj: { liveblocksType: "LiveObject", data: { a: 0 } }, - }, - }); - - expect(state).toEqual({ syncObj: { a: 0 } }); - - const oldState = JSON.parse(JSON.stringify(state)); - - state.syncObj.a = () => {}; - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - state["syncObj"] - ); - - expect(consoleErrorSpy).toHaveBeenCalledTimes(1); - - await expectStorage({ syncObj: { a: 0 } }); - }); - - test("Production env - new state contains a function", async () => { - const { storage, state } = await prepareStorageImmutableTest<{ - syncObj: { a: any }; - }>({ - liveblocksType: "LiveObject", - data: { - syncObj: { liveblocksType: "LiveObject", data: { a: 0 } }, - }, - }); - - expect(state).toEqual({ syncObj: { a: 0 } }); - - process.env = { - ...originalEnv, - NODE_ENV: "production", - }; - - const oldState = JSON.parse(JSON.stringify(state)); - - state.syncObj.a = () => {}; - - legacy_patchLiveObjectKey( - storage.root, - "syncObj", - oldState["syncObj"], - state["syncObj"] - ); - - expect(consoleErrorSpy).toHaveBeenCalledTimes(0); - }); - }); -}); - -describe("legacy_patchImmutableObject", () => { - test("update one sub object", () => { - const state = { subA: { subsubA: { a: 1 } }, subB: { b: 1 } }; - - const root = new LiveObject(); - root.set("subA", new LiveObject({ subsubA: new LiveObject({ a: 1 }) })); - root.set("subB", new LiveObject({ b: 2 })); - - const updates: StorageUpdate[] = [ - { - type: "LiveObject", - node: root, - updates: { subB: { type: "update" } }, - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.subB === state.subB).toBeFalsy(); - expect(newState.subA === state.subA).toBeTruthy(); - expect(newState).toEqual({ subA: { subsubA: { a: 1 } }, subB: { b: 2 } }); - }); - - test("update one sub object of sub object", () => { - const state = { - subA: { subsubA: { a: 1 }, subsubB: { b: 1 } }, - subB: { b: 1 }, - }; - - const root = new LiveObject<{ - subA: LiveObject<{ - subsubA: LiveObject<{ a: number }>; - subsubB: LiveObject<{ b: number }>; - }>; - subB: LiveObject<{ b: number }>; - }>(); - root.set( - "subA", - new LiveObject({ - subsubA: new LiveObject({ a: 2 }), - subsubB: new LiveObject({ b: 1 }), - }) - ); - root.set("subB", new LiveObject({ b: 1 })); - - const updates: StorageUpdate[] = [ - { - type: "LiveObject", - node: root.get("subA"), - updates: { subsubA: { type: "update" } }, - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.subB === state.subB).toBeTruthy(); - expect(newState.subA === state.subA).toBeFalsy(); - expect(newState.subA.subsubB === state.subA.subsubB).toBeTruthy(); - expect(newState.subA.subsubA === state.subA.subsubA).toBeFalsy(); - expect(newState).toEqual({ - subA: { subsubA: { a: 2 }, subsubB: { b: 1 } }, - subB: { b: 1 }, - }); - }); - - test("multiple updates", () => { - const state = { - subA: { subsubA: { a: 1 }, subsubB: { b: 1 } }, - subB: { b: 1 }, - }; - - const root = new LiveObject<{ - subA: LiveObject<{ - subsubA: LiveObject<{ a: number }>; - subsubB?: LiveObject<{ b: number }>; - }>; - subB: LiveObject<{ b: number }>; - }>(); - root.set( - "subA", - new LiveObject({ - subsubA: new LiveObject({ a: 2 }), - }) - ); - root.set("subB", new LiveObject({ b: 2 })); - - const updates: StorageUpdate[] = [ - { - type: "LiveObject", - node: root.get("subA"), - updates: { subsubA: { type: "update" } }, - }, - { - type: "LiveObject", - node: root.get("subA"), - updates: { subsubB: { type: "delete", deletedItem: "" } }, - }, - { - type: "LiveObject", - node: root.get("subB"), - updates: { b: { type: "update" } }, - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.subB === state.subB).toBeFalsy(); - expect(newState.subA === state.subA).toBeFalsy(); - expect(newState.subA.subsubA === state.subA.subsubA).toBeFalsy(); - expect(newState).toEqual({ - subA: { subsubA: { a: 2 } }, - subB: { b: 2 }, - }); - }); - - test("add element to Map/LiveMap", () => { - const state = { - map: { el1: { a: 1 } }, - }; - - const root = new LiveObject<{ map: typeof liveMap }>(); - const liveMap = new LiveMap>(); - liveMap.set("el1", new LiveObject({ a: 1 })); - liveMap.set("el2", new LiveObject({ a: 2 })); - - root.set("map", liveMap); - - const updates: StorageUpdate[] = [ - { - type: "LiveMap", - node: root.get("map"), - updates: { el2: { type: "update" } }, - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.map.el1 === state.map.el1).toBeTruthy(); - - expect(newState).toEqual({ - map: { el1: { a: 1 }, el2: { a: 2 } }, - }); - }); - - test("remove element from Map/LiveMap", () => { - const state = { - map: { el1: { a: 1 }, el2: { a: 2 } }, - }; - - const root = new LiveObject<{ map: typeof liveMap }>(); - const liveMap = new LiveMap(); - liveMap.set("el1", new LiveObject({ a: 1 })); - - root.set("map", liveMap); - - const updates: StorageUpdate[] = [ - { - type: "LiveMap", - node: root.get("map"), - updates: { el2: { type: "delete", deletedItem: "" } }, - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.map.el1 === state.map.el1).toBeTruthy(); - - expect(newState).toEqual({ - map: { el1: { a: 1 } }, - }); - }); - - test("replace an element in Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }, { a: 3 }], - }; - - const root = new LiveObject<{ - list: typeof liveList; - }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - liveList.push(new LiveObject({ a: 2 })); - liveList.push(new LiveObject({ a: 3 })); - const obj1 = new LiveObject({ a: 4 }); - liveList.set(1, obj1); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 1, item: obj1, type: "set" }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - expect(newState.list[1] === state.list[1]).toBeFalsy(); - expect(newState.list[2] === state.list[2]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 1 }, { a: 4 }, { a: 3 }], - }); - }); - - test("insert element at the end of Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }], - }; - - const root = new LiveObject<{ - list: typeof liveList; - }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - liveList.push(new LiveObject({ a: 2 })); - const obj1 = new LiveObject({ a: 3 }); - liveList.push(obj1); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 2, item: obj1, type: "insert" }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - expect(newState.list[1] === state.list[1]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 1 }, { a: 2 }, { a: 3 }], - }); - }); - - test("insert element at the beginning of and Array/LiveList", () => { - const state = { - list: [{ a: 1 }], - }; - - const root = new LiveObject<{ - list: typeof liveList; - }>(); - const liveList = new LiveList>([]); - const newObj = new LiveObject({ a: 0 }); - liveList.push(newObj); - liveList.push(new LiveObject({ a: 1 })); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 0, item: newObj, type: "insert" }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeFalsy(); - expect(newState.list[1] === state.list[1]).toBeFalsy(); - - expect(newState).toEqual({ - list: [{ a: 0 }, { a: 1 }], - }); - }); - - test("insert 2 elements at the beginning of and Array/LiveList", () => { - const state = { - list: [{ a: 1 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - const newObj1 = new LiveObject({ a: 2 }); - const newObj2 = new LiveObject({ a: 3 }); - - liveList.push(newObj2); - liveList.push(newObj1); - - liveList.push(new LiveObject({ a: 1 })); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 0, item: newObj1, type: "insert" }, - { index: 0, item: newObj2, type: "insert" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[2] === state.list[0]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 3 }, { a: 2 }, { a: 1 }], - }); - }); - - test("insert 2 elements at the end of and Array/LiveList", () => { - const state = { - list: [{ a: 1 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - const newObj1 = new LiveObject({ a: 2 }); - const newObj2 = new LiveObject({ a: 3 }); - - liveList.push(new LiveObject({ a: 1 })); - liveList.push(newObj1); - liveList.push(newObj2); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 1, item: newObj1, type: "insert" }, - { index: 2, item: newObj2, type: "insert" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 1 }, { a: 2 }, { a: 3 }], - }); - }); - - test("insert element in the middle of Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - const newObj = new LiveObject({ a: 15 }); - liveList.push(newObj); - liveList.push(new LiveObject({ a: 2 })); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 1, item: newObj, type: "insert" }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - expect(newState.list[2] === state.list[1]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 1 }, { a: 15 }, { a: 2 }], - }); - }); - - test("delete element from the end of Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - liveList.push(new LiveObject({ a: 2 })); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 1, type: "delete", deletedItem: liveList.get(1)! }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 1 }], - }); - }); - - test("delete element from the beginning of Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - liveList.push(new LiveObject({ a: 2 })); - liveList.delete(0); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [{ index: 0, type: "delete", deletedItem: liveList.get(0)! }], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[1]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 2 }], - }); - }); - - test("delete 2 elements from the beginning of Array/LiveList", () => { - const state = { - list: [{ a: 1 }, { a: 2 }, { a: 3 }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ a: 1 })); - liveList.push(new LiveObject({ a: 2 })); - liveList.push(new LiveObject({ a: 3 })); - const x = liveList.get(0)!; - liveList.delete(0); - const y = liveList.get(0)!; - liveList.delete(0); - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 0, type: "delete", deletedItem: x }, - { index: 0, type: "delete", deletedItem: y }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[2]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ a: 3 }], - }); - }); - - describe("move items in array/LiveList", () => { - test("move index 2 to 0", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - const movedObj = new LiveObject({ i: "c" }); - liveList.push(movedObj); - liveList.push(new LiveObject({ i: "a" })); - liveList.push(new LiveObject({ i: "b" })); - liveList.push(new LiveObject({ i: "d" })); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 0, previousIndex: 2, item: movedObj, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[1] === state.list[0]).toBeTruthy(); - expect(newState.list[2] === state.list[1]).toBeTruthy(); - expect(newState.list[3] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "c" }, { i: "a" }, { i: "b" }, { i: "d" }], - }); - }); - - test("move index 0 to 3", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ i: "b" })); - liveList.push(new LiveObject({ i: "c" })); - liveList.push(new LiveObject({ i: "d" })); - const movedObj = new LiveObject({ i: "a" }); - liveList.push(movedObj); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 3, previousIndex: 0, item: movedObj, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[1]).toBeTruthy(); - expect(newState.list[1] === state.list[2]).toBeTruthy(); - expect(newState.list[2] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "b" }, { i: "c" }, { i: "d" }, { i: "a" }], - }); - }); - - test("move index 1 to 3", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ i: "a" })); - liveList.push(new LiveObject({ i: "c" })); - liveList.push(new LiveObject({ i: "d" })); - const movedObj = new LiveObject({ i: "b" }); - liveList.push(movedObj); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 3, previousIndex: 1, item: movedObj, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - expect(newState.list[1] === state.list[2]).toBeTruthy(); - expect(newState.list[2] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "a" }, { i: "c" }, { i: "d" }, { i: "b" }], - }); - }); - - test("move index 1 to 2", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - liveList.push(new LiveObject({ i: "a" })); - liveList.push(new LiveObject({ i: "c" })); - const movedObj = new LiveObject({ i: "b" }); - liveList.push(movedObj); - liveList.push(new LiveObject({ i: "d" })); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 2, previousIndex: 1, item: movedObj, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[0]).toBeTruthy(); - expect(newState.list[1] === state.list[2]).toBeTruthy(); - expect(newState.list[3] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "a" }, { i: "c" }, { i: "b" }, { i: "d" }], - }); - }); - - test("2 moves different places", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - const objA = new LiveObject({ i: "a" }); - const objB = new LiveObject({ i: "b" }); - const objC = new LiveObject({ i: "c" }); - const objD = new LiveObject({ i: "d" }); - - liveList.push(objB); - liveList.push(objA); - liveList.push(objD); - liveList.push(objC); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 1, previousIndex: 0, item: objA, type: "move" }, - { index: 3, previousIndex: 2, item: objC, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[0] === state.list[1]).toBeTruthy(); - expect(newState.list[2] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "b" }, { i: "a" }, { i: "d" }, { i: "c" }], - }); - }); - - test("2 moves same place ([a b c d] => [b a c d] => [c b a d])", () => { - const state = { - list: [{ i: "a" }, { i: "b" }, { i: "c" }, { i: "d" }], - }; - - const root = new LiveObject<{ list: typeof liveList }>(); - const liveList = new LiveList>([]); - const objA = new LiveObject({ i: "a" }); - const objB = new LiveObject({ i: "b" }); - const objC = new LiveObject({ i: "c" }); - const objD = new LiveObject({ i: "d" }); - - liveList.push(objC); - liveList.push(objB); - liveList.push(objA); - liveList.push(objD); - - root.set("list", liveList); - - const updates: StorageUpdate[] = [ - { - type: "LiveList", - node: root.get("list"), - updates: [ - { index: 0, previousIndex: 1, item: objB, type: "move" }, - { index: 0, previousIndex: 2, item: objC, type: "move" }, - ], - }, - ]; - - const newState = legacy_patchImmutableObject(state, updates); - - expect(newState.list[2] === state.list[0]).toBeTruthy(); - expect(newState.list[3] === state.list[3]).toBeTruthy(); - - expect(newState).toEqual({ - list: [{ i: "c" }, { i: "b" }, { i: "a" }, { i: "d" }], - }); - }); - }); }); diff --git a/packages/liveblocks-core/src/__tests__/room.devserver.test.ts b/packages/liveblocks-core/src/__tests__/room.devserver.test.ts index ef5994e67d6..11c6222d7fe 100644 --- a/packages/liveblocks-core/src/__tests__/room.devserver.test.ts +++ b/packages/liveblocks-core/src/__tests__/room.devserver.test.ts @@ -9,8 +9,6 @@ import { describe, expect, onTestFinished, test } from "vitest"; import { LiveList } from "../crdts/LiveList"; import { LiveObject } from "../crdts/LiveObject"; -import type { StorageUpdate } from "../crdts/StorageUpdates"; -import { legacy_patchImmutableObject } from "../immutable"; import { kInternal } from "../internal"; import { nn } from "../lib/assert"; import { prepareIsolatedStorageTest } from "./_devserver"; @@ -46,17 +44,17 @@ describe("room (dev server)", () => { room.history.resume(); room.history.resume(); // Resuming again should also be a no-op! - expect(items.toImmutable()).toEqual([{ a: 1, b: 2 }]); + expect(items.toJSON()).toEqual([{ a: 1, b: 2 }]); expect(room.history.canUndo()).toBe(true); expect(room.history.canRedo()).toBe(false); room.history.undo(); - expect(items.toImmutable()).toEqual([{}]); + expect(items.toJSON()).toEqual([{}]); expect(room.history.canUndo()).toBe(false); expect(room.history.canRedo()).toBe(true); room.history.redo(); - expect(items.toImmutable()).toEqual([{ a: 1, b: 2 }]); + expect(items.toJSON()).toEqual([{ a: 1, b: 2 }]); expect(room.history.canUndo()).toBe(true); expect(room.history.canRedo()).toBe(false); }); @@ -89,13 +87,13 @@ describe("room (dev server)", () => { items.set(0, new LiveObject({ a: 2 })); }); - expect(items.toImmutable()).toEqual([{ a: 2 }]); + expect(items.toJSON()).toEqual([{ a: 2 }]); room.history.undo(); - expect(items.toImmutable()).toEqual([{}]); + expect(items.toJSON()).toEqual([{}]); room.history.redo(); - expect(items.toImmutable()).toEqual([{ a: 2 }]); + expect(items.toJSON()).toEqual([{ a: 2 }]); expect(receivedUpdates).toEqual([ [listUpdate([{ a: 2 }], [listUpdateSet(0, { a: 2 })])], [listUpdate([{}], [listUpdateSet(0, {})])], @@ -148,7 +146,7 @@ describe("room (dev server)", () => { room.history.undo(); // won't do anything now - expect(root.toObject()).toEqual({ a: 3 }); + expect(root.toJSON()).toEqual({ a: 3 }); }); describe("subscription", () => { @@ -228,19 +226,13 @@ describe("room (dev server)", () => { }); const jsonUpdates: JsonStorageUpdate[][] = []; - let receivedUpdates: StorageUpdate[] = []; onTestFinished( room.events.storageBatch.subscribe((updates) => { jsonUpdates.push(updates.map(serializeUpdateToJson)); - receivedUpdates = updates; }) ); - const immutableState = root.toImmutable() as { - items: Array<{ names: Array }>; - }; - room.batch(() => { const items = root.get("items"); items.insert(new LiveObject({ names: new LiveList(["John Doe"]) }), 0); @@ -264,13 +256,6 @@ describe("room (dev server)", () => { listUpdate(["Jane Doe"], [listUpdateInsert(0, "Jane Doe")]), ], ]); - - // Additional check to prove that generated updates could patch an immutable state - const newImmutableState = legacy_patchImmutableObject( - immutableState, - receivedUpdates - ); - expect(newImmutableState).toEqual(root.toImmutable()); }); }); diff --git a/packages/liveblocks-core/src/__tests__/room.mockserver.test.ts b/packages/liveblocks-core/src/__tests__/room.mockserver.test.ts index 3c766be4c00..80e243e720b 100644 --- a/packages/liveblocks-core/src/__tests__/room.mockserver.test.ts +++ b/packages/liveblocks-core/src/__tests__/room.mockserver.test.ts @@ -24,7 +24,6 @@ import { LiveList } from "../crdts/LiveList"; import { LiveMap } from "../crdts/LiveMap"; import { LiveObject } from "../crdts/LiveObject"; import type { LsonObject } from "../crdts/Lson"; -import { lsonToJson } from "../immutable"; import { kInternal } from "../internal"; import { makeEventSource } from "../lib/EventSource"; import * as console from "../lib/fancy-console"; @@ -999,8 +998,8 @@ describe("room", () => { room.connect(); const storage = await room.getStorage(); - expect(storage.root.toObject()).toEqual({ foo: 1234 }); - // ^^^ Added by the client, from initialStorage + expect(storage.root.toJSON()).toEqual({ foo: 1234 }); + // ^^^ Added by the client, from initialStorage expect(room.history.canUndo()).toBe(false); }); @@ -1039,9 +1038,9 @@ describe("room", () => { room.connect(); try { const { root } = await room.getStorage(); - expect(root.toImmutable()).toEqual({ + expect(root.toJSON()).toEqual({ list: [13, 42], - map: new Map([["a", 1]]), + map: { a: 1 }, obj: { x: 0 }, }); @@ -1073,7 +1072,7 @@ describe("room", () => { room.connect(); const storage = await room.getStorage(); - expect(storage.root.toObject()).toEqual({ x: 0 }); + expect(storage.root.toJSON()).toEqual({ x: 0 }); }); test("undo redo with presence", async () => { @@ -1126,7 +1125,7 @@ describe("room", () => { room.history.undo(); expect(room.getPresence()).toEqual({ x: 1 }); - expect(storage.root.toObject()).toEqual({ x: 0 }); + expect(storage.root.toJSON()).toEqual({ x: 0 }); room.history.redo(); }); @@ -1241,12 +1240,12 @@ describe("room", () => { expect(room[kInternal].presenceBuffer).toEqual({ x: 0 }); expect(room.getPresence()).toEqual({ x: 0 }); - expect(storage.root.toObject()).toEqual({ x: 0 }); + expect(storage.root.toJSON()).toEqual({ x: 0 }); room.history.redo(); expect(room[kInternal].presenceBuffer).toEqual({ x: 1 }); - expect(storage.root.toObject()).toEqual({ x: 1 }); + expect(storage.root.toJSON()).toEqual({ x: 1 }); expect(room.getPresence()).toEqual({ x: 1 }); }); @@ -1270,12 +1269,12 @@ describe("room", () => { storage.root.set("x", 1); room.history.undo(); - expect(storage.root.toObject()).toEqual({ x: 0 }); + expect(storage.root.toJSON()).toEqual({ x: 0 }); room.batch(() => {}); room.history.redo(); - expect(storage.root.toObject()).toEqual({ x: 1 }); + expect(storage.root.toJSON()).toEqual({ x: 1 }); }); describe("subscription", () => { @@ -1660,9 +1659,9 @@ describe("room", () => { // Other client (which is still online), deletes "C". refStorage.root.get("items").delete(1); - const storageJson = lsonToJson(storage.root); + const storageJson = storage.root.toJSON(); expect(storageJson).toEqual({ items: ["A", "C", "B"] }); - const refStorageJson = lsonToJson(refStorage.root); + const refStorageJson = refStorage.root.toJSON(); expect(refStorageJson).toEqual({ items: ["A"] }); const newInitStorage: StorageNode[] = [ @@ -1813,9 +1812,9 @@ describe("room", () => { expect(storageStatusCallback).toHaveBeenCalledWith("synchronizing"); expect(room.getStorageStatus()).toBe("synchronizing"); - const storageJson = lsonToJson(storage.root); + const storageJson = storage.root.toJSON(); expect(storageJson).toEqual({ x: 1 }); - const refStorageJson = lsonToJson(refStorage.root); + const refStorageJson = refStorage.root.toJSON(); expect(refStorageJson).toEqual({ x: 0 }); const newInitStorage: StorageNode[] = [createSerializedRoot({ x: 0 })]; diff --git a/packages/liveblocks-core/src/__tests__/sync-config.test.ts b/packages/liveblocks-core/src/__tests__/sync-config.test.ts index ab4386b9a0c..ff67049ed7c 100644 --- a/packages/liveblocks-core/src/__tests__/sync-config.test.ts +++ b/packages/liveblocks-core/src/__tests__/sync-config.test.ts @@ -51,7 +51,7 @@ describe("LiveObject.from() with SyncConfig", () => { const pos2 = result.get("pos2"); assertThat(pos2, isLiveObject); - expect(pos2.toObject()).toEqual({ x: 50, y: 60 }); + expect(pos2.toJSON()).toEqual({ x: 50, y: 60 }); }); test("stores array value as plain Json (no LiveList wrapping)", () => { @@ -66,7 +66,7 @@ describe("LiveObject.from() with SyncConfig", () => { const other = result.get("other"); assertThat(other, isLiveList); - expect(other.toArray()).toEqual([4, 5]); + expect(other.toJSON()).toEqual([4, 5]); }); }); @@ -421,8 +421,41 @@ function syncConfigFor(keys: string[]): fc.Arbitrary { }); } +describe("reconcilePartially", () => { + test("leaves keys not in the partial object untouched", () => { + const lo = LiveObject.from({ a: 1, b: 2, c: 3 }); + lo.reconcilePartially({ a: 10 }); + expect(lo.toJSON()).toEqual({ a: 10, b: 2, c: 3 }); + }); + + test("adds new keys that don't exist yet", () => { + const lo = LiveObject.from({ a: 1 }); + lo.reconcilePartially({ b: 2 }); + expect(lo.toJSON()).toEqual({ a: 1, b: 2 }); + }); + + test("updates nested structures recursively", () => { + const lo = LiveObject.from({ obj: { x: 1, y: 2 }, other: 99 }); + lo.reconcilePartially({ obj: { x: 10 } }); + // Nested reconciliation is full — y is deleted because it's absent from the nested object + expect(lo.toJSON()).toEqual({ obj: { x: 10 }, other: 99 }); + }); + + test("reconcile (full) deletes key when value is undefined", () => { + const lo = LiveObject.from({ a: 1, b: 2 }); + lo.reconcile({ a: undefined, b: 2 }); + expect(lo.toJSON()).toEqual({ b: 2 }); + }); + + test("ignores explicitly-undefined keys (does not delete them)", () => { + const lo = LiveObject.from({ a: 1, b: 2 }); + lo.reconcilePartially({ a: undefined }); + expect(lo.toJSON()).toEqual({ a: 1, b: 2 }); + }); +}); + describe("property tests", () => { - test("LiveObject.from(obj, config).toImmutable() === obj for any config", () => { + test("LiveObject.from(obj, config).toJSON() === obj for any config", () => { fc.assert( fc.property( jsonObject.chain((obj) => @@ -432,13 +465,13 @@ describe("property tests", () => { ), ([obj, config]) => { const liveObj = LiveObject.from(obj, config); - expect(liveObj.toImmutable()).toEqual(obj); + expect(liveObj.toJSON()).toEqual(obj); } ) ); }); - test("lo.reconcile(obj, config).toImmutable() === obj for any config", () => { + test("lo.reconcile(obj, config).toJSON() === obj for any config", () => { fc.assert( fc.property( fc @@ -450,7 +483,7 @@ describe("property tests", () => { ), ([lo, target, config]) => { lo.reconcile(target, config); - expect(lo.toImmutable()).toEqual(target); + expect(lo.toJSON()).toEqual(target); } ) ); diff --git a/packages/liveblocks-core/src/client.ts b/packages/liveblocks-core/src/client.ts index 2a933511bb2..9342b812c89 100644 --- a/packages/liveblocks-core/src/client.ts +++ b/packages/liveblocks-core/src/client.ts @@ -4,6 +4,8 @@ import { createApiClient } from "./api-client"; import { createAuthManager } from "./auth-manager"; import { isIdle, StopRetrying } from "./connection"; import { DEFAULT_BASE_URL } from "./constants"; +import { isLiveObject } from "./crdts/liveblocks-helpers"; +import type { LiveObject } from "./crdts/LiveObject"; import type { LsonObject } from "./crdts/Lson"; import { linkDevTools, setupDevTools, unlinkDevTools } from "./devtools"; import type { @@ -156,7 +158,7 @@ export type EnterOptions

= /** * The initial Storage to use when entering a new Room. */ - initialStorage: S | ((roomId: string) => S); + initialStorage: S | LiveObject | ((roomId: string) => S | LiveObject); } > >; @@ -777,10 +779,20 @@ export function createClient( ? options.initialPresence(roomId) : options.initialPresence) ?? ({} as P); - const initialStorage = + const rawStorage = (typeof options.initialStorage === "function" ? options.initialStorage(roomId) : options.initialStorage) ?? ({} as S); + let initialStorage: S; + if (isLiveObject(rawStorage)) { + const obj: Record = {}; + for (const key of rawStorage.keys()) { + obj[key] = (rawStorage as LiveObject).get(key); + } + initialStorage = obj as S; + } else { + initialStorage = rawStorage; + } const newRoom = createRoom( { initialPresence, initialStorage }, diff --git a/packages/liveblocks-core/src/crdts/AbstractCrdt.ts b/packages/liveblocks-core/src/crdts/AbstractCrdt.ts index 6de816f446b..17324dab311 100644 --- a/packages/liveblocks-core/src/crdts/AbstractCrdt.ts +++ b/packages/liveblocks-core/src/crdts/AbstractCrdt.ts @@ -1,4 +1,5 @@ import { assertNever } from "../lib/assert"; +import type { ReadonlyJson } from "../lib/Json"; import type { Pos } from "../lib/position"; import { asPos } from "../lib/position"; import type { @@ -10,7 +11,6 @@ import type { import { OpCode } from "../protocol/Op"; import type { SerializedCrdt } from "../protocol/StorageNode"; import type * as DevTools from "../types/DevToolsTreeNode"; -import type { Immutable } from "../types/Immutable"; import type { LiveNode, Lson } from "./Lson"; import type { StorageUpdate } from "./StorageUpdates"; @@ -419,8 +419,8 @@ export abstract class AbstractCrdt { /** @internal */ abstract _serialize(): SerializedCrdt; - /** This caches the result of the last .toImmutable() call for this Live node. */ - #cachedImmutable?: Immutable; + /** This caches the result of the last .toJSON() call for this Live node. */ + #cachedJson?: ReadonlyJson; #cachedTreeNodeKey?: string | number; /** This caches the result of the last .toTreeNode() call for this Live node. */ @@ -429,16 +429,12 @@ export abstract class AbstractCrdt { /** * @internal * - * Clear the Immutable cache, so that the next call to `.toImmutable()` will - * recompute the equivalent Immutable value again. Call this after every - * mutation to the Live node. + * Clear the cached snapshots, so that the next call to `.toJSON()` will + * recompute. Call this after every mutation to the Live node. */ invalidate(): void { - if ( - this.#cachedImmutable !== undefined || - this.#cachedTreeNode !== undefined - ) { - this.#cachedImmutable = undefined; + if (this.#cachedJson !== undefined || this.#cachedTreeNode !== undefined) { + this.#cachedJson = undefined; this.#cachedTreeNode = undefined; if (this.parent.type === "HasParent") { @@ -465,29 +461,30 @@ export abstract class AbstractCrdt { } /** @internal */ - abstract _toImmutable(): Immutable; + abstract _toJSON(): ReadonlyJson; /** * @private - * Returns true if the cached immutable snapshot exists and is - * reference-equal to the given value. Does not trigger a recompute. + * Returns true if the cached JSON snapshot exists and is reference-equal + * to the given value. Does not trigger a recompute. */ - immutableIs(value: unknown): boolean { - return ( - this.#cachedImmutable !== undefined && this.#cachedImmutable === value - ); + hasCache(value: unknown): boolean { + return this.#cachedJson !== undefined && this.#cachedJson === value; } /** - * Return an immutable snapshot of this Live node and its children. + * Return a JSON-compatible snapshot of this Live node and its children. + * LiveObject values become plain objects, LiveList values become arrays, + * and LiveMap values also become plain objects (not Map instances). + * The result is cached and only recomputed when the contents change. */ - toImmutable(): Immutable { - if (this.#cachedImmutable === undefined) { - this.#cachedImmutable = this._toImmutable(); + toJSON(): ReadonlyJson { + if (this.#cachedJson === undefined) { + this.#cachedJson = this._toJSON(); } // Return cached version - return this.#cachedImmutable; + return this.#cachedJson; } /** diff --git a/packages/liveblocks-core/src/crdts/LiveList.ts b/packages/liveblocks-core/src/crdts/LiveList.ts index a06f7d9601d..e24673b2512 100644 --- a/packages/liveblocks-core/src/crdts/LiveList.ts +++ b/packages/liveblocks-core/src/crdts/LiveList.ts @@ -1,4 +1,5 @@ import { nn } from "../lib/assert"; +import { freeze } from "../lib/freeze"; import { nanoid } from "../lib/nanoid"; import type { Pos } from "../lib/position"; import { asPos, makePosition } from "../lib/position"; @@ -18,8 +19,7 @@ import { lsonToLiveNode, } from "./liveblocks-helpers"; import { LiveRegister } from "./LiveRegister"; -import type { LiveNode, Lson } from "./Lson"; -import type { ToImmutable } from "./utils"; +import type { LiveNode, Lson, ToJson } from "./Lson"; export type LiveListUpdateDelta = | { type: "insert"; index: number; item: Lson } @@ -1099,13 +1099,8 @@ export class LiveList extends AbstractCrdt { } } - /** - * Returns an Array of all the elements in the LiveList. - */ - toArray(): TItem[] { - return Array.from(this.#items, (entry) => liveNodeToLson(entry) as TItem); - // ^^^^^^^^ - // FIXME! This isn't safe. + #unwrap(node: LiveNode): TItem { + return liveNodeToLson(node) as TItem; } /** @@ -1114,7 +1109,9 @@ export class LiveList extends AbstractCrdt { * @returns true if the predicate function returns a truthy value for every element. Otherwise, false. */ every(predicate: (value: TItem, index: number) => unknown): boolean { - return this.toArray().every(predicate); + return this.#items.rawArray.every((node, i) => + predicate(this.#unwrap(node), i) + ); } /** @@ -1123,7 +1120,12 @@ export class LiveList extends AbstractCrdt { * @returns An array with the elements that pass the test. */ filter(predicate: (value: TItem, index: number) => unknown): TItem[] { - return this.toArray().filter(predicate); + const result: TItem[] = []; + this.#items.rawArray.forEach((node, i) => { + const item = this.#unwrap(node); + if (predicate(item, i)) result.push(item); + }); + return result; } /** @@ -1132,7 +1134,11 @@ export class LiveList extends AbstractCrdt { * @returns The value of the first element in the LiveList that satisfies the provided testing function. Otherwise, undefined is returned. */ find(predicate: (value: TItem, index: number) => unknown): TItem | undefined { - return this.toArray().find(predicate); + for (const [i, node] of this.#items.rawArray.entries()) { + const item = this.#unwrap(node); + if (predicate(item, i)) return item; + } + return undefined; } /** @@ -1141,7 +1147,9 @@ export class LiveList extends AbstractCrdt { * @returns The index of the first element in the LiveList that passes the test. Otherwise, -1. */ findIndex(predicate: (value: TItem, index: number) => unknown): number { - return this.toArray().findIndex(predicate); + return this.#items.rawArray.findIndex((node, i) => + predicate(this.#unwrap(node), i) + ); } /** @@ -1149,7 +1157,9 @@ export class LiveList extends AbstractCrdt { * @param callbackfn Function to execute on each element. */ forEach(callbackfn: (value: TItem, index: number) => void): void { - return this.toArray().forEach(callbackfn); + this.#items.rawArray.forEach((node, i) => + callbackfn(this.#unwrap(node), i) + ); } /** @@ -1158,14 +1168,8 @@ export class LiveList extends AbstractCrdt { * @returns The element at the specified index or undefined. */ get(index: number): TItem | undefined { - if (index < 0 || index >= this.#items.length) { - return undefined; - } - const item = this.#items.at(index); - return item ? (liveNodeToLson(item) as TItem | undefined) : undefined; - // ^^^^^^^^^^^^^^^^^ - // FIXME! This isn't safe. + return item !== undefined ? this.#unwrap(item) : undefined; } /** @@ -1175,17 +1179,23 @@ export class LiveList extends AbstractCrdt { * @returns The first index of the element in the LiveList; -1 if not found. */ indexOf(searchElement: TItem, fromIndex?: number): number { - return this.toArray().indexOf(searchElement, fromIndex); + return this.#items.rawArray.findIndex( + (node, i) => i >= (fromIndex ?? 0) && this.#unwrap(node) === searchElement + ); } /** - * Returns the last index at which a given element can be found in the LiveList, or -1 if it is not present. The LiveLsit is searched backwards, starting at fromIndex. + * Returns the last index at which a given element can be found in the LiveList, or -1 if it is not present. The LiveList is searched backwards, starting at fromIndex. * @param searchElement Element to locate. * @param fromIndex The index at which to start searching backwards. - * @returns + * @returns The last index of the element in the LiveList; -1 if not found. */ lastIndexOf(searchElement: TItem, fromIndex?: number): number { - return this.toArray().lastIndexOf(searchElement, fromIndex); + const arr = this.#items.rawArray; + for (let i = fromIndex ?? arr.length - 1; i >= 0; i--) { + if (this.#unwrap(arr[i]) === searchElement) return i; + } + return -1; } /** @@ -1194,20 +1204,9 @@ export class LiveList extends AbstractCrdt { * @returns An array with each element being the result of the callback function. */ map(callback: (value: TItem, index: number) => U): U[] { - const result: U[] = []; - let i = 0; - for (const entry of this.#items) { - result.push( - callback( - liveNodeToLson(entry) as TItem, - // ^^^^^^^^ - // FIXME! This isn't safe. - i - ) - ); - i++; - } - return result; + return this.#items.rawArray.map((node, i) => + callback(this.#unwrap(node), i) + ); } /** @@ -1216,11 +1215,15 @@ export class LiveList extends AbstractCrdt { * @returns true if the callback function returns a truthy value for at least one element. Otherwise, false. */ some(predicate: (value: TItem, index: number) => unknown): boolean { - return this.toArray().some(predicate); + return this.#items.rawArray.some((node, i) => + predicate(this.#unwrap(node), i) + ); } - [Symbol.iterator](): IterableIterator { - return new LiveListIterator(this.#items); + *[Symbol.iterator](): IterableIterator { + for (const node of this.#items) { + yield this.#unwrap(node); + } } #createAttachItemAndSort( @@ -1269,19 +1272,17 @@ export class LiveList extends AbstractCrdt { }; } - toImmutable(): readonly ToImmutable[] { - // Don't implement actual toJson logic in here. Implement it in ._toImmutable() - // instead. This helper merely exists to help TypeScript infer better - // return types. - return super.toImmutable() as readonly ToImmutable[]; + toJSON(): readonly ToJson[] { + // Don't implement actual toJSON logic in here. Implement it in + // ._toJSON() instead. This helper merely exists to help TypeScript + // infer better return types. + return super.toJSON() as readonly ToJson[]; } /** @internal */ - _toImmutable(): readonly ToImmutable[] { - const result = Array.from(this.#items, (node) => node.toImmutable()); - return ( - process.env.NODE_ENV === "production" ? result : Object.freeze(result) - ) as readonly ToImmutable[]; + _toJSON(): readonly ToJson[] { + const result = Array.from(this.#items, (node) => node.toJSON()); + return freeze(result) as ToJson[]; } clone(): LiveList { @@ -1291,34 +1292,6 @@ export class LiveList extends AbstractCrdt { } } -class LiveListIterator implements IterableIterator { - #innerIterator: IterableIterator; - - constructor(items: SortedList) { - this.#innerIterator = items[Symbol.iterator](); - } - - [Symbol.iterator](): IterableIterator { - return this; - } - - next(): IteratorResult { - const result = this.#innerIterator.next(); - - if (result.done) { - return { - done: true, - value: undefined, - }; - } - - const value = liveNodeToLson(result.value) as T; - // ^^^^ - // FIXME! This isn't safe. - return { value }; - } -} - function makeUpdate( liveList: LiveList, deltaUpdates: LiveListUpdateDelta[] diff --git a/packages/liveblocks-core/src/crdts/LiveMap.ts b/packages/liveblocks-core/src/crdts/LiveMap.ts index 58ae2f96b65..747023ab79c 100644 --- a/packages/liveblocks-core/src/crdts/LiveMap.ts +++ b/packages/liveblocks-core/src/crdts/LiveMap.ts @@ -16,9 +16,8 @@ import { liveNodeToLson, lsonToLiveNode, } from "./liveblocks-helpers"; -import type { LiveNode, Lson } from "./Lson"; +import type { LiveNode, Lson, ToJson } from "./Lson"; import type { UpdateDelta } from "./UpdateDelta"; -import type { ToImmutable } from "./utils"; /** * A LiveMap notification that is sent in-client to any subscribers whenever @@ -453,20 +452,20 @@ export class LiveMap< }; } - toImmutable(): ReadonlyMap> { - // Don't implement actual toImmutable logic in here. Implement it in - // ._toImmutable() instead. This helper merely exists to help TypeScript + toJSON(): { readonly [P in TKey]: ToJson } { + // Don't implement actual toJSON logic in here. Implement it in + // ._toJSON() instead. This helper merely exists to help TypeScript // infer better return types. - return super.toImmutable() as ReadonlyMap>; + return super.toJSON() as { readonly [P in TKey]: ToJson }; } /** @internal */ - _toImmutable(): ReadonlyMap> { - const result: Map> = new Map(); + _toJSON(): { readonly [P in TKey]: ToJson } { + const result: { [key: string]: unknown } = {}; for (const [key, value] of this.#map) { - result.set(key, value.toImmutable() as ToImmutable); + result[key] = value.toJSON(); } - return freeze(result); + return freeze(result) as { [P in TKey]: ToJson }; } clone(): LiveMap { diff --git a/packages/liveblocks-core/src/crdts/LiveObject.ts b/packages/liveblocks-core/src/crdts/LiveObject.ts index 395ffe79c00..b294741a08d 100644 --- a/packages/liveblocks-core/src/crdts/LiveObject.ts +++ b/packages/liveblocks-core/src/crdts/LiveObject.ts @@ -1,5 +1,6 @@ -import type { LiveNode, Lson, LsonObject } from "../crdts/Lson"; +import type { LiveNode, Lson, LsonObject, ToJson } from "../crdts/Lson"; import { nn } from "../lib/assert"; +import { freeze } from "../lib/freeze"; import { isPlainObject } from "../lib/guards"; import type { Json, JsonObject } from "../lib/Json"; import { nanoid } from "../lib/nanoid"; @@ -36,7 +37,6 @@ import { import type { SyncConfig } from "./reconcile"; import { reconcileLiveObject } from "./reconcile"; import type { UpdateDelta } from "./UpdateDelta"; -import type { ToImmutable } from "./utils"; /** * Optional keys of O whose non-undefined type is plain Json (not a @@ -516,17 +516,6 @@ export class LiveObject extends AbstractCrdt { return result; } - /** - * Transform the LiveObject into a javascript object - */ - toObject(): O { - const result = Object.fromEntries(this.#synced); - for (const [key, value] of this.#local) { - result[key] = value; - } - return result as O; - } - /** * Adds or updates a property with a specified key and a value. * @param key The key of the property to add @@ -539,10 +528,9 @@ export class LiveObject extends AbstractCrdt { /** * @experimental * - * Sets a local-only property that is not synchronized over the wire. - * The value will be visible via get(), toObject(), and toImmutable() on - * this client only. Other clients and the server will see `undefined` - * for this key. + * Sets a local-only property that is not synchronized over the wire. The + * value will be visible via get(), and toJSON() on this client only. Other + * clients and the server will see `undefined` for this key. * * Caveat: this method will not add changes to the undo/redo stack. */ @@ -870,11 +858,11 @@ export class LiveObject extends AbstractCrdt { /** * Creates a new LiveObject from a plain JSON object, recursively converting - * nested objects to LiveObjects and arrays to LiveLists. An optional - * SyncConfig controls per-key behavior (local-only, atomic, or deep). - * - * @private + * nested objects to LiveObjects and arrays to LiveLists. */ + static from(obj: JsonObject): LiveObject; + /** @private */ + static from(obj: JsonObject, config?: SyncConfig): LiveObject; static from(obj: JsonObject, config?: SyncConfig): LiveObject { if (!isPlainObject(obj)) throw new Error("Expected a JSON object"); const liveObj = new LiveObject({}); @@ -883,26 +871,40 @@ export class LiveObject extends AbstractCrdt { } /** - * Reconciles a LiveObject tree to match the given JSON object and sync - * config. Only mutates keys that actually changed. Recursively reconciles - * the entire Live tree below it. - * - * @private + * Reconciles this LiveObject tree to match the given JSON object. Only + * mutates keys that actually changed. Keys present on this LiveObject but + * absent from `jsonObj` will be deleted. Nested structures are recursively + * reconciled. */ + reconcile(jsonObj: JsonObject): void; + /** @private */ + reconcile(jsonObj: JsonObject, config?: SyncConfig): void; reconcile(jsonObj: JsonObject, config?: SyncConfig): void { - if (this.immutableIs(jsonObj)) return; + if (this.hasCache(jsonObj)) return; if (!isPlainObject(jsonObj)) throw new Error( "Reconciling the document root expects a plain object value" ); - reconcileLiveObject(this, jsonObj, config); + reconcileLiveObject(this, jsonObj, "full", config); } - toImmutable(): ToImmutable { - // Don't implement actual toImmutable logic in here. Implement it in - // ._toImmutable() instead. This helper merely exists to help TypeScript - // infer better return types. - return super.toImmutable() as ToImmutable; + /** + * Like reconcile(), but only touches the top-level keys present in + * `partialObj`. Keys on this LiveObject that are absent from `partialObj` + * are left untouched. Typically called on the storage root when + * reconciling a subset of keys without affecting other keys on the root. + * + * Note: the partial behavior only applies to the top-level keys of this + * object. Nested structures are always fully reconciled. + * + * @private + */ + reconcilePartially(partialObj: JsonObject, config?: SyncConfig): void { + if (!isPlainObject(partialObj)) + throw new Error( + "Reconciling the document root expects a plain object value" + ); + reconcileLiveObject(this, partialObj, "partial", config); } /** @internal */ @@ -928,18 +930,23 @@ export class LiveObject extends AbstractCrdt { }; } + toJSON(): ToJson { + // Don't implement actual toJSON logic in here. Implement it in + // ._toJSON() instead. This helper merely exists to help TypeScript + // infer better return types. + return super.toJSON() as ToJson; + } + /** @internal */ - _toImmutable(): ToImmutable { + _toJSON(): ToJson { const result: { [key: string]: unknown } = {}; for (const [key, val] of this.#synced) { - result[key] = isLiveStructure(val) ? val.toImmutable() : val; + result[key] = isLiveStructure(val) ? val.toJSON() : val; } for (const [key, val] of this.#local) { result[key] = val; } - return ( - process.env.NODE_ENV === "production" ? result : Object.freeze(result) - ) as ToImmutable; + return freeze(result) as ToJson; } clone(): LiveObject { diff --git a/packages/liveblocks-core/src/crdts/LiveRegister.ts b/packages/liveblocks-core/src/crdts/LiveRegister.ts index 2637ae82a1f..3d4a904e7a7 100644 --- a/packages/liveblocks-core/src/crdts/LiveRegister.ts +++ b/packages/liveblocks-core/src/crdts/LiveRegister.ts @@ -1,6 +1,6 @@ import type { LiveNode } from "../crdts/Lson"; import { nn } from "../lib/assert"; -import type { Json } from "../lib/Json"; +import type { Json, ReadonlyJson } from "../lib/Json"; import { nanoid } from "../lib/nanoid"; import { deepClone } from "../lib/utils"; import type { CreateOp, CreateRegisterOp, Op } from "../protocol/Op"; @@ -11,7 +11,6 @@ import type { } from "../protocol/StorageNode"; import { CrdtType } from "../protocol/StorageNode"; import type * as DevTools from "../types/DevToolsTreeNode"; -import type { Immutable } from "../types/Immutable"; import type { ParentToChildNodeMap } from "../types/NodeMap"; import type { ApplyResult, ManagedPool } from "./AbstractCrdt"; import { AbstractCrdt } from "./AbstractCrdt"; @@ -101,7 +100,7 @@ export class LiveRegister extends AbstractCrdt { } /** @internal */ - _toImmutable(): Immutable { + _toJSON(): ReadonlyJson { return this.#data; } diff --git a/packages/liveblocks-core/src/crdts/Lson.ts b/packages/liveblocks-core/src/crdts/Lson.ts index 47144f01022..c55aedf80e6 100644 --- a/packages/liveblocks-core/src/crdts/Lson.ts +++ b/packages/liveblocks-core/src/crdts/Lson.ts @@ -2,7 +2,7 @@ import type { LiveList } from "../crdts/LiveList"; import type { LiveMap } from "../crdts/LiveMap"; import type { LiveObject } from "../crdts/LiveObject"; import type { LiveRegister } from "../crdts/LiveRegister"; -import type { Json } from "../lib/Json"; +import type { Json, ReadonlyJsonObject } from "../lib/Json"; export type LiveStructure = | LiveObject @@ -41,31 +41,31 @@ export type LsonObject = { [key: string]: Lson | undefined }; * ToJson<'hi'> // 'hi' * ToJson // number * ToJson // string - * ToJson> // string | number[] + * ToJson> // string | readonly number[] * ToJson>> - * // { [key: string]: number[] } + * // { readonly [key: string]: readonly number[] } * ToJson, c?: number }>> - * // { a: null, b: string[], c?: number } - * + * // { readonly a: null, readonly b: readonly string[], readonly c?: number } */ // prettier-ignore -export type ToJson = - // Any Json value already is a legal Json value - T extends Json ? T : - - // Any LsonObject recursively becomes a JsonObject - T extends LsonObject ? - { [K in keyof T]: ToJson> - | (undefined extends T[K] ? undefined : never) } : - +export type ToJson = // A LiveList serializes to an equivalent JSON array - T extends LiveList ? ToJson[] : + L extends LiveList ? readonly ToJson[] : // A LiveObject serializes to an equivalent JSON object - T extends LiveObject ? ToJson : + L extends LiveObject ? ToJson : // A LiveMap serializes to a JSON object with string-V pairs - T extends LiveMap ? { [K in KS]: ToJson } : + L extends LiveMap ? { readonly [P in KS]: ToJson } : + + // Any LsonObject recursively becomes a JsonObject + L extends LsonObject ? + string extends keyof L ? ReadonlyJsonObject : + { readonly [K in keyof L]: ToJson> + | (undefined extends L[K] ? undefined : never) } : + + // Any Json value already is a legal Json value + L extends Json ? L : // Otherwise, this is not possible never; diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveList.devserver.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveList.devserver.test.ts index cbdda552c7e..e34e4221464 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveList.devserver.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveList.devserver.test.ts @@ -29,9 +29,9 @@ describe("LiveList", () => { expect(list.get(0)).toEqual("first"); expect(list.length).toBe(3); - expect(list.toArray()).toEqual(["first", "second", "third"]); + expect(list.toJSON()).toEqual(["first", "second", "third"]); - expect(Array.from(list)).toEqual(["first", "second", "third"]); + expect(list.toJSON()).toEqual(["first", "second", "third"]); expect(list.map((item) => item.toUpperCase())).toEqual([ "FIRST", @@ -53,12 +53,12 @@ describe("LiveList", () => { list.delete(0); - expect(list.toArray()).toEqual(["second", "third"]); + expect(list.toJSON()).toEqual(["second", "third"]); expect(list.get(2)).toBe(undefined); expect(list.length).toBe(2); list.clear(); - expect(list.toArray()).toEqual([]); + expect(list.toJSON()).toEqual([]); }); }); @@ -180,7 +180,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); await expectStorage({ items: [] }); @@ -206,7 +206,7 @@ describe("LiveList", () => { items.push(new LiveMap([["first", 0]])); - await expectStorage({ items: [new Map([["first", 0]])] }); + await expectStorage({ items: [{ first: 0 }] }); await assertUndoRedo(); }); @@ -219,7 +219,7 @@ describe("LiveList", () => { data: { items: { liveblocksType: "LiveList", data: [] } }, }); - const items = root.toObject().items; + const items = root.get("items"); const object = new LiveObject({ a: 0 }); @@ -295,7 +295,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); items.insert(new LiveObject({ a: 0 }), 0); @@ -365,7 +365,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); await expectStorage({ items: ["A", "B"], @@ -408,7 +408,7 @@ describe("LiveList", () => { items: [{ child: { a: 0 } }], }); - storageA.root.toObject().items.delete(0); + storageA.root.get("items").delete(0); await expectStorage({ items: [], @@ -485,7 +485,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); items.move(0, 1); await expectStorage({ items: ["B", "A", "C"] }); @@ -534,7 +534,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); items.move(0, 2); await expectStorage({ @@ -692,7 +692,7 @@ describe("LiveList", () => { test("set register on detached list", () => { const list = new LiveList(["A", "B", "C"]); list.set(0, "D"); - expect(list.toArray()).toEqual(["D", "B", "C"]); + expect(list.toJSON()).toEqual(["D", "B", "C"]); }); test("set at invalid position should throw", () => { @@ -717,7 +717,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); await expectStorage({ items: ["A", "B", "C"] }); @@ -745,7 +745,7 @@ describe("LiveList", () => { }); const root = storageA.root; - const items = root.toObject().items; + const items = root.get("items"); await expectStorage({ items: [{ a: 1 }] }); @@ -818,29 +818,29 @@ describe("LiveList", () => { }); }); - describe("immutableIs", () => { - test("returns true when cached immutable matches the given value", () => { + describe("hasCache", () => { + test("returns true when cached JSON matches the given value", () => { const list = new LiveList(["a", "b", "c"]); - const imm = list.toImmutable(); - expect(list.immutableIs(imm)).toBe(true); + const json = list.toJSON(); + expect(list.hasCache(json)).toBe(true); }); test("returns false for a different array with equal contents", () => { const list = new LiveList(["a", "b"]); - list.toImmutable(); - expect(list.immutableIs(["a", "b"])).toBe(false); + list.toJSON(); + expect(list.hasCache(["a", "b"])).toBe(false); }); test("returns false when cache has been invalidated", () => { const list = new LiveList(["a"]); - const imm = list.toImmutable(); + const json = list.toJSON(); list.push("b"); - expect(list.immutableIs(imm)).toBe(false); + expect(list.hasCache(json)).toBe(false); }); - test("returns false when toImmutable has never been called", () => { + test("returns false when toJSON has never been called", () => { const list = new LiveList([1, 2, 3]); - expect(list.immutableIs([1, 2, 3])).toBe(false); + expect(list.hasCache([1, 2, 3])).toBe(false); }); }); }); diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveMap.devserver.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveMap.devserver.test.ts index 7622ac5df81..6ee3d004e1b 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveMap.devserver.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveMap.devserver.test.ts @@ -103,7 +103,7 @@ describe("LiveMap", () => { const map = root.get("map"); expect(Array.from(map.entries())).toEqual([]); - expectStorage({ map: new Map() }); + expectStorage({ map: {} }); }); // TODO: Needs read-only permission support in dev server @@ -144,20 +144,14 @@ describe("LiveMap", () => { const map = root.get("map"); - expect(map.toImmutable()).toEqual( - new Map([ - ["first", { a: 0 }], - ["second", { a: 1 }], - ["third", { a: 2 }], - ]) - ); + expect(map.toJSON()).toEqual({ + first: { a: 0 }, + second: { a: 1 }, + third: { a: 2 }, + }); expectStorage({ - map: new Map([ - ["first", { a: 0 }], - ["second", { a: 1 }], - ["third", { a: 2 }], - ]), + map: { first: { a: 0 }, second: { a: 1 }, third: { a: 2 } }, }); }); @@ -173,28 +167,21 @@ describe("LiveMap", () => { const root = storageA.root; const map = root.get("map"); - await expectStorage({ map: new Map() }); + await expectStorage({ map: {} }); map.set("first", 0); await expectStorage({ - map: new Map([["first", 0]]), + map: { first: 0 }, }); map.set("second", 1); await expectStorage({ - map: new Map([ - ["first", 0], - ["second", 1], - ]), + map: { first: 0, second: 1 }, }); map.set("third", 2); await expectStorage({ - map: new Map([ - ["first", 0], - ["second", 1], - ["third", 2], - ]), + map: { first: 0, second: 1, third: 2 }, }); await assertUndoRedo(); @@ -238,29 +225,22 @@ describe("LiveMap", () => { const map = root.get("map"); await expectStorage({ - map: new Map([ - ["first", 0], - ["second", 1], - ["third", 2], - ]), + map: { first: 0, second: 1, third: 2 }, }); map.delete("first"); await expectStorage({ - map: new Map([ - ["second", 1], - ["third", 2], - ]), + map: { second: 1, third: 2 }, }); map.delete("second"); await expectStorage({ - map: new Map([["third", 2]]), + map: { third: 2 }, }); map.delete("third"); await expectStorage({ - map: new Map(), + map: {}, }); await assertUndoRedo(); @@ -283,7 +263,7 @@ describe("LiveMap", () => { }); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); const root = storageA.root; @@ -294,7 +274,7 @@ describe("LiveMap", () => { expect(roomA[kInternal].nodeCount).toBe(2); await expectStorage({ - map: new Map(), + map: {}, }); await assertUndoRedo(); @@ -317,7 +297,7 @@ describe("LiveMap", () => { }); await expectStorage({ - map: new Map([["first", [0]]]), + map: { first: [0] }, }); const root = storageA.root; @@ -328,7 +308,7 @@ describe("LiveMap", () => { expect(roomA[kInternal].nodeCount).toBe(2); await expectStorage({ - map: new Map(), + map: {}, }); await assertUndoRedo(); @@ -421,13 +401,13 @@ describe("LiveMap", () => { const root = storageA.root; const map = root.get("map"); await expectStorage({ - map: new Map(), + map: {}, }); map.set("first", new LiveObject({ a: 0 })); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); await assertUndoRedo(); @@ -481,7 +461,7 @@ describe("LiveMap", () => { }); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); const root = storageA.root; @@ -490,7 +470,7 @@ describe("LiveMap", () => { map.set("first", new LiveObject({ a: 1 })); await expectStorage({ - map: new Map([["first", { a: 1 }]]), + map: { first: { a: 1 } }, }); await assertUndoRedo(); @@ -510,7 +490,7 @@ describe("LiveMap", () => { storageA.root.set("map", new LiveMap([["first", { a: 0 }]])); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); await assertUndoRedo(); @@ -533,7 +513,7 @@ describe("LiveMap", () => { ); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); await assertUndoRedo(); @@ -553,7 +533,7 @@ describe("LiveMap", () => { storageA.root.set("map", new LiveMap([["first", { a: 0 }]])); await expectStorage({ - map: new Map([["first", { a: 0 }]]), + map: { first: { a: 0 } }, }); await assertUndoRedo(); @@ -568,13 +548,13 @@ describe("LiveMap", () => { data: { map: { liveblocksType: "LiveMap", data: {} } }, }); - await expectStorage({ map: new Map() }); + await expectStorage({ map: {} }); const map = storageA.root.get("map"); map.set("list", new LiveList(["itemA", "itemB", "itemC"])); await expectStorage({ - map: new Map([["list", ["itemA", "itemB", "itemC"]]]), + map: { list: ["itemA", "itemB", "itemC"] }, }); await assertUndoRedo(); @@ -589,13 +569,13 @@ describe("LiveMap", () => { data: { map: { liveblocksType: "LiveMap", data: {} } }, }); - await expectStorage({ map: new Map() }); + await expectStorage({ map: {} }); const map = storageA.root.get("map"); map.set("map", new LiveMap([["first", "itemA"]])); await expectStorage({ - map: new Map([["map", new Map([["first", "itemA"]])]]), + map: { map: { first: "itemA" } }, }); await assertUndoRedo(); @@ -686,7 +666,7 @@ describe("LiveMap", () => { room.subscribe(root, rootDeepCallback, { isDeep: true }); room.subscribe(map, mapCallback); - expectStorage({ map: new Map([["first", "a"]]) }); + expectStorage({ map: { first: "a" } }); await replaceStorageAndReconnectDevServer(room.id, { liveblocksType: "LiveObject", @@ -698,12 +678,9 @@ describe("LiveMap", () => { }, }); - await vi.waitUntil(() => root.toImmutable().map.has("second")); + await vi.waitUntil(() => "second" in root.toJSON().map); expectStorage({ - map: new Map([ - ["first", "a"], - ["second", "b"], - ]), + map: { first: "a", second: "b" }, }); expect(rootDeepCallback).toHaveBeenCalledTimes(1); @@ -720,32 +697,32 @@ describe("LiveMap", () => { }); }); - describe("immutableIs", () => { - test("returns true when cached immutable matches the given value", () => { + describe("hasCache", () => { + test("returns true when cached JSON matches the given value", () => { const map = new LiveMap([ ["a", 1], ["b", 2], ]); - const imm = map.toImmutable(); - expect(map.immutableIs(imm)).toBe(true); + const json = map.toJSON(); + expect(map.hasCache(json)).toBe(true); }); - test("returns false for a different map with equal contents", () => { + test("returns false for a different object with equal contents", () => { const map = new LiveMap([["a", 1]]); - map.toImmutable(); - expect(map.immutableIs(new Map([["a", 1]]))).toBe(false); + map.toJSON(); + expect(map.hasCache({ a: 1 })).toBe(false); }); test("returns false when cache has been invalidated", () => { const map = new LiveMap([["a", 1]]); - const imm = map.toImmutable(); + const json = map.toJSON(); map.set("b", 2); - expect(map.immutableIs(imm)).toBe(false); + expect(map.hasCache(json)).toBe(false); }); - test("returns false when toImmutable has never been called", () => { + test("returns false when toJSON has never been called", () => { const map = new LiveMap([["x", 42]]); - expect(map.immutableIs(new Map([["x", 42]]))).toBe(false); + expect(map.hasCache({ x: 42 })).toBe(false); }); }); }); diff --git a/packages/liveblocks-core/src/crdts/__tests__/LiveObject.devserver.test.ts b/packages/liveblocks-core/src/crdts/__tests__/LiveObject.devserver.test.ts index c9b9aa57722..f9b424ad8e6 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/LiveObject.devserver.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/LiveObject.devserver.test.ts @@ -447,7 +447,7 @@ describe("LiveObject", () => { }); const root = storage.root; - const child = root.toObject().child; + const child = root.get("child"); await expectStorage({ a: 0, @@ -500,14 +500,14 @@ describe("LiveObject", () => { }); const root = storage.root; - const child = root.toObject().child; - const grandChild = child.toObject().grandChild; - expect(root.toObject()).toMatchObject({ a: 0 }); - expect(child.toObject()).toMatchObject({ b: 0 }); - expect(grandChild.toObject()).toMatchObject({ c: 0 }); + const child = root.get("child"); + const grandChild = child.get("grandChild"); + expect(root.toJSON()).toMatchObject({ a: 0 }); + expect(child.toJSON()).toMatchObject({ b: 0 }); + expect(grandChild.toJSON()).toMatchObject({ c: 0 }); grandChild.update({ c: 1 }); - expect(grandChild.toObject()).toMatchObject({ c: 1 }); + expect(grandChild.toJSON()).toMatchObject({ c: 1 }); await expectStorage({ a: 0, @@ -551,7 +551,7 @@ describe("LiveObject", () => { items.set("b", "B"); }); - expect(items.toObject()).toEqual({ a: "A", b: "B" }); + expect(items.toJSON()).toEqual({ a: "A", b: "B" }); expect(receivedUpdates).toEqual([ [ objectUpdate( @@ -563,7 +563,7 @@ describe("LiveObject", () => { room.history.undo(); - expect(items.toObject()).toEqual({ a: "initial" }); + expect(items.toJSON()).toEqual({ a: "initial" }); expect(receivedUpdates).toEqual([ [ objectUpdate( @@ -1453,7 +1453,7 @@ describe("LiveObject", () => { ]); }); - test("setLocal value is visible via get, toObject, and toImmutable", async () => { + test("setLocal value is visible via get, and toJson", async () => { const { root } = await prepareIsolatedStorageTest<{ a: number; b?: string; @@ -1465,8 +1465,8 @@ describe("LiveObject", () => { root.setLocal("b", "local"); expect(root.get("b")).toBe("local"); - expect(root.toObject()).toEqual({ a: 1, b: "local" }); - expect(root.toImmutable()).toEqual({ a: 1, b: "local" }); + expect(root.toJSON()).toEqual({ a: 1, b: "local" }); + expect(root.toJSON()).toEqual({ a: 1, b: "local" }); }); test("setLocal does not sync to other clients", async () => { @@ -1485,7 +1485,7 @@ describe("LiveObject", () => { // Client B does not see local value (wait a bit to confirm nothing syncs) await vi.waitFor(() => { - expect(storageB.root.toImmutable()).toEqual({ a: 1 }); + expect(storageB.root.toJSON()).toEqual({ a: 1 }); }); }); @@ -1508,7 +1508,7 @@ describe("LiveObject", () => { // Client B only sees bar, not foo await vi.waitFor(() => { - expect(storageB.root.toImmutable()).toEqual({ a: 1, bar: "synced" }); + expect(storageB.root.toJSON()).toEqual({ a: 1, bar: "synced" }); }); }); @@ -1527,7 +1527,7 @@ describe("LiveObject", () => { // Wait for B's change to sync await vi.waitFor(() => { - expect(storageB.root.toImmutable()).toEqual({ a: 1, bar: "from-B" }); + expect(storageB.root.toJSON()).toEqual({ a: 1, bar: "from-B" }); }); // Wait for A to receive B's synced change @@ -1599,7 +1599,7 @@ describe("LiveObject", () => { expect(cloned.get("a")).toBe(1); expect(cloned.get("b")).toBe("local-only"); - expect(cloned.toImmutable()).toEqual({ a: 1, b: "local-only" }); + expect(cloned.toJSON()).toEqual({ a: 1, b: "local-only" }); }); test("clone preserves local-only properties on detached LiveObject", () => { @@ -1609,7 +1609,7 @@ describe("LiveObject", () => { expect(cloned.get("a")).toBe(1); expect(cloned.get("b")).toBe("local-only"); - expect(cloned.toImmutable()).toEqual({ a: 1, b: "local-only" }); + expect(cloned.toJSON()).toEqual({ a: 1, b: "local-only" }); }); test("clone with local props injected into sibling: both have local prop on A, neither on B", async () => { @@ -1776,34 +1776,34 @@ describe("LiveObject", () => { // Client B should still not see foo (nothing was synced) await vi.waitFor(() => { - expect(storageB.root.toImmutable()).toEqual({ a: 1 }); + expect(storageB.root.toJSON()).toEqual({ a: 1 }); }); }); }); - describe("immutableIs", () => { - test("returns true when cached immutable matches the given value", () => { + describe("hasCache", () => { + test("returns true when cached JSON matches the given value", () => { const obj = new LiveObject({ a: 1, b: "hello" }); - const imm = obj.toImmutable(); - expect(obj.immutableIs(imm)).toBe(true); + const json = obj.toJSON(); + expect(obj.hasCache(json)).toBe(true); }); test("returns false for a different value with equal contents", () => { const obj = new LiveObject({ a: 1 }); - obj.toImmutable(); - expect(obj.immutableIs({ a: 1 })).toBe(false); + obj.toJSON(); + expect(obj.hasCache({ a: 1 })).toBe(false); }); test("returns false when cache has been invalidated", () => { const obj = new LiveObject<{ a: number }>({ a: 1 }); - const imm = obj.toImmutable(); + const json = obj.toJSON(); obj.set("a", 2); - expect(obj.immutableIs(imm)).toBe(false); + expect(obj.hasCache(json)).toBe(false); }); - test("returns false when toImmutable has never been called", () => { + test("returns false when toJSON has never been called", () => { const obj = new LiveObject({ a: 1 }); - expect(obj.immutableIs({ a: 1 })).toBe(false); + expect(obj.hasCache({ a: 1 })).toBe(false); }); }); }); diff --git a/packages/liveblocks-core/src/crdts/__tests__/_arbitraries.ts b/packages/liveblocks-core/src/crdts/__tests__/_arbitraries.ts index 6890cbb8c44..6ed237d7aa7 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/_arbitraries.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/_arbitraries.ts @@ -16,11 +16,24 @@ export const json = fc export const jsonObject: fc.Arbitrary = fc.dictionary(key, json); -export const { liveList, liveMap, liveObject, liveStructure, lson } = fc.letrec( - (tie) => ({ +interface LsonArbitraryOptions { + /** Generates Live trees that can include LiveMaps. Defaults to true. */ + withLiveMap?: boolean; +} + +function makeLsonArbitraries(options?: LsonArbitraryOptions) { + const withLiveMap = options?.withLiveMap ?? true; + + return fc.letrec((tie) => ({ lson: fc.oneof(json, tie("liveStructure")).map((x) => x as Lson), liveStructure: fc - .oneof(tie("liveList"), tie("liveMap"), tie("liveObject")) + .oneof( + ...[ + tie("liveList"), + tie("liveObject"), + ...(withLiveMap ? [tie("liveMap")] : []), + ] + ) .map((x) => x as LiveStructure), liveList: fc.array(tie("lson")).map((x) => new LiveList(x as Lson[])), liveMap: fc @@ -31,5 +44,12 @@ export const { liveList, liveMap, liveObject, liveStructure, lson } = fc.letrec( .map( (pairs) => new LiveObject(Object.fromEntries(pairs as [string, Lson][])) ), - }) -); + })); +} + +export const { liveList, liveMap, liveObject, liveStructure, lson } = + makeLsonArbitraries(); + +export const { liveStructure: liveStructureWithoutMap } = makeLsonArbitraries({ + withLiveMap: false, +}); diff --git a/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts b/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts index 605d39d4e59..5d83d224328 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/cloning.test.ts @@ -80,7 +80,7 @@ describe("cloning LiveStructures", () => { root.set("a", data); root.set("b", data.clone()); - const imm = root.toImmutable(); + const imm = root.toJSON(); expect(imm.a).toEqual(imm.b); } ) @@ -99,7 +99,7 @@ describe("cloning LiveStructures", () => { root.set("b", data.clone().clone()); // ^^^^^^^^ Deliberately cloning twice in this test - const imm = root.toImmutable(); + const imm = root.toJSON(); expect(imm.a).toEqual(imm.b); } ) @@ -120,7 +120,7 @@ describe("cloning LiveStructures", () => { // work on _any_ LSON value, even if data is // a JSON value - const imm = root.toImmutable(); + const imm = root.toJSON(); expect(imm.a).toEqual(imm.b); } ) diff --git a/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts b/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts index c94ae549aaf..bfcaf55cf06 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/doc.test.ts @@ -410,14 +410,14 @@ describe("Storage", () => { storage.root.set("a", i + 1); } - expect(storage.root.toImmutable()).toEqual({ a: 100 }); + expect(storage.root.toJSON()).toEqual({ a: 100 }); for (let i = 0; i < 100; i++) { room.history.undo(); } // Max undo stack is 50, so undoing 100 times only goes back to 50 - expect(storage.root.toImmutable()).toEqual({ a: 50 }); + expect(storage.root.toJSON()).toEqual({ a: 50 }); }); test("storage operation should clear redo stack", async () => { diff --git a/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts b/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts index 39d0c110114..2728bf97cb5 100644 --- a/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts +++ b/packages/liveblocks-core/src/crdts/__tests__/liveblocks-helpers.test.ts @@ -10,10 +10,7 @@ import { import { OpCode } from "../../protocol/Op"; import type { NodeMap } from "../../protocol/StorageNode"; import { CrdtType } from "../../protocol/StorageNode"; -import { - findNonSerializableValue, - getTreesDiffOperations, -} from "../liveblocks-helpers"; +import { getTreesDiffOperations } from "../liveblocks-helpers"; import { LiveList } from "../LiveList"; import { LiveMap } from "../LiveMap"; import { LiveObject } from "../LiveObject"; @@ -253,32 +250,6 @@ describe("getTreesDiffOperations", () => { }); }); -describe("findNonSerializableValue", () => { - test("findNonSerializableValue should return path and value of non serializable value", () => { - for (const [value, expectedPath] of [ - [null, false], - [undefined, false], - [1, false], - [true, false], - [[], false], - ["a", false], - [{ a: "a" }, false], - [{ a: () => {} }, "a"], - [() => {}, "root"], - [[() => {}], "0"], - [{ a: [() => {}] }, "a.0"], - [{ a: new Map() }, "a"], // Map will be accepted in the future - ]) { - const result = findNonSerializableValue(value); - if (result) { - expect(result.path).toEqual(expectedPath); - } else { - expect(result).toEqual(false); - } - } - }); -}); - describe("toPlainLson", () => { test("toPlainLson with a plain object should not change", () => { const mockPlainObject = { diff --git a/packages/liveblocks-core/src/crdts/liveblocks-helpers.ts b/packages/liveblocks-core/src/crdts/liveblocks-helpers.ts index a7e8bbd39b6..841a0f12d8f 100644 --- a/packages/liveblocks-core/src/crdts/liveblocks-helpers.ts +++ b/packages/liveblocks-core/src/crdts/liveblocks-helpers.ts @@ -1,5 +1,4 @@ import { assertNever, nn } from "../lib/assert"; -import { isPlainObject } from "../lib/guards"; import type { Json } from "../lib/Json"; import { stringifyOrLog as stringify } from "../lib/stringify"; import { deepClone, entries } from "../lib/utils"; @@ -311,65 +310,3 @@ export function mergeStorageUpdates( return second; } - -function isPlain( - value: unknown -): value is - | undefined - | null - | string - | boolean - | number - | unknown[] - | { [key: string]: unknown } { - const type = typeof value; - return ( - value === undefined || - value === null || - type === "string" || - type === "boolean" || - type === "number" || - Array.isArray(value) || - isPlainObject(value) - ); -} - -export function findNonSerializableValue( - value: unknown, - path: string = "" -): { path: string; value: unknown } | false { - if (!isPlain) { - return { - path: path || "root", - value, - }; - } - - if (typeof value !== "object" || value === null) { - return false; - } - - for (const [key, nestedValue] of Object.entries(value)) { - const nestedPath = path ? path + "." + key : key; - - if (!isPlain(nestedValue)) { - return { - path: nestedPath, - value: nestedValue, - }; - } - - if (typeof nestedValue === "object") { - const nonSerializableNestedValue = findNonSerializableValue( - nestedValue, - nestedPath - ); - - if (nonSerializableNestedValue) { - return nonSerializableNestedValue; - } - } - } - - return false; -} diff --git a/packages/liveblocks-core/src/crdts/reconcile.ts b/packages/liveblocks-core/src/crdts/reconcile.ts index 8c1c3731fcb..3e0c597d4e7 100644 --- a/packages/liveblocks-core/src/crdts/reconcile.ts +++ b/packages/liveblocks-core/src/crdts/reconcile.ts @@ -1,5 +1,5 @@ import { isPlainObject } from "../lib/guards"; -import type { Json, JsonObject } from "../lib/Json"; +import type { Json, JsonObject, ReadonlyJson } from "../lib/Json"; import { isLiveList, isLiveMap, @@ -63,7 +63,7 @@ export function deepLiveify(value: Json, config?: SyncMode): Lson { return new LiveList(value.map((v) => deepLiveify(v, config))); } else if (isPlainObject(value)) { const init: LsonObject = {}; - const locals: Record = {}; + const locals: Record = {}; for (const key in value) { const val = value[key]; if (val === undefined) { @@ -102,7 +102,7 @@ export function deepLiveify(value: Json, config?: SyncMode): Lson { */ function reconcile(live: Lson, json: Json, config?: SyncMode): Lson { if (isLiveObject(live) && isPlainObject(json)) { - return reconcileLiveObject(live, json, config); + return reconcileLiveObject(live, json, "full", config); } else if (isLiveList(live) && Array.isArray(json)) { return reconcileLiveList(live, json, config); } else if (isLiveMap(live) && isPlainObject(json)) { @@ -121,9 +121,19 @@ function reconcileLiveMap( // return liveMap; } +/** + * Reconciles a LiveObject to match the given JSON object. + * + * In full mode, makes the LiveObject equal the input. + * In partial mode, all given keys will get reconciled, but existing other keys + * will not get deleted. + * + * @private + */ export function reconcileLiveObject( liveObj: LiveObject, jsonObj: JsonObject, + extent: "full" | "partial", config?: SyncMode ): LiveObject { type L = O[keyof O]; @@ -135,7 +145,9 @@ export function reconcileLiveObject( const newVal = jsonObj[key]; if (newVal === undefined) { - liveObj.delete(key); + if (extent === "full") { + liveObj.delete(key); + } continue; } @@ -166,9 +178,10 @@ export function reconcileLiveObject( } } - // Delete keys absent from jsonObj - for (const key of currentKeys) { - liveObj.delete(key); + if (extent === "full") { + for (const key of currentKeys) { + liveObj.delete(key); + } } return liveObj; diff --git a/packages/liveblocks-core/src/crdts/utils.ts b/packages/liveblocks-core/src/crdts/utils.ts index cc47f9e4345..5374dff65d8 100644 --- a/packages/liveblocks-core/src/crdts/utils.ts +++ b/packages/liveblocks-core/src/crdts/utils.ts @@ -1,61 +1,22 @@ -import type { Json } from "../lib/Json"; import type { PlainLson } from "../types/PlainLson"; import { LiveList } from "./LiveList"; import { LiveMap } from "./LiveMap"; import { LiveObject } from "./LiveObject"; -import type { Lson, LsonObject } from "./Lson"; - -/** - * Helper type to convert any valid Lson type to the equivalent Json type. - * - * Examples: - * - * ToImmutable<42> // 42 - * ToImmutable<'hi'> // 'hi' - * ToImmutable // number - * ToImmutable // string - * ToImmutable> // string | readonly number[] - * ToImmutable>> - * // ReadonlyMap - * ToImmutable, c?: number }>> - * // { readonly a: null, readonly b: readonly string[], readonly c?: number } - * - */ -// prettier-ignore -export type ToImmutable = - // A LiveList serializes to an equivalent JSON array - L extends LiveList ? readonly ToImmutable[] : - - // A LiveObject serializes to an equivalent JSON object - L extends LiveObject ? ToImmutable : - - // A LiveMap serializes to a JSON object with string-V pairs - L extends LiveMap ? ReadonlyMap> : - - // Any LsonObject recursively becomes a JsonObject - L extends LsonObject ? - { readonly [K in keyof L]: ToImmutable> - | (undefined extends L[K] ? undefined : never) } : - - // Any Json value already is a legal Json value - L extends Json ? L : - - // Otherwise, this is not possible - never; +import type { Lson } from "./Lson"; /** * Returns PlainLson for a given Json or LiveStructure, suitable for calling the storage init api */ export function toPlainLson(lson: Lson): PlainLson { if (lson instanceof LiveObject) { - return { - liveblocksType: "LiveObject", - data: Object.fromEntries( - Object.entries(lson.toObject()).flatMap(([key, value]) => - value !== undefined ? [[key, toPlainLson(value)]] : [] - ) - ), - }; + const data: Record = {}; + for (const key of lson.keys()) { + const value = lson.get(key); + if (value !== undefined) { + data[key] = toPlainLson(value); + } + } + return { liveblocksType: "LiveObject", data }; } else if (lson instanceof LiveMap) { return { liveblocksType: "LiveMap", diff --git a/packages/liveblocks-core/src/immutable.ts b/packages/liveblocks-core/src/immutable.ts index 5def03e42f6..376d4487718 100644 --- a/packages/liveblocks-core/src/immutable.ts +++ b/packages/liveblocks-core/src/immutable.ts @@ -1,423 +1,17 @@ -import { - findNonSerializableValue, - isLiveList, - isLiveObject, -} from "./crdts/liveblocks-helpers"; -import { LiveList } from "./crdts/LiveList"; -import { LiveMap } from "./crdts/LiveMap"; -import { LiveObject } from "./crdts/LiveObject"; -import { LiveRegister } from "./crdts/LiveRegister"; -import type { LiveNode, Lson, LsonObject, ToJson } from "./crdts/Lson"; -import { deepLiveify } from "./crdts/reconcile"; -import type { StorageUpdate } from "./crdts/StorageUpdates"; -import * as console from "./lib/fancy-console"; -import { isPlainObject } from "./lib/guards"; -import type { Json, JsonObject } from "./lib/Json"; -import { isJsonObject } from "./lib/Json"; +import { isLiveStructure } from "./crdts/liveblocks-helpers"; +import type { Lson } from "./crdts/Lson"; +import type { Json } from "./lib/Json"; export type { SyncConfig, SyncMode } from "./crdts/reconcile"; export { reconcileLiveObject } from "./crdts/reconcile"; -function lsonObjectToJson( - obj: O -): { [K in keyof O]: Json } { - const result = {} as { [K in keyof O]: Json }; - for (const key in obj) { - const val = obj[key]; - if (val !== undefined) { - result[key] = lsonToJson(val); - } - } - return result; -} - -export function liveObjectToJson( - liveObject: LiveObject -): { [K in keyof O]: Json } { - return lsonObjectToJson(liveObject.toObject()); -} - -function liveMapToJson( - map: LiveMap -): { [K in TKey]: Json } { - const result = {} as { [K in TKey]: Json }; - for (const [key, value] of map.entries()) { - result[key] = lsonToJson(value); - } - return result; -} - -function lsonListToJson(value: Lson[]): Json[] { - return value.map(lsonToJson); -} - -function liveListToJson(value: LiveList): Json[] { - return lsonListToJson(value.toArray()); -} - +/** + * Converts any Lson value to its Json equivalent. Live structures are + * converted via .toJSON(), plain values pass through as-is. + */ export function lsonToJson(value: Lson): Json { - // Check for LiveStructure datastructures first - if (value instanceof LiveObject) { - return liveObjectToJson(value); - } else if (value instanceof LiveList) { - return liveListToJson(value); - } else if (value instanceof LiveMap) { - return liveMapToJson(value); - } else if (value instanceof LiveRegister) { - // NOTE: This branch should never be taken, because LiveRegister isn't a valid Lson value - return value.data as Json; - } - - // Then for composite Lson values - if (Array.isArray(value)) { - return lsonListToJson(value); - } else if (isPlainObject(value)) { - return lsonObjectToJson(value); + if (isLiveStructure(value)) { + return value.toJSON() as Json; } - - // Finally, if value is an LsonScalar, then it's also a valid JsonScalar return value; } - -export function legacy_patchLiveList( - liveList: LiveList, - prev: Array, - next: Array -): void { - let i = 0; - let prevEnd = prev.length - 1; - let nextEnd = next.length - 1; - - let prevNode = prev[0]; - let nextNode = next[0]; - - /** - * For A,B,C => A,B,C,D - * i = 3, prevEnd = 2, nextEnd = 3 - * - * For A,B,C => B,C - * i = 2, prevEnd = 2, nextEnd = 1 - * - * For B,C => A,B,C - * i = 0, pre - */ - - outer: { - while (prevNode === nextNode) { - ++i; - if (i > prevEnd || i > nextEnd) { - break outer; - } - prevNode = prev[i]; - nextNode = next[i]; - } - - prevNode = prev[prevEnd]; - nextNode = next[nextEnd]; - - while (prevNode === nextNode) { - prevEnd--; - nextEnd--; - - if (i > prevEnd || i > nextEnd) { - break outer; - } - - prevNode = prev[prevEnd]; - nextNode = next[nextEnd]; - } - } - - if (i > prevEnd) { - if (i <= nextEnd) { - while (i <= nextEnd) { - liveList.insert(deepLiveify(next[i] as Json) as T, i); - i++; - } - } - } else if (i > nextEnd) { - let localI = i; - while (localI <= prevEnd) { - liveList.delete(i); - localI++; - } - } else { - while (i <= prevEnd && i <= nextEnd) { - prevNode = prev[i]; - nextNode = next[i]; - const liveListNode = liveList.get(i); - - if ( - isLiveObject(liveListNode) && - isPlainObject(prevNode) && - isPlainObject(nextNode) - ) { - legacy_patchLiveObject(liveListNode, prevNode, nextNode); - } else { - liveList.set(i, deepLiveify(nextNode as Json) as T); - } - - i++; - } - while (i <= nextEnd) { - liveList.insert(deepLiveify(next[i] as Json) as T, i); - i++; - } - let localI = i; - while (localI <= prevEnd) { - liveList.delete(i); - localI++; - } - } -} - -export function legacy_patchLiveObjectKey< - O extends LsonObject, - K extends keyof O, - V extends Json, ->(liveObject: LiveObject, key: K, prev?: V, next?: V): void { - if (process.env.NODE_ENV !== "production") { - const nonSerializableValue = findNonSerializableValue(next); - if (nonSerializableValue) { - console.error( - `New state path: '${nonSerializableValue.path}' value: '${String( - nonSerializableValue.value - )}' is not serializable.\nOnly serializable value can be synced with Liveblocks.` - ); - return; - } - } - - const value = liveObject.get(key); - - if (next === undefined) { - liveObject.delete(key); - } else if (value === undefined) { - liveObject.set(key, deepLiveify(next) as O[K]); - } else if (prev === next) { - return; - } else if (isLiveList(value) && Array.isArray(prev) && Array.isArray(next)) { - legacy_patchLiveList(value, prev, next); - } else if ( - isLiveObject(value) && - isPlainObject(prev) && - isPlainObject(next) - ) { - legacy_patchLiveObject(value, prev, next); - } else { - liveObject.set(key, deepLiveify(next) as O[K]); - } -} - -export function legacy_patchLiveObject( - root: LiveObject, - prev: ToJson, - next: ToJson -): void { - const updates: Partial = {}; - - for (const key in next) { - legacy_patchLiveObjectKey(root, key, prev[key] as Json, next[key] as Json); - } - - for (const key in prev) { - if (next[key] === undefined) { - root.delete(key); - } - } - - if (Object.keys(updates).length > 0) { - root.update(updates); - } -} - -function getParentsPath(node: LiveNode): Array { - const path = []; - while (node.parent.type === "HasParent") { - if (isLiveList(node.parent.node)) { - path.push(node.parent.node._indexOfPosition(node.parent.key)); - } else { - path.push(node.parent.key); - } - node = node.parent.node; - } - return path; -} - -// -// TODO: Remove `patchImmutableObject`! -// -// This helper is now only used internally, to support our Zustand and -// Redux packages. We should be able to reimplement those using the new -// `.toImmutable()` APIs. -// -export function legacy_patchImmutableObject( - state: TState, - updates: StorageUpdate[] -): TState { - return updates.reduce( - (state, update) => legacy_patchImmutableObjectWithUpdate(state, update), - state - ); -} - -function legacy_patchImmutableObjectWithUpdate( - state: TState, - update: StorageUpdate -): TState { - const path = getParentsPath(update.node); - return legacy_patchImmutableNode(state, path, update); -} - -function legacy_patchImmutableNode( - state: S, - path: Array, - update: StorageUpdate -): S { - // FIXME: Split this function up into a few smaller ones! In each of them, - // the types can be define much more narrowly and correctly, and there will - // be less type shoehorning necessary. - - const pathItem = path.pop(); - if (pathItem === undefined) { - switch (update.type) { - case "LiveObject": { - if (!isJsonObject(state)) { - throw new Error( - "Internal: received update on LiveObject but state was not an object" - ); - } - - const newState: JsonObject = Object.assign({}, state); - - for (const key in update.updates) { - if (update.updates[key]?.type === "update") { - const val = update.node.get(key); - if (val !== undefined) { - newState[key] = lsonToJson(val); - } - } else if (update.updates[key]?.type === "delete") { - delete newState[key]; - } - } - - return newState as S; - // ^^^^ - // FIXME Not completely true, because we could have been - // updating keys from StorageUpdate here that aren't in S, - // technically. - } - - case "LiveList": { - if (!Array.isArray(state)) { - throw new Error( - "Internal: received update on LiveList but state was not an array" - ); - } - - let newState: Json[] = state.map((x: Json) => x); - - for (const listUpdate of update.updates) { - if (listUpdate.type === "set") { - newState = newState.map((item, index) => - index === listUpdate.index ? lsonToJson(listUpdate.item) : item - ); - } else if (listUpdate.type === "insert") { - if (listUpdate.index === newState.length) { - newState.push(lsonToJson(listUpdate.item)); - } else { - newState = [ - ...newState.slice(0, listUpdate.index), - lsonToJson(listUpdate.item), - ...newState.slice(listUpdate.index), - ]; - } - } else if (listUpdate.type === "delete") { - newState.splice(listUpdate.index, 1); - } else if (listUpdate.type === "move") { - if (listUpdate.previousIndex > listUpdate.index) { - newState = [ - ...newState.slice(0, listUpdate.index), - lsonToJson(listUpdate.item), - ...newState.slice(listUpdate.index, listUpdate.previousIndex), - ...newState.slice(listUpdate.previousIndex + 1), - ]; - } else { - newState = [ - ...newState.slice(0, listUpdate.previousIndex), - ...newState.slice( - listUpdate.previousIndex + 1, - listUpdate.index + 1 - ), - lsonToJson(listUpdate.item), - ...newState.slice(listUpdate.index + 1), - ]; - } - } - } - - return newState as S; - // ^^^^ - // FIXME Not completely true, because we could have been - // updating keys from StorageUpdate here that aren't in S, - // technically. - } - - case "LiveMap": { - if (!isJsonObject(state)) { - throw new Error( - "Internal: received update on LiveMap but state was not an object" - ); - } - const newState: JsonObject = Object.assign({}, state); - - for (const key in update.updates) { - if (update.updates[key]?.type === "update") { - const value = update.node.get(key); - if (value !== undefined) { - newState[key] = lsonToJson(value); - } - } else if (update.updates[key]?.type === "delete") { - delete newState[key]; - } - } - - return newState as S; - // ^^^^ - // FIXME Not completely true, because we could have been - // updating keys from StorageUpdate here that aren't in S, - // technically. - } - } - } - - if (Array.isArray(state)) { - const newArray: Json[] = [...state]; - newArray[pathItem as number] = legacy_patchImmutableNode( - state[pathItem as number], - path, - update - ); - return newArray as S; - // ^^^^ - // FIXME Not completely true, because we could have been - // updating indexes from StorageUpdate here that aren't in S, - // technically. - } else if (isJsonObject(state)) { - const node = state[pathItem]; - if (node === undefined) { - return state; - } else { - const stateAsObj: JsonObject = state; - return { - ...stateAsObj, - [pathItem]: legacy_patchImmutableNode(node, path, update), - } as S; - // ^ - // FIXME Not completely true, because we could have been updating - // indexes from StorageUpdate here that aren't in S, technically. - } - } else { - return state; - } -} diff --git a/packages/liveblocks-core/src/index.ts b/packages/liveblocks-core/src/index.ts index 46eedb51082..6929898125b 100644 --- a/packages/liveblocks-core/src/index.ts +++ b/packages/liveblocks-core/src/index.ts @@ -93,7 +93,6 @@ export type { LiveObjectUpdate, StorageUpdate, } from "./crdts/StorageUpdates"; -export type { ToImmutable } from "./crdts/utils"; export { toPlainLson } from "./crdts/utils"; export type { DAD, @@ -110,11 +109,6 @@ export type { KDAD, } from "./globals/augmentation"; export type { SyncConfig, SyncMode } from "./immutable"; -export { - legacy_patchImmutableObject, - legacy_patchLiveObjectKey, - lsonToJson, -} from "./immutable"; export { kInternal } from "./internal"; export { makeAbortController } from "./lib/abortController"; export { assert, assertNever, nn } from "./lib/assert"; @@ -154,7 +148,14 @@ export { isPlainObject, isStartsWithOperator, } from "./lib/guards"; -export type { Json, JsonArray, JsonObject, JsonScalar } from "./lib/Json"; +export type { + Json, + JsonArray, + JsonObject, + JsonScalar, + ReadonlyJson, + ReadonlyJsonObject, +} from "./lib/Json"; export { isJsonArray, isJsonObject, isJsonScalar } from "./lib/Json"; export { nanoid } from "./lib/nanoid"; export type { NoInfr } from "./lib/NoInfer"; diff --git a/packages/liveblocks-core/src/lib/Json.ts b/packages/liveblocks-core/src/lib/Json.ts index 12e7c6a65f1..7792e893680 100644 --- a/packages/liveblocks-core/src/lib/Json.ts +++ b/packages/liveblocks-core/src/lib/Json.ts @@ -16,6 +16,21 @@ export type JsonArray = Json[]; */ export type JsonObject = { [key: string]: Json | undefined }; +/** + * Like Json, but with readonly arrays and objects. + */ +export type ReadonlyJson = + | JsonScalar + | readonly ReadonlyJson[] + | ReadonlyJsonObject; + +/** + * Like JsonObject, but readonly. + */ +export type ReadonlyJsonObject = { + readonly [key: string]: ReadonlyJson | undefined; +}; + export function isJsonScalar(data: Json): data is JsonScalar { return ( data === null || diff --git a/packages/liveblocks-core/src/types/Immutable.ts b/packages/liveblocks-core/src/types/Immutable.ts index 67a01470def..1506a4322ea 100644 --- a/packages/liveblocks-core/src/types/Immutable.ts +++ b/packages/liveblocks-core/src/types/Immutable.ts @@ -1,6 +1,6 @@ /** * Represents an indefinitely deep arbitrary immutable data - * structure, as returned by the .toImmutable(). + * structure. */ export type Immutable = Scalar | ImmutableList | ImmutableObject | ImmutableMap; diff --git a/packages/liveblocks-node/src/__tests__/client.test.ts b/packages/liveblocks-node/src/__tests__/client.test.ts index 33d70eb3ee1..4d714cd1fa2 100644 --- a/packages/liveblocks-node/src/__tests__/client.test.ts +++ b/packages/liveblocks-node/src/__tests__/client.test.ts @@ -2956,9 +2956,9 @@ describe("client", () => { const client = new Liveblocks({ secret: "sk_xxx" }); await expect( client.mutateStorage("my-room", ({ root }) => { - expect(root.toImmutable() as unknown).toEqual({ + expect(root.toJSON()).toEqual({ a: [{ abc: 123 }, { xyz: 3.14 }], - b: new Map(), + b: {}, }); // Mutate it! diff --git a/packages/liveblocks-node/src/client.ts b/packages/liveblocks-node/src/client.ts index ea2275d0ded..1e258f04138 100644 --- a/packages/liveblocks-node/src/client.ts +++ b/packages/liveblocks-node/src/client.ts @@ -34,7 +34,6 @@ import type { Json, JsonObject, KDAD, - LsonObject, NotificationSettings, NotificationSettingsPlain, Op, @@ -52,7 +51,7 @@ import type { SubscriptionDataPlain, ThreadData, ThreadDataPlain, - ToImmutable, + ToJson, URLSafeString, UserRoomSubscriptionSettings, UserSubscriptionData, @@ -91,23 +90,6 @@ import { normalizeStatusCode, } from "./utils"; -// Recursively convert ReadonlyMap to { [key: K]: V } -type SerializeMaps = - T extends ReadonlyMap - ? K extends string - ? { readonly [P in K]: SerializeMaps } - : { readonly [key: string]: SerializeMaps } - : T extends object - ? { readonly [P in keyof T]: SerializeMaps } - : T; - -type ToSimplifiedJson = LsonObject extends S - ? JsonObject - : // ToImmutable converts LiveMap instances to ReadonlyMap versions, but - // the "simplified JSON" format actually requires (because of serialization) - // and converts the maps to plain objects. - SerializeMaps>; - export type LiveblocksOptions = { /** * The Liveblocks secret key. Must start with "sk_". @@ -1421,13 +1403,13 @@ export class Liveblocks { roomId: string, format: "json", options?: RequestOptions - ): Promise>; + ): Promise>; public async getStorageDocument( roomId: string, format: "plain-lson" | "json" = "plain-lson", options?: RequestOptions - ): Promise> { + ): Promise> { const res = await this.#get( url`/v2/rooms/${roomId}/storage`, { format }, @@ -1436,7 +1418,7 @@ export class Liveblocks { if (!res.ok) { throw await LiveblocksError.from(res); } - return (await res.json()) as PlainLsonObject | ToSimplifiedJson; + return (await res.json()) as PlainLsonObject | ToJson; } async #requestStorageMutation( diff --git a/packages/liveblocks-node/test-d/no-augmentation.test-d.ts b/packages/liveblocks-node/test-d/no-augmentation.test-d.ts index e7523afddfb..d736d56c83c 100644 --- a/packages/liveblocks-node/test-d/no-augmentation.test-d.ts +++ b/packages/liveblocks-node/test-d/no-augmentation.test-d.ts @@ -7,7 +7,7 @@ import type { CommentData, Json, PlainLson, - JsonObject, + ReadonlyJsonObject, } from "@liveblocks/core"; async () => { @@ -129,7 +129,7 @@ async () => { // .getStorageDocument() (simplified JSON format) { const root = await client.getStorageDocument("my-room", "json"); - expectType(root); + expectType(root); } // .getComment() diff --git a/packages/liveblocks-react-flow/check-node-entrypoint.mjs b/packages/liveblocks-react-flow/check-node-entrypoint.mjs new file mode 100644 index 00000000000..ce8e222891f --- /dev/null +++ b/packages/liveblocks-react-flow/check-node-entrypoint.mjs @@ -0,0 +1,54 @@ +/** + * Post-build check that verifies the /node entry point does not transitively + * depend on React or other browser-only packages. Uses esbuild to temporarily + * bundle dist/node.js in memory, then checks which external packages remain. + */ +import { build } from "esbuild"; + +const result = await build({ + entryPoints: ["dist/node.js"], + bundle: true, + write: false, + format: "esm", + platform: "node", + packages: "external", +}); + +const code = result.outputFiles[0].text; + +// Only these packages are allowed as external dependencies of the /node entry point +const allowed = [ + "@liveblocks/core", + "@liveblocks/client", + "@liveblocks/node", +]; + +const importPattern = /from\s+["']([^"']+)["']/g; +const errors = []; + +for (const match of code.matchAll(importPattern)) { + const dep = match[1]; + if (!allowed.some((a) => dep === a || dep.startsWith(a + "/"))) { + errors.push(dep); + } +} + +if (errors.length > 0) { + const unique = [...new Set(errors)]; + console.error( + [ + `This script checks that the @liveblocks/react-flow/node subpath`, + `only depends on server-safe packages. The /node entry is used in Node.js`, + `backends (e.g. to mutate React Flow document state from a server). It`, + `must NOT pull in React, browser-only, or UI packages — even transitively.`, + ``, + `Allowed dependencies: ${allowed.join(", ")}`, + ``, + `The following disallowed imports were found:`, + ...unique.map((d) => ` - ${d}`), + ].join("\n") + ); + process.exit(1); +} + +console.log("✓ node entry is React-free"); diff --git a/packages/liveblocks-react-flow/package.json b/packages/liveblocks-react-flow/package.json index ce76f9c2230..29915c217aa 100644 --- a/packages/liveblocks-react-flow/package.json +++ b/packages/liveblocks-react-flow/package.json @@ -7,6 +7,11 @@ "type": "module", "main": "./dist/index.cjs", "types": "./dist/index.d.cts", + "typesVersions": { + "*": { + "node": ["./dist/node.d.ts"] + } + }, "exports": { ".": { "import": { @@ -19,6 +24,17 @@ "default": "./dist/index.cjs" } }, + "./node": { + "import": { + "types": "./dist/node.d.ts", + "default": "./dist/node.js" + }, + "require": { + "types": "./dist/node.d.cts", + "module": "./dist/node.js", + "default": "./dist/node.cjs" + } + }, "./styles.css": { "types": "./styles.css.d.cts", "default": "./styles.css" @@ -37,6 +53,7 @@ "build": "rollup --config rollup.config.js", "start": "npm run dev", "format": "(eslint --fix src/ || true) && stylelint --fix src/styles/ && prettier --write src/", + "lint:package": "publint --strict && attw --pack && node check-node-entrypoint.mjs", "lint": "eslint src/ && stylelint src/styles/", "test": "npx liveblocks dev -p 1154 -c 'vitest run --coverage'", "test:ci": "vitest run", @@ -64,6 +81,7 @@ }, "devDependencies": { "@liveblocks/eslint-config": "*", + "@liveblocks/node": "*", "@liveblocks/rollup-config": "*", "@liveblocks/vitest-config": "*", "@testing-library/jest-dom": "^6.4.6", diff --git a/packages/liveblocks-react-flow/rollup.config.js b/packages/liveblocks-react-flow/rollup.config.js index f10ab31ea41..f4716ea8047 100644 --- a/packages/liveblocks-react-flow/rollup.config.js +++ b/packages/liveblocks-react-flow/rollup.config.js @@ -7,7 +7,7 @@ import pkg from "./package.json" with { type: "json" }; export default createConfig({ pkg, - entries: ["src/index.ts"], + entries: ["src/index.ts", "src/node.ts"], styles: [ { entry: "src/styles/index.css", diff --git a/packages/liveblocks-react-flow/src/__tests__/flow.test.tsx b/packages/liveblocks-react-flow/src/__tests__/flow.test.tsx index 76a1334acf7..c87d175695a 100644 --- a/packages/liveblocks-react-flow/src/__tests__/flow.test.tsx +++ b/packages/liveblocks-react-flow/src/__tests__/flow.test.tsx @@ -6,7 +6,7 @@ import { Suspense } from "react"; import { describe, expect, test } from "vitest"; import { useLiveblocksFlow } from "../index"; -import type { LiveblocksFlow } from "../types"; +import type { LiveblocksFlow } from "../lib/types"; import { render, renderHook } from "./_utils"; const NODES: BuiltInNode[] = [ diff --git a/packages/liveblocks-react-flow/src/__tests__/mutate-flow-from-backend.test.ts b/packages/liveblocks-react-flow/src/__tests__/mutate-flow-from-backend.test.ts new file mode 100644 index 00000000000..8849c5c4355 --- /dev/null +++ b/packages/liveblocks-react-flow/src/__tests__/mutate-flow-from-backend.test.ts @@ -0,0 +1,937 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + +import type { JsonObject } from "@liveblocks/core"; +import { createClient, nanoid } from "@liveblocks/core"; +import { Liveblocks } from "@liveblocks/node"; +import type { Node } from "@xyflow/react"; +import { describe, expect, onTestFinished, test, vi } from "vitest"; + +import { mutateFlow } from "../node"; + +const DEV_SERVER = "http://localhost:1154"; + +const client = new Liveblocks({ + secret: "sk_localdev", + baseUrl: DEV_SERVER, +}); + +/** + * Creates a room on the dev server and optionally initializes its storage. + */ +async function initRoom(storage?: Record): Promise { + const roomId = `room-${nanoid()}`; + + await fetch(`${DEV_SERVER}/v2/rooms`, { + method: "POST", + headers: { + Authorization: "Bearer sk_localdev", + "Content-Type": "application/json", + }, + body: JSON.stringify({ id: roomId }), + }); + + if (storage) { + await fetch( + `${DEV_SERVER}/v2/rooms/${encodeURIComponent(roomId)}/storage`, + { + method: "POST", + headers: { + Authorization: "Bearer sk_localdev", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + liveblocksType: "LiveObject", + data: storage, + }), + } + ); + } + + return roomId; +} + +async function getStorage(roomId: string): Promise> { + const resp = await fetch( + `${DEV_SERVER}/v2/rooms/${encodeURIComponent(roomId)}/storage?format=json`, + { headers: { Authorization: "Bearer sk_localdev" } } + ); + return (await resp.json()) as Record; +} + +/** + * Connects a live observer client to a room via WebSocket and returns a + * function that collects storage update batches. Useful for verifying that + * mutations emit the expected number of ops. + */ +async function connectObserver(roomId: string) { + const res = await fetch(`${DEV_SERVER}/v2/authorize-user`, { + method: "POST", + headers: { + Authorization: "Bearer sk_localdev", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + userId: `observer-${nanoid()}`, + userInfo: {}, + permissions: { [roomId]: ["room:write"] }, + }), + }); + const { token } = (await res.json()) as { token: string }; + + const liveClient = createClient({ + baseUrl: DEV_SERVER, + authEndpoint: () => Promise.resolve({ token }), + polyfills: { WebSocket: globalThis.WebSocket }, + }); + + const { room, leave } = liveClient.enterRoom(roomId, { + initialPresence: {}, + initialStorage: {}, + }); + + onTestFinished(leave); + + // Wait for connection + initial storage sync + await vi.waitUntil(() => room.getStatus() === "connected"); + await room.getStorage(); + + const batches: number[] = []; + room.events.storageBatch.subscribe((updates) => { + batches.push(updates.length); + }); + + return { + room, + /** Returns array where each element = number of updates in one batch */ + getBatches: () => batches, + }; +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe("mutateFlow", () => { + // -- Empty room / initialization -- + + test("auto-initializes empty flow storage when room is empty", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + expect(flow.nodes).toEqual([]); + expect(flow.edges).toEqual([]); + }); + }); + + test("reads existing nodes and edges from storage", async () => { + const roomId = await initRoom({ + flow: { + liveblocksType: "LiveObject", + data: { + nodes: { + liveblocksType: "LiveMap", + data: { + n1: { + liveblocksType: "LiveObject", + data: { + id: "n1", + position: { + liveblocksType: "LiveObject", + data: { x: 0, y: 0 }, + }, + data: { + liveblocksType: "LiveObject", + data: { label: "Hello" }, + }, + }, + }, + }, + }, + edges: { + liveblocksType: "LiveMap", + data: { + e1: { + liveblocksType: "LiveObject", + data: { id: "e1", source: "n1", target: "n2" }, + }, + }, + }, + }, + }, + }); + + await mutateFlow({ client, roomId }, (flow) => { + const nodes = flow.nodes; + expect(nodes).toHaveLength(1); + expect(nodes[0]).toMatchObject({ id: "n1", data: { label: "Hello" } }); + + const edges = flow.edges; + expect(edges).toHaveLength(1); + expect(edges[0]).toMatchObject({ id: "e1", source: "n1", target: "n2" }); + }); + }); + + // -- toJSON -- + + test("toJSON returns both nodes and edges", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "A" }, + }); + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + + const { nodes, edges } = flow; + expect(nodes).toHaveLength(1); + expect(nodes[0]).toMatchObject({ id: "n1" }); + expect(edges).toHaveLength(1); + expect(edges[0]).toMatchObject({ id: "e1" }); + + // JSON.stringify calls toJSON() automatically + expect(JSON.parse(JSON.stringify(flow))).toEqual({ + nodes: [ + { + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "A" }, + }, + ], + edges: [{ id: "e1", source: "n1", target: "n2" }], + }); + }); + }); + + // -- getNode / getEdge -- + + test("getNode returns a single node by id", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + type: "default", + id: "n1", + position: { x: 0, y: 0 }, + data: { label: "A" }, + }); + expect(flow.getNode("n1")).toMatchObject({ id: "n1" }); + expect(flow.getNode("nope")).toBeUndefined(); + }); + }); + + test("getEdge returns a single edge by id", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + expect(flow.getEdge("e1")).toMatchObject({ id: "e1" }); + expect(flow.getEdge("nope")).toBeUndefined(); + }); + }); + + // -- addNode / addNodes -- + + test("addNode adds a node to an empty flow", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "input", + position: { x: 10, y: 20 }, + data: { label: "New" }, + }); + + const nodes = flow.nodes; + expect(nodes).toHaveLength(1); + expect(nodes[0]).toMatchObject({ + id: "n1", + type: "input", + position: { x: 10, y: 20 }, + data: { label: "New" }, + }); + }); + + // Verify storage was persisted + const storage = await getStorage(roomId); + expect(storage).toMatchObject({ + flow: { nodes: { n1: { id: "n1", type: "input" } } }, + }); + }); + + test("addNodes adds multiple nodes at once", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNodes([ + { + id: "a", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "one" }, + }, + { + id: "b", + type: "default", + position: { x: 1, y: 1 }, + data: { label: "two" }, + }, + ]); + + expect(flow.nodes).toHaveLength(2); + }); + }); + + // -- updateNode -- + + test("updateNode with partial object", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + type: "default", + id: "n1", + position: { x: 0, y: 0 }, + data: { label: "Old" }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNode("n1", { position: { x: 99, y: 99 } }); + + const node = flow.getNode("n1"); + expect(node).toMatchObject({ position: { x: 99, y: 99 } }); + // data should still be there + expect(node?.data).toMatchObject({ label: "Old" }); + }); + }); + + test("updateNode with updater function", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + type: "default", + id: "n1", + position: { x: 0, y: 0 }, + data: { label: "Old" }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNode("n1", (node) => ({ + ...node, + position: { x: 42, y: 42 }, + })); + + expect(flow.getNode("n1")).toMatchObject({ + position: { x: 42, y: 42 }, + }); + }); + }); + + test("updateNode on non-existent node is a no-op", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNode("nonexistent", { position: { x: 1, y: 1 } }); + expect(flow.nodes).toHaveLength(0); + }); + }); + + // -- updateNodeData -- + + test("updateNodeData with partial object", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ label: string; color: string }, "custom">; + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { label: "Hello", color: "red" }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNodeData("n1", { color: "blue" }); + + const node = flow.getNode("n1"); + expect(node?.data).toMatchObject({ label: "Hello", color: "blue" }); + }); + }); + + test("updateNodeData with updater function", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ count: number }, "custom">; + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { count: 1 }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNodeData("n1", (data) => ({ + ...data, + count: (data.count ?? 0) + 1, + })); + + expect(flow.getNode("n1")?.data).toMatchObject({ count: 2 }); + }); + }); + + test("updateNodeData on non-existent node is a no-op", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNodeData("nonexistent", { label: "X" }); + expect(flow.nodes).toHaveLength(0); + }); + }); + + // -- removeNode / removeNodes -- + + test("removeNode removes a single node", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNodes([ + { + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "one" }, + }, + { + id: "n2", + type: "default", + position: { x: 1, y: 1 }, + data: { label: "two" }, + }, + ]); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.removeNode("n1"); + expect(flow.nodes).toHaveLength(1); + expect(flow.nodes[0]).toMatchObject({ id: "n2" }); + }); + }); + + test("removeNodes removes multiple nodes", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNodes([ + { + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "one" }, + }, + { + id: "n2", + type: "default", + position: { x: 1, y: 1 }, + data: { label: "two" }, + }, + { + id: "n3", + type: "default", + position: { x: 2, y: 2 }, + data: { label: "three" }, + }, + ]); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.removeNodes(["n1", "n3"]); + expect(flow.nodes).toHaveLength(1); + expect(flow.nodes[0]).toMatchObject({ id: "n2" }); + }); + }); + + // -- Edge mutations -- + + test("addEdge adds an edge", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + expect(flow.edges).toHaveLength(1); + expect(flow.edges[0]).toMatchObject({ + id: "e1", + source: "n1", + target: "n2", + }); + }); + }); + + test("addEdges adds multiple edges", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdges([ + { id: "e1", source: "n1", target: "n2" }, + { id: "e2", source: "n2", target: "n3" }, + ]); + expect(flow.edges).toHaveLength(2); + }); + }); + + test("updateEdge with partial object", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdge("e1", { label: "Updated" }); + expect(flow.getEdge("e1")).toMatchObject({ label: "Updated" }); + }); + }); + + test("updateEdge with updater function", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdge("e1", (edge) => ({ ...edge, label: "My edge" })); + expect(flow.getEdge("e1")).toMatchObject({ label: "My edge" }); + }); + }); + + test("updateEdge on non-existent edge is a no-op", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdge("nonexistent", { label: "X" }); + expect(flow.edges).toHaveLength(0); + }); + }); + + test("updateEdgeData with partial object", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ + id: "e1", + source: "n1", + target: "n2", + data: { color: "red" }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdgeData("e1", { color: "blue" }); + expect(flow.getEdge("e1")?.data).toMatchObject({ color: "blue" }); + }); + }); + + test("updateEdgeData with updater function", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ + id: "e1", + source: "n1", + target: "n2", + data: { color: "red" }, + }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdgeData("e1", (data) => ({ + ...data, + color: "blue", + })); + expect(flow.getEdge("e1")?.data).toMatchObject({ color: "blue" }); + }); + }); + + test("removeEdge removes a single edge", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdges([ + { id: "e1", source: "n1", target: "n2" }, + { id: "e2", source: "n2", target: "n3" }, + ]); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.removeEdge("e1"); + expect(flow.edges).toHaveLength(1); + expect(flow.edges[0]).toMatchObject({ id: "e2" }); + }); + }); + + test("removeEdges removes multiple edges", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdges([ + { id: "e1", source: "n1", target: "n2" }, + { id: "e2", source: "n2", target: "n3" }, + ]); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.removeEdges(["e1", "e2"]); + expect(flow.edges).toHaveLength(0); + }); + }); + + // -- storageKey -- + + test("uses custom storage key", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId, storageKey: "myFlow" }, (flow) => { + flow.addNode({ + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "Custom" }, + }); + }); + + await mutateFlow({ client, roomId, storageKey: "myFlow" }, (flow) => { + expect(flow.nodes).toHaveLength(1); + expect(flow.nodes[0]).toMatchObject({ + id: "n1", + data: { label: "Custom" }, + }); + }); + + // Default storage key should still be empty + await mutateFlow({ client, roomId }, (flow) => { + expect(flow.nodes).toHaveLength(0); + }); + }); + + // -- Persistence -- + + test("mutations are persisted across separate mutateFlow calls", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "default", + position: { x: 10, y: 20 }, + data: { label: "Test" }, + }); + }); + + // Second call should see the persisted data + await mutateFlow({ client, roomId }, (flow) => { + const nodes = flow.nodes; + expect(nodes).toHaveLength(1); + expect(nodes[0]).toMatchObject({ + id: "n1", + type: "default", + position: { x: 10, y: 20 }, + data: { label: "Test" }, + }); + }); + }); + + // -- Multiple mutations in one callback -- + + test("multiple mutations in one callback are all applied", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ v: number }, "custom">; + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { v: 1 }, + }); + flow.addNode({ + id: "n2", + type: "custom", + position: { x: 1, y: 1 }, + data: { v: 2 }, + }); + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + + expect(flow.nodes).toHaveLength(2); + expect(flow.edges).toHaveLength(1); + + flow.updateNodeData("n1", { v: 10 }); + expect(flow.getNode("n1")?.data).toMatchObject({ v: 10 }); + + flow.removeNode("n2"); + expect(flow.nodes).toHaveLength(1); + }); + }); + + // -- Sync config -- + + test("respects per-type node sync config", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ label: string; local: string }, "custom">; + + await mutateFlow( + { + client, + roomId, + nodes: { + sync: { + custom: { local: false }, + }, + }, + }, + (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { label: "Hello", local: "not-synced" }, + }); + } + ); + + // "local" field should not be persisted + const storage = await getStorage(roomId); + const nodeData = (storage as any).flow?.nodes?.n1?.data; + expect(nodeData).toMatchObject({ label: "Hello" }); + expect(nodeData).not.toHaveProperty("local"); + }); + + test("respects wildcard (*) node sync config", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ label: string; temp: string }, "custom">; + + await mutateFlow( + { + client, + roomId, + nodes: { + sync: { + "*": { temp: false }, + }, + }, + }, + (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { label: "Hello", temp: "not-synced" }, + }); + } + ); + + const storage = await getStorage(roomId); + const nodeData = (storage as any).flow?.nodes?.n1?.data; + expect(nodeData).toMatchObject({ label: "Hello" }); + expect(nodeData).not.toHaveProperty("temp"); + }); + + test("ignores undefined entries in sync config", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ label: string }, "custom">; + + await mutateFlow( + { + client, + roomId, + nodes: { + sync: { + custom: undefined, // Explicitly undefined — should be skipped + "*": { label: "atomic" }, + }, + }, + }, + (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { label: "Hello" }, + }); + } + ); + + // The wildcard config should still apply + const storage = await getStorage(roomId); + expect((storage as any).flow?.nodes?.n1?.data).toMatchObject({ + label: "Hello", + }); + }); + + // -- Edge data edge cases -- + + test("updateEdgeData on edge with no data uses updater", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addEdge({ id: "e1", source: "n1", target: "n2" }); + }); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateEdgeData("e1", (data) => { + // data may be undefined for edges without initial data + return { ...data, color: "red" }; + }); + + expect(flow.getEdge("e1")?.data).toMatchObject({ color: "red" }); + }); + }); + + // -- Upsert behavior -- + + test("addNode overwrites existing node with same ID", async () => { + const roomId = await initRoom(); + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "Original" }, + }); + + flow.addNode({ + id: "n1", + type: "default", + position: { x: 99, y: 99 }, + data: { label: "Replaced" }, + }); + + expect(flow.nodes).toHaveLength(1); + expect(flow.getNode("n1")).toMatchObject({ + position: { x: 99, y: 99 }, + data: { label: "Replaced" }, + }); + }); + }); + + // -- Minimal ops -- + + test("updateNode with local-only field emits no ops", async () => { + const roomId = await initRoom(); + + // Set up initial node + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "default", + position: { x: 0, y: 0 }, + data: { label: "Hello" }, + }); + }); + + // Connect observer before mutation + const observer = await connectObserver(roomId); + + // Update only `selected`, which is local-only per NODE_BASE_CONFIG + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNode("n1", { selected: true }); + }); + + // Give the server a moment to propagate + await vi.waitFor(() => { + // No batches should arrive — `selected` is local-only + expect(observer.getBatches()).toEqual([]); + }); + }); + + test("updateNodeData emits a single update for one field change", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ color: string; label: string }, "custom">; + + await mutateFlow({ client, roomId }, (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { color: "red", label: "Hello" }, + }); + }); + + const observer = await connectObserver(roomId); + + await mutateFlow({ client, roomId }, (flow) => { + flow.updateNodeData("n1", { color: "blue" }); + }); + + await vi.waitFor(() => { + // Expect exactly one batch with one update (only the data.color change) + expect(observer.getBatches()).toEqual([1]); + }); + }); + + test("updateNodeData with local-only field emits no ops, synced field emits one", async () => { + const roomId = await initRoom(); + + type CustomNode = Node<{ color: string; local: string }, "custom">; + + await mutateFlow( + { + client, + roomId, + nodes: { sync: { custom: { local: false } } }, + }, + (flow) => { + flow.addNode({ + id: "n1", + type: "custom", + position: { x: 0, y: 0 }, + data: { color: "red", local: "initial" }, + }); + } + ); + + const observer = await connectObserver(roomId); + + await mutateFlow( + { + client, + roomId, + nodes: { sync: { custom: { local: false } } }, + }, + (flow) => { + // This should NOT propagate — `local` is marked as not synced + flow.updateNodeData("n1", { local: "changed" }); + // This SHOULD propagate — `color` is synced + flow.updateNodeData("n1", { color: "blue" }); + + // But the local client sees both updates + expect(flow.getNode("n1")?.data).toMatchObject({ + color: "blue", + local: "changed", + }); + } + ); + + await vi.waitFor(() => { + // Only the color change should reach the observer + expect(observer.getBatches()).toEqual([1]); + }); + }); +}); diff --git a/packages/liveblocks-react-flow/src/constants.ts b/packages/liveblocks-react-flow/src/constants.ts deleted file mode 100644 index fa09c1c311a..00000000000 --- a/packages/liveblocks-react-flow/src/constants.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { SyncMode } from "@liveblocks/core"; -import type { Edge, Node } from "@xyflow/react"; - -export const DEFAULT_STORAGE_KEY = "flow"; - -// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow. -type NodeSyncConfig = { [K in keyof Node]?: SyncMode }; -type EdgeSyncConfig = { [K in keyof Edge]?: SyncMode }; - -export const NODE_BASE_CONFIG = { - // Local-only (not synced) - selected: false, - dragging: false, - measured: false, - resizing: false, - - // Atomic (synced as plain Json) - position: "atomic", - sourcePosition: "atomic", - targetPosition: "atomic", - extent: "atomic", - origin: "atomic", - handles: "atomic", - - // Note: the `data` key is intentionally left out of this base config, as it - // is expected to be provided by the end user -} as const satisfies NodeSyncConfig; - -export const EDGE_BASE_CONFIG = { - // Local-only (not synced) - selected: false, - - // Atomic (synced as plain Json) - markerStart: "atomic", - markerEnd: "atomic", - label: "atomic", - labelBgPadding: "atomic", - - // Note: the `data` key is intentionally left out of this base config, as it - // is expected to be provided by the end user -} as const satisfies EdgeSyncConfig; diff --git a/packages/liveblocks-react-flow/src/helpers.ts b/packages/liveblocks-react-flow/src/helpers.ts deleted file mode 100644 index e6cf3b74a72..00000000000 --- a/packages/liveblocks-react-flow/src/helpers.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { JsonObject, SyncConfig } from "@liveblocks/core"; -import { LiveObject } from "@liveblocks/core"; -import type { Edge, Node } from "@xyflow/react"; - -import { EDGE_BASE_CONFIG, NODE_BASE_CONFIG } from "./constants"; -import type { - InternalLiveblocksEdge, - InternalLiveblocksNode, - LiveblocksEdge, - LiveblocksNode, -} from "./types"; - -export function toLiveblocksInternalNode( - node: N, - config: SyncConfig -): InternalLiveblocksNode { - return LiveObject.from( - node as unknown as JsonObject, - config - ) as InternalLiveblocksNode; -} - -export function toLiveblocksInternalEdge( - edge: E, - config: SyncConfig -): InternalLiveblocksEdge { - return LiveObject.from( - edge as unknown as JsonObject, - config - ) as InternalLiveblocksEdge; -} - -/** - * @experimental - * - * Converts a React Flow `Node` into a Liveblocks Storage version. - * Keys marked `false` in config are set as local-only (not synced). - * Keys marked `"atomic"` are stored as plain Json (no deep wrapping). - * All other keys are deep-liveified (objects→LiveObject, arrays→LiveList). - */ -export function toLiveblocksNode( - node: N, - config?: SyncConfig -): LiveblocksNode { - return toLiveblocksInternalNode(node, { - ...NODE_BASE_CONFIG, - data: config, - }) as unknown as LiveblocksNode; -} - -/** - * @experimental - * - * Converts a React Flow `Edge` into a Liveblocks Storage version. - * Keys marked `false` in config are set as local-only (not synced). - * Keys marked `"atomic"` are stored as plain Json (no deep wrapping). - * All other keys are deep-liveified (objects→LiveObject, arrays→LiveList). - */ -export function toLiveblocksEdge( - edge: E, - config?: SyncConfig -): LiveblocksEdge { - return toLiveblocksInternalEdge(edge, { - ...EDGE_BASE_CONFIG, - data: config, - }) as unknown as LiveblocksEdge; -} diff --git a/packages/liveblocks-react-flow/src/index.ts b/packages/liveblocks-react-flow/src/index.ts index a51e828a290..0c9ac95383c 100644 --- a/packages/liveblocks-react-flow/src/index.ts +++ b/packages/liveblocks-react-flow/src/index.ts @@ -1,13 +1,12 @@ import { detectDupes } from "@liveblocks/core"; -import { PKG_FORMAT, PKG_NAME, PKG_VERSION } from "./version"; +import { PKG_FORMAT, PKG_NAME, PKG_VERSION } from "./lib/version"; detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT); export type { CursorsCursorProps, CursorsProps } from "./cursors"; export { Cursors } from "./cursors"; -export { useLiveblocksFlow } from "./flow"; -export { toLiveblocksEdge, toLiveblocksNode } from "./helpers"; +export { useLiveblocksFlow } from "./lib/flow"; export type { EdgeSyncConfig, LiveblocksEdge, @@ -16,4 +15,4 @@ export type { NodeSyncConfig, SyncConfig, SyncMode, -} from "./types"; +} from "./lib/types"; diff --git a/packages/liveblocks-react-flow/src/flow.ts b/packages/liveblocks-react-flow/src/lib/flow.ts similarity index 87% rename from packages/liveblocks-react-flow/src/flow.ts rename to packages/liveblocks-react-flow/src/lib/flow.ts index 9359e41bc21..7347c904e2f 100644 --- a/packages/liveblocks-react-flow/src/flow.ts +++ b/packages/liveblocks-react-flow/src/lib/flow.ts @@ -1,8 +1,9 @@ import type { History, JsonObject, + ReadonlyJsonObject, Resolve, - ToImmutable, + ToJson, } from "@liveblocks/core"; import { kInternal, LiveMap, LiveObject } from "@liveblocks/core"; import { useHistory, useMutation, useStorage } from "@liveblocks/react"; @@ -27,11 +28,12 @@ import { addEdge as defaultAddEdge } from "@xyflow/react"; import { useEffect, useMemo } from "react"; import { + buildEdgeConfigCache, + buildNodeConfigCache, DEFAULT_STORAGE_KEY, - EDGE_BASE_CONFIG, - NODE_BASE_CONFIG, -} from "./constants"; -import { toLiveblocksInternalEdge, toLiveblocksInternalNode } from "./helpers"; + toLiveblocksInternalEdge, + toLiveblocksInternalNode, +} from "./shared"; import type { EdgeSyncConfig, InternalLiveblocksEdge, @@ -71,42 +73,6 @@ type LiveblocksFlowSuspenseResult< E extends Edge = BuiltInEdge, > = Extract, { isLoading: false }>; -function mergeAndBuildDataConfigCache( - base: SyncConfig, - data?: Record -): (type: string | undefined) => SyncConfig { - if (!data) return () => base; - - const dataFallback = data["*"]; - const fallback = dataFallback ? { ...base, data: dataFallback } : base; - - // Pre-compute full node/edge sync configs for all explicitly declared types - const cache = new Map(); - for (const type in data) { - if (type === "*") continue; - const specific = data[type]; - if (!specific) continue; - const dataConfig: SyncConfig = { ...dataFallback, ...specific }; - cache.set(type, { ...base, data: dataConfig }); - } - - return (type) => cache.get(type) || fallback; -} - -function buildNodeConfigCache( - /** The user-provided node data sync configuration, if any. */ - nodeDataConfig?: NodeSyncConfig -): (type: string | undefined) => SyncConfig { - return mergeAndBuildDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig); -} - -function buildEdgeConfigCache( - /** The user-provided edge data sync configuration, if any. */ - edgeDataConfig?: EdgeSyncConfig -): (type: string | undefined) => SyncConfig { - return mergeAndBuildDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig); -} - type UseLiveblocksFlowOptions = { nodes?: { /** @@ -359,6 +325,45 @@ function applyEdgeChanges( } } +// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes +// in topological order (parents before children), deferring any node with a +// parentId until its parent has been emitted. +function nodeMapToList( + nodesMap: ReadonlyJsonObject | null +): N[] | null { + if (nodesMap === null) return null; + return Object.values(nodesMap) as unknown as N[]; +} + +function edgeMapToList( + edgesMap: ReadonlyJsonObject | null +): E[] | null { + if (edgesMap === null) return null; + return Object.values(edgesMap) as unknown as E[]; +} + +function useNodesAndEdges(storageKey: string) { + // Storage already includes local overlays via toJSON(), so no separate local + // layer is needed. Individual node/edge immutable references are already + // stable (only change when the underlying LiveObject changes). + const nodesMap = useStorage((storage) => { + const flow = storage[storageKey] as + | ToJson + | undefined; + return flow?.nodes ?? null; + }); + const edgesMap = useStorage((storage) => { + const flow = storage[storageKey] as + | ToJson + | undefined; + return flow?.edges ?? null; + }); + + const nodes = useMemo(() => nodeMapToList(nodesMap), [nodesMap]); + const edges = useMemo(() => edgeMapToList(edgesMap), [edgesMap]); + return { nodes, edges }; +} + /** * Returns a controlled React Flow state backed by Liveblocks Storage. * @@ -421,21 +426,7 @@ export function useLiveblocksFlow< [frozenOptions] ); - // Storage already includes local overlays via toImmutable(), so no - // separate local layer is needed. Individual node/edge immutable references - // are already stable (only change when the underlying LiveObject changes). - const nodes = useStorage((storage) => { - const flow = storage[frozenOptions.storageKey] as - | ToImmutable - | undefined; - return flow?.nodes ? ([...flow.nodes.values()] as unknown as N[]) : null; - }); - const edges = useStorage((storage) => { - const flow = storage[frozenOptions.storageKey] as - | ToImmutable - | undefined; - return flow?.edges ? ([...flow.edges.values()] as unknown as E[]) : null; - }); + const { nodes, edges } = useNodesAndEdges(frozenOptions.storageKey); const onNodesChange = useMutation( ({ storage }, changes: NodeChange[]) => { diff --git a/packages/liveblocks-react-flow/src/lib/shared.ts b/packages/liveblocks-react-flow/src/lib/shared.ts new file mode 100644 index 00000000000..8c845c78154 --- /dev/null +++ b/packages/liveblocks-react-flow/src/lib/shared.ts @@ -0,0 +1,108 @@ +/** + * Module with utilities shared between the React Flow frontend and the React + * Flow Node backend. There are no runtime dependencies on @xyflow/react, + * react, or any other frontend-specific libraries from this module, and this + * should stay that way. + */ +import type { JsonObject, SyncConfig, SyncMode } from "@liveblocks/core"; +import { LiveObject } from "@liveblocks/core"; +import type { Edge, Node } from "@xyflow/react"; + +import type { InternalLiveblocksEdge, InternalLiveblocksNode } from "./types"; + +export const DEFAULT_STORAGE_KEY = "flow"; + +// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow. +type NodeSyncConfig = { [K in keyof Node]?: SyncMode }; +type EdgeSyncConfig = { [K in keyof Edge]?: SyncMode }; + +export const NODE_BASE_CONFIG = { + // Local-only (not synced) + selected: false, + dragging: false, + measured: false, + resizing: false, + + // Atomic (synced as plain Json) + position: "atomic", + sourcePosition: "atomic", + targetPosition: "atomic", + extent: "atomic", + origin: "atomic", + handles: "atomic", + + // Note: the `data` key is intentionally left out of this base config, as it + // is expected to be provided by the end user +} as const satisfies NodeSyncConfig; + +export const EDGE_BASE_CONFIG = { + // Local-only (not synced) + selected: false, + + // Atomic (synced as plain Json) + markerStart: "atomic", + markerEnd: "atomic", + label: "atomic", + labelBgPadding: "atomic", + + // Note: the `data` key is intentionally left out of this base config, as it + // is expected to be provided by the end user +} as const satisfies EdgeSyncConfig; + +/** + * Merges a base config with per-type user data configs, returning a lookup + * function that resolves the full SyncConfig for a given type string. + */ +export function buildFlowDataConfigCache( + base: SyncConfig, + data?: Record +): (type: string | undefined) => SyncConfig { + if (!data) return () => base; + + const dataFallback = data["*"]; + const fallback = dataFallback ? { ...base, data: dataFallback } : base; + + // Pre-compute full sync configs for all explicitly declared types + const cache = new Map(); + for (const type in data) { + if (type === "*") continue; + const specific = data[type]; + if (!specific) continue; + const dataConfig: SyncConfig = { ...dataFallback, ...specific }; + cache.set(type, { ...base, data: dataConfig }); + } + + return (type) => cache.get(type) || fallback; +} + +export function buildNodeConfigCache( + nodeDataConfig?: Record +): (type: string | undefined) => SyncConfig { + return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig); +} + +export function buildEdgeConfigCache( + edgeDataConfig?: Record +): (type: string | undefined) => SyncConfig { + return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig); +} + +export function toLiveblocksInternalNode( + node: N, + config: SyncConfig +): InternalLiveblocksNode { + return LiveObject.from( + node as unknown as JsonObject, + config + ) as InternalLiveblocksNode; +} + +export function toLiveblocksInternalEdge( + edge: E, + config: SyncConfig +): InternalLiveblocksEdge { + return LiveObject.from( + edge as unknown as JsonObject, + config + ) as InternalLiveblocksEdge; +} diff --git a/packages/liveblocks-react-flow/src/types.ts b/packages/liveblocks-react-flow/src/lib/types.ts similarity index 98% rename from packages/liveblocks-react-flow/src/types.ts rename to packages/liveblocks-react-flow/src/lib/types.ts index 3322f8cb947..9991f19fe47 100644 --- a/packages/liveblocks-react-flow/src/types.ts +++ b/packages/liveblocks-react-flow/src/lib/types.ts @@ -10,7 +10,7 @@ import type { } from "@liveblocks/core"; import type { BuiltInEdge, BuiltInNode, Edge, Node } from "@xyflow/react"; -import type { EDGE_BASE_CONFIG, NODE_BASE_CONFIG } from "./constants"; +import type { EDGE_BASE_CONFIG, NODE_BASE_CONFIG } from "./shared"; export type { SyncConfig, SyncMode }; diff --git a/packages/liveblocks-react-flow/src/version.ts b/packages/liveblocks-react-flow/src/lib/version.ts similarity index 100% rename from packages/liveblocks-react-flow/src/version.ts rename to packages/liveblocks-react-flow/src/lib/version.ts diff --git a/packages/liveblocks-react-flow/src/node.ts b/packages/liveblocks-react-flow/src/node.ts new file mode 100644 index 00000000000..974e1b82688 --- /dev/null +++ b/packages/liveblocks-react-flow/src/node.ts @@ -0,0 +1,294 @@ +import type { JsonObject, LsonObject } from "@liveblocks/core"; +import { LiveMap, LiveObject } from "@liveblocks/core"; +import type { BuiltInEdge, BuiltInNode, Edge, Node } from "@xyflow/react"; + +import { + buildEdgeConfigCache, + buildNodeConfigCache, + DEFAULT_STORAGE_KEY, + toLiveblocksInternalEdge, + toLiveblocksInternalNode, +} from "./lib/shared"; +import type { + EdgeSyncConfig, + InternalLiveblocksFlow, + NodeSyncConfig, +} from "./lib/types"; + +/** + * A minimal interface for the Liveblocks Node client — just the + * `mutateStorage` method we actually need. This avoids importing + * `@liveblocks/node` as a dependency. + */ +interface ILiveblocksClient { + mutateStorage( + roomId: string, + callback: (context: { + root: LiveObject; + }) => void | Promise + ): Promise; +} + +/** Options for `mutateFlow()`. */ +export interface MutateFlowOptions< + N extends Node = BuiltInNode, + E extends Edge = BuiltInEdge, +> { + client: ILiveblocksClient; + roomId: string; + storageKey?: string; + nodes?: { sync?: NodeSyncConfig }; + edges?: { sync?: EdgeSyncConfig }; +} + +export interface MutableFlow { + /** The current list of nodes. */ + readonly nodes: readonly N[]; + /** The current list of edges. */ + readonly edges: readonly E[]; + /** Returns a plain object snapshot with `nodes` and `edges` arrays. */ + toJSON(): { + nodes: readonly N[]; + edges: readonly E[]; + }; + + /** Returns a single node by ID, or `undefined` if not found. */ + getNode(id: string): N | undefined; + /** Returns a single edge by ID, or `undefined` if not found. */ + getEdge(id: string): E | undefined; + + /** Adds a node. If a node with the same ID already exists, it is replaced. */ + addNode(node: N): void; + /** Adds multiple nodes. Existing nodes with the same IDs are replaced. */ + addNodes(nodes: N[]): void; + /** Updates a node by merging a partial object. No-op if the node does not exist. */ + updateNode(id: string, partial: Partial): void; + /** Updates a node using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */ + updateNode(id: string, updater: (node: N) => N): void; + /** Updates a node's `data` by merging a partial object. No-op if the node does not exist. */ + updateNodeData(id: string, partial: Partial): void; + /** Updates a node's `data` using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */ + updateNodeData( + id: string, + updater: (data: D) => D + ): void; + /** Removes a node by ID. */ + removeNode(id: string): void; + /** Removes multiple nodes by ID. */ + removeNodes(ids: string[]): void; + + /** Adds an edge. If an edge with the same ID already exists, it is replaced. */ + addEdge(edge: E): void; + /** Adds multiple edges. Existing edges with the same IDs are replaced. */ + addEdges(edges: E[]): void; + /** Updates an edge by merging a partial object. No-op if the edge does not exist. */ + updateEdge(id: string, partial: Partial): void; + /** Updates an edge using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */ + updateEdge(id: string, updater: (edge: E) => E): void; + /** Updates an edge's `data` by merging a partial object. No-op if the edge does not exist. */ + updateEdgeData(id: string, partial: Partial>): void; + /** Updates an edge's `data` using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */ + updateEdgeData( + id: string, + updater: (data: D) => D + ): void; + /** Removes an edge by ID. */ + removeEdge(id: string): void; + /** Removes multiple edges by ID. */ + removeEdges(ids: string[]): void; +} + +/** + * Opens a flow (a collection of React Flow nodes and edges) for reading and + * mutating, then automatically flushes all changes when the callback + * completes. + * + * @example + * ```ts + * await mutateFlow({ client, roomId: "my-room" }, (flow) => { + * flow.addNode({ id: "1", position: { x: 0, y: 0 }, data: {} }); + * flow.updateNodeData("1", { label: "Hello" }); + * }); + * ``` + */ +export async function mutateFlow< + N extends Node = BuiltInNode, + E extends Edge = BuiltInEdge, +>( + options: MutateFlowOptions, + callback: (flow: MutableFlow) => void | Promise +): Promise { + const { client, roomId } = options; + const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY; + + const getNodeSyncConfig = buildNodeConfigCache(options.nodes?.sync); + const getEdgeSyncConfig = buildEdgeConfigCache(options.edges?.sync); + + const nodeListCache = new WeakMap, N[]>(); + const edgeListCache = new WeakMap, E[]>(); + + await client.mutateStorage(roomId, async ({ root }) => { + let flow = root.get(storageKey) as InternalLiveblocksFlow | undefined; + if (!flow) { + const newFlow = new LiveObject({ + nodes: new LiveMap(), + edges: new LiveMap(), + }) satisfies InternalLiveblocksFlow; + root.set(storageKey, newFlow); + flow = newFlow; + } + + const nodesLiveMap = flow.get("nodes"); + const edgesLiveMap = flow.get("edges"); + + function getNodes(): readonly N[] { + const nodeMap = nodesLiveMap.toJSON() as unknown as Record; + if (!nodeListCache.has(nodeMap)) { + // TODO (LB-3665): To support sub-nodes, this function will need to emit nodes + // in topological order (parents before children), deferring any node with a + // parentId until its parent has been emitted. + nodeListCache.set(nodeMap, Object.values(nodeMap)); + } + return nodeListCache.get(nodeMap)!; + } + + function getEdges(): readonly E[] { + const edgeMap = edgesLiveMap.toJSON() as unknown as Record; + if (!edgeListCache.has(edgeMap)) { + edgeListCache.set(edgeMap, Object.values(edgeMap)); + } + return edgeListCache.get(edgeMap)!; + } + + function getNode(id: string) { + return nodesLiveMap.get(id)?.toJSON() as N | undefined; + } + function getEdge(id: string) { + return edgesLiveMap.get(id)?.toJSON() as E | undefined; + } + + function upsertNode(id: string, newNode: N) { + const existing = nodesLiveMap.get(id); + const syncConfig = getNodeSyncConfig(newNode.type); + if (!existing) { + nodesLiveMap.set(id, toLiveblocksInternalNode(newNode, syncConfig)); + } else { + existing.reconcile(newNode as unknown as JsonObject, syncConfig); + } + } + + function upsertEdge(id: string, newEdge: E) { + const existing = edgesLiveMap.get(id); + const syncConfig = getEdgeSyncConfig(newEdge.type); + if (!existing) { + edgesLiveMap.set(id, toLiveblocksInternalEdge(newEdge, syncConfig)); + } else { + existing.reconcile(newEdge as unknown as JsonObject, syncConfig); + } + } + + const mutableFlow: MutableFlow = { + get nodes() { + return getNodes(); + }, + get edges() { + return getEdges(); + }, + toJSON() { + return { nodes: getNodes(), edges: getEdges() }; + }, + getNode, + getEdge, + + addNode(node: N) { + upsertNode(node.id, node); + }, + addNodes(nodes: N[]) { + for (const node of nodes) { + mutableFlow.addNode(node); + } + }, + updateNode(id: string, partialOrUpdater: Partial | ((node: N) => N)) { + const oldNode = getNode(id); + if (!oldNode) return; + + let newNode: N; + if (typeof partialOrUpdater === "function") { + newNode = partialOrUpdater(oldNode); + } else { + newNode = { ...oldNode, ...partialOrUpdater }; + } + return upsertNode(id, newNode); + }, + updateNodeData( + id: string, + partialOrUpdater: + | Partial + | ((data: D) => D) + ) { + return mutableFlow.updateNode(id, (node) => { + const currData = node.data ?? ({} as N["data"]); + const newData = + typeof partialOrUpdater === "function" + ? partialOrUpdater(currData) + : { ...currData, ...partialOrUpdater }; + return { ...node, data: newData }; + }); + }, + removeNode(id: string) { + nodesLiveMap.delete(id); + }, + removeNodes(ids: string[]) { + for (const id of ids) { + nodesLiveMap.delete(id); + } + }, + + addEdge(edge: E) { + upsertEdge(edge.id, edge); + }, + addEdges(edges: E[]) { + for (const edge of edges) { + mutableFlow.addEdge(edge); + } + }, + updateEdge(id: string, partialOrUpdater: Partial | ((edge: E) => E)) { + const oldEdge = getEdge(id); + if (!oldEdge) return; + + let newEdge: E; + if (typeof partialOrUpdater === "function") { + newEdge = partialOrUpdater(oldEdge); + } else { + newEdge = { ...oldEdge, ...partialOrUpdater }; + } + return upsertEdge(id, newEdge); + }, + updateEdgeData( + id: string, + partialOrUpdater: + | Partial> + | ((data: D) => D) + ) { + return mutableFlow.updateEdge(id, (edge) => { + const currData = edge.data; + const newData = + typeof partialOrUpdater === "function" + ? partialOrUpdater(currData) + : { ...currData, ...partialOrUpdater }; + return { ...edge, data: newData }; + }); + }, + removeEdge(id: string) { + edgesLiveMap.delete(id); + }, + removeEdges(ids: string[]) { + for (const id of ids) { + edgesLiveMap.delete(id); + } + }, + }; + + await callback(mutableFlow); + }); +} diff --git a/packages/liveblocks-react-flow/test-d/mutate-flow.test-d.ts b/packages/liveblocks-react-flow/test-d/mutate-flow.test-d.ts new file mode 100644 index 00000000000..3d35f5baa4d --- /dev/null +++ b/packages/liveblocks-react-flow/test-d/mutate-flow.test-d.ts @@ -0,0 +1,145 @@ +/* eslint-disable */ + +import type { Edge, Node } from "@xyflow/react"; +import { expectError, expectType } from "tsd"; + +import type { MutableFlow } from "../dist/node"; + +// -- Custom types used by the tests below -- + +type CustomNodeData = { label: string; priority: number }; +type CustomNode = Node; + +type CustomEdgeData = { weight: number }; +type CustomEdge = Edge; + +/** + * MutableFlow with custom node/edge types — getters + */ +{ + const flow = {} as MutableFlow; + + expectType(flow.nodes); + expectType(flow.edges); + expectType<{ nodes: readonly CustomNode[]; edges: readonly CustomEdge[] }>( + flow.toJSON() + ); + expectType(flow.getNode("n1")); + expectType(flow.getEdge("e1")); +} + +/** + * MutableFlow — addNode requires correct shape + */ +{ + const flow = {} as MutableFlow; + + // Correct node should be accepted + flow.addNode({ + id: "n1", + type: "task", + position: { x: 0, y: 0 }, + data: { label: "Hello", priority: 1 }, + }); + + // Missing required data field should error + expectError( + flow.addNode({ + id: "n2", + type: "task", + position: { x: 0, y: 0 }, + data: { label: "Hello" }, + }) + ); + + // Wrong node type should error + expectError( + flow.addNode({ + id: "n3", + type: "wrong", + position: { x: 0, y: 0 }, + data: { label: "Hello", priority: 1 }, + }) + ); +} + +/** + * MutableFlow — addEdge requires correct shape + */ +{ + const flow = {} as MutableFlow; + + // Correct edge should be accepted + flow.addEdge({ + id: "e1", + type: "weighted", + source: "n1", + target: "n2", + data: { weight: 5 }, + }); + + // Wrong edge type should error + expectError( + flow.addEdge({ + id: "e2", + type: "wrong", + source: "n1", + target: "n2", + data: { weight: 5 }, + }) + ); +} + +/** + * MutableFlow — updateNode + */ +{ + const flow = {} as MutableFlow; + + // Partial update + flow.updateNode("n1", { position: { x: 10, y: 20 } }); + + // Updater function receives the correct type + flow.updateNode("n1", (node) => { + expectType(node); + return { ...node, position: { x: 0, y: 0 } }; + }); +} + +/** + * MutableFlow — updateNodeData + */ +{ + const flow = {} as MutableFlow; + + // Partial data update with known key + flow.updateNodeData("n1", { priority: 2 }); + + // Unknown data key should error + expectError(flow.updateNodeData("n1", { unknown: true })); + + // Updater function receives the correct data type + flow.updateNodeData("n1", (data) => { + expectType(data); + return { ...data, priority: data.priority + 1 }; + }); +} + +/** + * MutableFlow — updateEdgeData + */ +{ + const flow = {} as MutableFlow; + + // Partial data update with known key + flow.updateEdgeData("e1", { weight: 5 }); + + // Unknown data key should error + expectError(flow.updateEdgeData("e1", { unknown: true })); + + // Updater function receives possibly-undefined data (edge data is optional in React Flow) + flow.updateEdgeData("e1", (data) => { + expectType(data); + return { ...data!, weight: data!.weight + 1 }; + }); +} diff --git a/packages/liveblocks-react-lexical/src/mentions/mention-plugin.tsx b/packages/liveblocks-react-lexical/src/mentions/mention-plugin.tsx index 77f42465128..47b1f671c60 100644 --- a/packages/liveblocks-react-lexical/src/mentions/mention-plugin.tsx +++ b/packages/liveblocks-react-lexical/src/mentions/mention-plugin.tsx @@ -22,11 +22,12 @@ import { useMentionSuggestions, } from "@liveblocks/react/_private"; import { - Avatar, Group, + GroupAvatar, GroupDescription, Portal, User, + UserAvatar, UsersIcon, } from "@liveblocks/react-ui/_private"; import type { EditorState, NodeKey, NodeMutation, TextNode } from "lexical"; @@ -457,7 +458,7 @@ export function MentionPlugin() { > {mention.kind === "user" ? ( <> - @@ -468,7 +469,7 @@ export function MentionPlugin() { ) : mention.kind === "group" ? ( <> - } diff --git a/packages/liveblocks-react-tiptap/src/mentions/MentionsList.tsx b/packages/liveblocks-react-tiptap/src/mentions/MentionsList.tsx index 8d40cdae441..08bfb1b8252 100644 --- a/packages/liveblocks-react-tiptap/src/mentions/MentionsList.tsx +++ b/packages/liveblocks-react-tiptap/src/mentions/MentionsList.tsx @@ -15,10 +15,11 @@ import { useMentionSuggestions, } from "@liveblocks/react/_private"; import { - Avatar, Group, + GroupAvatar, GroupDescription, User, + UserAvatar, UsersIcon, } from "@liveblocks/react-ui/_private"; import type { HTMLAttributes, MouseEvent } from "react"; @@ -192,7 +193,7 @@ export const MentionsList = forwardRef( > {mention.kind === "user" ? ( <> - @@ -203,7 +204,7 @@ export const MentionsList = forwardRef( ) : mention.kind === "group" ? ( <> - } diff --git a/packages/liveblocks-react-ui/src/_private/index.ts b/packages/liveblocks-react-ui/src/_private/index.ts index 7d64a08314b..ff3414b1e62 100644 --- a/packages/liveblocks-react-ui/src/_private/index.ts +++ b/packages/liveblocks-react-ui/src/_private/index.ts @@ -1,6 +1,6 @@ // Private APIs -export { Avatar } from "../components/internal/Avatar"; +export { GroupAvatar, UserAvatar } from "../components/Avatar"; export { Button, SelectButton } from "../components/internal/Button"; export { Group } from "../components/internal/Group"; export { GroupDescription } from "../components/internal/GroupDescription"; diff --git a/packages/liveblocks-react-ui/src/components/Avatar.tsx b/packages/liveblocks-react-ui/src/components/Avatar.tsx new file mode 100644 index 00000000000..6a1dd49cb62 --- /dev/null +++ b/packages/liveblocks-react-ui/src/components/Avatar.tsx @@ -0,0 +1,246 @@ +"use client"; + +import { useGroupInfo, useUser } from "@liveblocks/react"; +import { + type ComponentProps, + type CSSProperties, + type ReactNode, + useMemo, +} from "react"; + +import { + FLOATING_ELEMENT_COLLISION_PADDING, + FLOATING_ELEMENT_SIDE_OFFSET, +} from "../constants"; +import { useOverrides } from "../overrides"; +import { cn } from "../utils/cn"; +import { getInitials } from "../utils/get-initials"; +import { px } from "../utils/px"; +import { Tooltip, TooltipProvider } from "./internal/Tooltip"; + +export interface AvatarProps extends ComponentProps<"div"> { + /** + * The URL of the avatar's image. + */ + src?: string; + + /** + * The name of the avatar. + */ + name?: string; + + /** + * The content to display in the avatar's tooltip. + */ + tooltip?: ReactNode; + + /** + * Whether and how the avatar should have an outline. + */ + outline?: + | string + | boolean + | { color?: string; width?: string | number; gap?: string | number }; + + /** + * Override the avatar's content. + */ + children?: ReactNode; +} + +export interface UserAvatarProps extends ComponentProps<"div"> { + userId?: string; + icon?: ReactNode; + tooltip?: ReactNode; + variant?: "default" | "outline"; +} + +export interface GroupAvatarProps extends ComponentProps<"div"> { + groupId?: string; + icon?: ReactNode; + tooltip?: ReactNode; + variant?: "default" | "outline"; +} + +type MakeRequired = Omit & Required>; + +export function Avatar({ + src, + name, + className, + children, + tooltip, + outline, + style, + ...props +}: AvatarProps) { + const initials = useMemo( + () => (name ? getInitials(name) : undefined), + [name] + ); + const resolvedOutline = + typeof outline === "object" + ? outline + : typeof outline === "string" + ? { color: outline } + : outline === true + ? {} + : undefined; + + const avatar = ( +

+
+ {children ?? + (src ? ( + {name} + ) : initials ? ( + + {initials} + + ) : null)} +
+
+ ); + + return tooltip ? ( + + + {avatar} + + + ) : ( + avatar + ); +} + +function ResolvedUserAvatar({ + userId, + icon, + variant = "default", + tooltip, + ...props +}: MakeRequired) { + const { user, isLoading } = useUser(userId); + + return ( + + {icon && (isLoading || !user?.avatar) ? icon : null} + + ); +} + +function ResolvedGroupAvatar({ + groupId, + icon, + variant = "default", + tooltip, + ...props +}: MakeRequired) { + const { info, isLoading } = useGroupInfo(groupId); + + return ( + + {icon && (isLoading || !info?.avatar) ? icon : null} + + ); +} + +/** + * @private + */ +export function UserAvatar({ + userId, + icon, + variant = "default", + ...props +}: UserAvatarProps) { + const $ = useOverrides(); + + if (!userId) { + return ( + + {icon} + + ); + } + + return ( + + ); +} + +/** + * @private + */ +export function GroupAvatar({ + groupId, + icon, + variant = "default", + ...props +}: GroupAvatarProps) { + if (!groupId) { + return ( + + {icon} + + ); + } + + return ( + + ); +} diff --git a/packages/liveblocks-react-ui/src/components/AvatarStack.tsx b/packages/liveblocks-react-ui/src/components/AvatarStack.tsx index 836e0baeca6..a8c0a20c3a5 100644 --- a/packages/liveblocks-react-ui/src/components/AvatarStack.tsx +++ b/packages/liveblocks-react-ui/src/components/AvatarStack.tsx @@ -12,7 +12,7 @@ import type { GlobalOverrides } from "../overrides"; import { useOverrides } from "../overrides"; import { cn } from "../utils/cn"; import { px } from "../utils/px"; -import { Avatar } from "./internal/Avatar"; +import { UserAvatar } from "./Avatar"; import { Tooltip, TooltipProvider } from "./internal/Tooltip"; import { User } from "./internal/User"; @@ -38,12 +38,22 @@ export interface AvatarStackProps extends ComponentPropsWithoutRef<"div"> { */ gap?: string | number; + /** + * The avatar stack visual variant. + */ + variant?: "default" | "outline"; + /** * Override the component's strings. */ overrides?: Partial; } +type AvatarStackUser = { + key: string; + userId: string | null; +}; + /** * Displays a stack of avatars for the users currently present in the room. */ @@ -54,6 +64,7 @@ export const AvatarStack = forwardRef( max = 3, size, gap, + variant = "default", overrides, className, style, @@ -62,31 +73,64 @@ export const AvatarStack = forwardRef( forwardedRef ) => { const $ = useOverrides(overrides); - const otherIds = useOthers((others) => + const otherUsers = useOthers((others) => [...others] .sort((a, b) => b.connectionId - a.connectionId) - .map((user) => user.id) + .map((user) => ({ + connectionId: user.connectionId, + userId: user.id, + })) ); - const selfId = useSelf((self) => self.id); - const userIds = useMemo(() => { - const uniqueUserIds = new Set( - [selfId, ...otherIds, ...additionalUserIds].filter( - (userId): userId is string => userId !== null && userId !== undefined - ) - ); - - return [...uniqueUserIds]; - }, [selfId, otherIds, additionalUserIds]); + const selfUser = useSelf((self) => ({ + connectionId: self.connectionId, + userId: self.id, + })); + const users = useMemo(() => { + const uniqueUsers = new Map(); + + const addUser = ({ + connectionId, + userId, + }: { + connectionId: number; + userId: string | null | undefined; + }) => { + if (userId !== null && userId !== undefined) { + const key = `user:${userId}`; + uniqueUsers.set(key, { key, userId }); + } else { + const key = `connection:${connectionId}`; + uniqueUsers.set(key, { key, userId: null }); + } + }; + + if (selfUser) { + addUser(selfUser); + } + + for (const otherUser of otherUsers) { + addUser(otherUser); + } + + for (const additionalUserId of additionalUserIds) { + if (additionalUserId !== null && additionalUserId !== undefined) { + const key = `user:${additionalUserId}`; + uniqueUsers.set(key, { key, userId: additionalUserId }); + } + } + + return [...uniqueUsers.values()]; + }, [selfUser, otherUsers, additionalUserIds]); const maxItems = max === null ? Infinity : Math.max(2, Math.floor(max)); - const shouldShowMore = userIds.length > maxItems; + const shouldShowMore = users.length > maxItems; const visibleAvatarsCount = shouldShowMore ? maxItems - 1 : maxItems; - const visibleUserIds = userIds.slice(0, visibleAvatarsCount); - const hiddenUserIds = userIds.slice(visibleUserIds.length); - const remainingUsersCount = hiddenUserIds.length; + const visibleUsers = users.slice(0, visibleAvatarsCount); + const hiddenUsers = users.slice(visibleUsers.length); + const remainingUsersCount = hiddenUsers.length; const visibleItemsCount = - visibleUserIds.length + Number(remainingUsersCount > 0); + visibleUsers.length + Number(remainingUsersCount > 0); - if (userIds.length === 0) { + if (users.length === 0) { return null; } @@ -106,40 +150,28 @@ export const AvatarStack = forwardRef( {...props} ref={forwardedRef} > - {visibleUserIds.map((userId, index) => { - if (!userId) { - return null; - } - + {visibleUsers.map((user, index) => { return ( - } - sideOffset={FLOATING_ELEMENT_SIDE_OFFSET} - collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING} - side="top" - align="center" - > - - + } + /> ); })} {remainingUsersCount > 0 ? ( - {hiddenUserIds.map((userId) => - userId ? ( -
  • - - -
  • - ) : null - )} + {hiddenUsers.map((user) => ( +
  • + + +
  • + ))} } sideOffset={FLOATING_ELEMENT_SIDE_OFFSET} @@ -152,7 +184,7 @@ export const AvatarStack = forwardRef( className="lb-avatar lb-avatar-stack-avatar lb-avatar-stack-more" style={ { - "--lb-avatar-stack-index": visibleUserIds.length, + "--lb-avatar-stack-index": visibleUsers.length, } as CSSProperties } > diff --git a/packages/liveblocks-react-ui/src/components/Comment.tsx b/packages/liveblocks-react-ui/src/components/Comment.tsx index fac1910af75..fd0573f1c7d 100644 --- a/packages/liveblocks-react-ui/src/components/Comment.tsx +++ b/packages/liveblocks-react-ui/src/components/Comment.tsx @@ -80,7 +80,6 @@ import { MediaAttachment, separateMediaAttachments, } from "./internal/Attachment"; -import { Avatar } from "./internal/Avatar"; import { Button, CustomButton } from "./internal/Button"; import { Dropdown, DropdownItem, DropdownTrigger } from "./internal/Dropdown"; import { Emoji } from "./internal/Emoji"; @@ -88,6 +87,7 @@ import { EmojiPicker, EmojiPickerTrigger } from "./internal/EmojiPicker"; import { Group } from "./internal/Group"; import { List } from "./internal/List"; import { ShortcutTooltip, Tooltip, TooltipProvider } from "./internal/Tooltip"; +import { UserAvatar } from "./Avatar"; import { User } from "./internal/User"; const REACTIONS_TRUNCATE = 5; @@ -261,7 +261,7 @@ export interface CommentDateProps } function CommentAvatar(props: CommentAvatarProps) { - return ; + return ; } function CommentAuthor(props: CommentAuthorProps) { @@ -1051,7 +1051,7 @@ export const Comment = Object.assign( {avatar} ) : ( - { /** @@ -72,7 +72,7 @@ export const CommentPin = forwardRef( > {children ?? (userId ? ( - + ) : null)} ); diff --git a/packages/liveblocks-react-ui/src/components/Composer.tsx b/packages/liveblocks-react-ui/src/components/Composer.tsx index d6aacbc785a..534b884a4f4 100644 --- a/packages/liveblocks-react-ui/src/components/Composer.tsx +++ b/packages/liveblocks-react-ui/src/components/Composer.tsx @@ -76,7 +76,7 @@ import { useControllableState } from "../utils/use-controllable-state"; import { useIsGroupMentionMember } from "../utils/use-group-mention"; import { FileAttachment } from "./internal/Attachment"; import { Attribution } from "./internal/Attribution"; -import { Avatar } from "./internal/Avatar"; +import { GroupAvatar, UserAvatar } from "./Avatar"; import { Button } from "./internal/Button"; import type { EmojiPickerProps } from "./internal/EmojiPicker"; import { EmojiPicker, EmojiPickerTrigger } from "./internal/EmojiPicker"; @@ -419,7 +419,7 @@ function ComposerMentionSuggestions({ > {mention.kind === "user" ? ( <> - @@ -430,7 +430,7 @@ function ComposerMentionSuggestions({ ) : mention.kind === "group" ? ( <> - } diff --git a/packages/liveblocks-react-ui/src/components/InboxNotification.tsx b/packages/liveblocks-react-ui/src/components/InboxNotification.tsx index 6a0538a2311..bb45feafbbb 100644 --- a/packages/liveblocks-react-ui/src/components/InboxNotification.tsx +++ b/packages/liveblocks-react-ui/src/components/InboxNotification.tsx @@ -51,7 +51,6 @@ import { Timestamp } from "../primitives/Timestamp"; import { useCurrentUserId } from "../shared"; import type { SlotProp } from "../types"; import { cn } from "../utils/cn"; -import { Avatar } from "./internal/Avatar"; import { Button } from "./internal/Button"; import { CodeBlock } from "./internal/CodeBlock"; import { Dropdown, DropdownItem, DropdownTrigger } from "./internal/Dropdown"; @@ -60,6 +59,7 @@ import { INBOX_NOTIFICATION_THREAD_MAX_COMMENTS, InboxNotificationComment, } from "./internal/InboxNotificationThread"; +import { UserAvatar } from "./Avatar"; import { List } from "./internal/List"; import { Room } from "./internal/Room"; import { Tooltip, TooltipProvider } from "./internal/Tooltip"; @@ -432,7 +432,7 @@ function InboxNotificationAvatar({ ...props }: InboxNotificationAvatarProps) { return ( - diff --git a/packages/liveblocks-react-ui/src/components/internal/Avatar.tsx b/packages/liveblocks-react-ui/src/components/internal/Avatar.tsx deleted file mode 100644 index de0f0a72cdc..00000000000 --- a/packages/liveblocks-react-ui/src/components/internal/Avatar.tsx +++ /dev/null @@ -1,94 +0,0 @@ -"use client"; - -import type { Relax } from "@liveblocks/core"; -import type { ComponentProps, ReactNode } from "react"; -import { useMemo } from "react"; - -import { cn } from "../../utils/cn"; -import { getInitials } from "../../utils/get-initials"; -import { useUserOrGroupInfo } from "../../utils/use-user-or-group-info"; - -interface AvatarLayoutProps extends ComponentProps<"div"> { - src?: string; - name?: string; - fallback?: string; - isLoading: boolean; -} - -export type AvatarProps = ComponentProps<"div"> & { - icon?: ReactNode; -} & Relax< - | { - /** - * The user ID to display the avatar for. - */ - userId: string; - } - | { - /** - * The group ID to display the avatar for. - */ - groupId: string; - } - >; - -function AvatarLayout({ - src, - name, - fallback, - isLoading, - className, - ...props -}: AvatarLayoutProps) { - const nameInitials = useMemo( - () => (name ? getInitials(name) : undefined), - [name] - ); - const fallbackInitials = useMemo( - () => (!isLoading && fallback && !name ? getInitials(fallback) : undefined), - [isLoading, fallback, name] - ); - - return ( -
    - {src ? ( - {name} - ) : nameInitials ? ( - - {nameInitials} - - ) : fallbackInitials ? ( - - {fallbackInitials} - - ) : null} -
    - ); -} - -export function Avatar({ userId, groupId, icon, ...props }: AvatarProps) { - const { info, isLoading } = useUserOrGroupInfo( - userId ? "user" : "group", - userId ?? groupId - ); - - return icon && (isLoading || !info?.avatar) ? ( -
    {icon}
    - ) : ( - - ); -} diff --git a/packages/liveblocks-react-ui/src/components/internal/User.tsx b/packages/liveblocks-react-ui/src/components/internal/User.tsx index 75a1243daa3..0c039feb38f 100644 --- a/packages/liveblocks-react-ui/src/components/internal/User.tsx +++ b/packages/liveblocks-react-ui/src/components/internal/User.tsx @@ -12,7 +12,7 @@ export interface UserProps extends ComponentProps<"span"> { /** * The user ID to display the user name for. */ - userId: string; + userId?: string; /** * Whether to replace the user name with "you" ($.USER_SELF) for the current user. @@ -20,13 +20,35 @@ export interface UserProps extends ComponentProps<"span"> { replaceSelf?: boolean; } -export function User({ - userId, - replaceSelf, +interface UserLayoutProps extends ComponentProps<"span"> { + isLoading: boolean; + name: string; +} + +function UserLayout({ + isLoading, + name, className, children, ...props -}: UserProps) { +}: UserLayoutProps) { + return ( + + {isLoading ? null : name} + {children} + + ); +} + +function ResolvedUser({ + userId, + replaceSelf, + ...props +}: UserProps & { userId: string }) { const currentId = useCurrentUserId(); const { user, isLoading } = useUser(userId); const $ = useOverrides(); @@ -37,13 +59,16 @@ export function User({ }, [replaceSelf, currentId, userId, $.USER_SELF, $.USER_UNKNOWN, user?.name]); return ( - - {isLoading ? null : resolvedUserName} - {children} - + ); } + +export function User({ userId, ...props }: UserProps) { + const $ = useOverrides(); + + if (!userId) { + return ; + } + + return ; +} diff --git a/packages/liveblocks-react-ui/src/index.ts b/packages/liveblocks-react-ui/src/index.ts index 6a767c2433b..e59a95b27a6 100644 --- a/packages/liveblocks-react-ui/src/index.ts +++ b/packages/liveblocks-react-ui/src/index.ts @@ -13,6 +13,8 @@ export type { export { AiChat } from "./components/AiChat"; export type { AiToolIconProps, AiToolProps } from "./components/AiTool"; export { AiTool } from "./components/AiTool"; +export type { AvatarProps } from "./components/Avatar"; +export { Avatar } from "./components/Avatar"; export type { AvatarStackProps } from "./components/AvatarStack"; export { AvatarStack } from "./components/AvatarStack"; export type { diff --git a/packages/liveblocks-react-ui/src/styles/index.css b/packages/liveblocks-react-ui/src/styles/index.css index 9facde62867..fd6e2d5b37f 100644 --- a/packages/liveblocks-react-ui/src/styles/index.css +++ b/packages/liveblocks-react-ui/src/styles/index.css @@ -1042,6 +1042,27 @@ background: var(--lb-foreground); opacity: $lb-loading-opacity; } + + &:where([data-variant="outline"]) { + --lb-avatar-outline-gap: 2px; + --lb-avatar-outline-width: 2px; + + padding: var(--lb-avatar-outline-gap); + border: var(--lb-avatar-outline-width) solid + var(--lb-avatar-outline-color, var(--lb-accent)); + background-clip: content-box; + } +} + +.lb-avatar-content { + position: relative; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + inline-size: 100%; + block-size: 100%; + border-radius: inherit; } .lb-avatar-image { diff --git a/packages/liveblocks-react-ui/src/utils/use-user-or-group-info.ts b/packages/liveblocks-react-ui/src/utils/use-user-or-group-info.ts deleted file mode 100644 index 794470d12ef..00000000000 --- a/packages/liveblocks-react-ui/src/utils/use-user-or-group-info.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { - assertNever, - type AsyncResult, - type AsyncSuccess, - type BaseGroupInfo, - type BaseUserMeta, -} from "@liveblocks/core"; -import { useGroupInfo, useUser } from "@liveblocks/react"; -import { - useGroupInfo as useGroupInfoSuspense, - useUser as useUserSuspense, -} from "@liveblocks/react/suspense"; - -import { useInitial } from "./use-initial"; - -type UserOrGroupInfoResult = AsyncResult< - BaseUserMeta["info"] | BaseGroupInfo, - "info" ->; - -type UserOrGroupInfoSuccess = AsyncSuccess< - BaseUserMeta["info"] | BaseGroupInfo, - "info" ->; - -export function useUserOrGroupInfo( - kind: "user" | "group", - id: string -): UserOrGroupInfoResult { - // Switching between user IDs and group IDs is not supported - // to support the Rules of Hooks. - const frozenKind = useInitial(kind); - - if (frozenKind === "user") { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { user, isLoading, error } = useUser(id); - - return { - info: user, - isLoading, - error, - } as UserOrGroupInfoResult; - } else if (frozenKind === "group") { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { info, isLoading, error } = useGroupInfo(id); - - return { - info, - isLoading, - error, - } as UserOrGroupInfoResult; - } - - return assertNever(frozenKind, "Invalid kind"); -} - -export function useUserOrGroupInfoSuspense( - kind: "user" | "group", - id: string -): UserOrGroupInfoSuccess { - // Switching between user IDs and group IDs is not supported - // to support the Rules of Hooks. - const frozenKind = useInitial(kind); - - if (frozenKind === "user") { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { user, isLoading, error } = useUserSuspense(id); - - return { - info: user, - isLoading, - error, - }; - } else if (frozenKind === "group") { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { info, isLoading, error } = useGroupInfoSuspense(id); - - return { - info, - isLoading, - error, - }; - } - - return assertNever(frozenKind, "Invalid kind"); -} diff --git a/packages/liveblocks-react/src/room.tsx b/packages/liveblocks-react/src/room.tsx index 3f3aab9ffe3..fa38054c009 100644 --- a/packages/liveblocks-react/src/room.tsx +++ b/packages/liveblocks-react/src/room.tsx @@ -41,7 +41,7 @@ import type { RoomSubscriptionSettings, SignalType, TextEditorType, - ToImmutable, + ToJson, UnsubscribeCallback, } from "@liveblocks/core"; import { @@ -127,7 +127,7 @@ import { useScrollToCommentOnLoadEffect } from "./use-scroll-to-comment-on-load- import { useSignal } from "./use-signal"; import { useSyncExternalStoreWithSelector } from "./use-sync-external-store-with-selector"; -const noop = () => { }; +const noop = () => {}; const identity: (x: T) => T = (x) => x; const STABLE_EMPTY_LIST = Object.freeze([]); @@ -363,28 +363,29 @@ function RoomProvider< // Produce a version of client.enterRoom() that when called for the same // room ID multiple times, will not keep producing multiple leave // functions, but instead return the cached one. - const stableEnterRoom: typeof client.enterRoom = useCallback( - ( - roomId: string, - options: EnterOptions - ): RoomLeavePair => { - const cached = cache.get(roomId); - if (cached) return cached; - - const rv = client.enterRoom(roomId, options); - - // Wrap the leave function to also delete the cached value - const origLeave = rv.leave; - rv.leave = () => { - origLeave(); - cache.delete(roomId); - }; - - cache.set(roomId, rv); - return rv; - }, - [client, cache] - ); + const stableEnterRoom: typeof client.enterRoom = + useCallback( + ( + roomId: string, + options: EnterOptions + ): RoomLeavePair => { + const cached = cache.get(roomId); + if (cached) return cached; + + const rv = client.enterRoom(roomId, options); + + // Wrap the leave function to also delete the cached value + const origLeave = rv.leave; + rv.leave = () => { + origLeave(); + cache.delete(roomId); + }; + + cache.set(roomId, rv); + return rv; + }, + [client, cache] + ); // // RATIONALE: @@ -682,7 +683,9 @@ function useRoom< CM extends BaseMetadata = DCM, FM extends Json = Json, FMD extends Json = Json, ->(options: { allowOutsideRoom: boolean }): Room | null; +>(options: { + allowOutsideRoom: boolean; +}): Room | null; function useRoom< P extends JsonObject = DP, S extends LsonObject = DS, @@ -692,7 +695,9 @@ function useRoom< CM extends BaseMetadata = DCM, FM extends Json = Json, FMD extends Json = Json, ->(options?: { allowOutsideRoom: boolean }): Room | null { +>(options?: { + allowOutsideRoom: boolean; +}): Room | null { return useRoom_withRoomContext( GlobalRoomContext, options @@ -1379,10 +1384,10 @@ function useStorageRoot(): [root: LiveObject | null] { */ function useStorage_withRoomContext( RoomContext: Context, - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T | null, curr: T | null) => boolean ): T | null { - type Snapshot = ToImmutable | null; + type Snapshot = ToJson | null; type Selection = T | null; const room = useRoom_withRoomContext( @@ -1409,8 +1414,7 @@ function useStorage_withRoomContext( return null; } else { const root = rootOrNull; - const imm = root.toImmutable(); - return imm; + return root.toJSON(); } }, [rootOrNull]); @@ -1426,7 +1430,7 @@ function useStorage_withRoomContext( } function useStorage( - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T | null, curr: T | null) => boolean ): T | null { return useStorage_withRoomContext(GlobalRoomContext, selector, isEqual); @@ -1621,7 +1625,9 @@ function useFeedMessagesSuspense_withRoomContext( const { store } = getRoomExtrasForClient(client); const queryKey = makeFeedMessagesQueryKey(room.id, feedId, options); - use(store.outputs.loadingFeedMessages.getOrCreate(queryKey).waitUntilLoaded()); + use( + store.outputs.loadingFeedMessages.getOrCreate(queryKey).waitUntilLoaded() + ); const result = useFeedMessages_withRoomContext(RoomContext, feedId, options); assert(!result.error, "Did not expect error"); @@ -2329,9 +2335,9 @@ function useEditRoomComment( const updatedMetadata = metadata !== undefined ? { - ...comment.metadata, - ...metadata, - } + ...comment.metadata, + ...metadata, + } : comment.metadata; const optimisticId = store.optimisticUpdates.add({ @@ -2972,9 +2978,9 @@ function useRoomThreadSubscription( function useRoomSubscriptionSettings_withRoomContext( RoomContext: Context ): [ - RoomSubscriptionSettingsAsyncResult, - (settings: Partial) => void, - ] { + RoomSubscriptionSettingsAsyncResult, + (settings: Partial) => void, +] { const updateRoomSubscriptionSettings = useUpdateRoomSubscriptionSettings_withRoomContext(RoomContext); const client = useClient(); @@ -3037,9 +3043,9 @@ function useRoomSubscriptionSettings(): [ function useRoomSubscriptionSettingsSuspense_withRoomContext( RoomContext: Context ): [ - RoomSubscriptionSettingsAsyncSuccess, - (settings: Partial) => void, - ] { + RoomSubscriptionSettingsAsyncSuccess, + (settings: Partial) => void, +] { // Throw error if we're calling this hook server side ensureNotServerSide(); @@ -3109,8 +3115,8 @@ function useHistoryVersionData_withRoomContext( error instanceof Error ? error : new Error( - "An unknown error occurred while loading this version" - ), + "An unknown error occurred while loading this version" + ), }); } }; @@ -3517,7 +3523,7 @@ export function useSuspendUntilStorageReady(): void { */ function useStorageSuspense_withRoomContext( RoomContext: Context, - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T, curr: T) => boolean ): T { useSuspendUntilStorageReady_withRoomContext(RoomContext); @@ -3529,7 +3535,7 @@ function useStorageSuspense_withRoomContext( } function useStorageSuspense( - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T, curr: T) => boolean ): T { return useStorageSuspense_withRoomContext( @@ -4017,9 +4023,7 @@ export function createRoomContext< return useUpdateRoomSubscriptionSettings_withRoomContext(BoundRoomContext); } - function useFeeds_withBoundRoomContext( - ...args: Parameters - ) { + function useFeeds_withBoundRoomContext(...args: Parameters) { return useFeeds_withRoomContext(BoundRoomContext, ...args); } @@ -4382,7 +4386,7 @@ const _useAddReaction: TypedBundle["useAddReaction"] = useAddReaction; * that gets passed into your callback will be a "mutation context". * * If you want get access to the immutable root somewhere in your mutation, - * you can use `storage.ToImmutable()`. + * you can use `storage.toJSON()`. * * @example * const fillLayers = useMutation( @@ -4579,8 +4583,7 @@ const _useFeedMessages: TypedBundle["useFeedMessages"] = useFeedMessages; * @example * const { feeds } = useFeeds(); */ -const _useFeedsSuspense: TypedBundle["suspense"]["useFeeds"] = - useFeedsSuspense; +const _useFeedsSuspense: TypedBundle["suspense"]["useFeeds"] = useFeedsSuspense; /** * Returns messages for a specific feed in the current room. diff --git a/packages/liveblocks-react/src/types/index.ts b/packages/liveblocks-react/src/types/index.ts index f8229a53fd0..48c3feca217 100644 --- a/packages/liveblocks-react/src/types/index.ts +++ b/packages/liveblocks-react/src/types/index.ts @@ -50,7 +50,7 @@ import type { SearchCommentsResult, SyncStatus, ThreadData, - ToImmutable, + ToJson, UrlMetadata, WithNavigation, WithRequired, @@ -417,7 +417,10 @@ export type RoomProviderProps

    = /** * The initial Storage to use when entering a new Room. */ - initialStorage: S | ((roomId: string) => S); + initialStorage: + | S + | LiveObject + | ((roomId: string) => S | LiveObject); } > >; @@ -839,7 +842,7 @@ type RoomContextBundleCommon< * that gets passed into your callback will be a "mutation context". * * If you want get access to the immutable root somewhere in your mutation, - * you can use `storage.ToImmutable()`. + * you can use `storage.toJSON()`. * * @example * const fillLayers = useMutation( @@ -1160,7 +1163,7 @@ export type RoomContextBundle< * those cases, you'll probably want to use a `shallow` comparison check. */ useStorage( - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T | null, curr: T | null) => boolean ): T | null; @@ -1371,7 +1374,7 @@ export type RoomContextBundle< * those cases, you'll probably want to use a `shallow` comparison check. */ useStorage( - selector: (root: ToImmutable) => T, + selector: (root: ToJson) => T, isEqual?: (prev: T, curr: T) => boolean ): T; diff --git a/packages/liveblocks-react/test-d/factories.test-d.tsx b/packages/liveblocks-react/test-d/factories.test-d.tsx index 59010608ac9..3c4af02ed68 100644 --- a/packages/liveblocks-react/test-d/factories.test-d.tsx +++ b/packages/liveblocks-react/test-d/factories.test-d.tsx @@ -286,7 +286,9 @@ expectType

    (ctx.suspense.useMyPresence()[0]); // The storage hooks expectType(ctx.useStorage((x) => x.animals)); -expectType | null>(ctx.useStorage((x) => x.scores)); +expectType<{ readonly [key: string]: number } | null>( + ctx.useStorage((x) => x.scores) +); expectType<{ readonly name: string; readonly age: number } | null>( ctx.useStorage((x) => x.person) ); @@ -295,7 +297,7 @@ expectType<[root: LiveObject | null]>(ctx.useStorageRoot()); // The storage hooks (suspense versions) expectType(ctx.suspense.useStorage((x) => x.animals)); -expectType>( +expectType<{ readonly [key: string]: number }>( ctx.suspense.useStorage((x) => x.scores) ); expectType<{ readonly name: string; readonly age: number }>( diff --git a/packages/liveblocks-redux/src/__tests__/index.test.ts b/packages/liveblocks-redux/src/__tests__/index.test.ts index aaa3827d1ed..0d22c68e980 100644 --- a/packages/liveblocks-redux/src/__tests__/index.test.ts +++ b/packages/liveblocks-redux/src/__tests__/index.test.ts @@ -676,6 +676,23 @@ describe("middleware", () => { }); describe("history", () => { + test("initial storage seeding should not be undoable", async () => { + // Create an empty room — Redux will seed defaults + const roomId = await initRoom(); + + const { client, store } = createBasicStore(); + await enterAndConnect(store, roomId); + await waitFor( + () => store.getState().liveblocks.isStorageLoading === false + ); + + // Defaults were seeded + expect(store.getState().value).toBe(0); + + // But undo stack should be empty + expect(client.getRoom(roomId)!.history.canUndo()).toBe(false); + }); + test("undo / redo", async () => { const roomId = await initRoom({ liveblocksType: "LiveObject", diff --git a/packages/liveblocks-redux/src/index.ts b/packages/liveblocks-redux/src/index.ts index d8f8473c05b..20dc1169b89 100644 --- a/packages/liveblocks-redux/src/index.ts +++ b/packages/liveblocks-redux/src/index.ts @@ -1,5 +1,6 @@ import type { BaseUserMeta, + Json, JsonObject, LiveObject, LsonObject, @@ -8,12 +9,7 @@ import type { User, } from "@liveblocks/client"; import type { EnterOptions, OpaqueClient, OpaqueRoom } from "@liveblocks/core"; -import { - detectDupes, - legacy_patchImmutableObject, - legacy_patchLiveObjectKey, - lsonToJson, -} from "@liveblocks/core"; +import { detectDupes, kInternal } from "@liveblocks/core"; import type { StoreEnhancer } from "redux"; import { @@ -65,6 +61,15 @@ export type WithLiveblocks< U extends BaseUserMeta, > = TState & { readonly liveblocks: LiveblocksContext }; +/** Ensures values of the provided object are not functions */ +function ensureNoFunctions(state: Record): void { + for (const key in state) { + if (typeof state[key] === "function") { + throw mappingToFunctionIsNotAllowed(key); + } + } +} + const internalEnhancer = (options: { client: OpaqueClient; storageMapping?: Mapping; @@ -86,6 +91,7 @@ const internalEnhancer = (options: { validateNoDuplicateKeys(storageMapping, presenceMapping); } const presenceKeys = Object.keys(presenceMapping); + const storageKeys = Object.keys(storageMapping); return (createStore: any) => { return (reducer: any, initialState: any, enhancer: any) => { @@ -145,21 +151,23 @@ const internalEnhancer = (options: { if (maybeRoom) { isPatching = true; try { - updatePresence( - maybeRoom, - state, - newState, - presenceMapping as any - ); - maybeRoom.batch(() => { + updatePresence( + maybeRoom!, + state, + newState, + presenceMapping as any + ); + if (storageRoot) { - patchLiveblocksStorage( - storageRoot, - state, + const partialState = pick( newState, - storageMapping as any - ); + storageKeys + ) as JsonObject; + if (process.env.NODE_ENV !== "production") { + ensureNoFunctions(partialState); + } + storageRoot.reconcilePartially(partialState); } }); } finally { @@ -241,41 +249,35 @@ const internalEnhancer = (options: { }); void room.getStorage().then(({ root }) => { - const updates: any = {}; - - maybeRoom!.batch(() => { - for (const key in storageMapping) { - const liveblocksStatePart = root.get(key); - if (liveblocksStatePart == null) { - updates[key] = store.getState()[key]; - legacy_patchLiveObjectKey( - root, - key, - undefined, - store.getState()[key] - ); - } else { - updates[key] = lsonToJson(liveblocksStatePart); - } + // Seed any missing storage keys from the current Redux state. + // Only writes keys that don't exist yet in storage — existing + // storage values are left untouched and will be read back below. + const reduxState = store.getState(); + const missing: JsonObject = {}; + for (const key of storageKeys) { + if (root.get(key) == null) { + missing[key] = reduxState[key] as Json; } + } + + room.history[kInternal].withoutHistory(() => { + maybeRoom!.batch(() => { + root.reconcilePartially(missing); + }); }); store.dispatch({ type: ACTION_TYPES.INIT_STORAGE, - state: updates, + state: pick(root.toJSON(), storageKeys), }); storageRoot = root; unsubscribeCallbacks.push( - maybeRoom!.events.storageBatch.subscribe((updates) => { + maybeRoom!.events.storageBatch.subscribe(() => { if (!isPatching) { store.dispatch({ type: ACTION_TYPES.PATCH_REDUX_STATE, - state: patchState( - store.getState(), - updates, - storageMapping as any - ), + state: pick(root.toJSON(), storageKeys), }); } }) @@ -367,28 +369,6 @@ export const liveblocksEnhancer = internalEnhancer as (options: { presenceMapping?: Mapping; }) => StoreEnhancer; -function patchLiveblocksStorage( - root: LiveObject, - oldState: TState, - newState: TState, - mapping: Mapping -) { - for (const key in mapping) { - if ( - process.env.NODE_ENV !== "production" && - typeof newState[key] === "function" - ) { - throw mappingToFunctionIsNotAllowed("value"); - } - - if (oldState[key] !== newState[key]) { - const oldVal = oldState[key]; - const newVal = newState[key]; - legacy_patchLiveObjectKey(root, key, oldVal as any, newVal); - } - } -} - function updatePresence

    ( room: Room, oldState: P, @@ -432,28 +412,6 @@ function pick( return result; } -function patchState( - state: TState, - updates: any[], // StorageUpdate - mapping: Mapping -) { - const partialState: Partial = {}; - - for (const key in mapping) { - partialState[key] = state[key]; - } - - const patched = legacy_patchImmutableObject(partialState, updates); - - const result: Partial = {}; - - for (const key in mapping) { - result[key] = patched[key]; - } - - return result; -} - /** * Remove false keys from mapping and generate to a new object to avoid potential mutation from outside the middleware */ diff --git a/packages/liveblocks-zustand/src/__tests__/index.test.ts b/packages/liveblocks-zustand/src/__tests__/index.test.ts index 138d9fc539a..a34f0c54cff 100644 --- a/packages/liveblocks-zustand/src/__tests__/index.test.ts +++ b/packages/liveblocks-zustand/src/__tests__/index.test.ts @@ -658,6 +658,23 @@ describe("middleware", () => { }); describe("history", () => { + test("initial storage seeding should not be undoable", async () => { + // Create an empty room — Zustand will seed defaults + const roomId = await initRoom(); + + const store = createBasicStore(); + await enterAndConnect(store, roomId); + await waitFor( + () => store.getState().liveblocks.isStorageLoading === false + ); + + // Defaults were seeded + expect(store.getState().value).toBe(0); + + // But undo stack should be empty + expect(store.getState().liveblocks.room!.history.canUndo()).toBe(false); + }); + test("undo / redo", async () => { const roomId = await initRoom({ liveblocksType: "LiveObject", @@ -682,7 +699,7 @@ describe("middleware", () => { expect(store.getState().value).toBe(2); }); - test("updating presence should not reset redo stack", async () => { + test("updating presence should not reset redo stack #1", async () => { const roomId = await initRoom({ liveblocksType: "LiveObject", data: { value: 1 }, @@ -707,7 +724,7 @@ describe("middleware", () => { expect(store.getState().value).toBe(2); }); - test("updating presence should not reset redo stack", async () => { + test("updating presence should not reset redo stack #2", async () => { const roomId = await initRoom({ liveblocksType: "LiveObject", data: { value: 1 }, diff --git a/packages/liveblocks-zustand/src/index.ts b/packages/liveblocks-zustand/src/index.ts index 407278cb74d..a2a9941ae3f 100644 --- a/packages/liveblocks-zustand/src/index.ts +++ b/packages/liveblocks-zustand/src/index.ts @@ -19,15 +19,8 @@ import type { EnterOptions, OpaqueClient, OpaqueRoom, - StorageUpdate, -} from "@liveblocks/core"; -import { - detectDupes, - errorIf, - legacy_patchImmutableObject, - legacy_patchLiveObjectKey, - lsonToJson, } from "@liveblocks/core"; +import { detectDupes, errorIf, kInternal } from "@liveblocks/core"; import type { StateCreator, StoreMutatorIdentifier } from "zustand"; import { PKG_FORMAT, PKG_NAME, PKG_VERSION } from "./version"; @@ -147,6 +140,15 @@ type ExtractPresence = type ExtractStorage = TRoom extends Room ? S : never; +/** Ensures values of the provided object are not functions */ +function ensureNoFunctions(state: Record): void { + for (const key in state) { + if (typeof state[key] === "function") { + throw mappingToFunctionIsNotAllowed(key); + } + } +} + const middlewareImpl: InnerLiveblocksMiddleware = (config, options) => { type TState = ReturnType; type TLiveblocksContext = TState["liveblocks"]; @@ -156,6 +158,7 @@ const middlewareImpl: InnerLiveblocksMiddleware = (config, options) => { const { client, presenceMapping, storageMapping } = validateOptions(options); const presenceKeys = Object.keys(presenceMapping); + const storageKeys = Object.keys(storageMapping); return (set, get, api) => { let maybeRoom: TRoom | null = null; let isPatching = false; @@ -211,34 +214,30 @@ const middlewareImpl: InnerLiveblocksMiddleware = (config, options) => { ); void room.getStorage().then(({ root }) => { - const updates = {} as Partial; - - room.batch(() => { - for (const key in storageMapping) { - const liveblocksStatePart = root.get(key); - if (liveblocksStatePart === undefined) { - updates[key] = get()[key]; - legacy_patchLiveObjectKey( - root, - key, - undefined, - get()[key] as Json | undefined - ); - } else { - updates[key] = lsonToJson( - liveblocksStatePart - ) as unknown as TState[Extract]; - } + // Seed any missing storage keys from the current Zustand state. + // Only writes keys that don't exist yet in storage — existing + // storage values are left untouched and will be read back below. + const state = get() as Record; + const missing: JsonObject = {}; + for (const key of storageKeys) { + if (root.get(key) === undefined) { + missing[key] = state[key] as Json; } + } + + room.history[kInternal].withoutHistory(() => { + room.batch(() => { + root.reconcilePartially(missing); + }); }); - set(updates); + set(pick(root.toJSON(), storageKeys) as Partial); storageRoot = root as LiveObject; unsubscribeCallbacks.push( - room.events.storageBatch.subscribe((updates) => { + room.events.storageBatch.subscribe(() => { if (!isPatching) { - set(patchState(get(), updates, storageMapping)); + set(pick(root.toJSON(), storageKeys) as Partial); } }) ); @@ -287,21 +286,20 @@ const middlewareImpl: InnerLiveblocksMiddleware = (config, options) => { const room = maybeRoom; isPatching = true; try { - updatePresence( - room, - oldState as JsonObject, - newState as JsonObject, - presenceMapping - ); - room.batch(() => { + updatePresence( + room, + oldState as JsonObject, + newState as JsonObject, + presenceMapping + ); + if (storageRoot) { - patchLiveblocksStorage( - storageRoot, - oldState, - newState, - storageMapping - ); + const partialState = pick(newState, storageKeys) as JsonObject; + if (process.env.NODE_ENV !== "production") { + ensureNoFunctions(partialState); + } + storageRoot.reconcilePartially(partialState); } }); } finally { @@ -330,32 +328,6 @@ const middlewareImpl: InnerLiveblocksMiddleware = (config, options) => { export const liveblocks = middlewareImpl as unknown as OuterLiveblocksMiddleware; -function patchState( - state: T, - updates: StorageUpdate[], - mapping: Mapping -) { - const partialState: Partial = {}; - - for (const key in mapping) { - partialState[key] = state[key]; - } - - const patched = legacy_patchImmutableObject( - partialState as JsonObject, - updates - ); - - const result: Partial = {}; - - for (const key in mapping) { - // @ts-expect-error key is a key of T - result[key] = patched[key]; - } - - return result; -} - function pick( source: Record, keys: Iterable @@ -413,28 +385,6 @@ function updatePresence< } } -function patchLiveblocksStorage( - root: LiveObject, - oldState: TState, - newState: TState, - mapping: Mapping -) { - for (const key in mapping) { - if ( - process.env.NODE_ENV !== "production" && - typeof newState[key] === "function" - ) { - throw mappingToFunctionIsNotAllowed(key); - } - - if (oldState[key] !== newState[key]) { - const oldVal = oldState[key] as Json | undefined; - const newVal = newState[key] as Json | undefined; - legacy_patchLiveObjectKey(root, key, oldVal, newVal); - } - } -} - function isObject(value: unknown): value is object { return Object.prototype.toString.call(value) === "[object Object]"; } From 1cddc8329fe628c82cd1af04e38dc1bd3223e9b9 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 8 Apr 2026 09:38:23 +0000 Subject: [PATCH 2/6] Bump to 3.18.0 --- package-lock.json | 114 +++++++++--------- .../liveblocks-chat-sdk-adapter/package.json | 6 +- packages/liveblocks-client/package.json | 4 +- packages/liveblocks-core/package.json | 2 +- packages/liveblocks-emails/package.json | 6 +- packages/liveblocks-node-lexical/package.json | 6 +- .../liveblocks-node-prosemirror/package.json | 6 +- packages/liveblocks-node/package.json | 4 +- .../liveblocks-react-blocknote/package.json | 14 +-- packages/liveblocks-react-flow/package.json | 14 ++- .../liveblocks-react-lexical/package.json | 12 +- packages/liveblocks-react-tiptap/package.json | 12 +- packages/liveblocks-react-ui/package.json | 8 +- packages/liveblocks-react/package.json | 6 +- packages/liveblocks-redux/package.json | 6 +- packages/liveblocks-yjs/package.json | 6 +- packages/liveblocks-zustand/package.json | 6 +- 17 files changed, 117 insertions(+), 115 deletions(-) diff --git a/package-lock.json b/package-lock.json index c08c0563bcb..a1b1f362f0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37537,11 +37537,11 @@ }, "packages/liveblocks-chat-sdk-adapter": { "name": "@liveblocks/chat-sdk-adapter", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37554,10 +37554,10 @@ }, "packages/liveblocks-client": { "name": "@liveblocks/client", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37566,7 +37566,7 @@ }, "packages/liveblocks-core": { "name": "@liveblocks/core", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37584,11 +37584,11 @@ }, "packages/liveblocks-emails": { "name": "@liveblocks/emails", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37607,10 +37607,10 @@ }, "packages/liveblocks-node": { "name": "@liveblocks/node", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" @@ -37625,11 +37625,11 @@ }, "packages/liveblocks-node-lexical": { "name": "@liveblocks/node-lexical", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.18" }, "devDependencies": { @@ -37646,11 +37646,11 @@ }, "packages/liveblocks-node-prosemirror": { "name": "@liveblocks/node-prosemirror", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.20" }, "devDependencies": { @@ -37670,11 +37670,11 @@ }, "packages/liveblocks-react": { "name": "@liveblocks/react", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37704,15 +37704,15 @@ }, "packages/liveblocks-react-blocknote": { "name": "@liveblocks/react-blocknote", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-tiptap": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-tiptap": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "vitest-tsconfig-paths": "^3.4.1" }, @@ -37749,13 +37749,13 @@ }, "packages/liveblocks-react-flow": { "name": "@liveblocks/react-flow", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -37819,15 +37819,15 @@ }, "packages/liveblocks-react-lexical": { "name": "@liveblocks/react-lexical", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, @@ -39461,15 +39461,15 @@ }, "packages/liveblocks-react-tiptap": { "name": "@liveblocks/react-tiptap", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -41117,13 +41117,13 @@ }, "packages/liveblocks-react-ui": { "name": "@liveblocks/react-ui", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -41497,11 +41497,11 @@ }, "packages/liveblocks-redux": { "name": "@liveblocks/redux", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", @@ -41657,11 +41657,11 @@ }, "packages/liveblocks-yjs": { "name": "@liveblocks/yjs", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" @@ -41726,11 +41726,11 @@ }, "packages/liveblocks-zustand": { "name": "@liveblocks/zustand", - "version": "3.17.0", + "version": "3.18.0", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", diff --git a/packages/liveblocks-chat-sdk-adapter/package.json b/packages/liveblocks-chat-sdk-adapter/package.json index e849cfd1904..935496d0d0a 100644 --- a/packages/liveblocks-chat-sdk-adapter/package.json +++ b/packages/liveblocks-chat-sdk-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/chat-sdk-adapter", - "version": "3.17.0", + "version": "3.18.0", "description": "Liveblocks adapter for the Chat SDK.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -35,8 +35,8 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "chat": ">=4.20.0" diff --git a/packages/liveblocks-client/package.json b/packages/liveblocks-client/package.json index 634b58851f2..2a833fd55aa 100644 --- a/packages/liveblocks-client/package.json +++ b/packages/liveblocks-client/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/client", - "version": "3.17.0", + "version": "3.18.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.", @@ -36,7 +36,7 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" }, "devDependencies": { "@liveblocks/eslint-config": "*", diff --git a/packages/liveblocks-core/package.json b/packages/liveblocks-core/package.json index 830698b1662..21d9b0c3720 100644 --- a/packages/liveblocks-core/package.json +++ b/packages/liveblocks-core/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/core", - "version": "3.17.0", + "version": "3.18.0", "description": "Private internals for Liveblocks. DO NOT import directly from this package!", "type": "module", "main": "./dist/index.cjs", diff --git a/packages/liveblocks-emails/package.json b/packages/liveblocks-emails/package.json index 11dd1287c79..eae5d7c3163 100644 --- a/packages/liveblocks-emails/package.json +++ b/packages/liveblocks-emails/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/emails", - "version": "3.17.0", + "version": "3.18.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.", @@ -37,8 +37,8 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" diff --git a/packages/liveblocks-node-lexical/package.json b/packages/liveblocks-node-lexical/package.json index c2b187f6bd6..a18cf1b8667 100644 --- a/packages/liveblocks-node-lexical/package.json +++ b/packages/liveblocks-node-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/node-lexical", - "version": "3.17.0", + "version": "3.18.0", "description": "A server-side utility that lets you modify lexical documents hosted in Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -36,8 +36,8 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.18" }, "peerDependencies": { diff --git a/packages/liveblocks-node-prosemirror/package.json b/packages/liveblocks-node-prosemirror/package.json index 284d4e2951e..50bc795af4e 100644 --- a/packages/liveblocks-node-prosemirror/package.json +++ b/packages/liveblocks-node-prosemirror/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/node-prosemirror", - "version": "3.17.0", + "version": "3.18.0", "description": "A server-side utility that lets you modify prosemirror and tiptap documents hosted in Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -36,8 +36,8 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.20" }, "peerDependencies": { diff --git a/packages/liveblocks-node/package.json b/packages/liveblocks-node/package.json index e9b0cd2b39e..d8e074c6543 100644 --- a/packages/liveblocks-node/package.json +++ b/packages/liveblocks-node/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/node", - "version": "3.17.0", + "version": "3.18.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.", @@ -36,7 +36,7 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" diff --git a/packages/liveblocks-react-blocknote/package.json b/packages/liveblocks-react-blocknote/package.json index 36ec69e78de..04c26e60135 100644 --- a/packages/liveblocks-react-blocknote/package.json +++ b/packages/liveblocks-react-blocknote/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react-blocknote", - "version": "3.17.0", + "version": "3.18.0", "description": "An integration of BlockNote + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -44,12 +44,12 @@ "test:watch": "NODE_OPTIONS=\"--no-deprecation\" vitest" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-tiptap": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-tiptap": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "vitest-tsconfig-paths": "^3.4.1" }, diff --git a/packages/liveblocks-react-flow/package.json b/packages/liveblocks-react-flow/package.json index 29915c217aa..74ced719ff3 100644 --- a/packages/liveblocks-react-flow/package.json +++ b/packages/liveblocks-react-flow/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react-flow", - "version": "3.17.0", + "version": "3.18.0", "description": "An integration of React Flow to enable collaboration and realtime cursors with Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -9,7 +9,9 @@ "types": "./dist/index.d.cts", "typesVersions": { "*": { - "node": ["./dist/node.d.ts"] + "node": [ + "./dist/node.d.ts" + ] } }, "exports": { @@ -61,10 +63,10 @@ "test:watch": "vitest" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0" }, "peerDependencies": { "@xyflow/react": "^12", diff --git a/packages/liveblocks-react-lexical/package.json b/packages/liveblocks-react-lexical/package.json index 187c95b7aec..98a8c895837 100644 --- a/packages/liveblocks-react-lexical/package.json +++ b/packages/liveblocks-react-lexical/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react-lexical", - "version": "3.17.0", + "version": "3.18.0", "description": "An integration of Lexical + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -45,11 +45,11 @@ }, "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, diff --git a/packages/liveblocks-react-tiptap/package.json b/packages/liveblocks-react-tiptap/package.json index 946cc3f680a..1c37b689e69 100644 --- a/packages/liveblocks-react-tiptap/package.json +++ b/packages/liveblocks-react-tiptap/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react-tiptap", - "version": "3.17.0", + "version": "3.18.0", "description": "An integration of TipTap + React to enable collaboration, comments, live cursors, and more with Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -45,11 +45,11 @@ }, "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", diff --git a/packages/liveblocks-react-ui/package.json b/packages/liveblocks-react-ui/package.json index 64f6e81af7e..de725afc3c8 100644 --- a/packages/liveblocks-react-ui/package.json +++ b/packages/liveblocks-react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react-ui", - "version": "3.17.0", + "version": "3.18.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.", @@ -78,9 +78,9 @@ }, "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/packages/liveblocks-react/package.json b/packages/liveblocks-react/package.json index 58a5f6eac16..d80a485dd41 100644 --- a/packages/liveblocks-react/package.json +++ b/packages/liveblocks-react/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/react", - "version": "3.17.0", + "version": "3.18.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.", @@ -63,8 +63,8 @@ "showdeps": "depcruise src --include-only '^src' --exclude='__tests__' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/packages/liveblocks-redux/package.json b/packages/liveblocks-redux/package.json index 73e8e6c6500..daf93e334fc 100644 --- a/packages/liveblocks-redux/package.json +++ b/packages/liveblocks-redux/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/redux", - "version": "3.17.0", + "version": "3.18.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.", @@ -35,8 +35,8 @@ "test:watch": "vitest" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "redux": "^4 || ^5" diff --git a/packages/liveblocks-yjs/package.json b/packages/liveblocks-yjs/package.json index c71d8fae450..64c7f521866 100644 --- a/packages/liveblocks-yjs/package.json +++ b/packages/liveblocks-yjs/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/yjs", - "version": "3.17.0", + "version": "3.18.0", "description": "Integrate your existing or new Yjs documents with Liveblocks.", "license": "Apache-2.0", "author": "Liveblocks Inc.", @@ -35,8 +35,8 @@ "test:watch": "vitest" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/packages/liveblocks-zustand/package.json b/packages/liveblocks-zustand/package.json index 8d6762e5e75..0d862290543 100644 --- a/packages/liveblocks-zustand/package.json +++ b/packages/liveblocks-zustand/package.json @@ -1,6 +1,6 @@ { "name": "@liveblocks/zustand", - "version": "3.17.0", + "version": "3.18.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.", @@ -36,8 +36,8 @@ "test:watch": "vitest" }, "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "zustand": "^5.0.1" From d7d17ab35d4dc94c3089a9ac6716cf5e069bad0f Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Wed, 8 Apr 2026 11:55:37 +0200 Subject: [PATCH 3/6] Fix missing route entry for upgrade guide (#3323) --- CLAUDE.md | 4 ++++ docs/routes.json | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index b7723d4982d..e6ba86493f6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,6 +58,10 @@ need to be updated separately when a new version is published. All documentation lives in the `docs/` directory, as Markdown files. +When adding a new page (e.g. an upgrading guide), the `.mdx` file alone is not +enough. You must also register it in `docs/routes.json` or it won't be +routable. + # Changelog CHANGELOG.md entries should use public-facing package names as subheadings (e.g. diff --git a/docs/routes.json b/docs/routes.json index 5bd60c316f7..ad15b0ecb9d 100644 --- a/docs/routes.json +++ b/docs/routes.json @@ -806,7 +806,8 @@ { "title": "Upgrading to 2.16", "path": "/upgrading/2.16" }, { "title": "Upgrading to 2.24", "path": "/upgrading/2.24" }, { "title": "Upgrading to 3.0", "path": "/upgrading/3.0" }, - { "title": "Upgrading to 3.10", "path": "/upgrading/3.10" } + { "title": "Upgrading to 3.10", "path": "/upgrading/3.10" }, + { "title": "Upgrading to 3.18", "path": "/upgrading/3.18" } ] }, { From be130eaf4d11a4c00c13dcbf935c3e098a90d42d Mon Sep 17 00:00:00 2001 From: Chris Nicholas Date: Wed, 8 Apr 2026 11:08:14 +0100 Subject: [PATCH 4/6] Chat SDK DX adjustments (#3312) --- examples/nextjs-chat-sdk-ai-bot/.env.example | 8 +++++ examples/nextjs-chat-sdk-ai-bot/app/bot.ts | 28 ++++++++++++++++-- .../nextjs-chat-sdk-ai-bot/app/database.ts | 2 +- .../nextjs-chat-sdk-ai-bot/next.config.ts | 7 +++-- .../public/ai-avatar.png | Bin 4208 -> 0 bytes examples/nextjs-chat-sdk-bot/.env.example | 5 ++++ examples/nextjs-chat-sdk-bot/app/database.ts | 2 +- examples/nextjs-chat-sdk-bot/next.config.ts | 4 +++ .../nextjs-chat-sdk-bot/public/bot-avatar.png | Bin 4208 -> 0 bytes .../liveblocks-chat-sdk-adapter/README.md | 2 +- 10 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 examples/nextjs-chat-sdk-ai-bot/.env.example delete mode 100644 examples/nextjs-chat-sdk-ai-bot/public/ai-avatar.png create mode 100644 examples/nextjs-chat-sdk-bot/.env.example delete mode 100644 examples/nextjs-chat-sdk-bot/public/bot-avatar.png diff --git a/examples/nextjs-chat-sdk-ai-bot/.env.example b/examples/nextjs-chat-sdk-ai-bot/.env.example new file mode 100644 index 00000000000..7150d536d56 --- /dev/null +++ b/examples/nextjs-chat-sdk-ai-bot/.env.example @@ -0,0 +1,8 @@ +# https://platform.claude.com/settings/keys +ANTHROPIC_API_KEY= + +# https://liveblocks.io/dashboard/apikeys +LIVEBLOCKS_SECRET_KEY= + +# https://liveblocks.io/dashboard/webhooks +LIVEBLOCKS_WEBHOOK_SECRET= \ No newline at end of file diff --git a/examples/nextjs-chat-sdk-ai-bot/app/bot.ts b/examples/nextjs-chat-sdk-ai-bot/app/bot.ts index bf317cd87ca..38c28ff39be 100644 --- a/examples/nextjs-chat-sdk-ai-bot/app/bot.ts +++ b/examples/nextjs-chat-sdk-ai-bot/app/bot.ts @@ -7,6 +7,7 @@ import { AiUserMessage, Chat, Message, + Thread, } from "chat"; import { createLiveblocksAdapter, @@ -44,7 +45,29 @@ export const bot = new Chat<{ liveblocks: LiveblocksAdapter }>({ }); // Handle @-mentions of the bot -bot.onNewMention(async (thread, message) => { +bot.onNewMention(postAiResponse); + +// ========================================================================== +// Optional: Automatically reply to further comments after the first mention +// This requires a permanent state adapter set up to persist the subscription +// e.g. import { createRedisState } from "@chat-adapter/state-redis"; + +// Handle @-mentions of the bot +// bot.onNewMention(async (thread, message) => { +// // After AI is mentioned, subscribe to thread +// await thread.subscribe(); + +// await postAiResponse(thread, message); +// }); + +// Handle replying to further comments in the subscribed thread +// bot.onSubscribedMessage(async (thread, message) => { +// await postAiResponse(thread, message); +// }); +// ========================================================================== + +// Generate an AI response to the message +async function postAiResponse(thread: Thread, message: Message) { await thread.adapter.addReaction(thread.id, message.id, "👀"); const model = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY! })( @@ -56,8 +79,9 @@ bot.onNewMention(async (thread, message) => { system: SYSTEM_PROMPT, messages: [await convertChatMessageToAiMessage(message)], }); + await thread.post(response.fullStream); -}); +} async function convertChatMessageToAiMessage( message: Message diff --git a/examples/nextjs-chat-sdk-ai-bot/app/database.ts b/examples/nextjs-chat-sdk-ai-bot/app/database.ts index 441303c76ff..415983721c4 100644 --- a/examples/nextjs-chat-sdk-ai-bot/app/database.ts +++ b/examples/nextjs-chat-sdk-ai-bot/app/database.ts @@ -24,7 +24,7 @@ const USER_INFO: Liveblocks["UserMeta"][] = [ info: { name: BOT_USER_NAME, color: "#000000", - avatar: "/ai-avatar.png", + avatar: "https://liveblocks.io/api/avatar?u=__ai__&agent=true", }, }, ]; diff --git a/examples/nextjs-chat-sdk-ai-bot/next.config.ts b/examples/nextjs-chat-sdk-ai-bot/next.config.ts index bf3c9c65b15..dd059472f33 100644 --- a/examples/nextjs-chat-sdk-ai-bot/next.config.ts +++ b/examples/nextjs-chat-sdk-ai-bot/next.config.ts @@ -4,11 +4,14 @@ import { fileURLToPath } from "node:url"; const configDir = path.dirname(fileURLToPath(import.meta.url)); -const config: NextConfig = { +const nextConfig: NextConfig = { + // Allow webhooks with ngrok and localtunnel + allowedDevOrigins: ["*.ngrok-free.app", "*.loca.lt"], + // Monorepo root (lockfile). Avoids Next picking a parent directory (e.g. another lockfile). turbopack: { root: path.join(configDir, "../.."), }, }; -export default config; +export default nextConfig; diff --git a/examples/nextjs-chat-sdk-ai-bot/public/ai-avatar.png b/examples/nextjs-chat-sdk-ai-bot/public/ai-avatar.png deleted file mode 100644 index aceaa9ed80c3075adf61c74b9f804cc9fc047d87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4208 zcmV-$5RdPPP)HYKN=lJgN`s@1m==1vP_WA1j_v-BX>-72U>iO;L`tJDn?CAIL@cQoj_UZic=Kb>K z>iF>d_3Hfd=Z~n@%r-m`0V`j==A#W==SsX z`0)Ml=JopYf7E*J`SbVr@$C2WsocDO&x420e*5?F{Pyt4<;>ab+kDN8qtBE2`0)Gn z?3~WCddiiO$$r4uv+nKJ{PgN}$C`u5ik!uL*2R>|ymH*pr;Esh^!4lf^6CBXuvG@Amfc`1a!N=;-wK_4oGn`1Set^!xShhP|4`v3LCR?EUfS>-G4K zzoW>lclP4d{qN=T_V|dlrTp{k#IcdUrGUz(c<%N1`uX?#?dkpS=-S`q>GS#c`1i`7 zdGgJ={qpSc_4vDE`_K?DX{cubG;{m51SvYVq;;y|&4y zptz-&sLzmm>hb%*z}TCXw#AQz>5O3g?&#|9`|a}kr>o48n7^))qq&fk(~5fCig2Wl zvE+$o$ccuri>C1B`@4sl+k|uO>HO=~;l_lN%!7s1gM9q!==}2V{O;`T@ca1n`1tbo z^zQil?C9yZy#4Iv_44@8m8`~olF)sG)_i>Y=;rG0{PyVb@bLQk@$v2N`}pqk^YHn} zcazd~g#72{`|t4Jrn&0w{POSm{O#=S?)&Y?)c5Q2&T)?X?Cb08{O#@g@a_Bh=j+dG zko)NA^6dKc?DzZY?ELEK?CkvS?EClZ_514U?CbpQ>-_TT`t|Gf`s(id>FM$6`uXbc z`swWR>G<~P^!4fX{OITK>HGNU@bc*S@96yW=l1yL@ABvQZvt8=000duNkl#Kcvb}7--9z37`be2VMn-jRz{t?Jja-)K>-8#d48EOj z-mMc^S%E3R$U>Ja0rsv>as&=YD;J z9HqrCU|15DlyxxG-u;h{x=3;$hJqmKy_dseW@hO7A8b+;tqMtoyucIw+NHl5{!3iL z(5+VMvlU^nBsYhx8g939T3n#TQh@((J5 z*)Fi%C}%Ek=+%5?o3%?upTU$45YW`^_j-N7WOQIV+pyKAuwBVwEoX2)!nOwk$%Efq zzQ13?Dq+=T{Pf1@NBbJ(LElItt`Wo!IDMR@JX;~yK15~>O5OrR+ry> ztak6o%Vk%I^^QkAXmH$6E1_;jS;Cx!nrU zCGav-ob(8m{FhJ-JKRYB^HCStty@tLhWj2D7M2+tnVFeUwPl5w86UkfXIt`4b=yC& zz4%)rIN!xQ7sV3^z{!uE>%*qcsn2PspFcx20rq918W{2h)_xhrWP@XIEEXY5H`_>wrBOsH9)a60Y5bw9$8)!9K6eKj5{c!cP$ir@|to-`&1Fsrn1 zm*MgTqiJW>=}f^EQj`T=(@+TyJQpxjfmbwsM-qmQj2p2dk-z7eIApl6d%b)n+qXh1 zlyzsQo03Fj1{GGp;tIS#py2{m0fveqw)1OgBIUDI6t9zIEknyt$aOuq?ZKNw8C|5{ z4g8~_hCxg3V4Hg-t2Eh~;6H1@j4oHXl-q7baE&Xfp`0XkftcDkc)wJ)T_{qu1esHkcg^Jp)TL6rF`1JG} zEqki48WvRBdT|DD$#DYk*}?h2!NtWv--RnM=~I)2MP-nKix<9osjs!;%mG)|u;Vzc zdv$eneSUs$egPRbS>&Gq6Ai*QH^bpgaIxQ>bjid;_5$#&G6e z!@H|)0PDqfDCiPq0;A*7$;sUDyEpE=dqx-X!^Np_$?9tjSHYAu{GL{@l8@)Ni?zGF zmoS*}1A2UalSw~44HUdF48rJt;Ah)DMvhKg41PI3e_*c{Zwi)+4Ozn;3-}*G=_;Xt zGm7GPm)3RgQg>I}lEEcbhm>$m#!|tZQh?KTaNtGt8D(Op|W1|K_8>8nJ`jVJk{Y+ZgSZE{d0RLmHhRvF0OS|4j_etCJgmsxFOG9;|O#=Wdzp;dcs2TdC`^0 zlde4U4vYe10n^sSat~uL*k;dIBr+ZmIm*cTaH5#E{X5D(Ic~>$FzG(6g{Zn7~B$BCA1dS6OkM>8?(R4bktS^STz3ol-nO_&HJX8l~G8skdVWe=gC!0v-aw!y{ zEUuIvNK3vnUFmPhJJ{aT;rC#d|ut5*{|9o$8W_p^Y2{RLp|I?hERajiei;Ii-Mbea)ia5$k%HrGl zZo-cUt82ngkpUwU*23X9uJH0oHmNRHdzJ25p|FmY3QMS5F2dZ{+}s3-b8>QMYiel9 z7_2ZA2aX5h@i<_%(;40k@2w=n6?w6;y1FJ6)(h)UvDw?S4^#rmAToMX>tTIy zTm+P<>)<=#ojuPy-Brh3X96GmVOi>SD2%}d%not5u<;j&%LHXd2q&^9>gV`I)9QZ<2!l)jW086{OlrN7LS5MH|DLOk_KRY`xSl1mgT@${5 zdr>V<8|>AUD+6YZ{PFS0qR4Qey6(0A`kL$(;^2mhfl4ah@D5ZWtFY3Ji$uOXrVIHD zlf4!a7bz=E{qYA*(`^jjfL8a4?5litcW1(sSK!{meZb!JM@tg+>B)tsph~JXhH-b{ zn;VcCS<0pj{Q3Um{{G?g;o;%zz;!1L*M;}@!BxZ3i}Qf2tiWz}t{nQ8F1o;RBZ#6X z>h(u08d%COlPJ(;W@c|8|JHNOPbHb#RKlZYbDK(+CBiLN_?=C)?(fZ2xatL%zC{?- ziZJ22+>qRm4SRZuN*}mXv$5t1re^cLiEO3R(Nl4}XIZ*;w9>r`%#JEc;$Tke+2cffK}_{H59cN3WH#tPQKVX+32 z;2>WaZ0^TT%UxKxJrfOoA$L<)YyjgI*;x{+kZWBkzX~?>FBh0@CI1KR_dnf%J~SMr zY$8*;8*0On)Lsu57Z{h)#Zp5@cHpqf4yT((-R`(ME>GkNHWxW@$<+W0C9xDpE4&)R z>2&JwY?ja^;48U=>!CV)dwYJKz%fh}T+e8S2|3SsuEy5K7w+7+;Ht&B72&?ObU1M( zW4oNkYQQzAnZbXubF|;stj}>~ggV z@`@sx!s}eE+X2pC&27#t+3qgvB4>eJC0t-+bIIKlUatdw2|R*DHZG*E*ibqcSgt1* zd8H6NP+UUJ)*tp4gVNmFY)~C`R&rq}R&BSR?k>9fy~sU*rf|N#yv!VSce8Mo&eIAB zOG{KsG8*(=@WGNCSne##kE&d;H2>OVapID>ii2RWg4Ox}OdU}A-3T45stra#9QXOV z?~4@fLj;#DT}j|lRH%tYqfKmQ@?|o#Cx`Zb0$Ki;?{c}=W#F3NsulPNvz-oc5n>?bsy*1ZQB`cQG^j)!dD#K&(r7Wb`#t%yY36xh_(As|aS2yiZ8)%s>YUXT_yv^R986>v zGD={x$}sA>b_Is#3{#aX82vA7^(S1Hz=35jgPg#2he0k&;J_XZ2dO(WvxHfIqdQE= zWeMyA+buG)YdEroArAvp;bRKF--7Kj!KMx8?ze#%9+_dI$go+-l@m@QMC)$8J3$&&fwg2Ywjc) zm8HYKN=lJgN`s@1m==1vP_WA1j_v-BX>-72U>iO;L`tJDn?CAIL@cQoj_UZic=Kb>K z>iF>d_3Hfd=Z~n@%r-m`0V`j==A#W==SsX z`0)Ml=JopYf7E*J`SbVr@$C2WsocDO&x420e*5?F{Pyt4<;>ab+kDN8qtBE2`0)Gn z?3~WCddiiO$$r4uv+nKJ{PgN}$C`u5ik!uL*2R>|ymH*pr;Esh^!4lf^6CBXuvG@Amfc`1a!N=;-wK_4oGn`1Set^!xShhP|4`v3LCR?EUfS>-G4K zzoW>lclP4d{qN=T_V|dlrTp{k#IcdUrGUz(c<%N1`uX?#?dkpS=-S`q>GS#c`1i`7 zdGgJ={qpSc_4vDE`_K?DX{cubG;{m51SvYVq;;y|&4y zptz-&sLzmm>hb%*z}TCXw#AQz>5O3g?&#|9`|a}kr>o48n7^))qq&fk(~5fCig2Wl zvE+$o$ccuri>C1B`@4sl+k|uO>HO=~;l_lN%!7s1gM9q!==}2V{O;`T@ca1n`1tbo z^zQil?C9yZy#4Iv_44@8m8`~olF)sG)_i>Y=;rG0{PyVb@bLQk@$v2N`}pqk^YHn} zcazd~g#72{`|t4Jrn&0w{POSm{O#=S?)&Y?)c5Q2&T)?X?Cb08{O#@g@a_Bh=j+dG zko)NA^6dKc?DzZY?ELEK?CkvS?EClZ_514U?CbpQ>-_TT`t|Gf`s(id>FM$6`uXbc z`swWR>G<~P^!4fX{OITK>HGNU@bc*S@96yW=l1yL@ABvQZvt8=000duNkl#Kcvb}7--9z37`be2VMn-jRz{t?Jja-)K>-8#d48EOj z-mMc^S%E3R$U>Ja0rsv>as&=YD;J z9HqrCU|15DlyxxG-u;h{x=3;$hJqmKy_dseW@hO7A8b+;tqMtoyucIw+NHl5{!3iL z(5+VMvlU^nBsYhx8g939T3n#TQh@((J5 z*)Fi%C}%Ek=+%5?o3%?upTU$45YW`^_j-N7WOQIV+pyKAuwBVwEoX2)!nOwk$%Efq zzQ13?Dq+=T{Pf1@NBbJ(LElItt`Wo!IDMR@JX;~yK15~>O5OrR+ry> ztak6o%Vk%I^^QkAXmH$6E1_;jS;Cx!nrU zCGav-ob(8m{FhJ-JKRYB^HCStty@tLhWj2D7M2+tnVFeUwPl5w86UkfXIt`4b=yC& zz4%)rIN!xQ7sV3^z{!uE>%*qcsn2PspFcx20rq918W{2h)_xhrWP@XIEEXY5H`_>wrBOsH9)a60Y5bw9$8)!9K6eKj5{c!cP$ir@|to-`&1Fsrn1 zm*MgTqiJW>=}f^EQj`T=(@+TyJQpxjfmbwsM-qmQj2p2dk-z7eIApl6d%b)n+qXh1 zlyzsQo03Fj1{GGp;tIS#py2{m0fveqw)1OgBIUDI6t9zIEknyt$aOuq?ZKNw8C|5{ z4g8~_hCxg3V4Hg-t2Eh~;6H1@j4oHXl-q7baE&Xfp`0XkftcDkc)wJ)T_{qu1esHkcg^Jp)TL6rF`1JG} zEqki48WvRBdT|DD$#DYk*}?h2!NtWv--RnM=~I)2MP-nKix<9osjs!;%mG)|u;Vzc zdv$eneSUs$egPRbS>&Gq6Ai*QH^bpgaIxQ>bjid;_5$#&G6e z!@H|)0PDqfDCiPq0;A*7$;sUDyEpE=dqx-X!^Np_$?9tjSHYAu{GL{@l8@)Ni?zGF zmoS*}1A2UalSw~44HUdF48rJt;Ah)DMvhKg41PI3e_*c{Zwi)+4Ozn;3-}*G=_;Xt zGm7GPm)3RgQg>I}lEEcbhm>$m#!|tZQh?KTaNtGt8D(Op|W1|K_8>8nJ`jVJk{Y+ZgSZE{d0RLmHhRvF0OS|4j_etCJgmsxFOG9;|O#=Wdzp;dcs2TdC`^0 zlde4U4vYe10n^sSat~uL*k;dIBr+ZmIm*cTaH5#E{X5D(Ic~>$FzG(6g{Zn7~B$BCA1dS6OkM>8?(R4bktS^STz3ol-nO_&HJX8l~G8skdVWe=gC!0v-aw!y{ zEUuIvNK3vnUFmPhJJ{aT;rC#d|ut5*{|9o$8W_p^Y2{RLp|I?hERajiei;Ii-Mbea)ia5$k%HrGl zZo-cUt82ngkpUwU*23X9uJH0oHmNRHdzJ25p|FmY3QMS5F2dZ{+}s3-b8>QMYiel9 z7_2ZA2aX5h@i<_%(;40k@2w=n6?w6;y1FJ6)(h)UvDw?S4^#rmAToMX>tTIy zTm+P<>)<=#ojuPy-Brh3X96GmVOi>SD2%}d%not5u<;j&%LHXd2q&^9>gV`I)9QZ<2!l)jW086{OlrN7LS5MH|DLOk_KRY`xSl1mgT@${5 zdr>V<8|>AUD+6YZ{PFS0qR4Qey6(0A`kL$(;^2mhfl4ah@D5ZWtFY3Ji$uOXrVIHD zlf4!a7bz=E{qYA*(`^jjfL8a4?5litcW1(sSK!{meZb!JM@tg+>B)tsph~JXhH-b{ zn;VcCS<0pj{Q3Um{{G?g;o;%zz;!1L*M;}@!BxZ3i}Qf2tiWz}t{nQ8F1o;RBZ#6X z>h(u08d%COlPJ(;W@c|8|JHNOPbHb#RKlZYbDK(+CBiLN_?=C)?(fZ2xatL%zC{?- ziZJ22+>qRm4SRZuN*}mXv$5t1re^cLiEO3R(Nl4}XIZ*;w9>r`%#JEc;$Tke+2cffK}_{H59cN3WH#tPQKVX+32 z;2>WaZ0^TT%UxKxJrfOoA$L<)YyjgI*;x{+kZWBkzX~?>FBh0@CI1KR_dnf%J~SMr zY$8*;8*0On)Lsu57Z{h)#Zp5@cHpqf4yT((-R`(ME>GkNHWxW@$<+W0C9xDpE4&)R z>2&JwY?ja^;48U=>!CV)dwYJKz%fh}T+e8S2|3SsuEy5K7w+7+;Ht&B72&?ObU1M( zW4oNkYQQzAnZbXubF|;stj}>~ggV z@`@sx!s}eE+X2pC&27#t+3qgvB4>eJC0t-+bIIKlUatdw2|R*DHZG*E*ibqcSgt1* zd8H6NP+UUJ)*tp4gVNmFY)~C`R&rq}R&BSR?k>9fy~sU*rf|N#yv!VSce8Mo&eIAB zOG{KsG8*(=@WGNCSne##kE&d;H2>OVapID>ii2RWg4Ox}OdU}A-3T45stra#9QXOV z?~4@fLj;#DT}j|lRH%tYqfKmQ@?|o#Cx`Zb0$Ki;?{c}=W#F3NsulPNvz-oc5n>?bsy*1ZQB`cQG^j)!dD#K&(r7Wb`#t%yY36xh_(As|aS2yiZ8)%s>YUXT_yv^R986>v zGD={x$}sA>b_Is#3{#aX82vA7^(S1Hz=35jgPg#2he0k&;J_XZ2dO(WvxHfIqdQE= zWeMyA+buG)YdEroArAvp;bRKF--7Kj!KMx8?ze#%9+_dI$go+-l@m@QMC)$8J3$&&fwg2Ywjc) zm8 Date: Wed, 8 Apr 2026 13:06:36 +0200 Subject: [PATCH 5/6] Upgrade all examples to 3.18.0 (#3324) --- .../javascript-live-cursors/package-lock.json | 16 +- examples/javascript-live-cursors/package.json | 2 +- .../javascript-todo-list/package-lock.json | 16 +- examples/javascript-todo-list/package.json | 2 +- examples/nextjs-3d-builder/package-lock.json | 28 +- examples/nextjs-3d-builder/package.json | 4 +- .../nextjs-ai-app-builder/package-lock.json | 52 ++-- examples/nextjs-ai-app-builder/package.json | 8 +- examples/nextjs-ai-calendar/package-lock.json | 52 ++-- examples/nextjs-ai-calendar/package.json | 8 +- examples/nextjs-ai-chats/package-lock.json | 52 ++-- examples/nextjs-ai-chats/package.json | 8 +- .../package-lock.json | 52 ++-- .../nextjs-ai-dashboard-reports/package.json | 8 +- examples/nextjs-ai-popup/package-lock.json | 52 ++-- examples/nextjs-ai-popup/package.json | 8 +- examples/nextjs-ai-support/package-lock.json | 52 ++-- examples/nextjs-ai-support/package.json | 8 +- .../nextjs-chat-sdk-ai-bot/package-lock.json | 64 ++-- examples/nextjs-chat-sdk-ai-bot/package.json | 10 +- .../nextjs-chat-sdk-bot/package-lock.json | 64 ++-- examples/nextjs-chat-sdk-bot/package.json | 10 +- .../nextjs-comments-ag-grid/package-lock.json | 52 ++-- examples/nextjs-comments-ag-grid/package.json | 8 +- examples/nextjs-comments-ai/package-lock.json | 52 ++-- examples/nextjs-comments-ai/package.json | 8 +- .../nextjs-comments-audio/package-lock.json | 52 ++-- examples/nextjs-comments-audio/package.json | 8 +- .../nextjs-comments-canvas/package-lock.json | 52 ++-- examples/nextjs-comments-canvas/package.json | 8 +- .../package-lock.json | 64 ++-- .../package.json | 10 +- .../package-lock.json | 64 ++-- .../package.json | 10 +- .../package-lock.json | 52 ++-- .../package.json | 8 +- .../nextjs-comments-overlay/package-lock.json | 52 ++-- examples/nextjs-comments-overlay/package.json | 8 +- .../package-lock.json | 52 ++-- .../nextjs-comments-primitives/package.json | 8 +- .../nextjs-comments-search/package-lock.json | 52 ++-- examples/nextjs-comments-search/package.json | 8 +- .../nextjs-comments-tiptap/package-lock.json | 80 ++--- examples/nextjs-comments-tiptap/package.json | 10 +- .../nextjs-comments-video/package-lock.json | 52 ++-- examples/nextjs-comments-video/package.json | 8 +- examples/nextjs-comments/package-lock.json | 52 ++-- examples/nextjs-comments/package.json | 8 +- .../package-lock.json | 28 +- .../nextjs-connection-status/package.json | 4 +- examples/nextjs-dashboard/package-lock.json | 28 +- examples/nextjs-dashboard/package.json | 4 +- .../package-lock.json | 68 ++--- .../nextjs-flowchart-builder/package.json | 10 +- examples/nextjs-form/package-lock.json | 38 +-- examples/nextjs-form/package.json | 6 +- .../package-lock.json | 92 +++--- .../nextjs-lexical-emails-resend/package.json | 12 +- examples/nextjs-lexical/package-lock.json | 80 ++--- examples/nextjs-lexical/package.json | 10 +- .../package-lock.json | 92 +++--- .../package.json | 12 +- .../src/liveblocks.config.ts | 4 +- .../package-lock.json | 38 +-- .../nextjs-live-avatars-advanced/package.json | 6 +- .../nextjs-live-avatars/package-lock.json | 52 ++-- examples/nextjs-live-avatars/package.json | 8 +- .../package-lock.json | 38 +-- .../nextjs-live-cursors-advanced/package.json | 6 +- .../package-lock.json | 38 +-- .../nextjs-live-cursors-chat/package.json | 6 +- .../package-lock.json | 28 +- .../nextjs-live-cursors-scroll/package.json | 4 +- .../nextjs-live-cursors/package-lock.json | 52 ++-- examples/nextjs-live-cursors/package.json | 8 +- .../package-lock.json | 28 +- .../nextjs-live-form-selection/package.json | 4 +- .../package-lock.json | 38 +-- .../package.json | 6 +- .../package-lock.json | 96 +++--- .../nextjs-notification-settings/package.json | 16 +- .../package-lock.json | 52 ++-- .../nextjs-notifications-custom/package.json | 8 +- .../package-lock.json | 92 +++--- .../nextjs-notion-like-ai-editor/package.json | 12 +- .../nextjs-react-flow-ai/package-lock.json | 68 ++--- examples/nextjs-react-flow-ai/package.json | 10 +- examples/nextjs-react-flow/package-lock.json | 68 ++--- examples/nextjs-react-flow/package.json | 10 +- .../package-lock.json | 38 +-- .../nextjs-spreadsheet-advanced/package.json | 6 +- .../nextjs-tiptap-advanced/package-lock.json | 80 ++--- examples/nextjs-tiptap-advanced/package.json | 10 +- examples/nextjs-tiptap-ai/package-lock.json | 82 ++--- examples/nextjs-tiptap-ai/package.json | 12 +- .../package-lock.json | 94 +++--- .../nextjs-tiptap-emails-resend/package.json | 14 +- examples/nextjs-tiptap/package-lock.json | 82 ++--- examples/nextjs-tiptap/package.json | 12 +- .../package-lock.json | 52 ++-- .../package.json | 8 +- .../package-lock.json | 64 ++-- .../nextjs-tldraw-whiteboard-yjs/package.json | 10 +- examples/nextjs-todo-list/package-lock.json | 28 +- examples/nextjs-todo-list/package.json | 4 +- .../package-lock.json | 38 +-- .../nextjs-whiteboard-advanced/package.json | 6 +- .../src/components/LayerComponent.tsx | 2 +- .../src/components/SelectionBox.tsx | 2 +- .../src/components/SelectionTools.tsx | 4 +- .../src/hooks/useSelectionBounds.ts | 2 +- .../nextjs-whiteboard-advanced/src/index.tsx | 2 +- .../nextjs-whiteboard-advanced/src/utils.ts | 4 +- examples/nextjs-whiteboard/package-lock.json | 38 +-- examples/nextjs-whiteboard/package.json | 6 +- examples/nextjs-whiteboard/pages/index.tsx | 11 +- .../package-lock.json | 50 ++-- .../package.json | 8 +- .../nextjs-yjs-blocknote/package-lock.json | 50 ++-- examples/nextjs-yjs-blocknote/package.json | 8 +- .../nextjs-yjs-codemirror/package-lock.json | 50 ++-- examples/nextjs-yjs-codemirror/package.json | 8 +- examples/nextjs-yjs-lexical/package-lock.json | 50 ++-- examples/nextjs-yjs-lexical/package.json | 8 +- examples/nextjs-yjs-monaco/package-lock.json | 50 ++-- examples/nextjs-yjs-monaco/package.json | 8 +- examples/nextjs-yjs-quill/package-lock.json | 50 ++-- examples/nextjs-yjs-quill/package.json | 8 +- examples/nextjs-yjs-slate/package-lock.json | 50 ++-- examples/nextjs-yjs-slate/package.json | 8 +- examples/nextjs-yjs-tiptap/package-lock.json | 50 ++-- examples/nextjs-yjs-tiptap/package.json | 8 +- .../nuxtjs-live-avatars/package-lock.json | 26 +- examples/nuxtjs-live-avatars/package.json | 4 +- examples/react-comments/package-lock.json | 52 ++-- examples/react-comments/package.json | 8 +- .../react-native-todo-list/package-lock.json | 28 +- examples/react-native-todo-list/package.json | 4 +- examples/redux-todo-list/package-lock.json | 28 +- examples/redux-todo-list/package.json | 4 +- examples/redux-whiteboard/package-lock.json | 28 +- examples/redux-whiteboard/package.json | 4 +- .../solidjs-live-avatars/package-lock.json | 16 +- examples/solidjs-live-avatars/package.json | 2 +- .../solidjs-live-cursors/package-lock.json | 16 +- examples/solidjs-live-cursors/package.json | 2 +- .../sveltekit-live-avatars/package-lock.json | 26 +- examples/sveltekit-live-avatars/package.json | 4 +- .../sveltekit-live-cursors/package-lock.json | 26 +- examples/sveltekit-live-cursors/package.json | 4 +- examples/vuejs-live-avatars/package-lock.json | 16 +- examples/vuejs-live-avatars/package.json | 2 +- examples/vuejs-live-cursors/package-lock.json | 16 +- examples/vuejs-live-cursors/package.json | 2 +- examples/zustand-todo-list/package-lock.json | 28 +- examples/zustand-todo-list/package.json | 4 +- examples/zustand-whiteboard/package-lock.json | 28 +- examples/zustand-whiteboard/package.json | 4 +- starter-kits/nextjs-starter-kit/.gitignore | 1 + .../components/Whiteboard/Whiteboard.tsx | 10 +- .../components/Whiteboard/WhiteboardNote.tsx | 2 +- starter-kits/nextjs-starter-kit/next-env.d.ts | 6 - .../nextjs-starter-kit/package-lock.json | 281 ++++++++++-------- starter-kits/nextjs-starter-kit/package.json | 20 +- 164 files changed, 2289 insertions(+), 2282 deletions(-) delete mode 100644 starter-kits/nextjs-starter-kit/next-env.d.ts diff --git a/examples/javascript-live-cursors/package-lock.json b/examples/javascript-live-cursors/package-lock.json index ca4721c5280..d6aae0e6254 100644 --- a/examples/javascript-live-cursors/package-lock.json +++ b/examples/javascript-live-cursors/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/javascript-live-cursors", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0" + "@liveblocks/client": "^3.18.0" }, "devDependencies": { "esbuild": "0.27.2", @@ -457,18 +457,18 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/javascript-live-cursors/package.json b/examples/javascript-live-cursors/package.json index f318f1e6f00..beadcb9fc74 100644 --- a/examples/javascript-live-cursors/package.json +++ b/examples/javascript-live-cursors/package.json @@ -7,7 +7,7 @@ "build": "esbuild app.ts --bundle --outfile=static/app.js" }, "dependencies": { - "@liveblocks/client": "^3.17.0" + "@liveblocks/client": "^3.18.0" }, "devDependencies": { "esbuild": "0.27.2", diff --git a/examples/javascript-todo-list/package-lock.json b/examples/javascript-todo-list/package-lock.json index b781af1a8f1..e92165e8eee 100644 --- a/examples/javascript-todo-list/package-lock.json +++ b/examples/javascript-todo-list/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/javascript-todo-list", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0" + "@liveblocks/client": "^3.18.0" }, "devDependencies": { "esbuild": "0.27.2", @@ -457,18 +457,18 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/javascript-todo-list/package.json b/examples/javascript-todo-list/package.json index 78af15411b3..056172bda39 100644 --- a/examples/javascript-todo-list/package.json +++ b/examples/javascript-todo-list/package.json @@ -12,6 +12,6 @@ "prettier": "^3.3.3" }, "dependencies": { - "@liveblocks/client": "^3.17.0" + "@liveblocks/client": "^3.18.0" } } diff --git a/examples/nextjs-3d-builder/package-lock.json b/examples/nextjs-3d-builder/package-lock.json index f486faf84a2..e85031303cf 100644 --- a/examples/nextjs-3d-builder/package-lock.json +++ b/examples/nextjs-3d-builder/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-3d-builder", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@react-three/drei": "^9.16.1", "@react-three/fiber": "^8.0.27", "next": "^16.1.6", @@ -513,31 +513,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-3d-builder/package.json b/examples/nextjs-3d-builder/package.json index 1e059cd5847..a5e7ce7e5f3 100644 --- a/examples/nextjs-3d-builder/package.json +++ b/examples/nextjs-3d-builder/package.json @@ -9,8 +9,8 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@react-three/drei": "^9.16.1", "@react-three/fiber": "^8.0.27", "next": "^16.1.6", diff --git a/examples/nextjs-ai-app-builder/package-lock.json b/examples/nextjs-ai-app-builder/package-lock.json index fc7bf74357f..2ebbe0471f0 100644 --- a/examples/nextjs-ai-app-builder/package-lock.json +++ b/examples/nextjs-ai-app-builder/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@codesandbox/sandpack-react": "^2.20.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@monaco-editor/react": "^4.7.0", "@types/node": "^18.11.19", "@types/react": "^18.0.38", @@ -829,43 +829,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -882,15 +882,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-app-builder/package.json b/examples/nextjs-ai-app-builder/package.json index 8dd3eda3d8f..9e3ae17ab03 100644 --- a/examples/nextjs-ai-app-builder/package.json +++ b/examples/nextjs-ai-app-builder/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@codesandbox/sandpack-react": "^2.20.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@monaco-editor/react": "^4.7.0", "@types/node": "^18.11.19", "@types/react": "^18.0.38", diff --git a/examples/nextjs-ai-calendar/package-lock.json b/examples/nextjs-ai-calendar/package-lock.json index b4a74cdf0b9..9347fc35c1b 100644 --- a/examples/nextjs-ai-calendar/package-lock.json +++ b/examples/nextjs-ai-calendar/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@faker-js/faker": "^9.9.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-slot": "^1.2.4", @@ -623,43 +623,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -676,15 +676,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-calendar/package.json b/examples/nextjs-ai-calendar/package.json index 48582687d98..77e294ac79a 100644 --- a/examples/nextjs-ai-calendar/package.json +++ b/examples/nextjs-ai-calendar/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@faker-js/faker": "^9.9.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-slot": "^1.2.4", diff --git a/examples/nextjs-ai-chats/package-lock.json b/examples/nextjs-ai-chats/package-lock.json index 23235f4bbfa..768b298b430 100644 --- a/examples/nextjs-ai-chats/package-lock.json +++ b/examples/nextjs-ai-chats/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-ai-chats", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.0.38", "@types/react-dom": "^18.0.11", @@ -599,43 +599,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -652,15 +652,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-chats/package.json b/examples/nextjs-ai-chats/package.json index 757a1137632..e97f094e196 100644 --- a/examples/nextjs-ai-chats/package.json +++ b/examples/nextjs-ai-chats/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.0.38", "@types/react-dom": "^18.0.11", diff --git a/examples/nextjs-ai-dashboard-reports/package-lock.json b/examples/nextjs-ai-dashboard-reports/package-lock.json index 239e5378c55..3c0b979366d 100644 --- a/examples/nextjs-ai-dashboard-reports/package-lock.json +++ b/examples/nextjs-ai-dashboard-reports/package-lock.json @@ -9,10 +9,10 @@ "version": "0.1.0", "dependencies": { "@internationalized/date": "^3.7.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-checkbox": "^1.1.5", "@radix-ui/react-dialog": "^1.1.15", @@ -1703,43 +1703,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1756,15 +1756,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-dashboard-reports/package.json b/examples/nextjs-ai-dashboard-reports/package.json index 0e04bdef177..3a662b70014 100644 --- a/examples/nextjs-ai-dashboard-reports/package.json +++ b/examples/nextjs-ai-dashboard-reports/package.json @@ -12,10 +12,10 @@ }, "dependencies": { "@internationalized/date": "^3.7.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-checkbox": "^1.1.5", "@radix-ui/react-dialog": "^1.1.15", diff --git a/examples/nextjs-ai-popup/package-lock.json b/examples/nextjs-ai-popup/package-lock.json index c444f66f204..18250063b8b 100644 --- a/examples/nextjs-ai-popup/package-lock.json +++ b/examples/nextjs-ai-popup/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-ai-popup", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.1.15", "@types/node": "^18.11.19", "@types/react": "^18.0.38", @@ -600,43 +600,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -653,15 +653,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-popup/package.json b/examples/nextjs-ai-popup/package.json index fdd588c5d82..1bd135a643b 100644 --- a/examples/nextjs-ai-popup/package.json +++ b/examples/nextjs-ai-popup/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.1.15", "@types/node": "^18.11.19", "@types/react": "^18.0.38", diff --git a/examples/nextjs-ai-support/package-lock.json b/examples/nextjs-ai-support/package-lock.json index 5fec96221e6..b21452651a3 100644 --- a/examples/nextjs-ai-support/package-lock.json +++ b/examples/nextjs-ai-support/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-ai-support", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.1.15", "@types/node": "^18.11.19", "@types/react": "^18.0.38", @@ -601,43 +601,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -654,15 +654,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-ai-support/package.json b/examples/nextjs-ai-support/package.json index f6754cfb927..bdbc7d632ce 100644 --- a/examples/nextjs-ai-support/package.json +++ b/examples/nextjs-ai-support/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.1.15", "@types/node": "^18.11.19", "@types/react": "^18.0.38", diff --git a/examples/nextjs-chat-sdk-ai-bot/package-lock.json b/examples/nextjs-chat-sdk-ai-bot/package-lock.json index 605051757e7..de42ab2cf03 100644 --- a/examples/nextjs-chat-sdk-ai-bot/package-lock.json +++ b/examples/nextjs-chat-sdk-ai-bot/package-lock.json @@ -9,11 +9,11 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.64", "@chat-adapter/state-memory": "^4.23.0", - "@liveblocks/chat-sdk-adapter": "^3.17.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/chat-sdk-adapter": "^3.18.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "ai": "^6.0.140", "chat": "^4.22.0", "next": "16.2.1", @@ -686,56 +686,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/chat-sdk-adapter": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/chat-sdk-adapter/-/chat-sdk-adapter-3.17.0.tgz", - "integrity": "sha512-sDEPJZ27SrVb3DMON2uAeJQ+827XcYgrQnob7qSgkPpvku/XDbC51lM1n+CfhpjzU/og+pmlQWkN2d/e5DRNZQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/chat-sdk-adapter/-/chat-sdk-adapter-3.18.0.tgz", + "integrity": "sha512-Abj0HH61ghlrTwaWmvTkooCJ/cijOfD7b32/+fbZNg98Ugcbtg8gaLIJ4fpFVDNZKbUsNOjpLuXDOnmoJfZQRA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "chat": ">=4.20.0" } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -752,15 +752,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-chat-sdk-ai-bot/package.json b/examples/nextjs-chat-sdk-ai-bot/package.json index aa38a7ddb8d..3d7a7100d53 100644 --- a/examples/nextjs-chat-sdk-ai-bot/package.json +++ b/examples/nextjs-chat-sdk-ai-bot/package.json @@ -11,11 +11,11 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.64", "@chat-adapter/state-memory": "^4.23.0", - "@liveblocks/chat-sdk-adapter": "^3.17.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/chat-sdk-adapter": "^3.18.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "ai": "^6.0.140", "chat": "^4.22.0", "next": "16.2.1", diff --git a/examples/nextjs-chat-sdk-bot/package-lock.json b/examples/nextjs-chat-sdk-bot/package-lock.json index 74582554612..4302e71881e 100644 --- a/examples/nextjs-chat-sdk-bot/package-lock.json +++ b/examples/nextjs-chat-sdk-bot/package-lock.json @@ -8,11 +8,11 @@ "license": "Apache-2.0", "dependencies": { "@chat-adapter/state-memory": "^4.23.0", - "@liveblocks/chat-sdk-adapter": "^3.17.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/chat-sdk-adapter": "^3.18.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "chat": "^4.22.0", "next": "16.2.1", "react": "19.2.4", @@ -621,56 +621,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/chat-sdk-adapter": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/chat-sdk-adapter/-/chat-sdk-adapter-3.17.0.tgz", - "integrity": "sha512-sDEPJZ27SrVb3DMON2uAeJQ+827XcYgrQnob7qSgkPpvku/XDbC51lM1n+CfhpjzU/og+pmlQWkN2d/e5DRNZQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/chat-sdk-adapter/-/chat-sdk-adapter-3.18.0.tgz", + "integrity": "sha512-Abj0HH61ghlrTwaWmvTkooCJ/cijOfD7b32/+fbZNg98Ugcbtg8gaLIJ4fpFVDNZKbUsNOjpLuXDOnmoJfZQRA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "chat": ">=4.20.0" } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -687,15 +687,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-chat-sdk-bot/package.json b/examples/nextjs-chat-sdk-bot/package.json index 5f70859fb40..c7d6c634a9b 100644 --- a/examples/nextjs-chat-sdk-bot/package.json +++ b/examples/nextjs-chat-sdk-bot/package.json @@ -10,11 +10,11 @@ }, "dependencies": { "@chat-adapter/state-memory": "^4.23.0", - "@liveblocks/chat-sdk-adapter": "^3.17.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/chat-sdk-adapter": "^3.18.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "chat": "^4.22.0", "next": "16.2.1", "react": "19.2.4", diff --git a/examples/nextjs-comments-ag-grid/package-lock.json b/examples/nextjs-comments-ag-grid/package-lock.json index 672612505ae..68e16222642 100644 --- a/examples/nextjs-comments-ag-grid/package-lock.json +++ b/examples/nextjs-comments-ag-grid/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-ag-grid", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "ag-grid-community": "^35.1.0", "ag-grid-react": "^35.1.0", "next": "^16.1.6", @@ -545,43 +545,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -598,15 +598,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-ag-grid/package.json b/examples/nextjs-comments-ag-grid/package.json index 61067251e72..15320177ce5 100644 --- a/examples/nextjs-comments-ag-grid/package.json +++ b/examples/nextjs-comments-ag-grid/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "ag-grid-community": "^35.1.0", "ag-grid-react": "^35.1.0", "next": "^16.1.6", diff --git a/examples/nextjs-comments-ai/package-lock.json b/examples/nextjs-comments-ai/package-lock.json index 1b3f3aa2489..95cc148b99d 100644 --- a/examples/nextjs-comments-ai/package-lock.json +++ b/examples/nextjs-comments-ai/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@ai-sdk/anthropic": "^3.0.64", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@tailwindcss/postcss": "^4.2.2", "ai": "^6.0.141", "next": "^16.1.6", @@ -1595,43 +1595,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1648,15 +1648,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-ai/package.json b/examples/nextjs-comments-ai/package.json index bc91cf27113..15ddad75074 100644 --- a/examples/nextjs-comments-ai/package.json +++ b/examples/nextjs-comments-ai/package.json @@ -10,10 +10,10 @@ }, "dependencies": { "@ai-sdk/anthropic": "^3.0.64", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@tailwindcss/postcss": "^4.2.2", "ai": "^6.0.141", "next": "^16.1.6", diff --git a/examples/nextjs-comments-audio/package-lock.json b/examples/nextjs-comments-audio/package-lock.json index 7927020977f..577b6072c7b 100644 --- a/examples/nextjs-comments-audio/package-lock.json +++ b/examples/nextjs-comments-audio/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-audio", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-tooltip": "^1.0.7", "@types/node": "20.3.3", @@ -616,43 +616,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -669,15 +669,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-audio/package.json b/examples/nextjs-comments-audio/package.json index 2eee68793f9..9b5fac64488 100644 --- a/examples/nextjs-comments-audio/package.json +++ b/examples/nextjs-comments-audio/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-tooltip": "^1.0.7", "@types/node": "20.3.3", diff --git a/examples/nextjs-comments-canvas/package-lock.json b/examples/nextjs-comments-canvas/package-lock.json index 01ea7c5c887..48561d53e08 100644 --- a/examples/nextjs-comments-canvas/package-lock.json +++ b/examples/nextjs-comments-canvas/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@dnd-kit/core": "^6.1.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -593,43 +593,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -646,15 +646,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-canvas/package.json b/examples/nextjs-comments-canvas/package.json index 85c60e45728..aaf9c1c5307 100644 --- a/examples/nextjs-comments-canvas/package.json +++ b/examples/nextjs-comments-canvas/package.json @@ -10,10 +10,10 @@ }, "dependencies": { "@dnd-kit/core": "^6.1.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/examples/nextjs-comments-emails-resend/package-lock.json b/examples/nextjs-comments-emails-resend/package-lock.json index 880a38e0f47..ca1500da904 100644 --- a/examples/nextjs-comments-emails-resend/package-lock.json +++ b/examples/nextjs-comments-emails-resend/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-comments-emails-resend", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@react-email/components": "^1.0.6", "@react-email/render": "1.0.6", "clsx": "^2.1.1", @@ -1206,56 +1206,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.17.0.tgz", - "integrity": "sha512-9IhyQILa2GgjrCGdHct07nG/NEWQZEKs1CqIHDUTh31mkm0Vws+Gttxlr6vVROiq+Rs8f48zsA7MgY4oHpc2NA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1272,15 +1272,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-emails-resend/package.json b/examples/nextjs-comments-emails-resend/package.json index 2b6f70bf2a2..00ba21259a9 100644 --- a/examples/nextjs-comments-emails-resend/package.json +++ b/examples/nextjs-comments-emails-resend/package.json @@ -11,11 +11,11 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@react-email/components": "^1.0.6", "@react-email/render": "1.0.6", "clsx": "^2.1.1", diff --git a/examples/nextjs-comments-emails-sendgrid/package-lock.json b/examples/nextjs-comments-emails-sendgrid/package-lock.json index 5b7c0252df4..1915fb0f21b 100644 --- a/examples/nextjs-comments-emails-sendgrid/package-lock.json +++ b/examples/nextjs-comments-emails-sendgrid/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-comments-emails-sendgrid", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@sendgrid/mail": "8.1.6", "clsx": "^2.1.1", "next": "^16.1.6", @@ -556,56 +556,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.17.0.tgz", - "integrity": "sha512-9IhyQILa2GgjrCGdHct07nG/NEWQZEKs1CqIHDUTh31mkm0Vws+Gttxlr6vVROiq+Rs8f48zsA7MgY4oHpc2NA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -622,15 +622,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-emails-sendgrid/package.json b/examples/nextjs-comments-emails-sendgrid/package.json index ce2a33206fb..8bf81b35c46 100644 --- a/examples/nextjs-comments-emails-sendgrid/package.json +++ b/examples/nextjs-comments-emails-sendgrid/package.json @@ -9,11 +9,11 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@sendgrid/mail": "8.1.6", "clsx": "^2.1.1", "next": "^16.1.6", diff --git a/examples/nextjs-comments-notifications/package-lock.json b/examples/nextjs-comments-notifications/package-lock.json index 6dd5ffa7712..dda6d563854 100644 --- a/examples/nextjs-comments-notifications/package-lock.json +++ b/examples/nextjs-comments-notifications/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-notifications", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.0.7", "clsx": "^2.1.1", "next": "^16.1.6", @@ -555,43 +555,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -608,15 +608,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-notifications/package.json b/examples/nextjs-comments-notifications/package.json index c2ebf5a8f0c..6443dd37ec6 100644 --- a/examples/nextjs-comments-notifications/package.json +++ b/examples/nextjs-comments-notifications/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-popover": "^1.0.7", "clsx": "^2.1.1", "next": "^16.1.6", diff --git a/examples/nextjs-comments-overlay/package-lock.json b/examples/nextjs-comments-overlay/package-lock.json index 893ec8e38bf..ca5bde80f3e 100644 --- a/examples/nextjs-comments-overlay/package-lock.json +++ b/examples/nextjs-comments-overlay/package-lock.json @@ -8,10 +8,10 @@ "name": "@liveblocks-examples/nextjs-comments-overlay", "version": "0.1.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "20.4.5", "@types/react-dom": "18.2.7", "clsx": "^2.0.0", @@ -99,43 +99,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -152,15 +152,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-overlay/package.json b/examples/nextjs-comments-overlay/package.json index 76e42b9876a..64cd42fbe82 100644 --- a/examples/nextjs-comments-overlay/package.json +++ b/examples/nextjs-comments-overlay/package.json @@ -11,10 +11,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "20.4.5", "@types/react-dom": "18.2.7", "clsx": "^2.0.0", diff --git a/examples/nextjs-comments-primitives/package-lock.json b/examples/nextjs-comments-primitives/package-lock.json index ad2c982c76a..f162beb6169 100644 --- a/examples/nextjs-comments-primitives/package-lock.json +++ b/examples/nextjs-comments-primitives/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-primitives", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "clsx": "^2.0.1", "frimousse": "^0.1.1", "next": "^16.1.6", @@ -625,43 +625,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -678,15 +678,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-primitives/package.json b/examples/nextjs-comments-primitives/package.json index 3aa047c9e97..9ada89686c7 100644 --- a/examples/nextjs-comments-primitives/package.json +++ b/examples/nextjs-comments-primitives/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "clsx": "^2.0.1", "frimousse": "^0.1.1", "next": "^16.1.6", diff --git a/examples/nextjs-comments-search/package-lock.json b/examples/nextjs-comments-search/package-lock.json index 5fff8143da7..e15ad114578 100644 --- a/examples/nextjs-comments-search/package-lock.json +++ b/examples/nextjs-comments-search/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-search", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -553,43 +553,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -606,15 +606,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-search/package.json b/examples/nextjs-comments-search/package.json index b55e1bea465..565995281b5 100644 --- a/examples/nextjs-comments-search/package.json +++ b/examples/nextjs-comments-search/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/examples/nextjs-comments-tiptap/package-lock.json b/examples/nextjs-comments-tiptap/package-lock.json index 43b1a3facbc..7d572105696 100644 --- a/examples/nextjs-comments-tiptap/package-lock.json +++ b/examples/nextjs-comments-tiptap/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-comments-tiptap", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-select": "^1.1.2", "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", @@ -569,43 +569,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -622,17 +622,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -660,15 +660,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -693,13 +693,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-comments-tiptap/package.json b/examples/nextjs-comments-tiptap/package.json index aea848ca012..4f8f03f5bfd 100644 --- a/examples/nextjs-comments-tiptap/package.json +++ b/examples/nextjs-comments-tiptap/package.json @@ -10,11 +10,11 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-select": "^1.1.2", "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", diff --git a/examples/nextjs-comments-video/package-lock.json b/examples/nextjs-comments-video/package-lock.json index f4980b0d93d..94e21b4ade9 100644 --- a/examples/nextjs-comments-video/package-lock.json +++ b/examples/nextjs-comments-video/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments-video", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-tooltip": "^1.0.7", "@types/node": "20.3.3", @@ -557,43 +557,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -610,15 +610,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments-video/package.json b/examples/nextjs-comments-video/package.json index 0a60b090335..0b84f6336f7 100644 --- a/examples/nextjs-comments-video/package.json +++ b/examples/nextjs-comments-video/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-tooltip": "^1.0.7", "@types/node": "20.3.3", diff --git a/examples/nextjs-comments/package-lock.json b/examples/nextjs-comments/package-lock.json index a721fc8e503..b5264452bd4 100644 --- a/examples/nextjs-comments/package-lock.json +++ b/examples/nextjs-comments/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-comments", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -553,43 +553,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -606,15 +606,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-comments/package.json b/examples/nextjs-comments/package.json index 2714314adfa..c00aaa0a965 100644 --- a/examples/nextjs-comments/package.json +++ b/examples/nextjs-comments/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/examples/nextjs-connection-status/package-lock.json b/examples/nextjs-connection-status/package-lock.json index 03de237e477..911ea037696 100644 --- a/examples/nextjs-connection-status/package-lock.json +++ b/examples/nextjs-connection-status/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-connection-status", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@types/node": "^20.3.3", "@types/react": "^18.3.27", "@types/react-dom": "^18.2.25", @@ -499,31 +499,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-connection-status/package.json b/examples/nextjs-connection-status/package.json index bf2b5f69244..78c3c3844e8 100644 --- a/examples/nextjs-connection-status/package.json +++ b/examples/nextjs-connection-status/package.json @@ -10,8 +10,8 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@types/node": "^20.3.3", "@types/react": "^18.3.27", "@types/react-dom": "^18.2.25", diff --git a/examples/nextjs-dashboard/package-lock.json b/examples/nextjs-dashboard/package-lock.json index 1870cce7ceb..f8fe2d9bfe9 100644 --- a/examples/nextjs-dashboard/package-lock.json +++ b/examples/nextjs-dashboard/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-dashboard", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", @@ -509,31 +509,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-dashboard/package.json b/examples/nextjs-dashboard/package.json index 7490c2ece88..7bf0ddb8505 100644 --- a/examples/nextjs-dashboard/package.json +++ b/examples/nextjs-dashboard/package.json @@ -4,8 +4,8 @@ "license": "Apache-2.0", "private": true, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/examples/nextjs-flowchart-builder/package-lock.json b/examples/nextjs-flowchart-builder/package-lock.json index 11f9407842b..87016d8d1f2 100644 --- a/examples/nextjs-flowchart-builder/package-lock.json +++ b/examples/nextjs-flowchart-builder/package-lock.json @@ -8,11 +8,11 @@ "license": "Apache-2.0", "dependencies": { "@dnd-kit/core": "^6.3.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "nanoid": "^5.1.7", "next": "^16.1.6", @@ -557,43 +557,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -610,15 +610,15 @@ } }, "node_modules/@liveblocks/react-flow": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.17.0.tgz", - "integrity": "sha512-pAuFm827OdvDW8s7i/qMEU+/5E2pJ59m/3h9hkGEEC80XdQt1urWDPwW2TYPnsRvfs7dZXe6n7bp4AdYOyfV4A==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.18.0.tgz", + "integrity": "sha512-uy+WUi2/kqV4UXTWFmNR8WoPc87uI0TUFkU+KMGp9p6DMgGKCaY3oJ5UYMmIUTFgguczp8KV3RyhKYkGERXp4A==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0" }, "peerDependencies": { "@xyflow/react": "^12", @@ -635,15 +635,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-flowchart-builder/package.json b/examples/nextjs-flowchart-builder/package.json index 37dc30af0e7..eb197e5c113 100644 --- a/examples/nextjs-flowchart-builder/package.json +++ b/examples/nextjs-flowchart-builder/package.json @@ -11,11 +11,11 @@ }, "dependencies": { "@dnd-kit/core": "^6.3.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "nanoid": "^5.1.7", "next": "^16.1.6", diff --git a/examples/nextjs-form/package-lock.json b/examples/nextjs-form/package-lock.json index 09cf9bed0ad..6106b1d4df0 100644 --- a/examples/nextjs-form/package-lock.json +++ b/examples/nextjs-form/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-form", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -498,43 +498,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-form/package.json b/examples/nextjs-form/package.json index 99469cf085e..cbfd9a1c711 100644 --- a/examples/nextjs-form/package.json +++ b/examples/nextjs-form/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-lexical-emails-resend/package-lock.json b/examples/nextjs-lexical-emails-resend/package-lock.json index 1e79eafeced..b2005dbc04f 100644 --- a/examples/nextjs-lexical-emails-resend/package-lock.json +++ b/examples/nextjs-lexical-emails-resend/package-lock.json @@ -12,12 +12,12 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@react-email/components": "^1.0.6", @@ -1439,56 +1439,56 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.17.0.tgz", - "integrity": "sha512-9IhyQILa2GgjrCGdHct07nG/NEWQZEKs1CqIHDUTh31mkm0Vws+Gttxlr6vVROiq+Rs8f48zsA7MgY4oHpc2NA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1505,17 +1505,17 @@ } }, "node_modules/@liveblocks/react-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.17.0.tgz", - "integrity": "sha512-JYjh7h8ijabyivDCK+6j93pJz9ojyiBLbcZyl4wIJTYcNuTqucAlOs6bf2Ko49uNr+gG8GSxn1B7SB/1oFfT0g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.18.0.tgz", + "integrity": "sha512-ZgipJ9FzzRBrnBd/eOBCX3GPyC2qyZgDdgQbLClHljJn4nJ+iUa/vs5k4ZQkgXtTaPC250kolad6HW+IhAdTMA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, @@ -1541,15 +1541,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -1574,13 +1574,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-lexical-emails-resend/package.json b/examples/nextjs-lexical-emails-resend/package.json index ea2c9620297..a86850e0066 100644 --- a/examples/nextjs-lexical-emails-resend/package.json +++ b/examples/nextjs-lexical-emails-resend/package.json @@ -17,12 +17,12 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@react-email/components": "^1.0.6", diff --git a/examples/nextjs-lexical/package-lock.json b/examples/nextjs-lexical/package-lock.json index 6191cd7585a..a602e95edec 100644 --- a/examples/nextjs-lexical/package-lock.json +++ b/examples/nextjs-lexical/package-lock.json @@ -12,11 +12,11 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@types/node": "^18.11.19", @@ -886,43 +886,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -939,17 +939,17 @@ } }, "node_modules/@liveblocks/react-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.17.0.tgz", - "integrity": "sha512-JYjh7h8ijabyivDCK+6j93pJz9ojyiBLbcZyl4wIJTYcNuTqucAlOs6bf2Ko49uNr+gG8GSxn1B7SB/1oFfT0g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.18.0.tgz", + "integrity": "sha512-ZgipJ9FzzRBrnBd/eOBCX3GPyC2qyZgDdgQbLClHljJn4nJ+iUa/vs5k4ZQkgXtTaPC250kolad6HW+IhAdTMA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, @@ -975,15 +975,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -1008,13 +1008,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-lexical/package.json b/examples/nextjs-lexical/package.json index 9702f70bf5c..9c76d7381b3 100644 --- a/examples/nextjs-lexical/package.json +++ b/examples/nextjs-lexical/package.json @@ -15,11 +15,11 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@types/node": "^18.11.19", diff --git a/examples/nextjs-linear-like-issue-tracker/package-lock.json b/examples/nextjs-linear-like-issue-tracker/package-lock.json index 72993f0f97b..610d2c0cb34 100644 --- a/examples/nextjs-linear-like-issue-tracker/package-lock.json +++ b/examples/nextjs-linear-like-issue-tracker/package-lock.json @@ -8,12 +8,12 @@ "license": "Apache-2.0", "dependencies": { "@lexical/react": "^0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/node-lexical": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/node-lexical": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-select": "^2.1.7", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", @@ -917,43 +917,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/node-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node-lexical/-/node-lexical-3.17.0.tgz", - "integrity": "sha512-g1qcu7ywaUt4uaWKRbFB0SfIeWlW8MS5JjFr0M/2AGmbYFctm04HlzsyMLhqaMH2WNJg0FfERndWIyoWuRQGvw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node-lexical/-/node-lexical-3.18.0.tgz", + "integrity": "sha512-SUgYOzO8lpd34DA6vGNpqOZAjfeyXniDoACmANhmNr5pLdefViP/po1X3eoGFUpYAtArObb2oZWk2Rx9ZTP1Sg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.18" }, "peerDependencies": { @@ -965,13 +965,13 @@ } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -988,17 +988,17 @@ } }, "node_modules/@liveblocks/react-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.17.0.tgz", - "integrity": "sha512-JYjh7h8ijabyivDCK+6j93pJz9ojyiBLbcZyl4wIJTYcNuTqucAlOs6bf2Ko49uNr+gG8GSxn1B7SB/1oFfT0g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.18.0.tgz", + "integrity": "sha512-ZgipJ9FzzRBrnBd/eOBCX3GPyC2qyZgDdgQbLClHljJn4nJ+iUa/vs5k4ZQkgXtTaPC250kolad6HW+IhAdTMA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, @@ -1024,15 +1024,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -1069,13 +1069,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-linear-like-issue-tracker/package.json b/examples/nextjs-linear-like-issue-tracker/package.json index 11d445d0426..d6055014244 100644 --- a/examples/nextjs-linear-like-issue-tracker/package.json +++ b/examples/nextjs-linear-like-issue-tracker/package.json @@ -11,12 +11,12 @@ }, "dependencies": { "@lexical/react": "^0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/node-lexical": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/node-lexical": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-select": "^2.1.7", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", diff --git a/examples/nextjs-linear-like-issue-tracker/src/liveblocks.config.ts b/examples/nextjs-linear-like-issue-tracker/src/liveblocks.config.ts index 920ad7f2653..9dac20e72c5 100644 --- a/examples/nextjs-linear-like-issue-tracker/src/liveblocks.config.ts +++ b/examples/nextjs-linear-like-issue-tracker/src/liveblocks.config.ts @@ -1,4 +1,4 @@ -import { LiveList, LiveObject, ToImmutable } from "@liveblocks/client"; +import { LiveList, LiveObject, ToJson } from "@liveblocks/client"; import { Metadata, PriorityState, ProgressState } from "@/config"; declare global { @@ -31,4 +31,4 @@ declare global { } } -export type ImmutableStorage = ToImmutable; +export type ImmutableStorage = ToJson; diff --git a/examples/nextjs-live-avatars-advanced/package-lock.json b/examples/nextjs-live-avatars-advanced/package-lock.json index d82095653bd..4d1a481435a 100644 --- a/examples/nextjs-live-avatars-advanced/package-lock.json +++ b/examples/nextjs-live-avatars-advanced/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-live-avatars-advanced", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "classnames": "^2.3.3", "framer-motion": "^10.16.16", "next": "^16.1.6", @@ -520,43 +520,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-live-avatars-advanced/package.json b/examples/nextjs-live-avatars-advanced/package.json index 10bb49bbbc5..f2bb4664550 100644 --- a/examples/nextjs-live-avatars-advanced/package.json +++ b/examples/nextjs-live-avatars-advanced/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "classnames": "^2.3.3", "framer-motion": "^10.16.16", "next": "^16.1.6", diff --git a/examples/nextjs-live-avatars/package-lock.json b/examples/nextjs-live-avatars/package-lock.json index 79b024cd532..ce96592011d 100644 --- a/examples/nextjs-live-avatars/package-lock.json +++ b/examples/nextjs-live-avatars/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-live-avatars", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -599,43 +599,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -652,15 +652,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-live-avatars/package.json b/examples/nextjs-live-avatars/package.json index b8c4a32bad0..c9f176292b6 100644 --- a/examples/nextjs-live-avatars/package.json +++ b/examples/nextjs-live-avatars/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-live-cursors-advanced/package-lock.json b/examples/nextjs-live-cursors-advanced/package-lock.json index b1f1ccfb4e9..81d7c74ca1d 100644 --- a/examples/nextjs-live-cursors-advanced/package-lock.json +++ b/examples/nextjs-live-cursors-advanced/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-live-cursors-advanced", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "framer-motion": "^10.16.16", "next": "^16.1.6", "react": "^18.3.1", @@ -519,43 +519,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-live-cursors-advanced/package.json b/examples/nextjs-live-cursors-advanced/package.json index 21ceac1a239..03ad96062f2 100644 --- a/examples/nextjs-live-cursors-advanced/package.json +++ b/examples/nextjs-live-cursors-advanced/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "framer-motion": "^10.16.16", "next": "^16.1.6", "react": "^18.3.1", diff --git a/examples/nextjs-live-cursors-chat/package-lock.json b/examples/nextjs-live-cursors-chat/package-lock.json index 26e168d4cfd..93835016e59 100644 --- a/examples/nextjs-live-cursors-chat/package-lock.json +++ b/examples/nextjs-live-cursors-chat/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-live-cursors-chat", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -554,43 +554,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-live-cursors-chat/package.json b/examples/nextjs-live-cursors-chat/package.json index 1de62ddd05e..ec5b1955be1 100644 --- a/examples/nextjs-live-cursors-chat/package.json +++ b/examples/nextjs-live-cursors-chat/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-live-cursors-scroll/package-lock.json b/examples/nextjs-live-cursors-scroll/package-lock.json index acb6b666230..04116428865 100644 --- a/examples/nextjs-live-cursors-scroll/package-lock.json +++ b/examples/nextjs-live-cursors-scroll/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-live-cursors-scroll", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -553,31 +553,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-live-cursors-scroll/package.json b/examples/nextjs-live-cursors-scroll/package.json index c97061ed0ae..b92d4cd3628 100644 --- a/examples/nextjs-live-cursors-scroll/package.json +++ b/examples/nextjs-live-cursors-scroll/package.json @@ -9,8 +9,8 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-live-cursors/package-lock.json b/examples/nextjs-live-cursors/package-lock.json index cab5a55e3a3..1e700fdb6a3 100644 --- a/examples/nextjs-live-cursors/package-lock.json +++ b/examples/nextjs-live-cursors/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-live-cusors", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@next/font": "^13.5.11", "@types/node": "^18.11.19", "@types/react": "^18.3.27", @@ -545,43 +545,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -598,15 +598,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-live-cursors/package.json b/examples/nextjs-live-cursors/package.json index 7d743a0292b..18dc115b6a1 100644 --- a/examples/nextjs-live-cursors/package.json +++ b/examples/nextjs-live-cursors/package.json @@ -9,10 +9,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@next/font": "^13.5.11", "@types/node": "^18.11.19", "@types/react": "^18.3.27", diff --git a/examples/nextjs-live-form-selection/package-lock.json b/examples/nextjs-live-form-selection/package-lock.json index 1d1a68c722a..609d611654d 100644 --- a/examples/nextjs-live-form-selection/package-lock.json +++ b/examples/nextjs-live-form-selection/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-live-form-selection", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -497,31 +497,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-live-form-selection/package.json b/examples/nextjs-live-form-selection/package.json index 1feb93167a6..1556c56aaf2 100644 --- a/examples/nextjs-live-form-selection/package.json +++ b/examples/nextjs-live-form-selection/package.json @@ -9,8 +9,8 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-nextauth-google-avatars/package-lock.json b/examples/nextjs-nextauth-google-avatars/package-lock.json index 1c9fdb40164..a7626b108b1 100644 --- a/examples/nextjs-nextauth-google-avatars/package-lock.json +++ b/examples/nextjs-nextauth-google-avatars/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-live-avatars", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "classnames": "^2.3.3", "next": "^16.1.6", "next-auth": "^4.23.2", @@ -2269,43 +2269,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-nextauth-google-avatars/package.json b/examples/nextjs-nextauth-google-avatars/package.json index 93a29300d42..23519bd8516 100644 --- a/examples/nextjs-nextauth-google-avatars/package.json +++ b/examples/nextjs-nextauth-google-avatars/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "classnames": "^2.3.3", "next": "^16.1.6", "next-auth": "^4.23.2", diff --git a/examples/nextjs-notification-settings/package-lock.json b/examples/nextjs-notification-settings/package-lock.json index 3a4266df797..c8aeaa6e412 100644 --- a/examples/nextjs-notification-settings/package-lock.json +++ b/examples/nextjs-notification-settings/package-lock.json @@ -8,14 +8,14 @@ "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.6", - "@liveblocks/client": "^3.17.0", - "@liveblocks/core": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/core": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", @@ -653,56 +653,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.17.0.tgz", - "integrity": "sha512-9IhyQILa2GgjrCGdHct07nG/NEWQZEKs1CqIHDUTh31mkm0Vws+Gttxlr6vVROiq+Rs8f48zsA7MgY4oHpc2NA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -719,17 +719,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -757,15 +757,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -790,13 +790,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-notification-settings/package.json b/examples/nextjs-notification-settings/package.json index 22d3ed2f9de..c48603527ab 100644 --- a/examples/nextjs-notification-settings/package.json +++ b/examples/nextjs-notification-settings/package.json @@ -13,14 +13,14 @@ }, "dependencies": { "@floating-ui/react-dom": "^2.1.6", - "@liveblocks/client": "^3.17.0", - "@liveblocks/core": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/core": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", diff --git a/examples/nextjs-notifications-custom/package-lock.json b/examples/nextjs-notifications-custom/package-lock.json index 9757ed1c8cf..a5270a13778 100644 --- a/examples/nextjs-notifications-custom/package-lock.json +++ b/examples/nextjs-notifications-custom/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-notifications-custom", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "clsx": "^2.1.1", "nanoid": "^5.0.9", "next": "^16.1.6", @@ -555,43 +555,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -608,15 +608,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-notifications-custom/package.json b/examples/nextjs-notifications-custom/package.json index adbada90759..6034e720389 100644 --- a/examples/nextjs-notifications-custom/package.json +++ b/examples/nextjs-notifications-custom/package.json @@ -9,10 +9,10 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "clsx": "^2.1.1", "nanoid": "^5.0.9", "next": "^16.1.6", diff --git a/examples/nextjs-notion-like-ai-editor/package-lock.json b/examples/nextjs-notion-like-ai-editor/package-lock.json index 43f65041c3e..87a887348df 100644 --- a/examples/nextjs-notion-like-ai-editor/package-lock.json +++ b/examples/nextjs-notion-like-ai-editor/package-lock.json @@ -17,12 +17,12 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/node-lexical": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/node-lexical": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@types/node": "^18.11.19", @@ -1038,43 +1038,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/node-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node-lexical/-/node-lexical-3.17.0.tgz", - "integrity": "sha512-g1qcu7ywaUt4uaWKRbFB0SfIeWlW8MS5JjFr0M/2AGmbYFctm04HlzsyMLhqaMH2WNJg0FfERndWIyoWuRQGvw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node-lexical/-/node-lexical-3.18.0.tgz", + "integrity": "sha512-SUgYOzO8lpd34DA6vGNpqOZAjfeyXniDoACmANhmNr5pLdefViP/po1X3eoGFUpYAtArObb2oZWk2Rx9ZTP1Sg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0", "yjs": "^13.6.18" }, "peerDependencies": { @@ -1086,13 +1086,13 @@ } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1109,17 +1109,17 @@ } }, "node_modules/@liveblocks/react-lexical": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.17.0.tgz", - "integrity": "sha512-JYjh7h8ijabyivDCK+6j93pJz9ojyiBLbcZyl4wIJTYcNuTqucAlOs6bf2Ko49uNr+gG8GSxn1B7SB/1oFfT0g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-lexical/-/react-lexical-3.18.0.tgz", + "integrity": "sha512-ZgipJ9FzzRBrnBd/eOBCX3GPyC2qyZgDdgQbLClHljJn4nJ+iUa/vs5k4ZQkgXtTaPC250kolad6HW+IhAdTMA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "radix-ui": "^1.4.0", "yjs": "^13.6.18" }, @@ -1145,15 +1145,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -1178,13 +1178,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-notion-like-ai-editor/package.json b/examples/nextjs-notion-like-ai-editor/package.json index 9f93f37bbcf..03f7d758737 100644 --- a/examples/nextjs-notion-like-ai-editor/package.json +++ b/examples/nextjs-notion-like-ai-editor/package.json @@ -20,12 +20,12 @@ "@lexical/rich-text": "0.35.0", "@lexical/selection": "0.35.0", "@lexical/utils": "0.35.0", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/node-lexical": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-lexical": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/node-lexical": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-lexical": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@types/node": "^18.11.19", diff --git a/examples/nextjs-react-flow-ai/package-lock.json b/examples/nextjs-react-flow-ai/package-lock.json index f14380794c4..171102a222e 100644 --- a/examples/nextjs-react-flow-ai/package-lock.json +++ b/examples/nextjs-react-flow-ai/package-lock.json @@ -8,11 +8,11 @@ "license": "Apache-2.0", "dependencies": { "@ai-sdk/openai": "^3.0.48", - "@liveblocks/client": "3.18.0-rc1", - "@liveblocks/node": "3.18.0-rc1", - "@liveblocks/react": "3.18.0-rc1", - "@liveblocks/react-flow": "3.18.0-rc1", - "@liveblocks/react-ui": "3.18.0-rc1", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "ai": "^6.0.136", "dedent": "^1.7.2", @@ -582,43 +582,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0-rc1.tgz", - "integrity": "sha512-0vKVmUVI4qmrvXqUWnmNxJIA3TdIBHYKGApbkRWJNZcUpPjCDi6FII6kEix8/HIPkoBLlLwnI1qXBkDzrEX9tQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.18.0-rc1" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0-rc1.tgz", - "integrity": "sha512-f7X0So8GMHUKmLH+Yep9N8qWtvmISiV4cY2orHr/0JgyA23hhIJFylesdRt7lCzyleA0TvY/sBtTPzUNrhDo0Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0-rc1.tgz", - "integrity": "sha512-8eGpKSC2pM+NZw9cF5ZBRk8NIR64kfeLozaq/HuPYd8XoTxmVyTdbCZIKTYoLj/cZQ3eCd7vw2jvqUbkFBIkrQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.18.0-rc1", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0-rc1.tgz", - "integrity": "sha512-+EFMryb+lcIjREUEGLiWTS7VSlaC3PsO/PJbszvKbpC1mJ4lwNqz+En4Aeqg4VCHoD+nIQCq0CRCeZ2x2ZDOow==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.18.0-rc1", - "@liveblocks/core": "3.18.0-rc1" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -635,15 +635,15 @@ } }, "node_modules/@liveblocks/react-flow": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.18.0-rc1.tgz", - "integrity": "sha512-2ZCR+DhrPvQyvDt/5ILxZ7bwjJa6Ci7xaCAvulYTzZuWJLZrQiQpKqMBzSBiQ08wI7sNGDiNv62VsnMBA0t57g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.18.0.tgz", + "integrity": "sha512-uy+WUi2/kqV4UXTWFmNR8WoPc87uI0TUFkU+KMGp9p6DMgGKCaY3oJ5UYMmIUTFgguczp8KV3RyhKYkGERXp4A==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.18.0-rc1", - "@liveblocks/core": "3.18.0-rc1", - "@liveblocks/react": "3.18.0-rc1", - "@liveblocks/react-ui": "3.18.0-rc1" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0" }, "peerDependencies": { "@xyflow/react": "^12", @@ -660,15 +660,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.18.0-rc1", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0-rc1.tgz", - "integrity": "sha512-uy4aNWlW+yxAi4d1Kof3pxYdDr2Dv8pGeEpy+xDlbrE67y/A6XdBKPjqQxvST4ZpRQ7Kh0Z/JNCd2BZSZyVCRw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.18.0-rc1", - "@liveblocks/core": "3.18.0-rc1", - "@liveblocks/react": "3.18.0-rc1", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-react-flow-ai/package.json b/examples/nextjs-react-flow-ai/package.json index 0f656e08711..47bc75a7549 100644 --- a/examples/nextjs-react-flow-ai/package.json +++ b/examples/nextjs-react-flow-ai/package.json @@ -11,11 +11,11 @@ }, "dependencies": { "@ai-sdk/openai": "^3.0.48", - "@liveblocks/client": "3.18.0-rc1", - "@liveblocks/node": "3.18.0-rc1", - "@liveblocks/react": "3.18.0-rc1", - "@liveblocks/react-flow": "3.18.0-rc1", - "@liveblocks/react-ui": "3.18.0-rc1", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "ai": "^6.0.136", "dedent": "^1.7.2", diff --git a/examples/nextjs-react-flow/package-lock.json b/examples/nextjs-react-flow/package-lock.json index 97ac7190c72..8326f408748 100644 --- a/examples/nextjs-react-flow/package-lock.json +++ b/examples/nextjs-react-flow/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-react-flow", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "next": "^16.1.6", "react": "^18.3.1", @@ -579,43 +579,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -632,15 +632,15 @@ } }, "node_modules/@liveblocks/react-flow": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.17.0.tgz", - "integrity": "sha512-pAuFm827OdvDW8s7i/qMEU+/5E2pJ59m/3h9hkGEEC80XdQt1urWDPwW2TYPnsRvfs7dZXe6n7bp4AdYOyfV4A==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-flow/-/react-flow-3.18.0.tgz", + "integrity": "sha512-uy+WUi2/kqV4UXTWFmNR8WoPc87uI0TUFkU+KMGp9p6DMgGKCaY3oJ5UYMmIUTFgguczp8KV3RyhKYkGERXp4A==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0" }, "peerDependencies": { "@xyflow/react": "^12", @@ -657,15 +657,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-react-flow/package.json b/examples/nextjs-react-flow/package.json index 4a3519cb287..4f570c9cbd9 100644 --- a/examples/nextjs-react-flow/package.json +++ b/examples/nextjs-react-flow/package.json @@ -10,11 +10,11 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-flow": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-flow": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@xyflow/react": "^12.10.1", "next": "^16.1.6", "react": "^18.3.1", diff --git a/examples/nextjs-spreadsheet-advanced/package-lock.json b/examples/nextjs-spreadsheet-advanced/package-lock.json index f6a2c9a303a..7afc531f480 100644 --- a/examples/nextjs-spreadsheet-advanced/package-lock.json +++ b/examples/nextjs-spreadsheet-advanced/package-lock.json @@ -11,9 +11,9 @@ "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.2", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@radix-ui/react-dropdown-menu": "^1.0.0", "@radix-ui/react-tooltip": "^1.0.7", "@use-gesture/react": "^10.3.1", @@ -2808,43 +2808,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-spreadsheet-advanced/package.json b/examples/nextjs-spreadsheet-advanced/package.json index a7dfd1c3708..654fa856f46 100644 --- a/examples/nextjs-spreadsheet-advanced/package.json +++ b/examples/nextjs-spreadsheet-advanced/package.json @@ -13,9 +13,9 @@ "@dnd-kit/modifiers": "^6.0.1", "@dnd-kit/sortable": "^7.0.2", "@dnd-kit/utilities": "^3.2.2", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@radix-ui/react-dropdown-menu": "^1.0.0", "@radix-ui/react-tooltip": "^1.0.7", "@use-gesture/react": "^10.3.1", diff --git a/examples/nextjs-tiptap-advanced/package-lock.json b/examples/nextjs-tiptap-advanced/package-lock.json index d5f0c5d0896..9ef75ecca57 100644 --- a/examples/nextjs-tiptap-advanced/package-lock.json +++ b/examples/nextjs-tiptap-advanced/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-tiptap-advanced", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^1.1.2", @@ -571,43 +571,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -624,17 +624,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -662,15 +662,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -695,13 +695,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-tiptap-advanced/package.json b/examples/nextjs-tiptap-advanced/package.json index 60e7825e7c0..96055717335 100644 --- a/examples/nextjs-tiptap-advanced/package.json +++ b/examples/nextjs-tiptap-advanced/package.json @@ -10,11 +10,11 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-select": "^1.1.2", diff --git a/examples/nextjs-tiptap-ai/package-lock.json b/examples/nextjs-tiptap-ai/package-lock.json index c86c0faf9f7..59ee1d70168 100644 --- a/examples/nextjs-tiptap-ai/package-lock.json +++ b/examples/nextjs-tiptap-ai/package-lock.json @@ -9,12 +9,12 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.25", "@ai-sdk/openai-compatible": "^0.1.17", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@tiptap/pm": "^3.4.6", @@ -723,43 +723,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -776,17 +776,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -814,15 +814,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -847,13 +847,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-tiptap-ai/package.json b/examples/nextjs-tiptap-ai/package.json index e47b3da555a..7b8fc1c3339 100644 --- a/examples/nextjs-tiptap-ai/package.json +++ b/examples/nextjs-tiptap-ai/package.json @@ -12,12 +12,12 @@ "dependencies": { "@ai-sdk/anthropic": "^3.0.25", "@ai-sdk/openai-compatible": "^0.1.17", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@tiptap/pm": "^3.4.6", diff --git a/examples/nextjs-tiptap-emails-resend/package-lock.json b/examples/nextjs-tiptap-emails-resend/package-lock.json index 368295425ff..1ab716efa5e 100644 --- a/examples/nextjs-tiptap-emails-resend/package-lock.json +++ b/examples/nextjs-tiptap-emails-resend/package-lock.json @@ -7,13 +7,13 @@ "name": "@liveblocks-examples/nextjs-tiptap-emails-resend", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@react-email/components": "^1.0.6", @@ -1179,56 +1179,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.17.0.tgz", - "integrity": "sha512-9IhyQILa2GgjrCGdHct07nG/NEWQZEKs1CqIHDUTh31mkm0Vws+Gttxlr6vVROiq+Rs8f48zsA7MgY4oHpc2NA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", - "@liveblocks/node": "3.17.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1245,17 +1245,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -1283,15 +1283,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -1316,13 +1316,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-tiptap-emails-resend/package.json b/examples/nextjs-tiptap-emails-resend/package.json index 3424a8cdf94..83d2fa00164 100644 --- a/examples/nextjs-tiptap-emails-resend/package.json +++ b/examples/nextjs-tiptap-emails-resend/package.json @@ -12,13 +12,13 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/emails": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@react-email/components": "^1.0.6", diff --git a/examples/nextjs-tiptap/package-lock.json b/examples/nextjs-tiptap/package-lock.json index 9f7b68818f4..de36d68986a 100644 --- a/examples/nextjs-tiptap/package-lock.json +++ b/examples/nextjs-tiptap/package-lock.json @@ -7,12 +7,12 @@ "name": "@liveblocks-examples/nextjs-tiptap", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@tiptap/pm": "^3.4.6", @@ -605,43 +605,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -658,17 +658,17 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.17.0.tgz", - "integrity": "sha512-IVAN5sZCOTtGy8alKw4EpArikBLu/dwjvbNya5IaH3ZiO6eoYmPFbHxinVN08BKPe208YjhZWefwrFr7bKAVNw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", - "@liveblocks/react-ui": "3.17.0", - "@liveblocks/yjs": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", @@ -696,15 +696,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -729,13 +729,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-tiptap/package.json b/examples/nextjs-tiptap/package.json index d8c7901e5e6..222f4533933 100644 --- a/examples/nextjs-tiptap/package.json +++ b/examples/nextjs-tiptap/package.json @@ -10,12 +10,12 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-tiptap": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-popover": "^1.0.7", "@tiptap/pm": "^3.4.6", diff --git a/examples/nextjs-tldraw-whiteboard-storage/package-lock.json b/examples/nextjs-tldraw-whiteboard-storage/package-lock.json index aef57e5ad5d..14d61edc294 100644 --- a/examples/nextjs-tldraw-whiteboard-storage/package-lock.json +++ b/examples/nextjs-tldraw-whiteboard-storage/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-tldraw-whiteboard-storage", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", "autoprefixer": "^10.4.23", @@ -556,43 +556,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -609,15 +609,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/nextjs-tldraw-whiteboard-storage/package.json b/examples/nextjs-tldraw-whiteboard-storage/package.json index a2594069f99..f3b59d7c9aa 100644 --- a/examples/nextjs-tldraw-whiteboard-storage/package.json +++ b/examples/nextjs-tldraw-whiteboard-storage/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", "autoprefixer": "^10.4.23", diff --git a/examples/nextjs-tldraw-whiteboard-yjs/package-lock.json b/examples/nextjs-tldraw-whiteboard-yjs/package-lock.json index eda38e22c62..136ea16726b 100644 --- a/examples/nextjs-tldraw-whiteboard-yjs/package-lock.json +++ b/examples/nextjs-tldraw-whiteboard-yjs/package-lock.json @@ -7,11 +7,11 @@ "name": "@liveblocks-examples/nextjs-tldraw-whiteboard-yjs", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", "autoprefixer": "^10.4.23", @@ -559,43 +559,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -612,15 +612,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", @@ -645,13 +645,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-tldraw-whiteboard-yjs/package.json b/examples/nextjs-tldraw-whiteboard-yjs/package.json index 89f7e1b5338..547046c9988 100644 --- a/examples/nextjs-tldraw-whiteboard-yjs/package.json +++ b/examples/nextjs-tldraw-whiteboard-yjs/package.json @@ -10,11 +10,11 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react-dom": "18.2.25", "autoprefixer": "^10.4.23", diff --git a/examples/nextjs-todo-list/package-lock.json b/examples/nextjs-todo-list/package-lock.json index 9f583d655b8..674a080a4dc 100644 --- a/examples/nextjs-todo-list/package-lock.json +++ b/examples/nextjs-todo-list/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/nextjs-todo-list", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@next/font": "^13.1.6", "@types/node": "^18.11.19", "@types/react": "^18.3.27", @@ -500,31 +500,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-todo-list/package.json b/examples/nextjs-todo-list/package.json index 8221805b52b..413614ef0a4 100644 --- a/examples/nextjs-todo-list/package.json +++ b/examples/nextjs-todo-list/package.json @@ -13,8 +13,8 @@ "test:ui": "playwright test --ui" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "@next/font": "^13.1.6", "@types/node": "^18.11.19", "@types/react": "^18.3.27", diff --git a/examples/nextjs-whiteboard-advanced/package-lock.json b/examples/nextjs-whiteboard-advanced/package-lock.json index e35602b8062..6005337d10b 100644 --- a/examples/nextjs-whiteboard-advanced/package-lock.json +++ b/examples/nextjs-whiteboard-advanced/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-whiteboard-advanced", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "nanoid": "^3.1.32", "next": "^16.1.6", "perfect-freehand": "^0.5.4", @@ -556,43 +556,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-whiteboard-advanced/package.json b/examples/nextjs-whiteboard-advanced/package.json index f09ed07b6a5..d8149f9cc99 100644 --- a/examples/nextjs-whiteboard-advanced/package.json +++ b/examples/nextjs-whiteboard-advanced/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "nanoid": "^3.1.32", "next": "^16.1.6", "perfect-freehand": "^0.5.4", diff --git a/examples/nextjs-whiteboard-advanced/src/components/LayerComponent.tsx b/examples/nextjs-whiteboard-advanced/src/components/LayerComponent.tsx index 869bda4ee0a..06c60092ba8 100644 --- a/examples/nextjs-whiteboard-advanced/src/components/LayerComponent.tsx +++ b/examples/nextjs-whiteboard-advanced/src/components/LayerComponent.tsx @@ -15,7 +15,7 @@ type Props = { const LayerComponent = memo( ({ mode, onLayerPointerDown, id, selectionColor }: Props) => { - const layer = useStorage((root) => root.layers.get(id)); + const layer = useStorage((root) => root.layers[id]); if (!layer) { return null; } diff --git a/examples/nextjs-whiteboard-advanced/src/components/SelectionBox.tsx b/examples/nextjs-whiteboard-advanced/src/components/SelectionBox.tsx index 28c165080d5..4d96a818f49 100644 --- a/examples/nextjs-whiteboard-advanced/src/components/SelectionBox.tsx +++ b/examples/nextjs-whiteboard-advanced/src/components/SelectionBox.tsx @@ -20,7 +20,7 @@ const SelectionBox = memo( const isShowingHandles = useStorage( (root) => - soleLayerId && root.layers.get(soleLayerId)?.type !== LayerType.Path + soleLayerId && root.layers[soleLayerId]?.type !== LayerType.Path ); const bounds = useSelectionBounds(); diff --git a/examples/nextjs-whiteboard-advanced/src/components/SelectionTools.tsx b/examples/nextjs-whiteboard-advanced/src/components/SelectionTools.tsx index 66145018b34..8c99af4f099 100644 --- a/examples/nextjs-whiteboard-advanced/src/components/SelectionTools.tsx +++ b/examples/nextjs-whiteboard-advanced/src/components/SelectionTools.tsx @@ -28,7 +28,7 @@ function SelectionTools({ const liveLayerIds = storage.get("layerIds"); const indices: number[] = []; - const arr = liveLayerIds.toArray(); + const arr = liveLayerIds.toJSON(); for (let i = 0; i < arr.length; i++) { if (selection.includes(arr[i])) { @@ -54,7 +54,7 @@ function SelectionTools({ const liveLayerIds = storage.get("layerIds"); const indices: number[] = []; - const arr = liveLayerIds.toArray(); + const arr = liveLayerIds.toJSON(); for (let i = 0; i < arr.length; i++) { if (selection.includes(arr[i])) { diff --git a/examples/nextjs-whiteboard-advanced/src/hooks/useSelectionBounds.ts b/examples/nextjs-whiteboard-advanced/src/hooks/useSelectionBounds.ts index 15217049956..ac675d4c146 100644 --- a/examples/nextjs-whiteboard-advanced/src/hooks/useSelectionBounds.ts +++ b/examples/nextjs-whiteboard-advanced/src/hooks/useSelectionBounds.ts @@ -41,7 +41,7 @@ export default function useSelectionBounds() { const selection = useSelf((me) => me.presence.selection); return useStorage((root) => { const selectedLayers = selection - .map((layerId) => root.layers.get(layerId)!) + .map((layerId) => root.layers[layerId]) .filter(Boolean); return boundingBox(selectedLayers); }, shallow); diff --git a/examples/nextjs-whiteboard-advanced/src/index.tsx b/examples/nextjs-whiteboard-advanced/src/index.tsx index b2d852f05bd..5c4b21ad03d 100644 --- a/examples/nextjs-whiteboard-advanced/src/index.tsx +++ b/examples/nextjs-whiteboard-advanced/src/index.tsx @@ -354,7 +354,7 @@ function Canvas() { */ const updateSelectionNet = useMutation( ({ storage, setMyPresence }, current: Point, origin: Point) => { - const layers = storage.get("layers").toImmutable(); + const layers = storage.get("layers").toJSON(); setState({ mode: CanvasMode.SelectionNet, origin: origin, diff --git a/examples/nextjs-whiteboard-advanced/src/utils.ts b/examples/nextjs-whiteboard-advanced/src/utils.ts index 33a3ec4174a..51585029417 100644 --- a/examples/nextjs-whiteboard-advanced/src/utils.ts +++ b/examples/nextjs-whiteboard-advanced/src/utils.ts @@ -109,7 +109,7 @@ export function isHittingEllipse(layer: EllipseLayer, point: Point) { */ export function findIntersectingLayersWithRectangle( layerIds: readonly string[], - layers: ReadonlyMap, + layers: Record, a: Point, b: Point ) { @@ -123,7 +123,7 @@ export function findIntersectingLayersWithRectangle( const ids = []; for (const layerId of layerIds) { - const layer = layers.get(layerId); + const layer = layers[layerId]; if (layer == null) { continue; } diff --git a/examples/nextjs-whiteboard/package-lock.json b/examples/nextjs-whiteboard/package-lock.json index faae270bdc8..8aa91a59724 100644 --- a/examples/nextjs-whiteboard/package-lock.json +++ b/examples/nextjs-whiteboard/package-lock.json @@ -7,9 +7,9 @@ "name": "@liveblocks-examples/nextjs-whiteboard", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" @@ -499,43 +499,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/nextjs-whiteboard/package.json b/examples/nextjs-whiteboard/package.json index 8a894e82435..ed7307f7171 100644 --- a/examples/nextjs-whiteboard/package.json +++ b/examples/nextjs-whiteboard/package.json @@ -9,9 +9,9 @@ "start": "next start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", "next": "^16.1.6", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/examples/nextjs-whiteboard/pages/index.tsx b/examples/nextjs-whiteboard/pages/index.tsx index 38972eba83d..6143b14fde2 100644 --- a/examples/nextjs-whiteboard/pages/index.tsx +++ b/examples/nextjs-whiteboard/pages/index.tsx @@ -8,7 +8,7 @@ import { useSelf, } from "@liveblocks/react/suspense"; import { LiveMap, LiveObject } from "@liveblocks/client"; -import { shallow, ClientSideSuspense } from "@liveblocks/react"; +import { ClientSideSuspense } from "@liveblocks/react"; import styles from "../styles/index.module.css"; import { useRouter } from "next/router"; @@ -31,10 +31,7 @@ export default function Room() { function Canvas() { const [isDragging, setIsDragging] = useState(false); - const shapeIds = useStorage( - (root) => Array.from(root.shapes.keys()), - shallow - ); + const shapes = useStorage((root) => root.shapes); const history = useHistory(); @@ -113,7 +110,7 @@ function Canvas() { onPointerMove={onCanvasPointerMove} onPointerUp={onCanvasPointerUp} > - {shapeIds.map((shapeId: string) => { + {Object.keys(shapes).map((shapeId: string) => { return ( root.shapes.get(id)) ?? {}; + const { x, y, fill } = useStorage((root) => root.shapes[id]) ?? {}; const selectedByMe = useSelf((me) => me.presence.selectedShape === id); const selectedByOthers = useOthers((others) => diff --git a/examples/nextjs-yjs-blocknote-advanced/package-lock.json b/examples/nextjs-yjs-blocknote-advanced/package-lock.json index df6c5631619..70d18c2e25c 100644 --- a/examples/nextjs-yjs-blocknote-advanced/package-lock.json +++ b/examples/nextjs-yjs-blocknote-advanced/package-lock.json @@ -10,10 +10,10 @@ "@blocknote/core": "^0.46.1", "@blocknote/mantine": "^0.46.1", "@blocknote/react": "^0.46.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react": "18.3.27", "@types/react-dom": "18.2.25", @@ -688,43 +688,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -741,13 +741,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-blocknote-advanced/package.json b/examples/nextjs-yjs-blocknote-advanced/package.json index 7ecc5a2ef0b..633bd865ca6 100644 --- a/examples/nextjs-yjs-blocknote-advanced/package.json +++ b/examples/nextjs-yjs-blocknote-advanced/package.json @@ -13,10 +13,10 @@ "@blocknote/core": "^0.46.1", "@blocknote/mantine": "^0.46.1", "@blocknote/react": "^0.46.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react": "18.3.27", "@types/react-dom": "18.2.25", diff --git a/examples/nextjs-yjs-blocknote/package-lock.json b/examples/nextjs-yjs-blocknote/package-lock.json index 5d8e51e250a..d5819f60267 100644 --- a/examples/nextjs-yjs-blocknote/package-lock.json +++ b/examples/nextjs-yjs-blocknote/package-lock.json @@ -10,10 +10,10 @@ "@blocknote/core": "^0.46.1", "@blocknote/mantine": "^0.46.1", "@blocknote/react": "^0.46.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react": "18.3.27", "@types/react-dom": "18.2.25", @@ -689,43 +689,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -742,13 +742,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-blocknote/package.json b/examples/nextjs-yjs-blocknote/package.json index e2de55e5ab2..1344ef25c50 100644 --- a/examples/nextjs-yjs-blocknote/package.json +++ b/examples/nextjs-yjs-blocknote/package.json @@ -13,10 +13,10 @@ "@blocknote/core": "^0.46.1", "@blocknote/mantine": "^0.46.1", "@blocknote/react": "^0.46.1", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "20.3.3", "@types/react": "18.3.27", "@types/react-dom": "18.2.25", diff --git a/examples/nextjs-yjs-codemirror/package-lock.json b/examples/nextjs-yjs-codemirror/package-lock.json index 0f5908486ca..ec7eaa3289d 100644 --- a/examples/nextjs-yjs-codemirror/package-lock.json +++ b/examples/nextjs-yjs-codemirror/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@codemirror/lang-javascript": "^6.1.9", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.3.27", "@types/react-dom": "^18.0.11", @@ -659,43 +659,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -712,13 +712,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-codemirror/package.json b/examples/nextjs-yjs-codemirror/package.json index 4b8023c1bab..cff38ef3427 100644 --- a/examples/nextjs-yjs-codemirror/package.json +++ b/examples/nextjs-yjs-codemirror/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@codemirror/lang-javascript": "^6.1.9", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.3.27", "@types/react-dom": "^18.0.11", diff --git a/examples/nextjs-yjs-lexical/package-lock.json b/examples/nextjs-yjs-lexical/package-lock.json index 09dfbf9166c..57f70077afc 100644 --- a/examples/nextjs-yjs-lexical/package-lock.json +++ b/examples/nextjs-yjs-lexical/package-lock.json @@ -8,10 +8,10 @@ "license": "Apache-2.0", "dependencies": { "@lexical/react": "^0.11.3", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.3.27", "@types/react-dom": "^18.0.11", @@ -792,43 +792,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -845,13 +845,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-lexical/package.json b/examples/nextjs-yjs-lexical/package.json index 9bda644e6b7..70ae1ec7cc3 100644 --- a/examples/nextjs-yjs-lexical/package.json +++ b/examples/nextjs-yjs-lexical/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@lexical/react": "^0.11.3", - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^18.11.19", "@types/react": "^18.3.27", "@types/react-dom": "^18.0.11", diff --git a/examples/nextjs-yjs-monaco/package-lock.json b/examples/nextjs-yjs-monaco/package-lock.json index 2166b9c3815..6cfcf4ad42f 100644 --- a/examples/nextjs-yjs-monaco/package-lock.json +++ b/examples/nextjs-yjs-monaco/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-yjs-monaco", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@monaco-editor/react": "^4.5.2", "@types/node": "^20.3.3", "@types/react": "^18.3.27", @@ -504,43 +504,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -557,13 +557,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-monaco/package.json b/examples/nextjs-yjs-monaco/package.json index 926397eb440..618a08a1757 100644 --- a/examples/nextjs-yjs-monaco/package.json +++ b/examples/nextjs-yjs-monaco/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@monaco-editor/react": "^4.5.2", "@types/node": "^20.3.3", "@types/react": "^18.3.27", diff --git a/examples/nextjs-yjs-quill/package-lock.json b/examples/nextjs-yjs-quill/package-lock.json index 911b91c19ff..128aadf19f6 100644 --- a/examples/nextjs-yjs-quill/package-lock.json +++ b/examples/nextjs-yjs-quill/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-yjs-quill", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^20.3.3", "@types/react": "^18.3.27", "@types/react-dom": "^18.2.25", @@ -506,43 +506,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -559,13 +559,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-quill/package.json b/examples/nextjs-yjs-quill/package.json index 14a9c1cec14..32ad7ec612c 100644 --- a/examples/nextjs-yjs-quill/package.json +++ b/examples/nextjs-yjs-quill/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@types/node": "^20.3.3", "@types/react": "^18.3.27", "@types/react-dom": "^18.2.25", diff --git a/examples/nextjs-yjs-slate/package-lock.json b/examples/nextjs-yjs-slate/package-lock.json index 972fa5ca408..baaae5feef1 100644 --- a/examples/nextjs-yjs-slate/package-lock.json +++ b/examples/nextjs-yjs-slate/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-yjs-slate", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@slate-yjs/core": "^1.0.2", "@slate-yjs/react": "^1.1.0", "@types/node": "^18.11.19", @@ -535,43 +535,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -588,13 +588,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-slate/package.json b/examples/nextjs-yjs-slate/package.json index 3892a3cff99..52d835ae762 100644 --- a/examples/nextjs-yjs-slate/package.json +++ b/examples/nextjs-yjs-slate/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@slate-yjs/core": "^1.0.2", "@slate-yjs/react": "^1.1.0", "@types/node": "^18.11.19", diff --git a/examples/nextjs-yjs-tiptap/package-lock.json b/examples/nextjs-yjs-tiptap/package-lock.json index ceac8aee221..aa6e594411b 100644 --- a/examples/nextjs-yjs-tiptap/package-lock.json +++ b/examples/nextjs-yjs-tiptap/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/nextjs-yjs-tiptap", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@tiptap/extension-collaboration": "^3.4.6", "@tiptap/extension-collaboration-caret": "^3.4.6", "@tiptap/pm": "^3.4.6", @@ -534,43 +534,43 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -587,13 +587,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.17.0.tgz", - "integrity": "sha512-TMdzjBeGjqSq3gxHkpWi8HffvfZAx/qRsSk0rdhhCngjYXNIpMUcfWoCwyXevWXy0ghgxfRh25jR54MMKWCQ/Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" diff --git a/examples/nextjs-yjs-tiptap/package.json b/examples/nextjs-yjs-tiptap/package.json index 613de188d4f..224049b0f6d 100644 --- a/examples/nextjs-yjs-tiptap/package.json +++ b/examples/nextjs-yjs-tiptap/package.json @@ -10,10 +10,10 @@ "lint": "next lint" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/yjs": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/yjs": "^3.18.0", "@tiptap/extension-collaboration": "^3.4.6", "@tiptap/extension-collaboration-caret": "^3.4.6", "@tiptap/pm": "^3.4.6", diff --git a/examples/nuxtjs-live-avatars/package-lock.json b/examples/nuxtjs-live-avatars/package-lock.json index ee832c282d0..8ff608164a8 100644 --- a/examples/nuxtjs-live-avatars/package-lock.json +++ b/examples/nuxtjs-live-avatars/package-lock.json @@ -8,8 +8,8 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" }, "devDependencies": { "@types/node": "^18", @@ -1235,30 +1235,30 @@ "license": "MIT" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" diff --git a/examples/nuxtjs-live-avatars/package.json b/examples/nuxtjs-live-avatars/package.json index f2760e69e2d..6559a8f93d0 100644 --- a/examples/nuxtjs-live-avatars/package.json +++ b/examples/nuxtjs-live-avatars/package.json @@ -17,7 +17,7 @@ "typescript": "^5.4.5" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" } } diff --git a/examples/react-comments/package-lock.json b/examples/react-comments/package-lock.json index 3926dc20ee8..2c5dcfd7d96 100644 --- a/examples/react-comments/package-lock.json +++ b/examples/react-comments/package-lock.json @@ -7,10 +7,10 @@ "name": "@liveblocks-examples/react-comments", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-error-boundary": "^4.0.13" @@ -852,43 +852,43 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -905,15 +905,15 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.17.0.tgz", - "integrity": "sha512-jbdxW1PuEu7jITvBDcBr99IcFuittYQcqDB1MAQ7f71ANdk5UPzQ5DpnHWvbh6CPkuvoXe2JwAcF1l2veaMY8g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { "@floating-ui/react-dom": "^2.1.0", - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0", - "@liveblocks/react": "3.17.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", "radix-ui": "^1.4.0", diff --git a/examples/react-comments/package.json b/examples/react-comments/package.json index 6aa6b0af63e..07864157ca5 100644 --- a/examples/react-comments/package.json +++ b/examples/react-comments/package.json @@ -10,10 +10,10 @@ "preview": "vite preview" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0", - "@liveblocks/react": "^3.17.0", - "@liveblocks/react-ui": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-error-boundary": "^4.0.13" diff --git a/examples/react-native-todo-list/package-lock.json b/examples/react-native-todo-list/package-lock.json index c4a5f1d9788..de4b7ad82d6 100644 --- a/examples/react-native-todo-list/package-lock.json +++ b/examples/react-native-todo-list/package-lock.json @@ -9,8 +9,8 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "base-64": "^1.0.0", "react": "19.2.0", "react-native": "^0.83.0", @@ -2690,31 +2690,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/react": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.17.0.tgz", - "integrity": "sha512-xqMc80oFNDIniZyok0rVdUmuzrIfO+tIflUG8yI+AN7b6r9u3ZQtcDzFiJLhCkZ3xFWOlKbnZgOXnvStvgpEQg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", diff --git a/examples/react-native-todo-list/package.json b/examples/react-native-todo-list/package.json index f9d36c10041..6b2d7ce26ae 100644 --- a/examples/react-native-todo-list/package.json +++ b/examples/react-native-todo-list/package.json @@ -11,8 +11,8 @@ "dev": "react-native start" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/react": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/react": "^3.18.0", "base-64": "^1.0.0", "react": "19.2.0", "react-native": "^0.83.0", diff --git a/examples/redux-todo-list/package-lock.json b/examples/redux-todo-list/package-lock.json index bacb4db65d3..495ca02b879 100644 --- a/examples/redux-todo-list/package-lock.json +++ b/examples/redux-todo-list/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/redux-todo-list", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/redux": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/redux": "^3.18.0", "@reduxjs/toolkit": "^2.8.2", "next": "^16.1.6", "react": "^18.3.1", @@ -502,31 +502,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/redux": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/redux/-/redux-3.17.0.tgz", - "integrity": "sha512-dSgmNLXwh+/0U9TNFE/+HSTRahm+cpGGD1NtZG8EKukkMD/HWCEhCMA/P67VfACehvlrUa1/f/w9ZYazxQIG+A==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/redux/-/redux-3.18.0.tgz", + "integrity": "sha512-VdLjo3mT5yoYXELFySAwBenvk8f1OkfpXJH7iOjRvOaJJ/IaT24BL/QB4bFPoiB4s/8GhPApKM1BO6FuI7SRLA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "redux": "^4 || ^5" diff --git a/examples/redux-todo-list/package.json b/examples/redux-todo-list/package.json index 6e8a64b846b..8816396e659 100644 --- a/examples/redux-todo-list/package.json +++ b/examples/redux-todo-list/package.json @@ -9,8 +9,8 @@ "dev": "next dev" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/redux": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/redux": "^3.18.0", "@reduxjs/toolkit": "^2.8.2", "next": "^16.1.6", "react": "^18.3.1", diff --git a/examples/redux-whiteboard/package-lock.json b/examples/redux-whiteboard/package-lock.json index e55d3af52ba..24ff31b3fdf 100644 --- a/examples/redux-whiteboard/package-lock.json +++ b/examples/redux-whiteboard/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/redux-whiteboard", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/redux": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/redux": "^3.18.0", "@reduxjs/toolkit": "^2.8.2", "next": "^16.1.6", "react": "^18.3.1", @@ -502,31 +502,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/redux": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/redux/-/redux-3.17.0.tgz", - "integrity": "sha512-dSgmNLXwh+/0U9TNFE/+HSTRahm+cpGGD1NtZG8EKukkMD/HWCEhCMA/P67VfACehvlrUa1/f/w9ZYazxQIG+A==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/redux/-/redux-3.18.0.tgz", + "integrity": "sha512-VdLjo3mT5yoYXELFySAwBenvk8f1OkfpXJH7iOjRvOaJJ/IaT24BL/QB4bFPoiB4s/8GhPApKM1BO6FuI7SRLA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "redux": "^4 || ^5" diff --git a/examples/redux-whiteboard/package.json b/examples/redux-whiteboard/package.json index a07fe79dcc1..a041ef34b52 100644 --- a/examples/redux-whiteboard/package.json +++ b/examples/redux-whiteboard/package.json @@ -9,8 +9,8 @@ "dev": "next dev" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/redux": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/redux": "^3.18.0", "@reduxjs/toolkit": "^2.8.2", "next": "^16.1.6", "react": "^18.3.1", diff --git a/examples/solidjs-live-avatars/package-lock.json b/examples/solidjs-live-avatars/package-lock.json index 3b61519de7e..a8d9ca52c1c 100644 --- a/examples/solidjs-live-avatars/package-lock.json +++ b/examples/solidjs-live-avatars/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/solidjs-live-avatars", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "solid-js": "^1.9.11" }, "devDependencies": { @@ -775,18 +775,18 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/solidjs-live-avatars/package.json b/examples/solidjs-live-avatars/package.json index 76279d63b9b..81e59605a13 100644 --- a/examples/solidjs-live-avatars/package.json +++ b/examples/solidjs-live-avatars/package.json @@ -15,7 +15,7 @@ "vite-plugin-solid": "^2.11.0" }, "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "solid-js": "^1.9.11" } } diff --git a/examples/solidjs-live-cursors/package-lock.json b/examples/solidjs-live-cursors/package-lock.json index ae0c6149843..549719e998c 100644 --- a/examples/solidjs-live-cursors/package-lock.json +++ b/examples/solidjs-live-cursors/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/solidjs-live-cursors", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "@motionone/solid": "^10.8.1", "@solid-primitives/keyed": "^1.0.0", "motion": "^10.8.1", @@ -778,18 +778,18 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/solidjs-live-cursors/package.json b/examples/solidjs-live-cursors/package.json index 221e1349941..a7bf5df6a76 100644 --- a/examples/solidjs-live-cursors/package.json +++ b/examples/solidjs-live-cursors/package.json @@ -14,7 +14,7 @@ "vite-plugin-solid": "^2.11.0" }, "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "@motionone/solid": "^10.8.1", "@solid-primitives/keyed": "^1.0.0", "motion": "^10.8.1", diff --git a/examples/sveltekit-live-avatars/package-lock.json b/examples/sveltekit-live-avatars/package-lock.json index 0da2d54a28a..d4e96e01cb8 100644 --- a/examples/sveltekit-live-avatars/package-lock.json +++ b/examples/sveltekit-live-avatars/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/sveltekit-live-avatars", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^6.1.1", @@ -468,30 +468,30 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" diff --git a/examples/sveltekit-live-avatars/package.json b/examples/sveltekit-live-avatars/package.json index c5ae83982b4..af17391b0b0 100644 --- a/examples/sveltekit-live-avatars/package.json +++ b/examples/sveltekit-live-avatars/package.json @@ -22,7 +22,7 @@ "vite": "^5.4.21" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" } } diff --git a/examples/sveltekit-live-cursors/package-lock.json b/examples/sveltekit-live-cursors/package-lock.json index da443fbe064..20e77214159 100644 --- a/examples/sveltekit-live-cursors/package-lock.json +++ b/examples/sveltekit-live-cursors/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/sveltekit-live-cursors", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^6.1.1", @@ -468,30 +468,30 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/node": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.17.0.tgz", - "integrity": "sha512-nwoYWj9m8aCgxTg5rcCknS87PoCXSYtNAXxvC4fMW9n0EZ90nAmdMXdRU+5o2pikINWu5MVi+Bm4wrpIlNyPiA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" diff --git a/examples/sveltekit-live-cursors/package.json b/examples/sveltekit-live-cursors/package.json index c087aa62ee4..5cb21281c69 100644 --- a/examples/sveltekit-live-cursors/package.json +++ b/examples/sveltekit-live-cursors/package.json @@ -22,7 +22,7 @@ "vite": "^5.4.21" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/node": "^3.17.0" + "@liveblocks/client": "^3.18.0", + "@liveblocks/node": "^3.18.0" } } diff --git a/examples/vuejs-live-avatars/package-lock.json b/examples/vuejs-live-avatars/package-lock.json index 24f142623be..9194c8de2df 100644 --- a/examples/vuejs-live-avatars/package-lock.json +++ b/examples/vuejs-live-avatars/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/vuejs-live-avatars", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "vue": "^3.3.13" }, "devDependencies": { @@ -449,18 +449,18 @@ "license": "MIT" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/vuejs-live-avatars/package.json b/examples/vuejs-live-avatars/package.json index 503e8b56944..aebb737734a 100644 --- a/examples/vuejs-live-avatars/package.json +++ b/examples/vuejs-live-avatars/package.json @@ -11,7 +11,7 @@ "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false" }, "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "vue": "^3.3.13" }, "devDependencies": { diff --git a/examples/vuejs-live-cursors/package-lock.json b/examples/vuejs-live-cursors/package-lock.json index 970e1979268..8dd32d22b87 100644 --- a/examples/vuejs-live-cursors/package-lock.json +++ b/examples/vuejs-live-cursors/package-lock.json @@ -7,7 +7,7 @@ "name": "@liveblocks-examples/vuejs-live-cursors", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "vue": "^3.3.13" }, "devDependencies": { @@ -449,18 +449,18 @@ "license": "MIT" }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" diff --git a/examples/vuejs-live-cursors/package.json b/examples/vuejs-live-cursors/package.json index 3a7626ed322..2ab9effa59c 100644 --- a/examples/vuejs-live-cursors/package.json +++ b/examples/vuejs-live-cursors/package.json @@ -11,7 +11,7 @@ "type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false" }, "dependencies": { - "@liveblocks/client": "^3.17.0", + "@liveblocks/client": "^3.18.0", "vue": "^3.3.13" }, "devDependencies": { diff --git a/examples/zustand-todo-list/package-lock.json b/examples/zustand-todo-list/package-lock.json index c4189048feb..f36ac88e524 100644 --- a/examples/zustand-todo-list/package-lock.json +++ b/examples/zustand-todo-list/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/zustand-todo-list", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/zustand": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/zustand": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^5.0.10" @@ -729,31 +729,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/zustand": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-3.17.0.tgz", - "integrity": "sha512-rg/MZrCJvNbnlcelovuMU+I39qk7ksK99sejGzmUXQhYeDOLym9JeNYuZXtfOBjSKfJpexw6F9AE5ecaBQW49Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-3.18.0.tgz", + "integrity": "sha512-QW309jtiB5EiWHlbQDb0MI4YIkF9PazweW6k+jhOfv9wW24mK0FVIB83UhTNogCkie/Nb36TsSifTuGZ6fjzag==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "zustand": "^5.0.1" diff --git a/examples/zustand-todo-list/package.json b/examples/zustand-todo-list/package.json index ab0076a3445..566296a7c74 100644 --- a/examples/zustand-todo-list/package.json +++ b/examples/zustand-todo-list/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/zustand": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/zustand": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^5.0.10" diff --git a/examples/zustand-whiteboard/package-lock.json b/examples/zustand-whiteboard/package-lock.json index d627db76b69..091bd79ff91 100644 --- a/examples/zustand-whiteboard/package-lock.json +++ b/examples/zustand-whiteboard/package-lock.json @@ -7,8 +7,8 @@ "name": "@liveblocks-examples/zustand-whiteboard", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/zustand": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/zustand": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^5.0.10" @@ -729,31 +729,31 @@ } }, "node_modules/@liveblocks/client": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.17.0.tgz", - "integrity": "sha512-DHKuYzMn6laLUyo2IB90gmUHOHT4S58DcqXqlide6MLl/XmrSIv9xduU+w7y0ndWhhbVlmEcPku7/Qd5rWBeWw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.17.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.17.0.tgz", - "integrity": "sha512-96xqhBDQCBY3hkNuBzbD4n52dS66P+ZqxeXfa1LegA32knIDD86UCSxMlAFQOM69k3r3vuSPBf0yyf2L/k7kxg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/zustand": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-3.17.0.tgz", - "integrity": "sha512-rg/MZrCJvNbnlcelovuMU+I39qk7ksK99sejGzmUXQhYeDOLym9JeNYuZXtfOBjSKfJpexw6F9AE5ecaBQW49Q==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/zustand/-/zustand-3.18.0.tgz", + "integrity": "sha512-QW309jtiB5EiWHlbQDb0MI4YIkF9PazweW6k+jhOfv9wW24mK0FVIB83UhTNogCkie/Nb36TsSifTuGZ6fjzag==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.17.0", - "@liveblocks/core": "3.17.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "zustand": "^5.0.1" diff --git a/examples/zustand-whiteboard/package.json b/examples/zustand-whiteboard/package.json index 77f778bc621..f0386f39353 100644 --- a/examples/zustand-whiteboard/package.json +++ b/examples/zustand-whiteboard/package.json @@ -9,8 +9,8 @@ "preview": "vite preview" }, "dependencies": { - "@liveblocks/client": "^3.17.0", - "@liveblocks/zustand": "^3.17.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/zustand": "^3.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "zustand": "^5.0.10" diff --git a/starter-kits/nextjs-starter-kit/.gitignore b/starter-kits/nextjs-starter-kit/.gitignore index c58cff0c772..7736d642e33 100644 --- a/starter-kits/nextjs-starter-kit/.gitignore +++ b/starter-kits/nextjs-starter-kit/.gitignore @@ -4,6 +4,7 @@ # next.js /.next /out +next-env.d.ts # production /build diff --git a/starter-kits/nextjs-starter-kit/components/Whiteboard/Whiteboard.tsx b/starter-kits/nextjs-starter-kit/components/Whiteboard/Whiteboard.tsx index 0a127daf637..cf6250de067 100644 --- a/starter-kits/nextjs-starter-kit/components/Whiteboard/Whiteboard.tsx +++ b/starter-kits/nextjs-starter-kit/components/Whiteboard/Whiteboard.tsx @@ -1,4 +1,4 @@ -import { LiveObject, shallow } from "@liveblocks/client"; +import { LiveObject } from "@liveblocks/client"; import { ClientSideSuspense } from "@liveblocks/react"; import { useCanRedo, @@ -55,11 +55,7 @@ function LiveblocksWhiteboard({ style, ...props }: Props) { - // An array of every note id - const noteIds: string[] = useStorage( - (root) => Array.from(root.notes.keys()), - shallow - ); + const notesById = useStorage((root) => root.notes); const history = useHistory(); const canUndo = useCanUndo(); @@ -196,7 +192,7 @@ function LiveblocksWhiteboard({ /* * Iterate through each note in the LiveMap and render it as a note */ - noteIds.map((id) => ( + Object.keys(notesById).map((id) => ( { const textAreaRef = useRef(null); - const note = useStorage((root) => root.notes.get(id)); + const note = useStorage((root) => root.notes[id]); const handleDoubleClick = useCallback(() => { textAreaRef.current?.focus(); diff --git a/starter-kits/nextjs-starter-kit/next-env.d.ts b/starter-kits/nextjs-starter-kit/next-env.d.ts deleted file mode 100644 index c4b7818fbb2..00000000000 --- a/starter-kits/nextjs-starter-kit/next-env.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// -import "./.next/dev/types/routes.d.ts"; - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/starter-kits/nextjs-starter-kit/package-lock.json b/starter-kits/nextjs-starter-kit/package-lock.json index 864117ada34..3efb10e43fa 100644 --- a/starter-kits/nextjs-starter-kit/package-lock.json +++ b/starter-kits/nextjs-starter-kit/package-lock.json @@ -7,17 +7,17 @@ "name": "@liveblocks-starter-kits/nextjs-starter-kit", "license": "Apache-2.0", "dependencies": { - "@blocknote/core": "^0.42.3", - "@blocknote/mantine": "^0.42.3", - "@blocknote/react": "^0.42.3", + "@blocknote/core": "^0.43.0", + "@blocknote/mantine": "^0.43.0", + "@blocknote/react": "^0.43.0", "@floating-ui/dom": "^1.7.4", - "@liveblocks/client": "^3.14.0", - "@liveblocks/emails": "^3.14.0", - "@liveblocks/node": "^3.14.0", - "@liveblocks/react": "^3.14.0", - "@liveblocks/react-blocknote": "^3.14.0", - "@liveblocks/react-tiptap": "^3.14.0", - "@liveblocks/react-ui": "^3.14.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-blocknote": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-popover": "^1.1.6", "@radix-ui/react-select": "^2.1.6", @@ -101,18 +101,19 @@ } }, "node_modules/@blocknote/core": { - "version": "0.42.3", - "resolved": "https://registry.npmjs.org/@blocknote/core/-/core-0.42.3.tgz", - "integrity": "sha512-wtZki6Gok5Ac9Ek6QTQztcDymstEQgVCisJwiUZTWXh8CD4UKfnIxM7C9+6eEnZMmQ8GNTvRf1HXFl+E4N78VA==", + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@blocknote/core/-/core-0.43.0.tgz", + "integrity": "sha512-cNR3HP0bacjEYkVOqC2AgqYu2DF4rP2IdMuN0jEU4gmsI5c5R6UYRXiEFqu2Xfz7EimJ15JXYByHXJVOFTaD3w==", "license": "MPL-2.0", "dependencies": { "@emoji-mart/data": "^1.2.1", + "@handlewithcare/prosemirror-inputrules": "0.1.3", "@shikijs/types": "3.13.0", + "@tanstack/store": "0.7.7", "@tiptap/core": "^3.11.0", "@tiptap/extension-bold": "^3.7.2", "@tiptap/extension-code": "^3.7.2", "@tiptap/extension-gapcursor": "^3.7.2", - "@tiptap/extension-history": "^3.7.2", "@tiptap/extension-horizontal-rule": "^3.7.2", "@tiptap/extension-italic": "^3.7.2", "@tiptap/extension-link": "^3.7.2", @@ -147,7 +148,7 @@ "yjs": "^13.6.27" }, "peerDependencies": { - "@hocuspocus/provider": "^2.15.2" + "@hocuspocus/provider": "^2.15.2 || ^3.0.0" }, "peerDependenciesMeta": { "@hocuspocus/provider": { @@ -156,13 +157,13 @@ } }, "node_modules/@blocknote/mantine": { - "version": "0.42.3", - "resolved": "https://registry.npmjs.org/@blocknote/mantine/-/mantine-0.42.3.tgz", - "integrity": "sha512-xzLweZG1KfFoOp/aSHTXE10IrfEHnhDlP0C2Qt2eNO2IHHa7l8XZJpIGhCoVMsn0yylm91OSynNfTO7JkZZi8w==", + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@blocknote/mantine/-/mantine-0.43.0.tgz", + "integrity": "sha512-iwUZQjG8kNv+A5xV5eaHat/PjEAY7FS8ej/J8gUf6dxiYeETsB5WgohqNuc5RveO5IXfy6OVNKL5I3ZilQIdqA==", "license": "MPL-2.0", "dependencies": { - "@blocknote/core": "0.42.3", - "@blocknote/react": "0.42.3", + "@blocknote/core": "0.43.0", + "@blocknote/react": "0.43.0", "react-icons": "^5.5.0" }, "peerDependencies": { @@ -174,26 +175,37 @@ } }, "node_modules/@blocknote/react": { - "version": "0.42.3", - "resolved": "https://registry.npmjs.org/@blocknote/react/-/react-0.42.3.tgz", - "integrity": "sha512-YnrQ1uyezDbaxYcFstWOJ2r8BMxqwwEc7QAhrEjCMEyBAiOxSCPnrM4/GE2mOgCS0Xa9wIp2LDoPQP2Syv+2EA==", + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@blocknote/react/-/react-0.43.0.tgz", + "integrity": "sha512-gG5clXUH/d0zpB7KSzCC2j0xNvz4zYEPZaEnE3lYdnRMbY4TufeDpOlAdbCsKKefyT46DCjm6hX0KubippzDOQ==", "license": "MPL-2.0", "dependencies": { - "@blocknote/core": "0.42.3", + "@blocknote/core": "0.43.0", "@emoji-mart/data": "^1.2.1", "@floating-ui/react": "^0.27.16", + "@floating-ui/utils": "0.2.10", + "@tanstack/react-store": "0.7.7", "@tiptap/core": "^3.11.0", "@tiptap/pm": "^3.11.0", "@tiptap/react": "^3.11.0", + "@types/use-sync-external-store": "1.5.0", "emoji-mart": "^5.6.0", + "fast-deep-equal": "^3.1.3", "lodash.merge": "^4.6.2", - "react-icons": "^5.5.0" + "react-icons": "^5.5.0", + "use-sync-external-store": "1.6.0" }, "peerDependencies": { "react": "^18.0 || ^19.0 || >= 19.0.0-rc", "react-dom": "^18.0 || ^19.0 || >= 19.0.0-rc" } }, + "node_modules/@blocknote/react/node_modules/@types/use-sync-external-store": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", + "integrity": "sha512-5dyB8nLC/qogMrlCizZnYWQTA4lnb/v+It+sqNl5YnSRAPMlIqY/X0Xn+gZw8vOL+TgTTr28VEbn3uf8fUtAkw==", + "license": "MIT" + }, "node_modules/@cush/relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@cush/relative/-/relative-1.0.0.tgz", @@ -379,6 +391,21 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, + "node_modules/@handlewithcare/prosemirror-inputrules": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@handlewithcare/prosemirror-inputrules/-/prosemirror-inputrules-0.1.3.tgz", + "integrity": "sha512-LjGitwgSFHICeU6Mfbt+0Bp4BuWyvHfDYJIf7rq1qdNO88tFcWV3CSqw75o/YbsnUObDgp5Dn+gXIQLRwiyCbg==", + "license": "MIT", + "dependencies": { + "prosemirror-history": "^1.4.1", + "prosemirror-transform": "^1.0.0" + }, + "peerDependencies": { + "prosemirror-model": "^1.0.0", + "prosemirror-state": "^1.0.0", + "prosemirror-view": "^1.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -949,56 +976,56 @@ "license": "Apache-2.0" }, "node_modules/@liveblocks/client": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.14.0.tgz", - "integrity": "sha512-+2VukE9iaVDaSTwMCQMBtIBwpn0t2PVfIVGLydT8O/nHGiA84ew2bV0pZc+Z+G4WQuFnAYcSBhddmZrdiQJyIQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/client/-/client-3.18.0.tgz", + "integrity": "sha512-pr9Os4P/Rc9tB4/7rEaVk64CVKF16S3+i/OjklxCvVV37DwTyslyyLEtQiyaT54CiNJDKVi4s6VywPTpp/yCOg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.14.0" + "@liveblocks/core": "3.18.0" } }, "node_modules/@liveblocks/core": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.14.0.tgz", - "integrity": "sha512-U57xnMLBv3O271YS/RiL9Wj/E1F28D2rmVPpWorlHyEytXeodmibWM4oLgmoRBF/GPSCpCJGMcCTSRKFOcTLPg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/core/-/core-3.18.0.tgz", + "integrity": "sha512-PXpcxvmc1+AOcp7v7qZD+eboIBjrZNySYKAxFJ8CJd9ElWQtK8fRKjzmlbU6ejbotem2X0qvxw5sltDkvEO4+Q==", "license": "Apache-2.0", "peerDependencies": { "@types/json-schema": "^7" } }, "node_modules/@liveblocks/emails": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.14.0.tgz", - "integrity": "sha512-ZFDWguHNpfWh0CBa+RvVUb8Da3+BbWyuMZl9JBQvNC0R4HzqQTvGiNeh5Ljg1YerI1cE4T1RYSb3Gnr/PY2dsw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/emails/-/emails-3.18.0.tgz", + "integrity": "sha512-zrtQnRbS2f8/KLOewLoipIbhs2f5FKpEDDI4+Lp7NR42zfaEDvtJa7q7x44pjSLm+BJAyeiFOm1ZwTKcByP8bQ==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.14.0", - "@liveblocks/node": "3.14.0" + "@liveblocks/core": "3.18.0", + "@liveblocks/node": "3.18.0" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc" } }, "node_modules/@liveblocks/node": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.14.0.tgz", - "integrity": "sha512-iGNMpiQDfuEI9YwsvVriIhFQrBITTwhH9Jdg91+xvYglvSWxSR30cOoYsBXKQvkBTNWMMcD/+DtH/gOMRTK5Aw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/node/-/node-3.18.0.tgz", + "integrity": "sha512-isB/0nGIW84Ez0pmPv3ANknyKtiGTI3WEQBagE9CxIXN95wlnmKn5XIFKEJEXeal/rmNHskKyu4VOU7scKdUiw==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/core": "3.14.0", + "@liveblocks/core": "3.18.0", "@stablelib/base64": "^1.0.1", "fast-sha256": "^1.3.0", "node-fetch": "^2.6.1" } }, "node_modules/@liveblocks/react": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.14.0.tgz", - "integrity": "sha512-MFX8WotVy+NAJwj9JjbUi0jDMJxDO8n5ZfNFZ8D7cl/2klL+OIyrOkXFIkbNDMRZ9hnpvJllPyeBAhhr0ROokQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react/-/react-3.18.0.tgz", + "integrity": "sha512-/b2E2nQatyEWsMVBEkYD5HczASDU9vwCM/gO9IECge6WfWQ9QHbgjdEAnTHcsGq/azDaMDjwyEoS0lMKjk2hPA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.14.0", - "@liveblocks/core": "3.14.0" + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0" }, "peerDependencies": { "@types/react": "*", @@ -1015,23 +1042,23 @@ } }, "node_modules/@liveblocks/react-blocknote": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-blocknote/-/react-blocknote-3.14.0.tgz", - "integrity": "sha512-RVlIi1LaHk85EFGlZ2MkY5I9jGDvkCUDyxLMiAoi5yPs2pq5AFZhZozOm2ikOW9lkRm8+dE/K3jTII7x4dMuSA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-blocknote/-/react-blocknote-3.18.0.tgz", + "integrity": "sha512-4GQSfGsrX6fP/GYm5dfhWBsiCrunSqPJI8dHoIJrf7miN8IjJjSVZgq1aGmhLy46VYIGuiW1gDfNwDqAAFF3kg==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.14.0", - "@liveblocks/core": "3.14.0", - "@liveblocks/react": "3.14.0", - "@liveblocks/react-tiptap": "3.14.0", - "@liveblocks/react-ui": "3.14.0", - "@liveblocks/yjs": "3.14.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-tiptap": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "vitest-tsconfig-paths": "^3.4.1" }, "peerDependencies": { - "@blocknote/core": "0.39.1 - 1.0.0", - "@blocknote/react": "0.39.1 - 1.0.0", + "@blocknote/core": "0.43.0 - 1.0.0", + "@blocknote/react": "0.43.0 - 1.0.0", "@tiptap/core": "^3.19.0", "@types/react": "*", "@types/react-dom": "*", @@ -1048,23 +1075,22 @@ } }, "node_modules/@liveblocks/react-tiptap": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.14.0.tgz", - "integrity": "sha512-xVqYmebg2Ccd09+JfDlNKsYu5etYcuFUY9a+sRjE4nLAzGAKSKowKEs2UDAmtNID0FMFSP77drvg1nYt0FlFhw==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-tiptap/-/react-tiptap-3.18.0.tgz", + "integrity": "sha512-Pi2tyaHGT4E5GYVaaFlSvzOyOECuvffBjCaZD2pu6u+9G/5uuX66lqePp9pIU9PWxmUH/0psQod6TiIazMRlHA==", "license": "Apache-2.0", "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@liveblocks/client": "3.14.0", - "@liveblocks/core": "3.14.0", - "@liveblocks/react": "3.14.0", - "@liveblocks/react-ui": "3.14.0", - "@liveblocks/yjs": "3.14.0", - "@radix-ui/react-select": "^2.1.2", - "@radix-ui/react-toggle": "^1.1.0", + "@floating-ui/react-dom": "^2.1.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", + "@liveblocks/react-ui": "3.18.0", + "@liveblocks/yjs": "3.18.0", "@tiptap/core": "^3.19.0", "@tiptap/react": "^3.19.0", "@tiptap/suggestion": "^3.19.0", "cmdk": "^1.0.4", + "radix-ui": "^1.4.0", "y-prosemirror": "^1.3.7", "yjs": "^13.6.18" }, @@ -1087,22 +1113,18 @@ } }, "node_modules/@liveblocks/react-ui": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.14.0.tgz", - "integrity": "sha512-oFfFrRq+gNhVxqr25nLp1S7pdoRfXvGnga0t40GlD1UUCUBrRMy1YW98V3d6RZbdd3XES2kA0QGqkXnRIRggjQ==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/react-ui/-/react-ui-3.18.0.tgz", + "integrity": "sha512-jHKOf5TGGV0iXVyGw55fZx+ECdtxS28x+lADscelNP+syGtFN8sXG/2P8h4IZkcfXe7M4k8xBXarlzWAQrUUMw==", "license": "Apache-2.0", "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@liveblocks/client": "3.14.0", - "@liveblocks/core": "3.14.0", - "@liveblocks/react": "3.14.0", - "@radix-ui/react-dropdown-menu": "^2.1.2", - "@radix-ui/react-popover": "^1.1.2", - "@radix-ui/react-slot": "^1.1.0", - "@radix-ui/react-toggle": "^1.1.0", - "@radix-ui/react-tooltip": "^1.1.3", + "@floating-ui/react-dom": "^2.1.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", + "@liveblocks/react": "3.18.0", "frimousse": "^0.2.0", "marked": "^15.0.11", + "radix-ui": "^1.4.0", "slate": "^0.110.2", "slate-history": "^0.110.3", "slate-hyperscript": "^0.100.0", @@ -1137,13 +1159,13 @@ } }, "node_modules/@liveblocks/yjs": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.14.0.tgz", - "integrity": "sha512-GDCU6c9i+DYRTM/NQK8RUwSGzdwQ/pPJZG6wcPcy+w7hLmgh3+aHJuBp0ISm1Uzgc+fKWybbJSH67xXcAw/ysA==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/@liveblocks/yjs/-/yjs-3.18.0.tgz", + "integrity": "sha512-vuWAQ86zfIjJ3f6keaJc69Xv4cMm/S1oVLNMYbQ5PEKkpVO8JcX0q/ASH2B7fPzddQ0tapXDJTE+7vsfUnRVXA==", "license": "Apache-2.0", "dependencies": { - "@liveblocks/client": "3.14.0", - "@liveblocks/core": "3.14.0", + "@liveblocks/client": "3.18.0", + "@liveblocks/core": "3.18.0", "@noble/hashes": "^1.8.0", "js-base64": "^3.7.7", "y-indexeddb": "^9.0.12" @@ -2664,24 +2686,6 @@ } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@radix-ui/react-switch": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", @@ -3144,17 +3148,45 @@ "tslib": "^2.8.0" } }, + "node_modules/@tanstack/react-store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.7.tgz", + "integrity": "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.7.7", + "use-sync-external-store": "^1.5.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/store": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.7.tgz", + "integrity": "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tiptap/core": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.20.0.tgz", - "integrity": "sha512-aC9aROgia/SpJqhsXFiX9TsligL8d+oeoI8W3u00WI45s0VfsqjgeKQLDLF7Tu7hC+7F02teC84SAHuup003VQ==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.2.tgz", + "integrity": "sha512-atq35NkpeEphH6vNYJ0pTLLBA73FAbvTV9Ovd3AaTC5s99/KF5Q86zVJXvml8xPRcMGM6dLp+eSSd06oTscMSA==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/pm": "^3.20.0" + "@tiptap/pm": "^3.22.2" } }, "node_modules/@tiptap/extension-blockquote": { @@ -3335,19 +3367,6 @@ "@tiptap/core": "^3.20.0" } }, - "node_modules/@tiptap/extension-history": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-3.20.0.tgz", - "integrity": "sha512-NA3dFanmnPTmz72yEVwOjs/3Y4ze9UObFo94yzzn6OBfhOfE7HDqHw/FS+abqy2OrZK5kI2+leOUDjH+qGqdeA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/ueberdosis" - }, - "peerDependencies": { - "@tiptap/extensions": "^3.20.0" - } - }, "node_modules/@tiptap/extension-horizontal-rule": { "version": "3.20.0", "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-3.20.0.tgz", @@ -3564,9 +3583,9 @@ } }, "node_modules/@tiptap/pm": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.20.0.tgz", - "integrity": "sha512-jn+2KnQZn+b+VXr8EFOJKsnjVNaA4diAEr6FOazupMt8W8ro1hfpYtZ25JL87Kao/WbMze55sd8M8BDXLUKu1A==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.2.tgz", + "integrity": "sha512-G2ENwIazoSKkAnN5MN5yN91TIZNFm6TxB74kPf3Empr2k9W51Hkcier70jHGpArhgcEaL4BVreuU1PRDRwCeGw==", "license": "MIT", "dependencies": { "prosemirror-changeset": "^2.3.0", @@ -3657,17 +3676,17 @@ } }, "node_modules/@tiptap/suggestion": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.20.0.tgz", - "integrity": "sha512-OA9Fe+1Q/Ex0ivTcpRcVFiLnNsVdIBmiEoctt/gu4H2ayCYmZ906veioXNdc1m/3MtVVUIuEnvwwsrOZXlfDEw==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.22.2.tgz", + "integrity": "sha512-t2GQSrF4eQyPb+KqXVfcC2cokYIDNfpLLq7B0ELlnWBJURnLOVJ2ssJ6ASI247scu9ZKPG1g5bFP4IXdBhyPgg==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" }, "peerDependencies": { - "@tiptap/core": "^3.20.0", - "@tiptap/pm": "^3.20.0" + "@tiptap/core": "^3.22.2", + "@tiptap/pm": "^3.22.2" } }, "node_modules/@tldraw/editor": { @@ -7856,9 +7875,9 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, "node_modules/lodash.isequal": { diff --git a/starter-kits/nextjs-starter-kit/package.json b/starter-kits/nextjs-starter-kit/package.json index 868f26671cf..00af48ebbd4 100644 --- a/starter-kits/nextjs-starter-kit/package.json +++ b/starter-kits/nextjs-starter-kit/package.json @@ -11,17 +11,17 @@ "typecheck": "tsc --project tsconfig.json --noEmit" }, "dependencies": { - "@blocknote/core": "^0.42.3", - "@blocknote/mantine": "^0.42.3", - "@blocknote/react": "^0.42.3", + "@blocknote/core": "^0.43.0", + "@blocknote/mantine": "^0.43.0", + "@blocknote/react": "^0.43.0", "@floating-ui/dom": "^1.7.4", - "@liveblocks/client": "^3.14.0", - "@liveblocks/emails": "^3.14.0", - "@liveblocks/node": "^3.14.0", - "@liveblocks/react": "^3.14.0", - "@liveblocks/react-blocknote": "^3.14.0", - "@liveblocks/react-tiptap": "^3.14.0", - "@liveblocks/react-ui": "^3.14.0", + "@liveblocks/client": "^3.18.0", + "@liveblocks/emails": "^3.18.0", + "@liveblocks/node": "^3.18.0", + "@liveblocks/react": "^3.18.0", + "@liveblocks/react-blocknote": "^3.18.0", + "@liveblocks/react-tiptap": "^3.18.0", + "@liveblocks/react-ui": "^3.18.0", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-popover": "^1.1.6", "@radix-ui/react-select": "^2.1.6", From 981b5c55cf882aa8ae00ad8fb97c5886a53e1831 Mon Sep 17 00:00:00 2001 From: Vincent Driessen Date: Wed, 8 Apr 2026 13:27:34 +0200 Subject: [PATCH 6/6] Port back the edits to the examples workflow (#3325) --- .github/workflows/deploy-examples.yml | 76 ++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy-examples.yml b/.github/workflows/deploy-examples.yml index 829731c74da..389d7ab9081 100644 --- a/.github/workflows/deploy-examples.yml +++ b/.github/workflows/deploy-examples.yml @@ -21,9 +21,39 @@ jobs: echo Triggering deployment for nextjs-3d-builder curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_ODKBX4EuSUo19sF7UcUUEUjULL50/ur6dsTOSvu; echo + echo Triggering deployment for nextjs-ai-app-builder + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_5PbrFsltmp5BKHnsBMAAHuJsj3lc/KiSCa1m4tB; echo + + echo Triggering deployment for nextjs-ai-calendar + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_H7bFg3Aslr8x4sOrwDTNwY4pPUvH/7lC9fUdumy; echo + + echo Triggering deployment for nextjs-ai-dashboard-reports + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_4sGozV6komE0oZ3pLCfmq2BmsKHQ/6JL2UE6nNU; echo + + echo Triggering deployment for nextjs-ai-chats + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_s3I6El0fFejHHo1mKmdmZwszO1Ez/Rp1uaVialk; echo + + echo Triggering deployment for nextjs-ai-popup + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_Dej5iVX3gTDoMyl4Zz7eQCeanbTL/ApOZUtheJg; echo + + echo Triggering deployment for nextjs-ai-support + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_EzObSh8qN6zbbRrIHTcjqtRZ5vre/TjSG9uidvC; echo + + echo Triggering deployment for nextjs-blocknote + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_3XoFyLmK5Gtx5twKRTGWFV0jcaUo/1u7c9EF5UX; echo + + echo Triggering deployment for nextjs-chat-sdk-bot + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_a4iBQG1ShzA12DyRjkpoI0U9tBSv/9ZYEH7EaZN; echo + + echo Triggering deployment for nextjs-chat-sdk-ai-bot + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_Wu8bdNCysHzkw6qpVjM11idJtbN5/9mplaVzS9X; echo + echo Triggering deployment for nextjs-comments curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_n44ypzbdWsirLcq3ZSSJ1wLoCAjQ/QWFQY2wKrB; echo + echo Triggering deployment for nextjs-comments-ag-grid + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_JdEZqlsSgHYvnKEtGcfyGnZvSTUn/6gaMVzgYrd; echo + echo Triggering deployment for nextjs-comments-ai curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_3ywNY3BnasLn51n9GRlUDp65tpo6/TTkfwrbB0X; echo @@ -33,6 +63,9 @@ jobs: echo Triggering deployment for nextjs-comments-canvas curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_yFy3klLqgmfMNMZI6FVhBj5w5UIl/hS0RaUAXGw; echo + echo Triggering deployment for nextjs-comments-emails-resend + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_Ht9CiMBXOz7fYMoPGvW0BiSXDeJa/zjNQ0VUNX6; echo + echo Triggering deployment for nextjs-comments-notifications curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_NeiWF6wVsvMmaLaje9MfWNelU0Ms/HU8HBQCHF4; echo @@ -42,6 +75,9 @@ jobs: echo Triggering deployment for nextjs-comments-primitives curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_OEUy8nEYDuKAfOtVKyNy4w3mxoFb/FtJGZAxTFm; echo + echo Triggering deployment for nextjs-comments-search + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_Spr2FA4X6qq9AVT072XA6RbpOndc/h4fqsUj4Il; echo + echo Triggering deployment for nextjs-comments-tiptap curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_uNQF4JRW3CMnoA08UWmLfSVVev5K/NusDhfUIma; echo @@ -54,12 +90,18 @@ jobs: echo Triggering deployment for nextjs-dashboard curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_huuoeSxbMYvNmqcu9UYBUVfP8Cuh/JObDpsWO1x; echo + echo Triggering deployment for nextjs-flowchart-builder + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_eIdloDR7ghI6tKtP1XcWtNvtzNv9/FL6HNiFmMn; echo + echo Triggering deployment for nextjs-form curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_tkr9dMtcFdxzbrZeo0CFzgsqptKI/CTlpFDvYqB; echo echo Triggering deployment for nextjs-lexical curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_qeKoPfUCRuI6jvBqV556q8V29YtA/IpvamWQh6G; echo - + + echo Triggering deployment for nextjs-lexical-emails-resend + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_ty91zX0hZ71c1KmNKGyT3iGSP4Wr/SbFf4Ans0B; echo + echo Triggering deployment for nextjs-linear-like-issue-tracker curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_ilOh5HbvxiAu723gnCAMBksCr3CH/3tTZc8ffgM; echo @@ -86,19 +128,40 @@ jobs: echo Triggering deployment for nextjs-notifications-custom curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_3MVsF7dPIZBQdUpfzQjVvZ1dBmPp/x1sO6CecOJ; echo - + + echo Triggering deployment for nextjs-notification-settings + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_7B4Yq0uUx6AUog07rLG6VFc5R7O4/Xw8EbvIqRl; echo + echo Triggering deployment for nextjs-notion-like-ai-editor curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_xvFy7XWt32Yz7gkigfCRZL6AeIBH/J4jKuBvLo8; echo + echo Triggering deployment for nextjs-react-flow + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_dcdHWlkYszdGyDO62UJByXPHnMNt/lkQC88XdTH; echo + + echo Triggering deployment for nextjs-react-flow-ai + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_mfXSZ8ZM97E6dkp1OGqzvRqfdqoo/Byq4XMwEnk; echo + echo Triggering deployment for nextjs-spreadsheet-advanced curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_ZJK9PEfgkfsqKRVjxFzwQgAVsdsF/gKp8sJ1f1c; echo + echo Triggering deployment for nextjs-tiptap + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_LhH3Ag7MdSKWGicQRRIZRHMCacrm/cCpeyZEfFF; echo + + echo Triggering deployment for nextjs-tiptap-advanced + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_J8TT5NanEfJYgWrASs0hqsR6nGa3/QPgzsSe4NF; echo + + echo Triggering deployment for nextjs-tiptap-emails-resend + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_HmPx17FgTo7OY0XkBYnAzttKGm5R/kEYZ6eqhsA; echo + + echo Triggering deployment for nextjs-tiptap-novel + curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_uoZ7A0CmwcswPxUqnCy51ds0GXaA/0W5pGVEbOJ; echo + echo Triggering deployment for nextjs-tldraw-storage curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_mKM14iPdQfC3jH6jQhCKtBoasxQY/0AfEGfHLws; echo - + echo Triggering deployment for nextjs-tldraw-yjs curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_g3L0m4dKUJ54aupCSjto2tNRjGD1/dH39Y2ZydF; echo - + echo Triggering deployment for nextjs-todo-list curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_IzfUkw9eZuOyiS7LbvftjAo812Yk/KvR90vWuGh; echo @@ -132,7 +195,7 @@ jobs: echo Triggering deployment for nextjs-yjs-tiptap curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_y3mEp1yQYraCLNghy7NcFcj5CPuS/JKf0W69EpG; echo - echo Triggering deployment for nextjs-yjs-tiptap-advanced + echo Triggering deployment for nextjs-tiptap-advanced curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_pCx1U7T80v9b2YS1JURFTFwOBjTe/PlnhiDwwts; echo echo Triggering deployment for nuxtjs-live-avatars @@ -165,9 +228,6 @@ jobs: echo Triggering deployment for vuejs-live-cursors curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_hy7iXLmWo1okV1dgr2OrMCn9JMWt/t7E6OY5oIX; echo - echo Triggering deployment for zustand-flowchart - curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_pASCvZXKn5uwLtBt0UrstPs4VwDx/yB1yWVTEYs; echo - echo Triggering deployment for zustand-todo-list curl -s -X POST https://api.vercel.com/v1/integrations/deploy/prj_YJIYYvzKUnVTmDsf0qASayLp7qqh/sNDHSdAMku; echo