diff --git a/lib/community-sync.ts b/lib/community-sync.ts index 44239e1..9bc542c 100644 --- a/lib/community-sync.ts +++ b/lib/community-sync.ts @@ -161,6 +161,7 @@ export class CommunitySync extends EventTarget { #offlineStore: OfflineStore | null = null; #saveDebounceTimer: ReturnType | null = null; #syncedDebounceTimer: ReturnType | null = null; + #initialSyncFired = false; #wsUrl: string | null = null; // ── Undo/Redo state ── @@ -292,6 +293,7 @@ export class CommunitySync extends EventTarget { this.#ws.onclose = () => { console.log(`[CommunitySync] Disconnected from ${this.#communitySlug}`); + this.#initialSyncFired = false; this.dispatchEvent(new CustomEvent("disconnected")); if (!this.#disconnectedIntentionally) { @@ -844,10 +846,12 @@ export class CommunitySync extends EventTarget { // Debounce the synced event — during initial sync negotiation, #applyDocToDOM() // is called for every Automerge sync message (100+ round-trips). Debounce to - // fire once after the burst settles. + // fire once after the burst settles. Only fires once per connection cycle. + if (this.#initialSyncFired) return; if (this.#syncedDebounceTimer) clearTimeout(this.#syncedDebounceTimer); this.#syncedDebounceTimer = setTimeout(() => { this.#syncedDebounceTimer = null; + this.#initialSyncFired = true; this.dispatchEvent(new CustomEvent("synced", { detail: { shapes } })); }, 300); } diff --git a/website/canvas.html b/website/canvas.html index 7630acc..46d95bb 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -3088,10 +3088,18 @@ let _tripCache = null; // { trips: [], detail: null, fetchedAt: 0 } const TRIP_CACHE_TTL = 60000; // 1 minute + function _authHeaders() { + try { + const s = JSON.parse(localStorage.getItem('encryptid_session') || '{}'); + if (s?.accessToken) return { 'Authorization': 'Bearer ' + s.accessToken }; + } catch {} + return {}; + } + async function fetchTripData() { if (_tripCache && Date.now() - _tripCache.fetchedAt < TRIP_CACHE_TTL) return _tripCache; try { - const res = await fetch(`/${communitySlug}/rtrips/api/trips`); + const res = await fetch(`/${communitySlug}/rtrips/api/trips`, { headers: _authHeaders() }); if (!res.ok) return { trips: [], detail: null, fetchedAt: Date.now() }; const trips = await res.json(); _tripCache = { trips, detail: null, fetchedAt: Date.now() }; @@ -3101,7 +3109,7 @@ async function fetchTripDetail(tripId) { try { - const res = await fetch(`/${communitySlug}/rtrips/api/trips/${tripId}`); + const res = await fetch(`/${communitySlug}/rtrips/api/trips/${tripId}`, { headers: _authHeaders() }); if (!res.ok) return null; return await res.json(); } catch { return null; } @@ -3145,7 +3153,7 @@ async function fetchNotesData() { if (_notesCache && Date.now() - _notesCache.fetchedAt < TRIP_CACHE_TTL) return _notesCache; try { - const res = await fetch(`/${communitySlug}/rnotes/api/notes?limit=50`); + const res = await fetch(`/${communitySlug}/rnotes/api/notes?limit=50`, { headers: _authHeaders() }); if (!res.ok) return { notes: [], fetchedAt: Date.now() }; const data = await res.json(); _notesCache = { notes: data.notes || [], fetchedAt: Date.now() };