@liveblocks/react-flow 3.18.2 → 3.18.3-test2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2021-present Liveblocks
2
+
3
+ This repository contains software under two licenses:
4
+
5
+ 1. Most of the code in this repository is licensed under the
6
+ Apache License 2.0 — see licenses/LICENSE-APACHE-2.0 for the
7
+ full license text.
8
+
9
+ 2. The following components are licensed under the
10
+ GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later)
11
+ — see licenses/LICENSE-AGPL-3.0 for the full license text:
12
+
13
+ - packages/liveblocks-server (published as @liveblocks/server)
14
+ - tools/liveblocks-cli (published as liveblocks)
15
+
16
+ Each package's own LICENSE or package.json specifies its applicable license.
package/dist/lib/flow.cjs CHANGED
@@ -27,8 +27,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
27
27
  }
28
28
  case "position": {
29
29
  const node = nodes.get(change.id);
30
- if (!node)
31
- break;
30
+ if (!node) break;
32
31
  if (change.dragging === true) {
33
32
  history.pause();
34
33
  }
@@ -48,8 +47,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
48
47
  }
49
48
  case "dimensions": {
50
49
  const node = nodes.get(change.id);
51
- if (!node)
52
- break;
50
+ if (!node) break;
53
51
  if (change.resizing === true) {
54
52
  history.pause();
55
53
  }
@@ -74,8 +72,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
74
72
  }
75
73
  case "select": {
76
74
  const node = nodes.get(change.id);
77
- if (!node)
78
- break;
75
+ if (!node) break;
79
76
  node.setLocal("selected", change.selected);
80
77
  break;
81
78
  }
@@ -103,8 +100,7 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
103
100
  }
104
101
  case "select": {
105
102
  const edge = edges.get(change.id);
106
- if (!edge)
107
- break;
103
+ if (!edge) break;
108
104
  edge.setLocal("selected", change.selected);
109
105
  break;
110
106
  }
@@ -114,13 +110,11 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
114
110
  }
115
111
  }
116
112
  function nodeMapToList(nodesMap) {
117
- if (nodesMap === null)
118
- return null;
113
+ if (nodesMap === null) return null;
119
114
  return Object.values(nodesMap);
120
115
  }
121
116
  function edgeMapToList(edgesMap) {
122
- if (edgesMap === null)
123
- return null;
117
+ if (edgesMap === null) return null;
124
118
  return Object.values(edgesMap);
125
119
  }
126
120
  function useNodesAndEdges(storageKey) {
@@ -1 +1 @@
1
- {"version":3,"file":"flow.cjs","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history.disable(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["toLiveblocksInternalNode","toLiveblocksInternalEdge","useStorage","useMemo","useHistory","useInitial","DEFAULT_STORAGE_KEY","buildNodeConfigCache","buildEdgeConfigCache","useMutation","defaultAddEdge","edges","LiveObject","LiveMap","useEffect","useSuspendUntilStorageReady"],"mappings":";;;;;;;;;AA6CA,MAAM,cAAc,EAAC,CAAA;AAqIrB,SAAS,gBACP,CAAA,OAAA,EACA,KACA,EAAA,OAAA,EACA,iBACM,EAAA;AACN,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAA,QAAQ,OAAO,IAAM;AAAA,MACnB,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,SAAW,EAAA;AACd,QAAA,MAAM,MAAS,GAAA,iBAAA,CAAkB,MAAO,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACjD,QAAA,MAAM,QAAW,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AACzC,QAAA,IAAI,QAAU,EAAA;AACZ,UAAS,QAAA,CAAA,SAAA,CAAU,MAAO,CAAA,IAAA,EAA+B,MAAM,CAAA,CAAA;AAAA,SAC1D,MAAA;AACL,UAAM,KAAA,CAAA,GAAA;AAAA,YACJ,OAAO,IAAK,CAAA,EAAA;AAAA,YACZA,+BAAA,CAAyB,MAAO,CAAA,IAAA,EAAM,MAAM,CAAA;AAAA,WAC9C,CAAA;AAAA,SACF;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,UAAY,EAAA;AACf,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAI,IAAA,MAAA,CAAO,aAAa,IAAM,EAAA;AAC5B,UAAA,OAAA,CAAQ,KAAM,EAAA,CAAA;AAAA,SAChB;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAM,MAAA,IAAA,GAAO,IAAK,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAChC,UAAI,IAAA,IAAA,EAAM,MAAM,MAAO,CAAA,QAAA,CAAS,KAAK,IAAM,EAAA,CAAA,KAAM,MAAO,CAAA,QAAA,CAAS,CAAG,EAAA;AAClE,YAAK,IAAA,CAAA,GAAA,CAAI,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,WACtC;AAAA,SACF;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAI,IAAA,MAAA,CAAO,aAAa,KAAO,EAAA;AAC7B,YAAA,OAAA,CAAQ,MAAO,EAAA,CAAA;AAAA,WACjB;AAEA,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,SAC3C;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,YAAc,EAAA;AACjB,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAI,IAAA,MAAA,CAAO,aAAa,IAAM,EAAA;AAC5B,UAAA,OAAA,CAAQ,KAAM,EAAA,CAAA;AAAA,SAChB;AAEA,QAAA,IACE,MAAO,CAAA,UAAA,KAAe,KACtB,CAAA,IAAA,MAAA,CAAO,kBAAkB,KACzB,CAAA,EAAA;AACA,UAAA,IACE,MAAO,CAAA,aAAA,KAAkB,IACzB,IAAA,MAAA,CAAO,kBAAkB,OACzB,EAAA;AACA,YAAA,IAAA,CAAK,GAAI,CAAA,OAAA,EAAS,MAAO,CAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAAA,WAC3C;AAEA,UAAA,IACE,MAAO,CAAA,aAAA,KAAkB,IACzB,IAAA,MAAA,CAAO,kBAAkB,QACzB,EAAA;AACA,YAAA,IAAA,CAAK,GAAI,CAAA,QAAA,EAAU,MAAO,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAAA,WAC7C;AAAA,SACF;AAEA,QAAI,IAAA,MAAA,CAAO,eAAe,KAAW,CAAA,EAAA;AAEnC,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,UAAU,CAAA,CAAA;AAAA,SAC7C;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAI,IAAA,MAAA,CAAO,aAAa,KAAO,EAAA;AAC7B,YAAA,OAAA,CAAQ,MAAO,EAAA,CAAA;AAAA,WACjB;AAEA,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,SAC3C;AAEA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAU,EAAA;AACb,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AACzC,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AAEH,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AACF,CAAA;AAKA,SAAS,gBAAA,CACP,OACA,EAAA,KAAA,EACA,iBACM,EAAA;AACN,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAA,QAAQ,OAAO,IAAM;AAAA,MACnB,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,SAAW,EAAA;AACd,QAAA,MAAM,MAAS,GAAA,iBAAA,CAAkB,MAAO,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACjD,QAAA,MAAM,QAAW,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AACzC,QAAA,IAAI,QAAU,EAAA;AACZ,UAAS,QAAA,CAAA,SAAA,CAAU,MAAO,CAAA,IAAA,EAA+B,MAAM,CAAA,CAAA;AAAA,SAC1D,MAAA;AACL,UAAM,KAAA,CAAA,GAAA;AAAA,YACJ,OAAO,IAAK,CAAA,EAAA;AAAA,YACZC,+BAAA,CAAyB,MAAO,CAAA,IAAA,EAAM,MAAM,CAAA;AAAA,WAC9C,CAAA;AAAA,SACF;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAU,EAAA;AACb,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAEX,QAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AACzC,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AAEH,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AACF,CAAA;AAKA,SAAS,cACP,QACY,EAAA;AACZ,EAAA,IAAI,QAAa,KAAA,IAAA;AAAM,IAAO,OAAA,IAAA,CAAA;AAC9B,EAAO,OAAA,MAAA,CAAO,OAAO,QAAQ,CAAA,CAAA;AAC/B,CAAA;AAEA,SAAS,cACP,QACY,EAAA;AACZ,EAAA,IAAI,QAAa,KAAA,IAAA;AAAM,IAAO,OAAA,IAAA,CAAA;AAC9B,EAAO,OAAA,MAAA,CAAO,OAAO,QAAQ,CAAA,CAAA;AAC/B,CAAA;AAEA,SAAS,iBAAiD,UAAoB,EAAA;AAI5E,EAAM,MAAA,QAAA,GAAWC,gBAAW,CAAA,CAAC,OAAY,KAAA;AACvC,IAAM,MAAA,IAAA,GAAO,QAAQ,UAAU,CAAA,CAAA;AAG/B,IAAA,OAAO,MAAM,KAAS,IAAA,IAAA,CAAA;AAAA,GACvB,CAAA,CAAA;AACD,EAAM,MAAA,QAAA,GAAWA,gBAAW,CAAA,CAAC,OAAY,KAAA;AACvC,IAAM,MAAA,IAAA,GAAO,QAAQ,UAAU,CAAA,CAAA;AAG/B,IAAA,OAAO,MAAM,KAAS,IAAA,IAAA,CAAA;AAAA,GACvB,CAAA,CAAA;AAED,EAAM,MAAA,KAAA,GAAQC,gBAAQ,MAAM,aAAA,CAAiB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,KAAA,GAAQA,gBAAQ,MAAM,aAAA,CAAiB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAClE,EAAO,OAAA,EAAE,OAAO,KAAM,EAAA,CAAA;AACxB,CAAA;AAqCgB,SAAA,iBAAA,CAId,OAA0C,GAAA,EACmC,EAAA;AAC7E,EAAA,MAAM,UAAUC,gBAAW,EAAA,CAAA;AAC3B,EAAA,MAAM,eAAkB,GAAAF,gBAAA,CAAW,MAAM,IAAI,CAAK,IAAA,KAAA,CAAA;AAGlD,EAAA,MAAM,gBAAgBG,mBAAW,CAAA;AAAA,IAC/B,OAAO,OAAQ,CAAA,KAAA;AAAA,IACf,OAAO,OAAQ,CAAA,KAAA;AAAA,IACf,UAAA,EAAY,QAAQ,UAAc,IAAAC,0BAAA;AAAA,IAClC,QAAA,EAAU,QAAQ,QAAY,IAAA,KAAA;AAAA,GAC/B,CAAA,CAAA;AAGD,EAAM,MAAA,CAAC,iBAAmB,EAAA,iBAAiB,CAAI,GAAAH,eAAA;AAAA,IAC7C,MACE;AAAA,MACEI,2BAAA,CAAqB,aAAc,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA,MAC9CC,2BAAA,CAAqB,aAAc,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA,KAChD;AAAA,IACF,CAAC,aAAa,CAAA;AAAA,GAChB,CAAA;AAEA,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAU,GAAA,gBAAA,CAAuB,cAAc,UAAU,CAAA,CAAA;AAExE,EAAA,MAAM,aAAgB,GAAAC,iBAAA;AAAA,IACpB,CAAC,EAAE,OAAQ,EAAA,EAAG,OAA6B,KAAA;AACzC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,gBAAA,CAAiB,SAAS,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,EAAG,SAAS,iBAAiB,CAAA,CAAA;AAAA,KACzE;AAAA,IACA,CAAC,OAAS,EAAA,aAAA,EAAe,iBAAiB,CAAA;AAAA,GAC5C,CAAA;AAEA,EAAA,MAAM,aAAgB,GAAAA,iBAAA;AAAA,IACpB,CAAC,EAAE,OAAQ,EAAA,EAAG,OAA6B,KAAA;AACzC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,gBAAA,CAAiB,OAAS,EAAA,IAAA,CAAK,GAAI,CAAA,OAAO,GAAG,iBAAiB,CAAA,CAAA;AAAA,KAChE;AAAA,IACA,CAAC,eAAe,iBAAiB,CAAA;AAAA,GACnC,CAAA;AAEA,EAAA,MAAM,SAAY,GAAAA,iBAAA;AAAA,IAChB,CAAC,EAAE,OAAQ,EAAA,EAAG,UAA2B,KAAA;AACvC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAKA,MAAA,MAAM,CAAC,OAAO,CAAA,GAAIC,eAAe,CAAA,UAAA,EAAY,EAAS,CAAA,CAAA;AACtD,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAA,OAAA;AAAA,OACF;AAEA,MAAMC,MAAAA,MAAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAC9B,MAAM,MAAA,MAAA,GAAS,iBAAkB,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAC7C,MAAAA,OAAM,GAAI,CAAA,OAAA,CAAQ,IAAIV,+BAAyB,CAAA,OAAA,EAAS,MAAM,CAAC,CAAA,CAAA;AAAA,KACjE;AAAA,IACA,CAAC,aAAc,CAAA,UAAA,EAAY,iBAAiB,CAAA;AAAA,GAC9C,CAAA;AAEA,EAAA,MAAM,QAAW,GAAAQ,iBAAA;AAAA,IACf,CAAC,EAAE,OAAQ,EAAA,EAAG,MAAuC,KAAA;AACnD,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAM,MAAA,QAAA,GAAW,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AACjC,MAAM,MAAA,QAAA,GAAW,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAEjC,MAAW,KAAA,MAAA,IAAA,IAAQ,OAAO,KAAO,EAAA;AAC/B,QAAS,QAAA,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AAAA,OACzB;AAEA,MAAW,KAAA,MAAA,IAAA,IAAQ,OAAO,KAAO,EAAA;AAC/B,QAAS,QAAA,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,IACA,CAAC,cAAc,UAAU,CAAA;AAAA,GAC3B,CAAA;AAEA,EAAA,MAAM,iBAAoB,GAAAA,iBAAA;AAAA,IACxB,CAAC,EAAE,OAAA,EAAc,KAAA;AAGf,MAAA,IAAI,OAAQ,CAAA,GAAA,CAAI,aAAc,CAAA,UAAU,MAAM,KAAW,CAAA,EAAA;AACvD,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,YAAe,GAAA,aAAA,CAAc,KAAO,EAAA,OAAA,IAAW,EAAC,CAAA;AACtD,MAAA,MAAM,YAAe,GAAA,aAAA,CAAc,KAAO,EAAA,OAAA,IAAW,EAAC,CAAA;AAEtD,MAAQ,OAAA,CAAA,GAAA;AAAA,QACN,aAAc,CAAA,UAAA;AAAA,QACd,IAAIG,eAAW,CAAA;AAAA,UACb,OAAO,IAAIC,YAAA;AAAA,YACT,YAAA,CAAa,GAAI,CAAA,CAAC,IAAS,KAAA;AAAA,cACzB,IAAK,CAAA,EAAA;AAAA,cACLb,+BAAyB,CAAA,IAAA,EAAM,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,aAC5D,CAAA;AAAA,WACH;AAAA,UACA,OAAO,IAAIa,YAAA;AAAA,YACT,YAAA,CAAa,GAAI,CAAA,CAAC,IAAS,KAAA;AAAA,cACzB,IAAK,CAAA,EAAA;AAAA,cACLZ,+BAAyB,CAAA,IAAA,EAAM,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,aAC5D,CAAA;AAAA,WACH;AAAA,SACD,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAAA,IACA,CAAC,aAAe,EAAA,iBAAA,EAAmB,iBAAiB,CAAA;AAAA,GACtD,CAAA;AAEA,EAAAa,iBAAA,CAAU,MAAM;AACd,IAAA,IAAI,eAAiB,EAAA;AACnB,MAAA,OAAA,CAAQ,QAAQ,MAAM;AACpB,QAAkB,iBAAA,EAAA,CAAA;AAAA,OACnB,CAAA,CAAA;AAAA,KACH;AAAA,GACC,EAAA,CAAC,eAAiB,EAAA,iBAAA,EAAmB,OAAO,CAAC,CAAA,CAAA;AAEhD,EAAA,IAAI,cAAc,QAAU,EAAA;AAE1B,IAA4BC,oCAAA,EAAA,CAAA;AAAA,GAC9B;AAEA,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,aAAA,CAAc,QAAY,GAAA,KAAA,IAAU,WAAuB,GAAA,KAAA;AAAA,IAClE,KAAO,EAAA,aAAA,CAAc,QAAY,GAAA,KAAA,IAAU,WAAuB,GAAA,KAAA;AAAA,IAClE,SAAW,EAAA,aAAA,CAAc,QAAW,GAAA,KAAA,GAAQ,CAAC,eAAA;AAAA,IAC7C,aAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,GACF,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"flow.cjs","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history.disable(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["toLiveblocksInternalNode","toLiveblocksInternalEdge","useStorage","useMemo","useHistory","useInitial","DEFAULT_STORAGE_KEY","buildNodeConfigCache","buildEdgeConfigCache","useMutation","defaultAddEdge","edges","LiveObject","LiveMap","useEffect","useSuspendUntilStorageReady"],"mappings":"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"}
package/dist/lib/flow.js CHANGED
@@ -25,8 +25,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
25
25
  }
26
26
  case "position": {
27
27
  const node = nodes.get(change.id);
28
- if (!node)
29
- break;
28
+ if (!node) break;
30
29
  if (change.dragging === true) {
31
30
  history.pause();
32
31
  }
@@ -46,8 +45,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
46
45
  }
47
46
  case "dimensions": {
48
47
  const node = nodes.get(change.id);
49
- if (!node)
50
- break;
48
+ if (!node) break;
51
49
  if (change.resizing === true) {
52
50
  history.pause();
53
51
  }
@@ -72,8 +70,7 @@ function applyNodeChanges(changes, nodes, history, getNodeSyncConfig) {
72
70
  }
73
71
  case "select": {
74
72
  const node = nodes.get(change.id);
75
- if (!node)
76
- break;
73
+ if (!node) break;
77
74
  node.setLocal("selected", change.selected);
78
75
  break;
79
76
  }
@@ -101,8 +98,7 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
101
98
  }
102
99
  case "select": {
103
100
  const edge = edges.get(change.id);
104
- if (!edge)
105
- break;
101
+ if (!edge) break;
106
102
  edge.setLocal("selected", change.selected);
107
103
  break;
108
104
  }
@@ -112,13 +108,11 @@ function applyEdgeChanges(changes, edges, getEdgeSyncConfig) {
112
108
  }
113
109
  }
