@@ -350,7 +350,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
350350 console . log ( "bootstrapping" )
351351 const start = Date . now ( ) - 30 * 24 * 60 * 60 * 1000
352352 const sessionListPromise = sdk . client . session
353- . list ( { start : start } )
353+ . list ( { start : start , roots : true } )
354354 . then ( ( x ) => ( x . data ?? [ ] ) . toSorted ( ( a , b ) => a . id . localeCompare ( b . id ) ) )
355355
356356 // blocking - include session.list when continuing a session
@@ -432,6 +432,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
432432 } )
433433
434434 const fullSyncedSessions = new Set < string > ( )
435+ const treeSyncedRoots = new Set < string > ( )
435436 const result = {
436437 data : store ,
437438 set : setStore ,
@@ -480,6 +481,60 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
480481 )
481482 fullSyncedSessions . add ( sessionID )
482483 } ,
484+ async syncTree ( sessionID : string ) {
485+ // Walk up to find the root session
486+ let rootID = sessionID
487+ const visited = new Set < string > ( )
488+ while ( true ) {
489+ if ( visited . has ( rootID ) ) break
490+ visited . add ( rootID )
491+ const match = Binary . search ( store . session , rootID , ( s ) => s . id )
492+ if ( ! match . found ) break
493+ const parentID = store . session [ match . index ] . parentID
494+ if ( ! parentID ) break
495+ const parentMatch = Binary . search ( store . session , parentID , ( s ) => s . id )
496+ if ( parentMatch . found ) {
497+ rootID = parentID
498+ continue
499+ }
500+ // Parent not in store — fetch it
501+ const res = await sdk . client . session . get ( { sessionID : parentID } ) . catch ( ( ) => undefined )
502+ if ( ! res ?. data ) break
503+ setStore (
504+ produce ( ( draft ) => {
505+ const idx = Binary . search ( draft . session , res . data ! . id , ( s ) => s . id )
506+ if ( ! idx . found ) draft . session . splice ( idx . index , 0 , res . data ! )
507+ } ) ,
508+ )
509+ rootID = parentID
510+ }
511+
512+ if ( treeSyncedRoots . has ( rootID ) ) return
513+ treeSyncedRoots . add ( rootID )
514+
515+ // BFS from root — load all descendants level by level
516+ const queue = [ rootID ]
517+ while ( queue . length > 0 ) {
518+ const level = [ ...queue ]
519+ queue . length = 0
520+ const results = await Promise . all (
521+ level . map ( ( id ) => sdk . client . session . children ( { sessionID : id } ) . catch ( ( ) => undefined ) ) ,
522+ )
523+ const all = results . flatMap ( ( r ) => r ?. data ?? [ ] )
524+ if ( all . length === 0 ) break
525+ setStore (
526+ produce ( ( draft ) => {
527+ for ( const child of all ) {
528+ const idx = Binary . search ( draft . session , child . id , ( s ) => s . id )
529+ if ( ! idx . found ) draft . session . splice ( idx . index , 0 , child )
530+ }
531+ } ) ,
532+ )
533+ for ( const child of all ) {
534+ queue . push ( child . id )
535+ }
536+ }
537+ } ,
483538 } ,
484539 bootstrap,
485540 }
0 commit comments