Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: PDS sync race — auth not ready when ensurePdsIdentity runs

initUsername() calls initAuth() but is fire-and-forget. The PDS sync
chain ran concurrently, calling getSession() before auth restored the
session — silently returning null and skipping all sync.

Fix: make initAuth() idempotent (cached promise) and await it explicitly
in both the landing sync chain and ensurePdsIdentity() itself (for doc
editor pages that never call initAuth at all).

+15 -3
+2
src/landing.ts
··· 19 19 import { setupDragAndDrop } from './landing-import.js'; 20 20 import { listDocuments, listTrashedDocuments } from './lib/local-store.js'; 21 21 import { mountOfflineIndicator } from './lib/offline-indicator.js'; 22 + import { initAuth } from './lib/auth.js'; 22 23 23 24 // --- DOM refs --- 24 25 const docListEl = document.getElementById('doc-list') as HTMLElement; ··· 344 345 ensureWrappingKey() 345 346 .then(() => syncKeys()) 346 347 .then(async () => { 348 + await initAuth(); 347 349 const { ensurePdsIdentity } = await import('./lib/pds-setup.js'); 348 350 const ready = await ensurePdsIdentity(); 349 351 if (ready) {
+8 -1
src/lib/auth.ts
··· 16 16 17 17 let _client: BrowserOAuthClient | null = null; 18 18 let _session: AtmosSession | null = null; 19 + let _initPromise: Promise<AtmosSession | null> | null = null; 19 20 20 21 async function getClient(): Promise<BrowserOAuthClient> { 21 22 if (_client) return _client; ··· 67 68 return params.has('code') && params.has('state'); 68 69 } 69 70 70 - export async function initAuth(): Promise<AtmosSession | null> { 71 + export function initAuth(): Promise<AtmosSession | null> { 72 + if (_initPromise) return _initPromise; 73 + _initPromise = _doInitAuth(); 74 + return _initPromise; 75 + } 76 + 77 + async function _doInitAuth(): Promise<AtmosSession | null> { 71 78 const wasCallback = isOAuthCallback(); 72 79 73 80 try {
+5 -2
src/lib/pds-setup.ts
··· 9 9 * Uses the existing showPassphraseModal() for UX consistency. 10 10 */ 11 11 12 - import { getSession, type AtmosSession } from './auth.js'; 12 + import { getSession, initAuth, type AtmosSession } from './auth.js'; 13 13 import { getInstanceInfo } from './instance-info.js'; 14 14 import { getSetupStatus, setupIdentity, recoverIdentity } from './pds-documents.js'; 15 15 import { showPassphraseModal } from './key-passphrase.js'; ··· 25 25 const info = await getInstanceInfo(); 26 26 if (!info.features.sync) return false; 27 27 28 - const session = getSession(); 28 + let session = getSession(); 29 + if (!session) { 30 + session = await initAuth(); 31 + } 29 32 if (!session) return false; 30 33 31 34 const status = await getSetupStatus(session.agent, session.did);