From e8d88cd10e9b2eb05776959e47109f9bf2763ab1 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Sat, 28 Mar 2026 16:34:08 -0700 Subject: [PATCH] fix(rnotes): resolve anonymous identity in comments, suggestions, and cursors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session was stored as { claims: { username, sub } } but getSessionInfo() read sess.username (top-level) instead of sess.claims.username — always falling back to "Anonymous". Fixed in all 3 locations: folk-notes-app, comment-panel, collab-presence. Also fixed awareness race: Yjs provider broadcast initial awareness before user field was set, creating a ghost "anonymous" peer. Now identity is set on awareness before provider connects, and the duplicate set is removed. Co-Authored-By: Claude Opus 4.6 --- modules/rnotes/components/comment-panel.ts | 5 +++-- modules/rnotes/components/folk-notes-app.ts | 20 +++++++++++--------- shared/collab-presence.ts | 5 +++-- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/modules/rnotes/components/comment-panel.ts b/modules/rnotes/components/comment-panel.ts index 3f212a2..6fce6e7 100644 --- a/modules/rnotes/components/comment-panel.ts +++ b/modules/rnotes/components/comment-panel.ts @@ -87,9 +87,10 @@ class NotesCommentPanel extends HTMLElement { private getSessionInfo(): { authorName: string; authorId: string } { try { const sess = JSON.parse(localStorage.getItem('encryptid_session') || '{}'); + const c = sess?.claims; return { - authorName: sess?.username || sess?.displayName || 'Anonymous', - authorId: sess?.userId || sess?.sub || 'anon', + authorName: c?.username || c?.displayName || sess?.username || 'Anonymous', + authorId: c?.sub || sess?.userId || 'anon', }; } catch { return { authorName: 'Anonymous', authorId: 'anon' }; diff --git a/modules/rnotes/components/folk-notes-app.ts b/modules/rnotes/components/folk-notes-app.ts index 2b77724..6328a5a 100644 --- a/modules/rnotes/components/folk-notes-app.ts +++ b/modules/rnotes/components/folk-notes-app.ts @@ -1306,9 +1306,17 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF // IndexedDB persistence for offline this.yIndexedDb = new IndexeddbPersistence(roomName, this.ydoc); + // Set awareness identity BEFORE connecting provider (avoids anonymous ghost) + const sessionForAwareness = this.getSessionInfo(); + // Connect Yjs provider over rSpace WebSocket if (runtime?.isInitialized) { this.yjsProvider = new RSpaceYjsProvider(note.id, this.ydoc, runtime); + // Pre-set user so the first awareness broadcast has the correct name + this.yjsProvider.awareness.setLocalStateField('user', { + name: sessionForAwareness.username || 'Anonymous', + color: this.userColor(sessionForAwareness.userId || 'anon'), + }); } // Content migration: if Y.Doc fragment is empty and Automerge has content @@ -1377,13 +1385,6 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF ); this.editor.registerPlugin(cursorPlugin); - // Set local user state on awareness - const session = this.getSessionInfo(); - this.yjsProvider.awareness.setLocalStateField('user', { - name: session.username || 'Anonymous', - color: this.userColor(session.userId || 'anon'), - }); - // Update collab status bar when peers change this.yjsProvider.awareness.on('update', () => { this.updatePeersIndicator(); @@ -1479,9 +1480,10 @@ Gear: EUR 400 (10%)

Maya is tracking expenses in rF private getSessionInfo(): { username: string; userId: string } { try { const sess = JSON.parse(localStorage.getItem('encryptid_session') || '{}'); + const c = sess?.claims; return { - username: sess?.username || sess?.displayName || 'Anonymous', - userId: sess?.userId || sess?.sub || 'anon', + username: c?.username || c?.displayName || sess?.username || 'Anonymous', + userId: c?.sub || sess?.userId || 'anon', }; } catch { return { username: 'Anonymous', userId: 'anon' }; diff --git a/shared/collab-presence.ts b/shared/collab-presence.ts index 63efd3a..975859f 100644 --- a/shared/collab-presence.ts +++ b/shared/collab-presence.ts @@ -12,9 +12,10 @@ function getSessionInfo(): { username: string; userId: string } { try { const sess = JSON.parse(localStorage.getItem('encryptid_session') || '{}'); + const c = sess?.claims; return { - username: sess?.username || sess?.displayName || 'Anonymous', - userId: sess?.userId || sess?.sub || 'anon', + username: c?.username || c?.displayName || sess?.username || 'Anonymous', + userId: c?.sub || sess?.userId || 'anon', }; } catch { return { username: 'Anonymous', userId: 'anon' };