114
110
  function nodeMapToList(nodesMap) {
115
- if (nodesMap === null)
116
- return null;
111
+ if (nodesMap === null) return null;
117
112
  return Object.values(nodesMap);
118
113
  }
119
114
  function edgeMapToList(edgesMap) {
120
- if (edgesMap === null)
121
- return null;
115
+ if (edgesMap === null) return null;
122
116
  return Object.values(edgesMap);
123
117
  }
124
118
  function useNodesAndEdges(storageKey) {
@@ -1 +1 @@
1
- {"version":3,"file":"flow.js","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history.disable(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["defaultAddEdge","edges"],"mappings":";;;;;;;AA6CA,MAAM,cAAc,EAAC,CAAA;AAqIrB,SAAS,gBACP,CAAA,OAAA,EACA,KACA,EAAA,OAAA,EACA,iBACM,EAAA;AACN,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAA,QAAQ,OAAO,IAAM;AAAA,MACnB,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,SAAW,EAAA;AACd,QAAA,MAAM,MAAS,GAAA,iBAAA,CAAkB,MAAO,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACjD,QAAA,MAAM,QAAW,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AACzC,QAAA,IAAI,QAAU,EAAA;AACZ,UAAS,QAAA,CAAA,SAAA,CAAU,MAAO,CAAA,IAAA,EAA+B,MAAM,CAAA,CAAA;AAAA,SAC1D,MAAA;AACL,UAAM,KAAA,CAAA,GAAA;AAAA,YACJ,OAAO,IAAK,CAAA,EAAA;AAAA,YACZ,wBAAA,CAAyB,MAAO,CAAA,IAAA,EAAM,MAAM,CAAA;AAAA,WAC9C,CAAA;AAAA,SACF;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,UAAY,EAAA;AACf,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAI,IAAA,MAAA,CAAO,aAAa,IAAM,EAAA;AAC5B,UAAA,OAAA,CAAQ,KAAM,EAAA,CAAA;AAAA,SAChB;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAM,MAAA,IAAA,GAAO,IAAK,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAChC,UAAI,IAAA,IAAA,EAAM,MAAM,MAAO,CAAA,QAAA,CAAS,KAAK,IAAM,EAAA,CAAA,KAAM,MAAO,CAAA,QAAA,CAAS,CAAG,EAAA;AAClE,YAAK,IAAA,CAAA,GAAA,CAAI,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,WACtC;AAAA,SACF;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAI,IAAA,MAAA,CAAO,aAAa,KAAO,EAAA;AAC7B,YAAA,OAAA,CAAQ,MAAO,EAAA,CAAA;AAAA,WACjB;AAEA,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,SAC3C;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,YAAc,EAAA;AACjB,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAI,IAAA,MAAA,CAAO,aAAa,IAAM,EAAA;AAC5B,UAAA,OAAA,CAAQ,KAAM,EAAA,CAAA;AAAA,SAChB;AAEA,QAAA,IACE,MAAO,CAAA,UAAA,KAAe,KACtB,CAAA,IAAA,MAAA,CAAO,kBAAkB,KACzB,CAAA,EAAA;AACA,UAAA,IACE,MAAO,CAAA,aAAA,KAAkB,IACzB,IAAA,MAAA,CAAO,kBAAkB,OACzB,EAAA;AACA,YAAA,IAAA,CAAK,GAAI,CAAA,OAAA,EAAS,MAAO,CAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAAA,WAC3C;AAEA,UAAA,IACE,MAAO,CAAA,aAAA,KAAkB,IACzB,IAAA,MAAA,CAAO,kBAAkB,QACzB,EAAA;AACA,YAAA,IAAA,CAAK,GAAI,CAAA,QAAA,EAAU,MAAO,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAAA,WAC7C;AAAA,SACF;AAEA,QAAI,IAAA,MAAA,CAAO,eAAe,KAAW,CAAA,EAAA;AAEnC,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,UAAU,CAAA,CAAA;AAAA,SAC7C;AAEA,QAAI,IAAA,MAAA,CAAO,aAAa,KAAW,CAAA,EAAA;AACjC,UAAI,IAAA,MAAA,CAAO,aAAa,KAAO,EAAA;AAC7B,YAAA,OAAA,CAAQ,MAAO,EAAA,CAAA;AAAA,WACjB;AAEA,UAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAAA,SAC3C;AAEA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAU,EAAA;AACb,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAGX,QAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AACzC,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AAEH,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AACF,CAAA;AAKA,SAAS,gBAAA,CACP,OACA,EAAA,KAAA,EACA,iBACM,EAAA;AACN,EAAA,KAAA,MAAW,UAAU,OAAS,EAAA;AAC5B,IAAA,QAAQ,OAAO,IAAM;AAAA,MACnB,KAAK,KAAA,CAAA;AAAA,MACL,KAAK,SAAW,EAAA;AACd,QAAA,MAAM,MAAS,GAAA,iBAAA,CAAkB,MAAO,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AACjD,QAAA,MAAM,QAAW,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AACzC,QAAA,IAAI,QAAU,EAAA;AACZ,UAAS,QAAA,CAAA,SAAA,CAAU,MAAO,CAAA,IAAA,EAA+B,MAAM,CAAA,CAAA;AAAA,SAC1D,MAAA;AACL,UAAM,KAAA,CAAA,GAAA;AAAA,YACJ,OAAO,IAAK,CAAA,EAAA;AAAA,YACZ,wBAAA,CAAyB,MAAO,CAAA,IAAA,EAAM,MAAM,CAAA;AAAA,WAC9C,CAAA;AAAA,SACF;AACA,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAU,EAAA;AACb,QAAA,MAAM,IAAO,GAAA,KAAA,CAAM,GAAI,CAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AAChC,QAAA,IAAI,CAAC,IAAA;AAAM,UAAA,MAAA;AAEX,QAAK,IAAA,CAAA,QAAA,CAAS,UAAY,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AACzC,QAAA,MAAA;AAAA,OACF;AAAA,MAEA,KAAK,QAAA;AAEH,QAAA,MAAA;AAAA,KACJ;AAAA,GACF;AACF,CAAA;AAKA,SAAS,cACP,QACY,EAAA;AACZ,EAAA,IAAI,QAAa,KAAA,IAAA;AAAM,IAAO,OAAA,IAAA,CAAA;AAC9B,EAAO,OAAA,MAAA,CAAO,OAAO,QAAQ,CAAA,CAAA;AAC/B,CAAA;AAEA,SAAS,cACP,QACY,EAAA;AACZ,EAAA,IAAI,QAAa,KAAA,IAAA;AAAM,IAAO,OAAA,IAAA,CAAA;AAC9B,EAAO,OAAA,MAAA,CAAO,OAAO,QAAQ,CAAA,CAAA;AAC/B,CAAA;AAEA,SAAS,iBAAiD,UAAoB,EAAA;AAI5E,EAAM,MAAA,QAAA,GAAW,UAAW,CAAA,CAAC,OAAY,KAAA;AACvC,IAAM,MAAA,IAAA,GAAO,QAAQ,UAAU,CAAA,CAAA;AAG/B,IAAA,OAAO,MAAM,KAAS,IAAA,IAAA,CAAA;AAAA,GACvB,CAAA,CAAA;AACD,EAAM,MAAA,QAAA,GAAW,UAAW,CAAA,CAAC,OAAY,KAAA;AACvC,IAAM,MAAA,IAAA,GAAO,QAAQ,UAAU,CAAA,CAAA;AAG/B,IAAA,OAAO,MAAM,KAAS,IAAA,IAAA,CAAA;AAAA,GACvB,CAAA,CAAA;AAED,EAAM,MAAA,KAAA,GAAQ,QAAQ,MAAM,aAAA,CAAiB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,KAAA,GAAQ,QAAQ,MAAM,aAAA,CAAiB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAClE,EAAO,OAAA,EAAE,OAAO,KAAM,EAAA,CAAA;AACxB,CAAA;AAqCgB,SAAA,iBAAA,CAId,OAA0C,GAAA,EACmC,EAAA;AAC7E,EAAA,MAAM,UAAU,UAAW,EAAA,CAAA;AAC3B,EAAA,MAAM,eAAkB,GAAA,UAAA,CAAW,MAAM,IAAI,CAAK,IAAA,KAAA,CAAA;AAGlD,EAAA,MAAM,gBAAgB,UAAW,CAAA;AAAA,IAC/B,OAAO,OAAQ,CAAA,KAAA;AAAA,IACf,OAAO,OAAQ,CAAA,KAAA;AAAA,IACf,UAAA,EAAY,QAAQ,UAAc,IAAA,mBAAA;AAAA,IAClC,QAAA,EAAU,QAAQ,QAAY,IAAA,KAAA;AAAA,GAC/B,CAAA,CAAA;AAGD,EAAM,MAAA,CAAC,iBAAmB,EAAA,iBAAiB,CAAI,GAAA,OAAA;AAAA,IAC7C,MACE;AAAA,MACE,oBAAA,CAAqB,aAAc,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA,MAC9C,oBAAA,CAAqB,aAAc,CAAA,KAAA,EAAO,IAAI,CAAA;AAAA,KAChD;AAAA,IACF,CAAC,aAAa,CAAA;AAAA,GAChB,CAAA;AAEA,EAAA,MAAM,EAAE,KAAO,EAAA,KAAA,EAAU,GAAA,gBAAA,CAAuB,cAAc,UAAU,CAAA,CAAA;AAExE,EAAA,MAAM,aAAgB,GAAA,WAAA;AAAA,IACpB,CAAC,EAAE,OAAQ,EAAA,EAAG,OAA6B,KAAA;AACzC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,gBAAA,CAAiB,SAAS,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,EAAG,SAAS,iBAAiB,CAAA,CAAA;AAAA,KACzE;AAAA,IACA,CAAC,OAAS,EAAA,aAAA,EAAe,iBAAiB,CAAA;AAAA,GAC5C,CAAA;AAEA,EAAA,MAAM,aAAgB,GAAA,WAAA;AAAA,IACpB,CAAC,EAAE,OAAQ,EAAA,EAAG,OAA6B,KAAA;AACzC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,gBAAA,CAAiB,OAAS,EAAA,IAAA,CAAK,GAAI,CAAA,OAAO,GAAG,iBAAiB,CAAA,CAAA;AAAA,KAChE;AAAA,IACA,CAAC,eAAe,iBAAiB,CAAA;AAAA,GACnC,CAAA;AAEA,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,EAAE,OAAQ,EAAA,EAAG,UAA2B,KAAA;AACvC,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAKA,MAAA,MAAM,CAAC,OAAO,CAAA,GAAIA,OAAe,CAAA,UAAA,EAAY,EAAS,CAAA,CAAA;AACtD,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAA,OAAA;AAAA,OACF;AAEA,MAAMC,MAAAA,MAAAA,GAAQ,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAC9B,MAAM,MAAA,MAAA,GAAS,iBAAkB,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAC7C,MAAAA,OAAM,GAAI,CAAA,OAAA,CAAQ,IAAI,wBAAyB,CAAA,OAAA,EAAS,MAAM,CAAC,CAAA,CAAA;AAAA,KACjE;AAAA,IACA,CAAC,aAAc,CAAA,UAAA,EAAY,iBAAiB,CAAA;AAAA,GAC9C,CAAA;AAEA,EAAA,MAAM,QAAW,GAAA,WAAA;AAAA,IACf,CAAC,EAAE,OAAQ,EAAA,EAAG,MAAuC,KAAA;AACnD,MAAA,MAAM,IAAO,GAAA,OAAA,CAAQ,GAAI,CAAA,aAAA,CAAc,UAAU,CAAA,CAAA;AAGjD,MAAA,IAAI,CAAC,IAAM,EAAA;AACT,QAAA,OAAA;AAAA,OACF;AAEA,MAAM,MAAA,QAAA,GAAW,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AACjC,MAAM,MAAA,QAAA,GAAW,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAEjC,MAAW,KAAA,MAAA,IAAA,IAAQ,OAAO,KAAO,EAAA;AAC/B,QAAS,QAAA,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AAAA,OACzB;AAEA,MAAW,KAAA,MAAA,IAAA,IAAQ,OAAO,KAAO,EAAA;AAC/B,QAAS,QAAA,CAAA,MAAA,CAAO,KAAK,EAAE,CAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,IACA,CAAC,cAAc,UAAU,CAAA;AAAA,GAC3B,CAAA;AAEA,EAAA,MAAM,iBAAoB,GAAA,WAAA;AAAA,IACxB,CAAC,EAAE,OAAA,EAAc,KAAA;AAGf,MAAA,IAAI,OAAQ,CAAA,GAAA,CAAI,aAAc,CAAA,UAAU,MAAM,KAAW,CAAA,EAAA;AACvD,QAAA,OAAA;AAAA,OACF;AAEA,MAAA,MAAM,YAAe,GAAA,aAAA,CAAc,KAAO,EAAA,OAAA,IAAW,EAAC,CAAA;AACtD,MAAA,MAAM,YAAe,GAAA,aAAA,CAAc,KAAO,EAAA,OAAA,IAAW,EAAC,CAAA;AAEtD,MAAQ,OAAA,CAAA,GAAA;AAAA,QACN,aAAc,CAAA,UAAA;AAAA,QACd,IAAI,UAAW,CAAA;AAAA,UACb,OAAO,IAAI,OAAA;AAAA,YACT,YAAA,CAAa,GAAI,CAAA,CAAC,IAAS,KAAA;AAAA,cACzB,IAAK,CAAA,EAAA;AAAA,cACL,wBAAyB,CAAA,IAAA,EAAM,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,aAC5D,CAAA;AAAA,WACH;AAAA,UACA,OAAO,IAAI,OAAA;AAAA,YACT,YAAA,CAAa,GAAI,CAAA,CAAC,IAAS,KAAA;AAAA,cACzB,IAAK,CAAA,EAAA;AAAA,cACL,wBAAyB,CAAA,IAAA,EAAM,iBAAkB,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,aAC5D,CAAA;AAAA,WACH;AAAA,SACD,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AAAA,IACA,CAAC,aAAe,EAAA,iBAAA,EAAmB,iBAAiB,CAAA;AAAA,GACtD,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,eAAiB,EAAA;AACnB,MAAA,OAAA,CAAQ,QAAQ,MAAM;AACpB,QAAkB,iBAAA,EAAA,CAAA;AAAA,OACnB,CAAA,CAAA;AAAA,KACH;AAAA,GACC,EAAA,CAAC,eAAiB,EAAA,iBAAA,EAAmB,OAAO,CAAC,CAAA,CAAA;AAEhD,EAAA,IAAI,cAAc,QAAU,EAAA;AAE1B,IAA4B,2BAAA,EAAA,CAAA;AAAA,GAC9B;AAEA,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,aAAA,CAAc,QAAY,GAAA,KAAA,IAAU,WAAuB,GAAA,KAAA;AAAA,IAClE,KAAO,EAAA,aAAA,CAAc,QAAY,GAAA,KAAA,IAAU,WAAuB,GAAA,KAAA;AAAA,IAClE,SAAW,EAAA,aAAA,CAAc,QAAW,GAAA,KAAA,GAAQ,CAAC,eAAA;AAAA,IAC7C,aAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,GACF,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"flow.js","sources":["../../src/lib/flow.ts"],"sourcesContent":["import type {\n History,\n JsonObject,\n ReadonlyJsonObject,\n Resolve,\n ToJson,\n} from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport { useHistory, useMutation, useStorage } from \"@liveblocks/react\";\nimport {\n useInitial,\n useSuspendUntilStorageReady,\n} from \"@liveblocks/react/_private\";\nimport type {\n BuiltInEdge,\n BuiltInNode,\n Connection,\n Edge,\n EdgeChange,\n Node,\n NodeChange,\n OnConnect,\n OnDelete,\n OnEdgesChange,\n OnNodesChange,\n} from \"@xyflow/react\";\nimport { addEdge as defaultAddEdge } from \"@xyflow/react\";\nimport { useEffect, useMemo } from \"react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksEdge,\n InternalLiveblocksFlow,\n InternalLiveblocksNode,\n NodeSyncConfig,\n SyncConfig,\n} from \"./types\";\n\nconst EMPTY_ARRAY = [] as unknown[];\n\ntype UseLiveblocksFlowResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Resolve<\n (\n | {\n nodes: null;\n edges: null;\n isLoading: true;\n }\n | {\n nodes: N[];\n edges: E[];\n isLoading: false;\n }\n ) & {\n onNodesChange: OnNodesChange<N>;\n onEdgesChange: OnEdgesChange<E>;\n onConnect: OnConnect;\n onDelete: OnDelete<N, E>;\n }\n>;\n\ntype LiveblocksFlowSuspenseResult<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> = Extract<UseLiveblocksFlowResult<N, E>, { isLoading: false }>;\n\ntype UseLiveblocksFlowOptions<N extends Node, E extends Edge> = {\n nodes?: {\n /**\n * The initial React Flow nodes.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * initial: [\n * { id: \"1\", position: { x: 0, y: 0 }, data: { label: \"Node 1\" } },\n * { id: \"2\", position: { x: 0, y: 100 }, data: { label: \"Node 2\" } },\n * ],\n * },\n * });\n * ```\n */\n initial?: N[];\n /**\n * Per-type sync configuration for node data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all node types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * nodes: {\n * sync: {\n * \"*\": {\n * label: false, // Don't sync node.data.label\n * color: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomNode: {\n * showPreview: false, // Don't sync myCustomNode.data.showPreview\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: NodeSyncConfig<N>;\n };\n\n edges?: {\n initial?: E[];\n /**\n * Per-type sync configuration for edge data keys.\n *\n * Each key in the config is either:\n * - `false` - Local-only, not synced to other clients\n * - `\"atomic\"` - Synced as a single value (replaced as-a-whole, not patched)\n * - `true` (or absent) - Deep sync (default, objects/arrays are patched)\n * - `{ ... }` - Nested config, applies recursively to sub-keys\n *\n * Use `\"*\"` as a fallback for all edge types. Type-specific entries are\n * deep-merged on top of `\"*\"`, with explicitly named keys taking\n * precedence.\n *\n * @example\n * ```tsx\n * const { ... } = useLiveblocksFlow({\n * edges: {\n * sync: {\n * \"*\": {\n * hovered: false, // Don't sync edge.data.hovered\n * style: \"atomic\", // Sync as a single value, replaced as-a-whole\n * },\n * myCustomEdge: {\n * isHighlighted: false, // Don't sync myCustomEdge.data.isHighlighted\n * },\n * },\n * },\n * });\n * ```\n */\n sync?: EdgeSyncConfig<E>;\n };\n\n /**\n * The key used to store the React Flow diagram in Liveblocks Storage.\n * Defaults to `\"flow\"`.\n */\n storageKey?: string;\n\n /**\n * When true, suspends until Storage is ready (use a React `Suspense`\n * boundary). Then `nodes` and `edges` are always arrays and `isLoading` is\n * always false.\n */\n suspense?: boolean;\n};\n\n// Similar to React Flow's `applyNodeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-node-changes\nfunction applyNodeChanges<N extends Node>(\n changes: NodeChange<N>[],\n nodes: LiveMap<string, InternalLiveblocksNode>,\n history: History,\n getNodeSyncConfig: (nodeType: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getNodeSyncConfig(change.item.type);\n const existing = nodes.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n nodes.set(\n change.item.id,\n toLiveblocksInternalNode(change.item, config)\n );\n }\n break;\n }\n\n case \"position\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.dragging === true) {\n history.pause();\n }\n\n if (change.position !== undefined) {\n const prev = node.get(\"position\");\n if (prev?.x !== change.position.x || prev?.y !== change.position.y) {\n node.set(\"position\", change.position);\n }\n }\n\n if (change.dragging !== undefined) {\n if (change.dragging === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `dragging: false`\n node.setLocal(\"dragging\", change.dragging);\n }\n break;\n }\n\n case \"dimensions\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Pause before setting the first position change so it doesn't create a separate undo step.\n if (change.resizing === true) {\n history.pause();\n }\n\n if (\n change.dimensions !== undefined &&\n change.setAttributes !== undefined\n ) {\n if (\n change.setAttributes === true ||\n change.setAttributes === \"width\"\n ) {\n node.set(\"width\", change.dimensions.width);\n }\n\n if (\n change.setAttributes === true ||\n change.setAttributes === \"height\"\n ) {\n node.set(\"height\", change.dimensions.height);\n }\n }\n\n if (change.dimensions !== undefined) {\n // Must match NODE_BASE_CONFIG's `measured: false`\n node.setLocal(\"measured\", change.dimensions);\n }\n\n if (change.resizing !== undefined) {\n if (change.resizing === false) {\n history.resume();\n }\n // Must match NODE_BASE_CONFIG's `resizing: false`\n node.setLocal(\"resizing\", change.resizing);\n }\n\n break;\n }\n\n case \"select\": {\n const node = nodes.get(change.id);\n if (!node) break;\n\n // Must match NODE_BASE_CONFIG's `selected: false`\n node.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// Similar to React Flow's `applyEdgeChanges()`, but writes local-only\n// properties via `setLocal()` / `delete()` on the LiveObject directly.\n// https://reactflow.dev/api-reference/utils/apply-edge-changes\nfunction applyEdgeChanges<E extends Edge>(\n changes: EdgeChange<E>[],\n edges: LiveMap<string, InternalLiveblocksEdge>,\n getEdgeSyncConfig: (type: string | undefined) => SyncConfig\n): void {\n for (const change of changes) {\n switch (change.type) {\n case \"add\":\n case \"replace\": {\n const config = getEdgeSyncConfig(change.item.type);\n const existing = edges.get(change.item.id);\n if (existing) {\n existing.reconcile(change.item as unknown as JsonObject, config);\n } else {\n edges.set(\n change.item.id,\n toLiveblocksInternalEdge(change.item, config)\n );\n }\n break;\n }\n\n case \"select\": {\n const edge = edges.get(change.id);\n if (!edge) break;\n // Must match EDGE_BASE_CONFIG's `selected: false`\n edge.setLocal(\"selected\", change.selected);\n break;\n }\n\n case \"remove\":\n // Removals are handled by onDelete for atomic undo\n break;\n }\n }\n}\n\n// TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n// in topological order (parents before children), deferring any node with a\n// parentId until its parent has been emitted.\nfunction nodeMapToList<N extends Node>(\n nodesMap: ReadonlyJsonObject | null\n): N[] | null {\n if (nodesMap === null) return null;\n return Object.values(nodesMap) as unknown as N[];\n}\n\nfunction edgeMapToList<E extends Edge>(\n edgesMap: ReadonlyJsonObject | null\n): E[] | null {\n if (edgesMap === null) return null;\n return Object.values(edgesMap) as unknown as E[];\n}\n\nfunction useNodesAndEdges<N extends Node, E extends Edge>(storageKey: string) {\n // Storage already includes local overlays via toJSON(), so no separate local\n // layer is needed. Individual node/edge immutable references are already\n // stable (only change when the underlying LiveObject changes).\n const nodesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.nodes ?? null;\n });\n const edgesMap = useStorage((storage) => {\n const flow = storage[storageKey] as\n | ToJson<InternalLiveblocksFlow>\n | undefined;\n return flow?.edges ?? null;\n });\n\n const nodes = useMemo(() => nodeMapToList<N>(nodesMap), [nodesMap]);\n const edges = useMemo(() => edgeMapToList<E>(edgesMap), [edgesMap]);\n return { nodes, edges };\n}\n\n/**\n * Returns a controlled React Flow state backed by Liveblocks Storage.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete, isLoading } = useLiveblocksFlow();\n *\n * if (isLoading) {\n * return <div>Loading…</div>\n * }\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n * Pass `{ suspense: true }` to suspend until Storage is ready, `nodes` and `edges` will never be `null`.\n *\n * @example\n * ```tsx\n * const { nodes, edges, onNodesChange, onEdgesChange, onConnect, onDelete } =\n * useLiveblocksFlow({ suspense: true });\n *\n * return <ReactFlow nodes={nodes} edges={edges} onNodesChange={onNodesChange} onEdgesChange={onEdgesChange} onConnect={onConnect} onDelete={onDelete} />;\n * ```\n */\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options?: UseLiveblocksFlowOptions<N, E> & { suspense?: false }\n): Resolve<UseLiveblocksFlowResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> & { suspense: true }\n): Resolve<LiveblocksFlowSuspenseResult<N, E>>;\nexport function useLiveblocksFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: UseLiveblocksFlowOptions<N, E> = {}\n): Resolve<UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>> {\n const history = useHistory();\n const isStorageLoaded = useStorage(() => true) ?? false;\n\n // These options are not reactive, only their initial values are used.\n const frozenOptions = useInitial({\n nodes: options.nodes,\n edges: options.edges,\n storageKey: options.storageKey ?? DEFAULT_STORAGE_KEY,\n suspense: options.suspense ?? false,\n });\n\n // Pre-compute sync config caches once (not on every render)\n const [getNodeSyncConfig, getEdgeSyncConfig] = useMemo(\n () =>\n [\n buildNodeConfigCache(frozenOptions.nodes?.sync),\n buildEdgeConfigCache(frozenOptions.edges?.sync),\n ] as const,\n [frozenOptions]\n );\n\n const { nodes, edges } = useNodesAndEdges<N, E>(frozenOptions.storageKey);\n\n const onNodesChange = useMutation(\n ({ storage }, changes: NodeChange<N>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyNodeChanges(changes, flow.get(\"nodes\"), history, getNodeSyncConfig);\n },\n [history, frozenOptions, getNodeSyncConfig]\n );\n\n const onEdgesChange = useMutation(\n ({ storage }, changes: EdgeChange<E>[]) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n applyEdgeChanges(changes, flow.get(\"edges\"), getEdgeSyncConfig);\n },\n [frozenOptions, getEdgeSyncConfig]\n );\n\n const onConnect = useMutation(\n ({ storage }, connection: Connection) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n // Delegate to React Flow's own `addEdge` helper for consistent default\n // edge ID generation, passing an empty array since de-duplication is\n // already handled above.\n const [newEdge] = defaultAddEdge(connection, [] as E[]);\n if (!newEdge) {\n return;\n }\n\n const edges = flow.get(\"edges\");\n const config = getEdgeSyncConfig(newEdge.type);\n edges.set(newEdge.id, toLiveblocksInternalEdge(newEdge, config));\n },\n [frozenOptions.storageKey, getEdgeSyncConfig]\n );\n\n const onDelete = useMutation(\n ({ storage }, params: { nodes: N[]; edges: E[] }) => {\n const flow = storage.get(frozenOptions.storageKey) as\n | InternalLiveblocksFlow\n | undefined;\n if (!flow) {\n return;\n }\n\n const nodesMap = flow.get(\"nodes\");\n const edgesMap = flow.get(\"edges\");\n\n for (const edge of params.edges) {\n edgesMap.delete(edge.id);\n }\n\n for (const node of params.nodes) {\n nodesMap.delete(node.id);\n }\n },\n [frozenOptions.storageKey]\n );\n\n const setInitialStorage = useMutation(\n ({ storage }) => {\n // Similarly to `initialStorage` on `Client.enterRoom` and `RoomProvider`, we only\n // initialize Storage if it doesn't already exist.\n if (storage.get(frozenOptions.storageKey) !== undefined) {\n return;\n }\n\n const initialNodes = frozenOptions.nodes?.initial ?? [];\n const initialEdges = frozenOptions.edges?.initial ?? [];\n\n storage.set(\n frozenOptions.storageKey,\n new LiveObject({\n nodes: new LiveMap(\n initialNodes.map((node) => [\n node.id,\n toLiveblocksInternalNode(node, getNodeSyncConfig(node.type)),\n ])\n ),\n edges: new LiveMap(\n initialEdges.map((edge) => [\n edge.id,\n toLiveblocksInternalEdge(edge, getEdgeSyncConfig(edge.type)),\n ])\n ),\n })\n );\n },\n [frozenOptions, getNodeSyncConfig, getEdgeSyncConfig]\n );\n\n useEffect(() => {\n if (isStorageLoaded) {\n history.disable(() => {\n setInitialStorage();\n });\n }\n }, [isStorageLoaded, setInitialStorage, history]);\n\n if (frozenOptions.suspense) {\n // eslint-disable-next-line react-hooks/rules-of-hooks -- `suspense` is frozen so this branch is stable\n useSuspendUntilStorageReady();\n }\n\n return {\n nodes: frozenOptions.suspense ? (nodes ?? (EMPTY_ARRAY as N[])) : nodes,\n edges: frozenOptions.suspense ? (edges ?? (EMPTY_ARRAY as E[])) : edges,\n isLoading: frozenOptions.suspense ? false : !isStorageLoaded,\n onNodesChange,\n onEdgesChange,\n onConnect,\n onDelete,\n } as UseLiveblocksFlowResult<N, E> | LiveblocksFlowSuspenseResult<N, E>;\n}\n"],"names":["defaultAddEdge","edges"],"mappings":"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"}
@@ -31,17 +31,14 @@ const EDGE_BASE_CONFIG = {
31
31
  // is expected to be provided by the end user
32
32
  };
33
33
  function buildFlowDataConfigCache(base, data) {
34
- if (!data)
35
- return () => base;
34
+ if (!data) return () => base;
36
35
  const dataFallback = data["*"];
37
36
  const fallback = dataFallback ? { ...base, data: dataFallback } : base;
38
37
  const cache = /* @__PURE__ */ new Map();
39
38
  for (const type in data) {
40
- if (type === "*")
41
- continue;
39
+ if (type === "*") continue;
42
40
  const specific = data[type];
43
- if (!specific)
44
- continue;
41
+ if (!specific) continue;
45
42
  const dataConfig = { ...dataFallback, ...specific };
46
43
  cache.set(type, { ...base, data: dataConfig });
47
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shared.cjs","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":["LiveObject"],"mappings":";;;;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAA,IAAI,CAAC,IAAA;AAAM,IAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,IAAS,KAAA,GAAA;AAAK,MAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAA;AAAU,MAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;;;;;;;;"}
1
+ {"version":3,"file":"shared.cjs","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":["LiveObject"],"mappings":";;;;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAI,IAAA,CAAC,IAAM,EAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,SAAS,GAAK,EAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAU,EAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAOA,eAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;;;;;;;;"}
@@ -29,17 +29,14 @@ const EDGE_BASE_CONFIG = {
29
29
  // is expected to be provided by the end user
30
30
  };
31
31
  function buildFlowDataConfigCache(base, data) {
32
- if (!data)
33
- return () => base;
32
+ if (!data) return () => base;
34
33
  const dataFallback = data["*"];
35
34
  const fallback = dataFallback ? { ...base, data: dataFallback } : base;
36
35
  const cache = /* @__PURE__ */ new Map();
37
36
  for (const type in data) {
38
- if (type === "*")
39
- continue;
37
+ if (type === "*") continue;
40
38
  const specific = data[type];
41
- if (!specific)
42
- continue;
39
+ if (!specific) continue;
43
40
  const dataConfig = { ...dataFallback, ...specific };
44
41
  cache.set(type, { ...base, data: dataConfig });
45
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":[],"mappings":";;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAA,IAAI,CAAC,IAAA;AAAM,IAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,IAAS,KAAA,GAAA;AAAK,MAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAA;AAAU,MAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;"}
1
+ {"version":3,"file":"shared.js","sources":["../../src/lib/shared.ts"],"sourcesContent":["/**\n * Module with utilities shared between the React Flow frontend and the React\n * Flow Node backend. There are no runtime dependencies on @xyflow/react,\n * react, or any other frontend-specific libraries from this module, and this\n * should stay that way.\n */\nimport type { JsonObject, SyncConfig, SyncMode } from \"@liveblocks/core\";\nimport { LiveObject } from \"@liveblocks/core\";\nimport type { Edge, Node } from \"@xyflow/react\";\n\nimport type { InternalLiveblocksEdge, InternalLiveblocksNode } from \"./types\";\n\nexport const DEFAULT_STORAGE_KEY = \"flow\";\n\n// React Flow specific versions of `SyncConfig` that only allow keys that are actually exposed by React Flow.\ntype NodeSyncConfig = { [K in keyof Node]?: SyncMode };\ntype EdgeSyncConfig = { [K in keyof Edge]?: SyncMode };\n\nexport const NODE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n dragging: false,\n measured: false,\n resizing: false,\n\n // Atomic (synced as plain Json)\n position: \"atomic\",\n sourcePosition: \"atomic\",\n targetPosition: \"atomic\",\n extent: \"atomic\",\n origin: \"atomic\",\n handles: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies NodeSyncConfig;\n\nexport const EDGE_BASE_CONFIG = {\n // Local-only (not synced)\n selected: false,\n\n // Atomic (synced as plain Json)\n markerStart: \"atomic\",\n markerEnd: \"atomic\",\n label: \"atomic\",\n labelBgPadding: \"atomic\",\n\n // Note: the `data` key is intentionally left out of this base config, as it\n // is expected to be provided by the end user\n} as const satisfies EdgeSyncConfig;\n\n/**\n * Merges a base config with per-type user data configs, returning a lookup\n * function that resolves the full SyncConfig for a given type string.\n */\nexport function buildFlowDataConfigCache(\n base: SyncConfig,\n data?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n if (!data) return () => base;\n\n const dataFallback = data[\"*\"];\n const fallback = dataFallback ? { ...base, data: dataFallback } : base;\n\n // Pre-compute full sync configs for all explicitly declared types\n const cache = new Map<string | undefined, SyncConfig>();\n for (const type in data) {\n if (type === \"*\") continue;\n const specific = data[type];\n if (!specific) continue;\n const dataConfig: SyncConfig = { ...dataFallback, ...specific };\n cache.set(type, { ...base, data: dataConfig });\n }\n\n return (type) => cache.get(type) || fallback;\n}\n\nexport function buildNodeConfigCache(\n nodeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(NODE_BASE_CONFIG, nodeDataConfig);\n}\n\nexport function buildEdgeConfigCache(\n edgeDataConfig?: Record<string, SyncConfig | undefined>\n): (type: string | undefined) => SyncConfig {\n return buildFlowDataConfigCache(EDGE_BASE_CONFIG, edgeDataConfig);\n}\n\nexport function toLiveblocksInternalNode<N extends Node>(\n node: N,\n config: SyncConfig\n): InternalLiveblocksNode {\n return LiveObject.from(\n node as unknown as JsonObject,\n config\n ) as InternalLiveblocksNode;\n}\n\nexport function toLiveblocksInternalEdge<E extends Edge>(\n edge: E,\n config: SyncConfig\n): InternalLiveblocksEdge {\n return LiveObject.from(\n edge as unknown as JsonObject,\n config\n ) as InternalLiveblocksEdge;\n}\n"],"names":[],"mappings":";;AAYO,MAAM,mBAAsB,GAAA,OAAA;AAM5B,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA,EACV,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,QAAU,EAAA,QAAA;AAAA,EACV,cAAgB,EAAA,QAAA;AAAA,EAChB,cAAgB,EAAA,QAAA;AAAA,EAChB,MAAQ,EAAA,QAAA;AAAA,EACR,MAAQ,EAAA,QAAA;AAAA,EACR,OAAS,EAAA,QAAA;AAAA;AAAA;AAIX,EAAA;AAEO,MAAM,gBAAmB,GAAA;AAAA;AAAA,EAE9B,QAAU,EAAA,KAAA;AAAA;AAAA,EAGV,WAAa,EAAA,QAAA;AAAA,EACb,SAAW,EAAA,QAAA;AAAA,EACX,KAAO,EAAA,QAAA;AAAA,EACP,cAAgB,EAAA,QAAA;AAAA;AAAA;AAIlB,EAAA;AAMgB,SAAA,wBAAA,CACd,MACA,IAC0C,EAAA;AAC1C,EAAI,IAAA,CAAC,IAAM,EAAA,OAAO,MAAM,IAAA,CAAA;AAExB,EAAM,MAAA,YAAA,GAAe,KAAK,GAAG,CAAA,CAAA;AAC7B,EAAA,MAAM,WAAW,YAAe,GAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,cAAiB,GAAA,IAAA,CAAA;AAGlE,EAAM,MAAA,KAAA,uBAAY,GAAoC,EAAA,CAAA;AACtD,EAAA,KAAA,MAAW,QAAQ,IAAM,EAAA;AACvB,IAAA,IAAI,SAAS,GAAK,EAAA,SAAA;AAClB,IAAM,MAAA,QAAA,GAAW,KAAK,IAAI,CAAA,CAAA;AAC1B,IAAA,IAAI,CAAC,QAAU,EAAA,SAAA;AACf,IAAA,MAAM,UAAyB,GAAA,EAAE,GAAG,YAAA,EAAc,GAAG,QAAS,EAAA,CAAA;AAC9D,IAAA,KAAA,CAAM,IAAI,IAAM,EAAA,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,YAAY,CAAA,CAAA;AAAA,GAC/C;AAEA,EAAA,OAAO,CAAC,IAAA,KAAS,KAAM,CAAA,GAAA,CAAI,IAAI,CAAK,IAAA,QAAA,CAAA;AACtC,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEO,SAAS,qBACd,cAC0C,EAAA;AAC1C,EAAO,OAAA,wBAAA,CAAyB,kBAAkB,cAAc,CAAA,CAAA;AAClE,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEgB,SAAA,wBAAA,CACd,MACA,MACwB,EAAA;AACxB,EAAA,OAAO,UAAW,CAAA,IAAA;AAAA,IAChB,IAAA;AAAA,IACA,MAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const PKG_NAME = "@liveblocks/react-flow";
4
- const PKG_VERSION = typeof "3.18.2" === "string" && "3.18.2";
4
+ const PKG_VERSION = typeof "3.18.3-test2" === "string" && "3.18.3-test2";
5
5
  const PKG_FORMAT = typeof TSUP_FORMAT === "string" && TSUP_FORMAT;
6
6
 
7
7
  exports.PKG_FORMAT = PKG_FORMAT;
@@ -1 +1 @@
1
- {"version":3,"file":"version.cjs","sources":["../../src/lib/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-flow\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,yBAAA;AACX,MAAA,WAAA,GAAc,OAAO,QAAA,KAAgB,QAAY,IAAA,SAAA;AACjD,MAAA,UAAA,GAAa,OAAO,WAAA,KAAgB,QAAY,IAAA;;;;;;"}
1
+ {"version":3,"file":"version.cjs","sources":["../../src/lib/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-flow\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,yBAAA;AACX,MAAA,WAAA,GAAc,OAAO,cAAA,KAAgB,QAAY,IAAA,eAAA;AACjD,MAAA,UAAA,GAAa,OAAO,WAAA,KAAgB,QAAY,IAAA;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  const PKG_NAME = "@liveblocks/react-flow";
2
- const PKG_VERSION = typeof "3.18.2" === "string" && "3.18.2";
2
+ const PKG_VERSION = typeof "3.18.3-test2" === "string" && "3.18.3-test2";
3
3
  const PKG_FORMAT = typeof TSUP_FORMAT === "string" && TSUP_FORMAT;
4
4
 
5
5
  export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sources":["../../src/lib/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-flow\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,yBAAA;AACX,MAAA,WAAA,GAAc,OAAO,QAAA,KAAgB,QAAY,IAAA,SAAA;AACjD,MAAA,UAAA,GAAa,OAAO,WAAA,KAAgB,QAAY,IAAA;;;;"}
1
+ {"version":3,"file":"version.js","sources":["../../src/lib/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const TSUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-flow\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof TSUP_FORMAT === \"string\" && TSUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,yBAAA;AACX,MAAA,WAAA,GAAc,OAAO,cAAA,KAAgB,QAAY,IAAA,eAAA;AACjD,MAAA,UAAA,GAAa,OAAO,WAAA,KAAgB,QAAY,IAAA;;;;"}
package/dist/node.cjs CHANGED
@@ -82,8 +82,7 @@ async function mutateFlow(options, callback) {
82
82
  },
83
83
  updateNode(id, partialOrUpdater) {
84
84
  const oldNode = getNode(id);
85
- if (!oldNode)
86
- return;
85
+ if (!oldNode) return;
87
86
  let newNode;
88
87
  if (typeof partialOrUpdater === "function") {
89
88
  newNode = partialOrUpdater(oldNode);
@@ -117,8 +116,7 @@ async function mutateFlow(options, callback) {
117
116
  },
118
117
  updateEdge(id, partialOrUpdater) {
119
118
  const oldEdge = getEdge(id);
120
- if (!oldEdge)
121
- return;
119
+ if (!oldEdge) return;
122
120
  let newEdge;
123
121
  if (typeof partialOrUpdater === "function") {
124
122
  newEdge = partialOrUpdater(oldEdge);
package/dist/node.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.cjs","sources":["../src/node.ts"],"sourcesContent":["import type { JsonObject, LsonObject } from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport type { BuiltInEdge, BuiltInNode, Edge, Node } from \"@xyflow/react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./lib/shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksFlow,\n NodeSyncConfig,\n} from \"./lib/types\";\n\n/**\n * A minimal interface for the Liveblocks Node client — just the\n * `mutateStorage` method we actually need. This avoids importing\n * `@liveblocks/node` as a dependency.\n */\ninterface ILiveblocksClient {\n mutateStorage(\n roomId: string,\n callback: (context: {\n root: LiveObject<LsonObject>;\n }) => void | Promise<void>\n ): Promise<void>;\n}\n\n/** Options for `mutateFlow()`. */\nexport interface MutateFlowOptions<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> {\n client: ILiveblocksClient;\n roomId: string;\n storageKey?: string;\n nodes?: { sync?: NodeSyncConfig<N> };\n edges?: { sync?: EdgeSyncConfig<E> };\n}\n\nexport interface MutableFlow<N extends Node, E extends Edge> {\n /** The current list of nodes. */\n readonly nodes: readonly N[];\n /** The current list of edges. */\n readonly edges: readonly E[];\n /** Returns a plain object snapshot with `nodes` and `edges` arrays. */\n toJSON(): {\n nodes: readonly N[];\n edges: readonly E[];\n };\n\n /** Returns a single node by ID, or `undefined` if not found. */\n getNode(id: string): N | undefined;\n /** Returns a single edge by ID, or `undefined` if not found. */\n getEdge(id: string): E | undefined;\n\n /** Adds a node. If a node with the same ID already exists, it is replaced. */\n addNode(node: N): void;\n /** Adds multiple nodes. Existing nodes with the same IDs are replaced. */\n addNodes(nodes: N[]): void;\n /** Updates a node by merging a partial object. No-op if the node does not exist. */\n updateNode(id: string, partial: Partial<N>): void;\n /** Updates a node using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */\n updateNode(id: string, updater: (node: N) => N): void;\n /** Updates a node's `data` by merging a partial object. No-op if the node does not exist. */\n updateNodeData(id: string, partial: Partial<N[\"data\"]>): void;\n /** 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. */\n updateNodeData<D extends N[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes a node by ID. */\n removeNode(id: string): void;\n /** Removes multiple nodes by ID. */\n removeNodes(ids: string[]): void;\n\n /** Adds an edge. If an edge with the same ID already exists, it is replaced. */\n addEdge(edge: E): void;\n /** Adds multiple edges. Existing edges with the same IDs are replaced. */\n addEdges(edges: E[]): void;\n /** Updates an edge by merging a partial object. No-op if the edge does not exist. */\n updateEdge(id: string, partial: Partial<E>): void;\n /** Updates an edge using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */\n updateEdge(id: string, updater: (edge: E) => E): void;\n /** Updates an edge's `data` by merging a partial object. No-op if the edge does not exist. */\n updateEdgeData(id: string, partial: Partial<NonNullable<E[\"data\"]>>): void;\n /** 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. */\n updateEdgeData<D extends E[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes an edge by ID. */\n removeEdge(id: string): void;\n /** Removes multiple edges by ID. */\n removeEdges(ids: string[]): void;\n}\n\n/**\n * Opens a flow (a collection of React Flow nodes and edges) for reading and\n * mutating, then automatically flushes all changes when the callback\n * completes.\n *\n * @example\n * ```ts\n * await mutateFlow({ client, roomId: \"my-room\" }, (flow) => {\n * flow.addNode({ id: \"1\", position: { x: 0, y: 0 }, data: {} });\n * flow.updateNodeData(\"1\", { label: \"Hello\" });\n * });\n * ```\n */\nexport async function mutateFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: MutateFlowOptions<N, E>,\n callback: (flow: MutableFlow<N, E>) => void | Promise<void>\n): Promise<void> {\n const { client, roomId } = options;\n const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n\n const getNodeSyncConfig = buildNodeConfigCache(options.nodes?.sync);\n const getEdgeSyncConfig = buildEdgeConfigCache(options.edges?.sync);\n\n const nodeListCache = new WeakMap<Record<string, N>, N[]>();\n const edgeListCache = new WeakMap<Record<string, E>, E[]>();\n\n await client.mutateStorage(roomId, async ({ root }) => {\n let flow = root.get(storageKey) as InternalLiveblocksFlow | undefined;\n if (!flow) {\n const newFlow = new LiveObject({\n nodes: new LiveMap(),\n edges: new LiveMap(),\n }) satisfies InternalLiveblocksFlow;\n root.set(storageKey, newFlow);\n flow = newFlow;\n }\n\n const nodesLiveMap = flow.get(\"nodes\");\n const edgesLiveMap = flow.get(\"edges\");\n\n function getNodes(): readonly N[] {\n const nodeMap = nodesLiveMap.toJSON() as unknown as Record<string, N>;\n if (!nodeListCache.has(nodeMap)) {\n // TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n // in topological order (parents before children), deferring any node with a\n // parentId until its parent has been emitted.\n nodeListCache.set(nodeMap, Object.values(nodeMap));\n }\n return nodeListCache.get(nodeMap)!;\n }\n\n function getEdges(): readonly E[] {\n const edgeMap = edgesLiveMap.toJSON() as unknown as Record<string, E>;\n if (!edgeListCache.has(edgeMap)) {\n edgeListCache.set(edgeMap, Object.values(edgeMap));\n }\n return edgeListCache.get(edgeMap)!;\n }\n\n function getNode(id: string) {\n return nodesLiveMap.get(id)?.toJSON() as N | undefined;\n }\n function getEdge(id: string) {\n return edgesLiveMap.get(id)?.toJSON() as E | undefined;\n }\n\n function upsertNode(id: string, newNode: N) {\n const existing = nodesLiveMap.get(id);\n const syncConfig = getNodeSyncConfig(newNode.type);\n if (!existing) {\n nodesLiveMap.set(id, toLiveblocksInternalNode(newNode, syncConfig));\n } else {\n existing.reconcile(newNode as unknown as JsonObject, syncConfig);\n }\n }\n\n function upsertEdge(id: string, newEdge: E) {\n const existing = edgesLiveMap.get(id);\n const syncConfig = getEdgeSyncConfig(newEdge.type);\n if (!existing) {\n edgesLiveMap.set(id, toLiveblocksInternalEdge(newEdge, syncConfig));\n } else {\n existing.reconcile(newEdge as unknown as JsonObject, syncConfig);\n }\n }\n\n const mutableFlow: MutableFlow<N, E> = {\n get nodes() {\n return getNodes();\n },\n get edges() {\n return getEdges();\n },\n toJSON() {\n return { nodes: getNodes(), edges: getEdges() };\n },\n getNode,\n getEdge,\n\n addNode(node: N) {\n upsertNode(node.id, node);\n },\n addNodes(nodes: N[]) {\n for (const node of nodes) {\n mutableFlow.addNode(node);\n }\n },\n updateNode(id: string, partialOrUpdater: Partial<N> | ((node: N) => N)) {\n const oldNode = getNode(id);\n if (!oldNode) return;\n\n let newNode: N;\n if (typeof partialOrUpdater === \"function\") {\n newNode = partialOrUpdater(oldNode);\n } else {\n newNode = { ...oldNode, ...partialOrUpdater };\n }\n return upsertNode(id, newNode);\n },\n updateNodeData(\n id: string,\n partialOrUpdater:\n | Partial<N[\"data\"]>\n | (<D extends N[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateNode(id, (node) => {\n const currData = node.data ?? ({} as N[\"data\"]);\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...node, data: newData };\n });\n },\n removeNode(id: string) {\n nodesLiveMap.delete(id);\n },\n removeNodes(ids: string[]) {\n for (const id of ids) {\n nodesLiveMap.delete(id);\n }\n },\n\n addEdge(edge: E) {\n upsertEdge(edge.id, edge);\n },\n addEdges(edges: E[]) {\n for (const edge of edges) {\n mutableFlow.addEdge(edge);\n }\n },\n updateEdge(id: string, partialOrUpdater: Partial<E> | ((edge: E) => E)) {\n const oldEdge = getEdge(id);\n if (!oldEdge) return;\n\n let newEdge: E;\n if (typeof partialOrUpdater === \"function\") {\n newEdge = partialOrUpdater(oldEdge);\n } else {\n newEdge = { ...oldEdge, ...partialOrUpdater };\n }\n return upsertEdge(id, newEdge);\n },\n updateEdgeData(\n id: string,\n partialOrUpdater:\n | Partial<NonNullable<E[\"data\"]>>\n | (<D extends E[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateEdge(id, (edge) => {\n const currData = edge.data;\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...edge, data: newData };\n });\n },\n removeEdge(id: string) {\n edgesLiveMap.delete(id);\n },\n removeEdges(ids: string[]) {\n for (const id of ids) {\n edgesLiveMap.delete(id);\n }\n },\n };\n\n await callback(mutableFlow);\n });\n}\n"],"names":["DEFAULT_STORAGE_KEY","buildNodeConfigCache","buildEdgeConfigCache","LiveObject","LiveMap","toLiveblocksInternalNode","toLiveblocksInternalEdge"],"mappings":"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"}
1
+ {"version":3,"file":"node.cjs","sources":["../src/node.ts"],"sourcesContent":["import type { JsonObject, LsonObject } from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport type { BuiltInEdge, BuiltInNode, Edge, Node } from \"@xyflow/react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./lib/shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksFlow,\n NodeSyncConfig,\n} from \"./lib/types\";\n\n/**\n * A minimal interface for the Liveblocks Node client — just the\n * `mutateStorage` method we actually need. This avoids importing\n * `@liveblocks/node` as a dependency.\n */\ninterface ILiveblocksClient {\n mutateStorage(\n roomId: string,\n callback: (context: {\n root: LiveObject<LsonObject>;\n }) => void | Promise<void>\n ): Promise<void>;\n}\n\n/** Options for `mutateFlow()`. */\nexport interface MutateFlowOptions<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> {\n client: ILiveblocksClient;\n roomId: string;\n storageKey?: string;\n nodes?: { sync?: NodeSyncConfig<N> };\n edges?: { sync?: EdgeSyncConfig<E> };\n}\n\nexport interface MutableFlow<N extends Node, E extends Edge> {\n /** The current list of nodes. */\n readonly nodes: readonly N[];\n /** The current list of edges. */\n readonly edges: readonly E[];\n /** Returns a plain object snapshot with `nodes` and `edges` arrays. */\n toJSON(): {\n nodes: readonly N[];\n edges: readonly E[];\n };\n\n /** Returns a single node by ID, or `undefined` if not found. */\n getNode(id: string): N | undefined;\n /** Returns a single edge by ID, or `undefined` if not found. */\n getEdge(id: string): E | undefined;\n\n /** Adds a node. If a node with the same ID already exists, it is replaced. */\n addNode(node: N): void;\n /** Adds multiple nodes. Existing nodes with the same IDs are replaced. */\n addNodes(nodes: N[]): void;\n /** Updates a node by merging a partial object. No-op if the node does not exist. */\n updateNode(id: string, partial: Partial<N>): void;\n /** Updates a node using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */\n updateNode(id: string, updater: (node: N) => N): void;\n /** Updates a node's `data` by merging a partial object. No-op if the node does not exist. */\n updateNodeData(id: string, partial: Partial<N[\"data\"]>): void;\n /** 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. */\n updateNodeData<D extends N[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes a node by ID. */\n removeNode(id: string): void;\n /** Removes multiple nodes by ID. */\n removeNodes(ids: string[]): void;\n\n /** Adds an edge. If an edge with the same ID already exists, it is replaced. */\n addEdge(edge: E): void;\n /** Adds multiple edges. Existing edges with the same IDs are replaced. */\n addEdges(edges: E[]): void;\n /** Updates an edge by merging a partial object. No-op if the edge does not exist. */\n updateEdge(id: string, partial: Partial<E>): void;\n /** Updates an edge using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */\n updateEdge(id: string, updater: (edge: E) => E): void;\n /** Updates an edge's `data` by merging a partial object. No-op if the edge does not exist. */\n updateEdgeData(id: string, partial: Partial<NonNullable<E[\"data\"]>>): void;\n /** 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. */\n updateEdgeData<D extends E[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes an edge by ID. */\n removeEdge(id: string): void;\n /** Removes multiple edges by ID. */\n removeEdges(ids: string[]): void;\n}\n\n/**\n * Opens a flow (a collection of React Flow nodes and edges) for reading and\n * mutating, then automatically flushes all changes when the callback\n * completes.\n *\n * @example\n * ```ts\n * await mutateFlow({ client, roomId: \"my-room\" }, (flow) => {\n * flow.addNode({ id: \"1\", position: { x: 0, y: 0 }, data: {} });\n * flow.updateNodeData(\"1\", { label: \"Hello\" });\n * });\n * ```\n */\nexport async function mutateFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: MutateFlowOptions<N, E>,\n callback: (flow: MutableFlow<N, E>) => void | Promise<void>\n): Promise<void> {\n const { client, roomId } = options;\n const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n\n const getNodeSyncConfig = buildNodeConfigCache(options.nodes?.sync);\n const getEdgeSyncConfig = buildEdgeConfigCache(options.edges?.sync);\n\n const nodeListCache = new WeakMap<Record<string, N>, N[]>();\n const edgeListCache = new WeakMap<Record<string, E>, E[]>();\n\n await client.mutateStorage(roomId, async ({ root }) => {\n let flow = root.get(storageKey) as InternalLiveblocksFlow | undefined;\n if (!flow) {\n const newFlow = new LiveObject({\n nodes: new LiveMap(),\n edges: new LiveMap(),\n }) satisfies InternalLiveblocksFlow;\n root.set(storageKey, newFlow);\n flow = newFlow;\n }\n\n const nodesLiveMap = flow.get(\"nodes\");\n const edgesLiveMap = flow.get(\"edges\");\n\n function getNodes(): readonly N[] {\n const nodeMap = nodesLiveMap.toJSON() as unknown as Record<string, N>;\n if (!nodeListCache.has(nodeMap)) {\n // TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n // in topological order (parents before children), deferring any node with a\n // parentId until its parent has been emitted.\n nodeListCache.set(nodeMap, Object.values(nodeMap));\n }\n return nodeListCache.get(nodeMap)!;\n }\n\n function getEdges(): readonly E[] {\n const edgeMap = edgesLiveMap.toJSON() as unknown as Record<string, E>;\n if (!edgeListCache.has(edgeMap)) {\n edgeListCache.set(edgeMap, Object.values(edgeMap));\n }\n return edgeListCache.get(edgeMap)!;\n }\n\n function getNode(id: string) {\n return nodesLiveMap.get(id)?.toJSON() as N | undefined;\n }\n function getEdge(id: string) {\n return edgesLiveMap.get(id)?.toJSON() as E | undefined;\n }\n\n function upsertNode(id: string, newNode: N) {\n const existing = nodesLiveMap.get(id);\n const syncConfig = getNodeSyncConfig(newNode.type);\n if (!existing) {\n nodesLiveMap.set(id, toLiveblocksInternalNode(newNode, syncConfig));\n } else {\n existing.reconcile(newNode as unknown as JsonObject, syncConfig);\n }\n }\n\n function upsertEdge(id: string, newEdge: E) {\n const existing = edgesLiveMap.get(id);\n const syncConfig = getEdgeSyncConfig(newEdge.type);\n if (!existing) {\n edgesLiveMap.set(id, toLiveblocksInternalEdge(newEdge, syncConfig));\n } else {\n existing.reconcile(newEdge as unknown as JsonObject, syncConfig);\n }\n }\n\n const mutableFlow: MutableFlow<N, E> = {\n get nodes() {\n return getNodes();\n },\n get edges() {\n return getEdges();\n },\n toJSON() {\n return { nodes: getNodes(), edges: getEdges() };\n },\n getNode,\n getEdge,\n\n addNode(node: N) {\n upsertNode(node.id, node);\n },\n addNodes(nodes: N[]) {\n for (const node of nodes) {\n mutableFlow.addNode(node);\n }\n },\n updateNode(id: string, partialOrUpdater: Partial<N> | ((node: N) => N)) {\n const oldNode = getNode(id);\n if (!oldNode) return;\n\n let newNode: N;\n if (typeof partialOrUpdater === \"function\") {\n newNode = partialOrUpdater(oldNode);\n } else {\n newNode = { ...oldNode, ...partialOrUpdater };\n }\n return upsertNode(id, newNode);\n },\n updateNodeData(\n id: string,\n partialOrUpdater:\n | Partial<N[\"data\"]>\n | (<D extends N[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateNode(id, (node) => {\n const currData = node.data ?? ({} as N[\"data\"]);\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...node, data: newData };\n });\n },\n removeNode(id: string) {\n nodesLiveMap.delete(id);\n },\n removeNodes(ids: string[]) {\n for (const id of ids) {\n nodesLiveMap.delete(id);\n }\n },\n\n addEdge(edge: E) {\n upsertEdge(edge.id, edge);\n },\n addEdges(edges: E[]) {\n for (const edge of edges) {\n mutableFlow.addEdge(edge);\n }\n },\n updateEdge(id: string, partialOrUpdater: Partial<E> | ((edge: E) => E)) {\n const oldEdge = getEdge(id);\n if (!oldEdge) return;\n\n let newEdge: E;\n if (typeof partialOrUpdater === \"function\") {\n newEdge = partialOrUpdater(oldEdge);\n } else {\n newEdge = { ...oldEdge, ...partialOrUpdater };\n }\n return upsertEdge(id, newEdge);\n },\n updateEdgeData(\n id: string,\n partialOrUpdater:\n | Partial<NonNullable<E[\"data\"]>>\n | (<D extends E[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateEdge(id, (edge) => {\n const currData = edge.data;\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...edge, data: newData };\n });\n },\n removeEdge(id: string) {\n edgesLiveMap.delete(id);\n },\n removeEdges(ids: string[]) {\n for (const id of ids) {\n edgesLiveMap.delete(id);\n }\n },\n };\n\n await callback(mutableFlow);\n });\n}\n"],"names":["DEFAULT_STORAGE_KEY","buildNodeConfigCache","buildEdgeConfigCache","LiveObject","LiveMap","toLiveblocksInternalNode","toLiveblocksInternalEdge"],"mappings":"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"}
package/dist/node.js CHANGED
@@ -80,8 +80,7 @@ async function mutateFlow(options, callback) {
80
80
  },
81
81
  updateNode(id, partialOrUpdater) {
82
82
  const oldNode = getNode(id);
83
- if (!oldNode)
84
- return;
83
+ if (!oldNode) return;
85
84
  let newNode;
86
85
  if (typeof partialOrUpdater === "function") {
87
86
  newNode = partialOrUpdater(oldNode);
@@ -115,8 +114,7 @@ async function mutateFlow(options, callback) {
115
114
  },
116
115
  updateEdge(id, partialOrUpdater) {
117
116
  const oldEdge = getEdge(id);
118
- if (!oldEdge)
119
- return;
117
+ if (!oldEdge) return;
120
118
  let newEdge;
121
119
  if (typeof partialOrUpdater === "function") {
122
120
  newEdge = partialOrUpdater(oldEdge);
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sources":["../src/node.ts"],"sourcesContent":["import type { JsonObject, LsonObject } from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport type { BuiltInEdge, BuiltInNode, Edge, Node } from \"@xyflow/react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./lib/shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksFlow,\n NodeSyncConfig,\n} from \"./lib/types\";\n\n/**\n * A minimal interface for the Liveblocks Node client — just the\n * `mutateStorage` method we actually need. This avoids importing\n * `@liveblocks/node` as a dependency.\n */\ninterface ILiveblocksClient {\n mutateStorage(\n roomId: string,\n callback: (context: {\n root: LiveObject<LsonObject>;\n }) => void | Promise<void>\n ): Promise<void>;\n}\n\n/** Options for `mutateFlow()`. */\nexport interface MutateFlowOptions<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> {\n client: ILiveblocksClient;\n roomId: string;\n storageKey?: string;\n nodes?: { sync?: NodeSyncConfig<N> };\n edges?: { sync?: EdgeSyncConfig<E> };\n}\n\nexport interface MutableFlow<N extends Node, E extends Edge> {\n /** The current list of nodes. */\n readonly nodes: readonly N[];\n /** The current list of edges. */\n readonly edges: readonly E[];\n /** Returns a plain object snapshot with `nodes` and `edges` arrays. */\n toJSON(): {\n nodes: readonly N[];\n edges: readonly E[];\n };\n\n /** Returns a single node by ID, or `undefined` if not found. */\n getNode(id: string): N | undefined;\n /** Returns a single edge by ID, or `undefined` if not found. */\n getEdge(id: string): E | undefined;\n\n /** Adds a node. If a node with the same ID already exists, it is replaced. */\n addNode(node: N): void;\n /** Adds multiple nodes. Existing nodes with the same IDs are replaced. */\n addNodes(nodes: N[]): void;\n /** Updates a node by merging a partial object. No-op if the node does not exist. */\n updateNode(id: string, partial: Partial<N>): void;\n /** Updates a node using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */\n updateNode(id: string, updater: (node: N) => N): void;\n /** Updates a node's `data` by merging a partial object. No-op if the node does not exist. */\n updateNodeData(id: string, partial: Partial<N[\"data\"]>): void;\n /** 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. */\n updateNodeData<D extends N[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes a node by ID. */\n removeNode(id: string): void;\n /** Removes multiple nodes by ID. */\n removeNodes(ids: string[]): void;\n\n /** Adds an edge. If an edge with the same ID already exists, it is replaced. */\n addEdge(edge: E): void;\n /** Adds multiple edges. Existing edges with the same IDs are replaced. */\n addEdges(edges: E[]): void;\n /** Updates an edge by merging a partial object. No-op if the edge does not exist. */\n updateEdge(id: string, partial: Partial<E>): void;\n /** Updates an edge using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */\n updateEdge(id: string, updater: (edge: E) => E): void;\n /** Updates an edge's `data` by merging a partial object. No-op if the edge does not exist. */\n updateEdgeData(id: string, partial: Partial<NonNullable<E[\"data\"]>>): void;\n /** 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. */\n updateEdgeData<D extends E[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes an edge by ID. */\n removeEdge(id: string): void;\n /** Removes multiple edges by ID. */\n removeEdges(ids: string[]): void;\n}\n\n/**\n * Opens a flow (a collection of React Flow nodes and edges) for reading and\n * mutating, then automatically flushes all changes when the callback\n * completes.\n *\n * @example\n * ```ts\n * await mutateFlow({ client, roomId: \"my-room\" }, (flow) => {\n * flow.addNode({ id: \"1\", position: { x: 0, y: 0 }, data: {} });\n * flow.updateNodeData(\"1\", { label: \"Hello\" });\n * });\n * ```\n */\nexport async function mutateFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: MutateFlowOptions<N, E>,\n callback: (flow: MutableFlow<N, E>) => void | Promise<void>\n): Promise<void> {\n const { client, roomId } = options;\n const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n\n const getNodeSyncConfig = buildNodeConfigCache(options.nodes?.sync);\n const getEdgeSyncConfig = buildEdgeConfigCache(options.edges?.sync);\n\n const nodeListCache = new WeakMap<Record<string, N>, N[]>();\n const edgeListCache = new WeakMap<Record<string, E>, E[]>();\n\n await client.mutateStorage(roomId, async ({ root }) => {\n let flow = root.get(storageKey) as InternalLiveblocksFlow | undefined;\n if (!flow) {\n const newFlow = new LiveObject({\n nodes: new LiveMap(),\n edges: new LiveMap(),\n }) satisfies InternalLiveblocksFlow;\n root.set(storageKey, newFlow);\n flow = newFlow;\n }\n\n const nodesLiveMap = flow.get(\"nodes\");\n const edgesLiveMap = flow.get(\"edges\");\n\n function getNodes(): readonly N[] {\n const nodeMap = nodesLiveMap.toJSON() as unknown as Record<string, N>;\n if (!nodeListCache.has(nodeMap)) {\n // TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n // in topological order (parents before children), deferring any node with a\n // parentId until its parent has been emitted.\n nodeListCache.set(nodeMap, Object.values(nodeMap));\n }\n return nodeListCache.get(nodeMap)!;\n }\n\n function getEdges(): readonly E[] {\n const edgeMap = edgesLiveMap.toJSON() as unknown as Record<string, E>;\n if (!edgeListCache.has(edgeMap)) {\n edgeListCache.set(edgeMap, Object.values(edgeMap));\n }\n return edgeListCache.get(edgeMap)!;\n }\n\n function getNode(id: string) {\n return nodesLiveMap.get(id)?.toJSON() as N | undefined;\n }\n function getEdge(id: string) {\n return edgesLiveMap.get(id)?.toJSON() as E | undefined;\n }\n\n function upsertNode(id: string, newNode: N) {\n const existing = nodesLiveMap.get(id);\n const syncConfig = getNodeSyncConfig(newNode.type);\n if (!existing) {\n nodesLiveMap.set(id, toLiveblocksInternalNode(newNode, syncConfig));\n } else {\n existing.reconcile(newNode as unknown as JsonObject, syncConfig);\n }\n }\n\n function upsertEdge(id: string, newEdge: E) {\n const existing = edgesLiveMap.get(id);\n const syncConfig = getEdgeSyncConfig(newEdge.type);\n if (!existing) {\n edgesLiveMap.set(id, toLiveblocksInternalEdge(newEdge, syncConfig));\n } else {\n existing.reconcile(newEdge as unknown as JsonObject, syncConfig);\n }\n }\n\n const mutableFlow: MutableFlow<N, E> = {\n get nodes() {\n return getNodes();\n },\n get edges() {\n return getEdges();\n },\n toJSON() {\n return { nodes: getNodes(), edges: getEdges() };\n },\n getNode,\n getEdge,\n\n addNode(node: N) {\n upsertNode(node.id, node);\n },\n addNodes(nodes: N[]) {\n for (const node of nodes) {\n mutableFlow.addNode(node);\n }\n },\n updateNode(id: string, partialOrUpdater: Partial<N> | ((node: N) => N)) {\n const oldNode = getNode(id);\n if (!oldNode) return;\n\n let newNode: N;\n if (typeof partialOrUpdater === \"function\") {\n newNode = partialOrUpdater(oldNode);\n } else {\n newNode = { ...oldNode, ...partialOrUpdater };\n }\n return upsertNode(id, newNode);\n },\n updateNodeData(\n id: string,\n partialOrUpdater:\n | Partial<N[\"data\"]>\n | (<D extends N[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateNode(id, (node) => {\n const currData = node.data ?? ({} as N[\"data\"]);\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...node, data: newData };\n });\n },\n removeNode(id: string) {\n nodesLiveMap.delete(id);\n },\n removeNodes(ids: string[]) {\n for (const id of ids) {\n nodesLiveMap.delete(id);\n }\n },\n\n addEdge(edge: E) {\n upsertEdge(edge.id, edge);\n },\n addEdges(edges: E[]) {\n for (const edge of edges) {\n mutableFlow.addEdge(edge);\n }\n },\n updateEdge(id: string, partialOrUpdater: Partial<E> | ((edge: E) => E)) {\n const oldEdge = getEdge(id);\n if (!oldEdge) return;\n\n let newEdge: E;\n if (typeof partialOrUpdater === \"function\") {\n newEdge = partialOrUpdater(oldEdge);\n } else {\n newEdge = { ...oldEdge, ...partialOrUpdater };\n }\n return upsertEdge(id, newEdge);\n },\n updateEdgeData(\n id: string,\n partialOrUpdater:\n | Partial<NonNullable<E[\"data\"]>>\n | (<D extends E[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateEdge(id, (edge) => {\n const currData = edge.data;\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...edge, data: newData };\n });\n },\n removeEdge(id: string) {\n edgesLiveMap.delete(id);\n },\n removeEdges(ids: string[]) {\n for (const id of ids) {\n edgesLiveMap.delete(id);\n }\n },\n };\n\n await callback(mutableFlow);\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"node.js","sources":["../src/node.ts"],"sourcesContent":["import type { JsonObject, LsonObject } from \"@liveblocks/core\";\nimport { LiveMap, LiveObject } from \"@liveblocks/core\";\nimport type { BuiltInEdge, BuiltInNode, Edge, Node } from \"@xyflow/react\";\n\nimport {\n buildEdgeConfigCache,\n buildNodeConfigCache,\n DEFAULT_STORAGE_KEY,\n toLiveblocksInternalEdge,\n toLiveblocksInternalNode,\n} from \"./lib/shared\";\nimport type {\n EdgeSyncConfig,\n InternalLiveblocksFlow,\n NodeSyncConfig,\n} from \"./lib/types\";\n\n/**\n * A minimal interface for the Liveblocks Node client — just the\n * `mutateStorage` method we actually need. This avoids importing\n * `@liveblocks/node` as a dependency.\n */\ninterface ILiveblocksClient {\n mutateStorage(\n roomId: string,\n callback: (context: {\n root: LiveObject<LsonObject>;\n }) => void | Promise<void>\n ): Promise<void>;\n}\n\n/** Options for `mutateFlow()`. */\nexport interface MutateFlowOptions<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n> {\n client: ILiveblocksClient;\n roomId: string;\n storageKey?: string;\n nodes?: { sync?: NodeSyncConfig<N> };\n edges?: { sync?: EdgeSyncConfig<E> };\n}\n\nexport interface MutableFlow<N extends Node, E extends Edge> {\n /** The current list of nodes. */\n readonly nodes: readonly N[];\n /** The current list of edges. */\n readonly edges: readonly E[];\n /** Returns a plain object snapshot with `nodes` and `edges` arrays. */\n toJSON(): {\n nodes: readonly N[];\n edges: readonly E[];\n };\n\n /** Returns a single node by ID, or `undefined` if not found. */\n getNode(id: string): N | undefined;\n /** Returns a single edge by ID, or `undefined` if not found. */\n getEdge(id: string): E | undefined;\n\n /** Adds a node. If a node with the same ID already exists, it is replaced. */\n addNode(node: N): void;\n /** Adds multiple nodes. Existing nodes with the same IDs are replaced. */\n addNodes(nodes: N[]): void;\n /** Updates a node by merging a partial object. No-op if the node does not exist. */\n updateNode(id: string, partial: Partial<N>): void;\n /** Updates a node using an updater function. Always return a new object, never mutate in-place. No-op if the node does not exist. */\n updateNode(id: string, updater: (node: N) => N): void;\n /** Updates a node's `data` by merging a partial object. No-op if the node does not exist. */\n updateNodeData(id: string, partial: Partial<N[\"data\"]>): void;\n /** 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. */\n updateNodeData<D extends N[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes a node by ID. */\n removeNode(id: string): void;\n /** Removes multiple nodes by ID. */\n removeNodes(ids: string[]): void;\n\n /** Adds an edge. If an edge with the same ID already exists, it is replaced. */\n addEdge(edge: E): void;\n /** Adds multiple edges. Existing edges with the same IDs are replaced. */\n addEdges(edges: E[]): void;\n /** Updates an edge by merging a partial object. No-op if the edge does not exist. */\n updateEdge(id: string, partial: Partial<E>): void;\n /** Updates an edge using an updater function. Always return a new object, never mutate in-place. No-op if the edge does not exist. */\n updateEdge(id: string, updater: (edge: E) => E): void;\n /** Updates an edge's `data` by merging a partial object. No-op if the edge does not exist. */\n updateEdgeData(id: string, partial: Partial<NonNullable<E[\"data\"]>>): void;\n /** 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. */\n updateEdgeData<D extends E[\"data\"]>(\n id: string,\n updater: (data: D) => D\n ): void;\n /** Removes an edge by ID. */\n removeEdge(id: string): void;\n /** Removes multiple edges by ID. */\n removeEdges(ids: string[]): void;\n}\n\n/**\n * Opens a flow (a collection of React Flow nodes and edges) for reading and\n * mutating, then automatically flushes all changes when the callback\n * completes.\n *\n * @example\n * ```ts\n * await mutateFlow({ client, roomId: \"my-room\" }, (flow) => {\n * flow.addNode({ id: \"1\", position: { x: 0, y: 0 }, data: {} });\n * flow.updateNodeData(\"1\", { label: \"Hello\" });\n * });\n * ```\n */\nexport async function mutateFlow<\n N extends Node = BuiltInNode,\n E extends Edge = BuiltInEdge,\n>(\n options: MutateFlowOptions<N, E>,\n callback: (flow: MutableFlow<N, E>) => void | Promise<void>\n): Promise<void> {\n const { client, roomId } = options;\n const storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n\n const getNodeSyncConfig = buildNodeConfigCache(options.nodes?.sync);\n const getEdgeSyncConfig = buildEdgeConfigCache(options.edges?.sync);\n\n const nodeListCache = new WeakMap<Record<string, N>, N[]>();\n const edgeListCache = new WeakMap<Record<string, E>, E[]>();\n\n await client.mutateStorage(roomId, async ({ root }) => {\n let flow = root.get(storageKey) as InternalLiveblocksFlow | undefined;\n if (!flow) {\n const newFlow = new LiveObject({\n nodes: new LiveMap(),\n edges: new LiveMap(),\n }) satisfies InternalLiveblocksFlow;\n root.set(storageKey, newFlow);\n flow = newFlow;\n }\n\n const nodesLiveMap = flow.get(\"nodes\");\n const edgesLiveMap = flow.get(\"edges\");\n\n function getNodes(): readonly N[] {\n const nodeMap = nodesLiveMap.toJSON() as unknown as Record<string, N>;\n if (!nodeListCache.has(nodeMap)) {\n // TODO (LB-3665): To support sub-nodes, this function will need to emit nodes\n // in topological order (parents before children), deferring any node with a\n // parentId until its parent has been emitted.\n nodeListCache.set(nodeMap, Object.values(nodeMap));\n }\n return nodeListCache.get(nodeMap)!;\n }\n\n function getEdges(): readonly E[] {\n const edgeMap = edgesLiveMap.toJSON() as unknown as Record<string, E>;\n if (!edgeListCache.has(edgeMap)) {\n edgeListCache.set(edgeMap, Object.values(edgeMap));\n }\n return edgeListCache.get(edgeMap)!;\n }\n\n function getNode(id: string) {\n return nodesLiveMap.get(id)?.toJSON() as N | undefined;\n }\n function getEdge(id: string) {\n return edgesLiveMap.get(id)?.toJSON() as E | undefined;\n }\n\n function upsertNode(id: string, newNode: N) {\n const existing = nodesLiveMap.get(id);\n const syncConfig = getNodeSyncConfig(newNode.type);\n if (!existing) {\n nodesLiveMap.set(id, toLiveblocksInternalNode(newNode, syncConfig));\n } else {\n existing.reconcile(newNode as unknown as JsonObject, syncConfig);\n }\n }\n\n function upsertEdge(id: string, newEdge: E) {\n const existing = edgesLiveMap.get(id);\n const syncConfig = getEdgeSyncConfig(newEdge.type);\n if (!existing) {\n edgesLiveMap.set(id, toLiveblocksInternalEdge(newEdge, syncConfig));\n } else {\n existing.reconcile(newEdge as unknown as JsonObject, syncConfig);\n }\n }\n\n const mutableFlow: MutableFlow<N, E> = {\n get nodes() {\n return getNodes();\n },\n get edges() {\n return getEdges();\n },\n toJSON() {\n return { nodes: getNodes(), edges: getEdges() };\n },\n getNode,\n getEdge,\n\n addNode(node: N) {\n upsertNode(node.id, node);\n },\n addNodes(nodes: N[]) {\n for (const node of nodes) {\n mutableFlow.addNode(node);\n }\n },\n updateNode(id: string, partialOrUpdater: Partial<N> | ((node: N) => N)) {\n const oldNode = getNode(id);\n if (!oldNode) return;\n\n let newNode: N;\n if (typeof partialOrUpdater === \"function\") {\n newNode = partialOrUpdater(oldNode);\n } else {\n newNode = { ...oldNode, ...partialOrUpdater };\n }\n return upsertNode(id, newNode);\n },\n updateNodeData(\n id: string,\n partialOrUpdater:\n | Partial<N[\"data\"]>\n | (<D extends N[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateNode(id, (node) => {\n const currData = node.data ?? ({} as N[\"data\"]);\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...node, data: newData };\n });\n },\n removeNode(id: string) {\n nodesLiveMap.delete(id);\n },\n removeNodes(ids: string[]) {\n for (const id of ids) {\n nodesLiveMap.delete(id);\n }\n },\n\n addEdge(edge: E) {\n upsertEdge(edge.id, edge);\n },\n addEdges(edges: E[]) {\n for (const edge of edges) {\n mutableFlow.addEdge(edge);\n }\n },\n updateEdge(id: string, partialOrUpdater: Partial<E> | ((edge: E) => E)) {\n const oldEdge = getEdge(id);\n if (!oldEdge) return;\n\n let newEdge: E;\n if (typeof partialOrUpdater === \"function\") {\n newEdge = partialOrUpdater(oldEdge);\n } else {\n newEdge = { ...oldEdge, ...partialOrUpdater };\n }\n return upsertEdge(id, newEdge);\n },\n updateEdgeData(\n id: string,\n partialOrUpdater:\n | Partial<NonNullable<E[\"data\"]>>\n | (<D extends E[\"data\"]>(data: D) => D)\n ) {\n return mutableFlow.updateEdge(id, (edge) => {\n const currData = edge.data;\n const newData =\n typeof partialOrUpdater === \"function\"\n ? partialOrUpdater(currData)\n : { ...currData, ...partialOrUpdater };\n return { ...edge, data: newData };\n });\n },\n removeEdge(id: string) {\n edgesLiveMap.delete(id);\n },\n removeEdges(ids: string[]) {\n for (const id of ids) {\n edgesLiveMap.delete(id);\n }\n },\n };\n\n await callback(mutableFlow);\n });\n}\n"],"names":[],"mappings":";;;AAiHsB,eAAA,UAAA,CAIpB,SACA,QACe,EAAA;AACf,EAAM,MAAA,EAAE,MAAQ,EAAA,MAAA,EAAW,GAAA,OAAA,CAAA;AAC3B,EAAM,MAAA,UAAA,GAAa,QAAQ,UAAc,IAAA,mBAAA,CAAA;AAEzC,EAAA,MAAM,iBAAoB,GAAA,oBAAA,CAAqB,OAAQ,CAAA,KAAA,EAAO,IAAI,CAAA,CAAA;AAClE,EAAA,MAAM,iBAAoB,GAAA,oBAAA,CAAqB,OAAQ,CAAA,KAAA,EAAO,IAAI,CAAA,CAAA;AAElE,EAAM,MAAA,aAAA,uBAAoB,OAAgC,EAAA,CAAA;AAC1D,EAAM,MAAA,aAAA,uBAAoB,OAAgC,EAAA,CAAA;AAE1D,EAAA,MAAM,OAAO,aAAc,CAAA,MAAA,EAAQ,OAAO,EAAE,MAAW,KAAA;AACrD,IAAI,IAAA,IAAA,GAAO,IAAK,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAC9B,IAAA,IAAI,CAAC,IAAM,EAAA;AACT,MAAM,MAAA,OAAA,GAAU,IAAI,UAAW,CAAA;AAAA,QAC7B,KAAA,EAAO,IAAI,OAAQ,EAAA;AAAA,QACnB,KAAA,EAAO,IAAI,OAAQ,EAAA;AAAA,OACpB,CAAA,CAAA;AACD,MAAK,IAAA,CAAA,GAAA,CAAI,YAAY,OAAO,CAAA,CAAA;AAC5B,MAAO,IAAA,GAAA,OAAA,CAAA;AAAA,KACT;AAEA,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AACrC,IAAM,MAAA,YAAA,GAAe,IAAK,CAAA,GAAA,CAAI,OAAO,CAAA,CAAA;AAErC,IAAA,SAAS,QAAyB,GAAA;AAChC,MAAM,MAAA,OAAA,GAAU,aAAa,MAAO,EAAA,CAAA;AACpC,MAAA,IAAI,CAAC,aAAA,CAAc,GAAI,CAAA,OAAO,CAAG,EAAA;AAI/B,QAAA,aAAA,CAAc,GAAI,CAAA,OAAA,EAAS,MAAO,CAAA,MAAA,CAAO,OAAO,CAAC,CAAA,CAAA;AAAA,OACnD;AACA,MAAO,OAAA,aAAA,CAAc,IAAI,OAAO,CAAA,CAAA;AAAA,KAClC;AAEA,IAAA,SAAS,QAAyB,GAAA;AAChC,MAAM,MAAA,OAAA,GAAU,aAAa,MAAO,EAAA,CAAA;AACpC,MAAA,IAAI,CAAC,aAAA,CAAc,GAAI,CAAA,OAAO,CAAG,EAAA;AAC/B,QAAA,aAAA,CAAc,GAAI,CAAA,OAAA,EAAS,MAAO,CAAA,MAAA,CAAO,OAAO,CAAC,CAAA,CAAA;AAAA,OACnD;AACA,MAAO,OAAA,aAAA,CAAc,IAAI,OAAO,CAAA,CAAA;AAAA,KAClC;AAEA,IAAA,SAAS,QAAQ,EAAY,EAAA;AAC3B,MAAA,OAAO,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,EAAG,MAAO,EAAA,CAAA;AAAA,KACtC;AACA,IAAA,SAAS,QAAQ,EAAY,EAAA;AAC3B,MAAA,OAAO,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,EAAG,MAAO,EAAA,CAAA;AAAA,KACtC;AAEA,IAAS,SAAA,UAAA,CAAW,IAAY,OAAY,EAAA;AAC1C,MAAM,MAAA,QAAA,GAAW,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AACpC,MAAM,MAAA,UAAA,GAAa,iBAAkB,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AACjD,MAAA,IAAI,CAAC,QAAU,EAAA;AACb,QAAA,YAAA,CAAa,GAAI,CAAA,EAAA,EAAI,wBAAyB,CAAA,OAAA,EAAS,UAAU,CAAC,CAAA,CAAA;AAAA,OAC7D,MAAA;AACL,QAAS,QAAA,CAAA,SAAA,CAAU,SAAkC,UAAU,CAAA,CAAA;AAAA,OACjE;AAAA,KACF;AAEA,IAAS,SAAA,UAAA,CAAW,IAAY,OAAY,EAAA;AAC1C,MAAM,MAAA,QAAA,GAAW,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AACpC,MAAM,MAAA,UAAA,GAAa,iBAAkB,CAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AACjD,MAAA,IAAI,CAAC,QAAU,EAAA;AACb,QAAA,YAAA,CAAa,GAAI,CAAA,EAAA,EAAI,wBAAyB,CAAA,OAAA,EAAS,UAAU,CAAC,CAAA,CAAA;AAAA,OAC7D,MAAA;AACL,QAAS,QAAA,CAAA,SAAA,CAAU,SAAkC,UAAU,CAAA,CAAA;AAAA,OACjE;AAAA,KACF;AAEA,IAAA,MAAM,WAAiC,GAAA;AAAA,MACrC,IAAI,KAAQ,GAAA;AACV,QAAA,OAAO,QAAS,EAAA,CAAA;AAAA,OAClB;AAAA,MACA,IAAI,KAAQ,GAAA;AACV,QAAA,OAAO,QAAS,EAAA,CAAA;AAAA,OAClB;AAAA,MACA,MAAS,GAAA;AACP,QAAA,OAAO,EAAE,KAAO,EAAA,QAAA,EAAY,EAAA,KAAA,EAAO,UAAW,EAAA,CAAA;AAAA,OAChD;AAAA,MACA,OAAA;AAAA,MACA,OAAA;AAAA,MAEA,QAAQ,IAAS,EAAA;AACf,QAAW,UAAA,CAAA,IAAA,CAAK,IAAI,IAAI,CAAA,CAAA;AAAA,OAC1B;AAAA,MACA,SAAS,KAAY,EAAA;AACnB,QAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,UAAA,WAAA,CAAY,QAAQ,IAAI,CAAA,CAAA;AAAA,SAC1B;AAAA,OACF;AAAA,MACA,UAAA,CAAW,IAAY,gBAAiD,EAAA;AACtE,QAAM,MAAA,OAAA,GAAU,QAAQ,EAAE,CAAA,CAAA;AAC1B,QAAA,IAAI,CAAC,OAAS,EAAA,OAAA;AAEd,QAAI,IAAA,OAAA,CAAA;AACJ,QAAI,IAAA,OAAO,qBAAqB,UAAY,EAAA;AAC1C,UAAA,OAAA,GAAU,iBAAiB,OAAO,CAAA,CAAA;AAAA,SAC7B,MAAA;AACL,UAAA,OAAA,GAAU,EAAE,GAAG,OAAS,EAAA,GAAG,gBAAiB,EAAA,CAAA;AAAA,SAC9C;AACA,QAAO,OAAA,UAAA,CAAW,IAAI,OAAO,CAAA,CAAA;AAAA,OAC/B;AAAA,MACA,cAAA,CACE,IACA,gBAGA,EAAA;AACA,QAAA,OAAO,WAAY,CAAA,UAAA,CAAW,EAAI,EAAA,CAAC,IAAS,KAAA;AAC1C,UAAM,MAAA,QAAA,GAAW,IAAK,CAAA,IAAA,IAAS,EAAC,CAAA;AAChC,UAAM,MAAA,OAAA,GACJ,OAAO,gBAAA,KAAqB,UACxB,GAAA,gBAAA,CAAiB,QAAQ,CAAA,GACzB,EAAE,GAAG,QAAU,EAAA,GAAG,gBAAiB,EAAA,CAAA;AACzC,UAAA,OAAO,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,OAAQ,EAAA,CAAA;AAAA,SACjC,CAAA,CAAA;AAAA,OACH;AAAA,MACA,WAAW,EAAY,EAAA;AACrB,QAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,OACxB;AAAA,MACA,YAAY,GAAe,EAAA;AACzB,QAAA,KAAA,MAAW,MAAM,GAAK,EAAA;AACpB,UAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,SACxB;AAAA,OACF;AAAA,MAEA,QAAQ,IAAS,EAAA;AACf,QAAW,UAAA,CAAA,IAAA,CAAK,IAAI,IAAI,CAAA,CAAA;AAAA,OAC1B;AAAA,MACA,SAAS,KAAY,EAAA;AACnB,QAAA,KAAA,MAAW,QAAQ,KAAO,EAAA;AACxB,UAAA,WAAA,CAAY,QAAQ,IAAI,CAAA,CAAA;AAAA,SAC1B;AAAA,OACF;AAAA,MACA,UAAA,CAAW,IAAY,gBAAiD,EAAA;AACtE,QAAM,MAAA,OAAA,GAAU,QAAQ,EAAE,CAAA,CAAA;AAC1B,QAAA,IAAI,CAAC,OAAS,EAAA,OAAA;AAEd,QAAI,IAAA,OAAA,CAAA;AACJ,QAAI,IAAA,OAAO,qBAAqB,UAAY,EAAA;AAC1C,UAAA,OAAA,GAAU,iBAAiB,OAAO,CAAA,CAAA;AAAA,SAC7B,MAAA;AACL,UAAA,OAAA,GAAU,EAAE,GAAG,OAAS,EAAA,GAAG,gBAAiB,EAAA,CAAA;AAAA,SAC9C;AACA,QAAO,OAAA,UAAA,CAAW,IAAI,OAAO,CAAA,CAAA;AAAA,OAC/B;AAAA,MACA,cAAA,CACE,IACA,gBAGA,EAAA;AACA,QAAA,OAAO,WAAY,CAAA,UAAA,CAAW,EAAI,EAAA,CAAC,IAAS,KAAA;AAC1C,UAAA,MAAM,WAAW,IAAK,CAAA,IAAA,CAAA;AACtB,UAAM,MAAA,OAAA,GACJ,OAAO,gBAAA,KAAqB,UACxB,GAAA,gBAAA,CAAiB,QAAQ,CAAA,GACzB,EAAE,GAAG,QAAU,EAAA,GAAG,gBAAiB,EAAA,CAAA;AACzC,UAAA,OAAO,EAAE,GAAG,IAAM,EAAA,IAAA,EAAM,OAAQ,EAAA,CAAA;AAAA,SACjC,CAAA,CAAA;AAAA,OACH;AAAA,MACA,WAAW,EAAY,EAAA;AACrB,QAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,OACxB;AAAA,MACA,YAAY,GAAe,EAAA;AACzB,QAAA,KAAA,MAAW,MAAM,GAAK,EAAA;AACpB,UAAA,YAAA,CAAa,OAAO,EAAE,CAAA,CAAA;AAAA,SACxB;AAAA,OACF;AAAA,KACF,CAAA;AAEA,IAAA,MAAM,SAAS,WAAW,CAAA,CAAA;AAAA,GAC3B,CAAA,CAAA;AACH;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-flow",
3
- "version": "3.18.2",
3
+ "version": "3.18.3-test2",
4
4
  "description": "An integration of React Flow to enable collaboration and realtime cursors with Liveblocks.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Liveblocks Inc.",
@@ -50,23 +50,11 @@
50
50
  "**/*.css.map",
51
51
  "README.md"
52
52
  ],
53
- "scripts": {
54
- "dev": "rollup --config rollup.config.js --watch",
55
- "build": "rollup --config rollup.config.js",
56
- "start": "npm run dev",
57
- "format": "(eslint --fix src/ || true) && stylelint --fix src/styles/ && prettier --write src/",
58
- "lint:package": "publint --strict && attw --pack && node check-node-entrypoint.mjs",
59
- "lint": "eslint src/ && stylelint src/styles/",
60
- "test": "npx liveblocks dev -p 1154 -c 'vitest run --coverage'",
61
- "test:ci": "vitest run",
62
- "test:types": "vitest run --config ./vitest.config.typecheck.ts",
63
- "test:watch": "vitest"
64
- },
65
53
  "dependencies": {
66
- "@liveblocks/client": "3.18.2",
67
- "@liveblocks/core": "3.18.2",
68
- "@liveblocks/react": "3.18.2",
69
- "@liveblocks/react-ui": "3.18.2"
54
+ "@liveblocks/client": "3.18.3-test2",
55
+ "@liveblocks/react": "3.18.3-test2",
56
+ "@liveblocks/core": "3.18.3-test2",
57
+ "@liveblocks/react-ui": "3.18.3-test2"
70
58
  },
71
59
  "peerDependencies": {
72
60
  "@xyflow/react": "^12",
@@ -81,21 +69,6 @@
81
69
  "optional": true
82
70
  }
83
71
  },
84
- "devDependencies": {
85
- "@liveblocks/eslint-config": "*",
86
- "@liveblocks/node": "*",
87
- "@liveblocks/rollup-config": "*",
88
- "@liveblocks/vitest-config": "*",
89
- "@testing-library/jest-dom": "^6.4.6",
90
- "@testing-library/react": "^13.1.1",
91
- "@xyflow/react": "^12.10.1",
92
- "eslint-plugin-react": "^7.33.2",
93
- "eslint-plugin-react-hooks": "^4.6.0",
94
- "stylelint": "^15.10.2",
95
- "stylelint-config-standard": "^34.0.0",
96
- "stylelint-order": "^6.0.3",
97
- "stylelint-plugin-logical-css": "^0.13.2"
98
- },
99
72
  "sideEffects": false,
100
73
  "bugs": {
101
74
  "url": "https://github.com/liveblocks/liveblocks/issues"
@@ -126,4 +99,4 @@
126
99
  "documents",
127
100
  "conflict resolution"
128
101
  ]
129
- }
102
+ }