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