@@ -121,6 +121,8 @@ export interface FlowchartData {
121121}
122122
123123export interface SessionState {
124+ /** Account these persisted drafts belong to. Null until sign-in binds them. */
125+ ownerUserId : string | null ;
124126 generateResult : GenerateOutput | null ;
125127 generateLoading : boolean ;
126128 /** The Generate section being regenerated; kept here so it survives leaving the page. */
@@ -229,6 +231,12 @@ export interface SessionState {
229231 serverHydration : 'pending' | 'partial' | 'complete' ;
230232 clearAllData : ( ) => Promise < void > ;
231233 resetLocalData : ( ) => void ;
234+ /**
235+ * Binds persisted drafts to the signed-in account. A different account, or
236+ * drafts saved before accounts were recorded, is cleared first so one
237+ * browser cannot show the previous person's work.
238+ */
239+ prepareForUser : ( userId : string ) => void ;
232240 clearSession : ( ) => void ;
233241
234242 pendingFlowchartData : FlowchartData | null ;
@@ -279,6 +287,53 @@ function normalizeFolder(folder?: string | null) {
279287 return trimmed || 'General' ;
280288}
281289
290+ /** Device-only work that must not cross accounts. Server lists reload after this. */
291+ function sessionWorkForAccount ( ownerUserId : string | null ) : Partial < SessionState > {
292+ return {
293+ ownerUserId,
294+ serverHydration : 'pending' ,
295+ savedCases : [ ] ,
296+ savedAttacks : [ ] ,
297+ savedBrainstorms : [ ] ,
298+ savedFactoids : [ ] ,
299+ savedChats : [ ] ,
300+ savedFlowcharts : [ ] ,
301+ savedCrossfires : [ ] ,
302+ autosavedCases : [ ] ,
303+ autosavedAttacks : [ ] ,
304+ autosavedBrainstorms : [ ] ,
305+ autosavedFactoids : [ ] ,
306+ askChatId : null ,
307+ askChatDebateId : null ,
308+ askPersistedCount : 0 ,
309+ sourceFolders : [ 'General' ] ,
310+ sourceLibrary : [ ] ,
311+ generateResult : null ,
312+ attackResult : null ,
313+ brainstormResult : null ,
314+ factoidsResult : null ,
315+ askMessages : [ ] ,
316+ askStreamingAssistant : null ,
317+ pendingFlowchartData : null ,
318+ generateForm : { } ,
319+ attackForm : { } ,
320+ brainstormForm : { } ,
321+ factoidsForm : { } ,
322+ } ;
323+ }
324+
325+ /**
326+ * Keeps a rehydrate that finishes after sign-in from putting another account's
327+ * snapshot back. Drafts with no owner are kept only while nobody is bound yet;
328+ * binding then clears them.
329+ */
330+ export function mergePersistedSessionState ( persistedState : unknown , currentState : SessionState ) : SessionState {
331+ const saved = persistedState && typeof persistedState === 'object' ? persistedState as Partial < SessionState > : { } ;
332+ const savedOwner = typeof saved . ownerUserId === 'string' ? saved . ownerUserId : null ;
333+ if ( currentState . ownerUserId && savedOwner !== currentState . ownerUserId ) return currentState ;
334+ return { ...currentState , ...saved , ownerUserId : savedOwner ?? currentState . ownerUserId } ;
335+ }
336+
282337function mergeSourceFolders ( currentFolders : string [ ] , sources : Source [ ] = [ ] ) {
283338 return Array . from ( new Set ( [
284339 'General' ,
@@ -454,6 +509,7 @@ export function parseSourceProvenance(value: unknown): SourceProvenance | undefi
454509export const useSessionStore = create < SessionState > ( ) (
455510 persist (
456511 ( set , get ) => ( {
512+ ownerUserId : null as string | null ,
457513 generateResult : null as GenerateOutput | null ,
458514 generateLoading : false ,
459515 generateRegeneratingSection : null as string | null ,
@@ -1233,38 +1289,11 @@ export const useSessionStore = create<SessionState>()(
12331289 askPersistedCount : 0 ,
12341290 } ) ;
12351291 } ,
1236- resetLocalData : ( ) => set ( {
1237- serverHydration : 'pending' ,
1238- savedCases : [ ] ,
1239- savedAttacks : [ ] ,
1240- savedBrainstorms : [ ] ,
1241- savedFactoids : [ ] ,
1242- savedChats : [ ] ,
1243- savedFlowcharts : [ ] ,
1244- savedCrossfires : [ ] ,
1245- autosavedCases : [ ] ,
1246- autosavedAttacks : [ ] ,
1247- autosavedBrainstorms : [ ] ,
1248- autosavedFactoids : [ ] ,
1249- askChatId : null ,
1250- askChatDebateId : null ,
1251- askPersistedCount : 0 ,
1252- sourceFolders : [ 'General' ] ,
1253- sourceLibrary : [ ] ,
1254- generateResult : null ,
1255- attackResult : null ,
1256- brainstormResult : null ,
1257- factoidsResult : null ,
1258- askMessages : [ ] ,
1259- askStreamingAssistant : null ,
1260- // Drafts belong to the signed-in user too; the next person on this
1261- // browser must not see them prefilled.
1262- pendingFlowchartData : null ,
1263- generateForm : { } ,
1264- attackForm : { } ,
1265- brainstormForm : { } ,
1266- factoidsForm : { } ,
1267- } ) ,
1292+ resetLocalData : ( ) => set ( sessionWorkForAccount ( null ) ) ,
1293+ prepareForUser : ( userId ) => {
1294+ if ( get ( ) . ownerUserId === userId ) return ;
1295+ set ( sessionWorkForAccount ( userId ) ) ;
1296+ } ,
12681297
12691298 clearSession : ( ) => set ( {
12701299 generateResult : null ,
@@ -1290,6 +1319,7 @@ export const useSessionStore = create<SessionState>()(
12901319 // older clients: the server replaces them on hydrate, and keeping them
12911320 // would resurrect purged legacy rows and debate-less sources.
12921321 version : 1 ,
1322+ merge : mergePersistedSessionState ,
12931323 migrate : ( persistedState ) => {
12941324 const state = { ...( persistedState as Record < string , unknown > ) } ;
12951325 for ( const key of [
0 commit comments