@@ -8,7 +8,10 @@ import {
88 type Value ,
99} from "loro-crdt" ;
1010import { LoroWebsocketClient } from "loro-websocket/client" ;
11- import { LoroAdaptor , LoroEphemeralAdaptor } from "loro-adaptors" ;
11+ import {
12+ LoroAdaptor ,
13+ createLoroEphemeralAdaptor ,
14+ } from "loro-adaptors" ;
1215import type {
1316 AppState as ExcalidrawAppState ,
1417 ExcalidrawImperativeAPI ,
@@ -46,6 +49,11 @@ type SceneUpdateArgs = Parameters<
4649type SceneElements = NonNullable < SceneUpdateArgs [ "elements" ] > ;
4750type SceneAppStateUpdate = NonNullable < SceneUpdateArgs [ "appState" ] > ;
4851type PresenceStoreState = Record < string , PresenceEntry > ;
52+ type EphemeralStoreInstance = ReturnType < typeof createLoroEphemeralAdaptor > extends {
53+ getStore ( ) : infer S ;
54+ }
55+ ? S
56+ : EphemeralStore < PresenceStoreState > ;
4957
5058export function useLoroSync ( {
5159 roomId,
@@ -57,8 +65,8 @@ export function useLoroSync({
5765} : UseLoroSyncOptions ) {
5866 const docRef = useRef < LoroDoc | null > ( null ) ;
5967 const clientRef = useRef < LoroWebsocketClient | null > ( null ) ;
60- const ephemeralRef =
61- useRef < EphemeralStore < PresenceStoreState > | null > ( null ) ;
68+ const ephemeralRef = useRef < EphemeralStoreInstance | null > ( null ) ;
69+ const ephemeralAdaptorRef = useRef < ReturnType < typeof createLoroEphemeralAdaptor > | null > ( null ) ;
6270
6371 const [ isConnected , setIsConnected ] = useState ( false ) ;
6472 const [ collaborators , setCollaborators ] = useState < Map < string , Collaborator > > ( new Map ( ) ) ;
@@ -69,11 +77,13 @@ export function useLoroSync({
6977 useEffect ( ( ) => {
7078 const doc = new LoroDoc ( ) ;
7179 const client = new LoroWebsocketClient ( { url : wsUrl } ) ;
72- const ephemeral = new EphemeralStore < PresenceStoreState > ( 30000 ) ; // 30 second timeout
80+ const ephAdaptor = createLoroEphemeralAdaptor ( { timeout : 30000 } ) ;
81+ const ephemeral = ephAdaptor . getStore ( ) ;
7382
7483 docRef . current = doc ;
7584 clientRef . current = client ;
7685 ephemeralRef . current = ephemeral ;
86+ ephemeralAdaptorRef . current = ephAdaptor ;
7787
7888 // Set up document structure
7989 const elementsContainer = doc . getList ( "elements" ) ;
@@ -121,7 +131,6 @@ export function useLoroSync({
121131 recalcCollaborators ( ) ;
122132 // Join rooms via loro-websocket client and adaptors
123133 const adaptor = new LoroAdaptor ( doc , { peerId : userId } ) ;
124- const ephAdaptor = new LoroEphemeralAdaptor ( ephemeral , { } ) ;
125134
126135 let rooms : { destroy : ( ) => Promise < void > } [ ] = [ ] ;
127136 client
@@ -148,7 +157,7 @@ export function useLoroSync({
148157 } ) ;
149158 // Adaptor destroy will also clean underlying stores/docs, but ensure store is destroyed
150159 try {
151- ephemeral . destroy ( ) ;
160+ ephemeralAdaptorRef . current ? .destroy ( ) ;
152161 } catch { }
153162 } ;
154163 } , [ roomId , userId , wsUrl ] ) ;
@@ -157,30 +166,34 @@ export function useLoroSync({
157166 const updateCursor = useCallback ( ( position : CursorPosition ) => {
158167 if ( ! ephemeralRef . current ) return ;
159168
160- const currentState = ephemeralRef . current . get ( userId ) || { } ;
161- ephemeralRef . current . set ( userId , {
169+ const currentState = ( ephemeralRef . current . get ( userId ) ??
170+ { } ) as PresenceEntry ;
171+ const nextState : PresenceEntry = {
162172 ...currentState ,
163173 userId,
164174 userName,
165175 userColor,
166176 cursor : position ,
167177 lastActive : Date . now ( ) ,
168- } ) ;
178+ } ;
179+ ephemeralRef . current . set ( userId , nextState ) ;
169180 } , [ userId , userName , userColor ] ) ;
170181
171182 // Update selected elements
172183 const updateSelection = useCallback ( ( selectedElementIds : string [ ] ) => {
173184 if ( ! ephemeralRef . current ) return ;
174185
175- const currentState = ephemeralRef . current . get ( userId ) || { } ;
176- ephemeralRef . current . set ( userId , {
186+ const currentState = ( ephemeralRef . current . get ( userId ) ??
187+ { } ) as PresenceEntry ;
188+ const nextState : PresenceEntry = {
177189 ...currentState ,
178190 userId,
179191 userName,
180192 userColor,
181193 selectedElementIds,
182194 lastActive : Date . now ( ) ,
183- } ) ;
195+ } ;
196+ ephemeralRef . current . set ( userId , nextState ) ;
184197 } , [ userId , userName , userColor ] ) ;
185198
186199 // Record local Excalidraw changes into LoroDoc with minimal ops
0 commit comments