fix: deep-clone Automerge proxies to prevent stale image data

Automerge proxy objects silently ignore property writes outside
change() calls. When this._thread was a proxy, removeTweetImage's
assignment to this._thread.tweetImages was silently discarded,
causing deleted photos to reappear.

Fix by deep-cloning all Automerge reads (subscribeOffline, onChange,
loadDraft) so this._thread is always a plain mutable object.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-05 21:14:46 -08:00
parent 0eb6e8fe42
commit b7111f01ee
1 changed files with 11 additions and 5 deletions

View File

@ -113,14 +113,18 @@ export class FolkThreadBuilder extends HTMLElement {
const doc = await runtime.subscribe(docId, socialsSchema);
if (this._threadId && doc?.threads?.[this._threadId] && !this._thread) {
this._thread = doc.threads[this._threadId];
// Deep-clone to get a plain object (not an Automerge proxy)
this._thread = JSON.parse(JSON.stringify(doc.threads[this._threadId]));
this._tweetImages = this._thread?.tweetImages || {};
this.render();
}
this._offlineUnsub = runtime.onChange(docId, (updated: SocialsDoc) => {
if (this._threadId && updated?.threads?.[this._threadId]) {
this._thread = updated.threads[this._threadId];
// Deep-clone to avoid Automerge proxy — direct property writes
// on proxies are silently ignored outside change() calls
this._thread = JSON.parse(JSON.stringify(updated.threads[this._threadId]));
this._tweetImages = this._thread?.tweetImages || {};
}
});
} catch (e: any) {
@ -551,9 +555,11 @@ export class FolkThreadBuilder extends HTMLElement {
const thread = doc?.threads?.[id];
if (!thread) return;
this._threadId = thread.id;
this._thread = thread;
this._tweetImages = thread.tweetImages || {};
// Deep-clone to get a plain object (Automerge proxies reject direct writes)
const plain = JSON.parse(JSON.stringify(thread)) as ThreadData;
this._threadId = plain.id;
this._thread = plain;
this._tweetImages = plain.tweetImages || {};
const sr = this.shadowRoot;
if (!sr) return;