fix: await saveDraft/saveToAutomerge in all image and share handlers

All callers of saveDraft() and saveToAutomerge() in generateImage,
uploadImage, uploadTweetImage, generateTweetImage, removeTweetImage,
and share handler now properly await these async methods. Without await,
runtime.change() fires before the Automerge doc subscription resolves,
causing "Document not open" errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-05 16:58:04 -08:00
parent f4edf3b7ae
commit ff5dd8c006
1 changed files with 13 additions and 13 deletions

View File

@ -405,7 +405,7 @@ export class FolkThreadBuilder extends HTMLElement {
// ── Draft management (Automerge) ── // ── Draft management (Automerge) ──
private saveDraft() { private async saveDraft() {
const sr = this.shadowRoot; const sr = this.shadowRoot;
if (!sr) return; if (!sr) return;
const textarea = sr.getElementById('thread-input') as HTMLTextAreaElement; const textarea = sr.getElementById('thread-input') as HTMLTextAreaElement;
@ -435,8 +435,8 @@ export class FolkThreadBuilder extends HTMLElement {
this._thread = thread; this._thread = thread;
// Save via Automerge // Save via Automerge (await ensures doc is open first)
this.saveToAutomerge(thread); await this.saveToAutomerge(thread);
// Update URL // Update URL
history.replaceState(null, '', this.basePath + 'thread/' + this._threadId + '/edit'); history.replaceState(null, '', this.basePath + 'thread/' + this._threadId + '/edit');
@ -562,7 +562,7 @@ export class FolkThreadBuilder extends HTMLElement {
private async generateImage() { private async generateImage() {
if (!this._threadId) { if (!this._threadId) {
this.saveDraft(); await this.saveDraft();
if (!this._threadId) return; if (!this._threadId) return;
} }
@ -588,7 +588,7 @@ export class FolkThreadBuilder extends HTMLElement {
// Update Automerge with new image URL // Update Automerge with new image URL
if (this._thread) { if (this._thread) {
this._thread.imageUrl = data.imageUrl; this._thread.imageUrl = data.imageUrl;
this.saveToAutomerge(this._thread); await this.saveToAutomerge(this._thread);
} }
} else { } else {
genBtn.textContent = 'Generation Failed'; genBtn.textContent = 'Generation Failed';
@ -604,7 +604,7 @@ export class FolkThreadBuilder extends HTMLElement {
private async uploadImage(file: File) { private async uploadImage(file: File) {
if (!this._threadId) { if (!this._threadId) {
this.saveDraft(); await this.saveDraft();
if (!this._threadId) return; if (!this._threadId) return;
} }
@ -631,7 +631,7 @@ export class FolkThreadBuilder extends HTMLElement {
genBtn.textContent = 'Replace with AI'; genBtn.textContent = 'Replace with AI';
if (this._thread) { if (this._thread) {
this._thread.imageUrl = data.imageUrl; this._thread.imageUrl = data.imageUrl;
this.saveToAutomerge(this._thread); await this.saveToAutomerge(this._thread);
} }
} else { } else {
uploadBtn.textContent = data.error || 'Upload Failed'; uploadBtn.textContent = data.error || 'Upload Failed';
@ -647,7 +647,7 @@ export class FolkThreadBuilder extends HTMLElement {
private async uploadTweetImage(index: string, file: File) { private async uploadTweetImage(index: string, file: File) {
if (!this._threadId) { if (!this._threadId) {
this.saveDraft(); await this.saveDraft();
if (!this._threadId) return; if (!this._threadId) return;
} }
@ -660,7 +660,7 @@ export class FolkThreadBuilder extends HTMLElement {
this._tweetImages[index] = data.imageUrl; this._tweetImages[index] = data.imageUrl;
if (this._thread) { if (this._thread) {
this._thread.tweetImages = { ...this._tweetImages }; this._thread.tweetImages = { ...this._tweetImages };
this.saveToAutomerge(this._thread); await this.saveToAutomerge(this._thread);
} }
this.renderPreview(); this.renderPreview();
} }
@ -669,7 +669,7 @@ export class FolkThreadBuilder extends HTMLElement {
private async generateTweetImage(index: string) { private async generateTweetImage(index: string) {
if (!this._threadId) { if (!this._threadId) {
this.saveDraft(); await this.saveDraft();
if (!this._threadId) return; if (!this._threadId) return;
} }
@ -684,7 +684,7 @@ export class FolkThreadBuilder extends HTMLElement {
this._tweetImages[index] = data.imageUrl; this._tweetImages[index] = data.imageUrl;
if (this._thread) { if (this._thread) {
this._thread.tweetImages = { ...this._tweetImages }; this._thread.tweetImages = { ...this._tweetImages };
this.saveToAutomerge(this._thread); await this.saveToAutomerge(this._thread);
} }
this.renderPreview(); this.renderPreview();
} else if (btn) { } else if (btn) {
@ -703,7 +703,7 @@ export class FolkThreadBuilder extends HTMLElement {
delete this._tweetImages[index]; delete this._tweetImages[index];
if (this._thread) { if (this._thread) {
this._thread.tweetImages = Object.keys(this._tweetImages).length ? { ...this._tweetImages } : undefined; this._thread.tweetImages = Object.keys(this._tweetImages).length ? { ...this._tweetImages } : undefined;
this.saveToAutomerge(this._thread); await this.saveToAutomerge(this._thread);
} }
this.renderPreview(); this.renderPreview();
} catch (e) { console.error('Tweet image removal failed:', e); } } catch (e) { console.error('Tweet image removal failed:', e); }
@ -919,7 +919,7 @@ export class FolkThreadBuilder extends HTMLElement {
shareBtn.disabled = true; shareBtn.disabled = true;
try { try {
this.saveDraft(); await this.saveDraft();
if (!this._threadId) { shareBtn.textContent = 'Share'; shareBtn.disabled = false; return; } if (!this._threadId) { shareBtn.textContent = 'Share'; shareBtn.disabled = false; return; }
if (imagePreview?.hidden) { if (imagePreview?.hidden) {