From 716012ee63592af15666bb8ed3ed649254f971e7 Mon Sep 17 00:00:00 2001 From: limina1 Date: Sun, 7 Sep 2025 19:14:06 -0400 Subject: [PATCH] fix: Resolve postMessage serialization error in event publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Events now publish successfully but don't appear in feed yet. Fixed the "Failed to execute 'postMessage' on 'Window'" error by ensuring all event data is properly serialized before passing between components. Changes: - Remove non-serializable tree property from exported events - Convert all NDKEvent properties to primitives in eventToPublishableObject - Add JSON deep cloning in handlePublish to ensure full serializability - Add debug logging to track event structure and serialization issues Status: Publishing works (events are sent to relays) but feed display needs investigation for relay read/write configuration mismatch. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/lib/components/ZettelEditor.svelte | 52 +++++++++++++++----- src/lib/utils/asciidoc_publication_parser.ts | 22 +++++---- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/lib/components/ZettelEditor.svelte b/src/lib/components/ZettelEditor.svelte index f992373..dbbec9f 100644 --- a/src/lib/components/ZettelEditor.svelte +++ b/src/lib/components/ZettelEditor.svelte @@ -70,7 +70,7 @@ import Asciidoctor from "asciidoctor"; }); // Effect to create PublicationTree when content changes - // Uses tree processor extension as Michael envisioned: + // Uses tree processor: // "register a tree processor extension in our Asciidoctor instance" // "use the AST that Asciidoctor generates during parsing" // "publication tree side-loads into memory as AsciiDoc is parsed" @@ -93,6 +93,16 @@ import Asciidoctor from "asciidoctor"; return exportEventsFromTree(result); }) .then(events => { + // Debug: Check what we're getting from exportEventsFromTree + console.log("Events from exportEventsFromTree:", events); + console.log("Event keys:", Object.keys(events)); + if (events.indexEvent) { + console.log("Index event keys:", Object.keys(events.indexEvent)); + } + if (events.contentEvents?.[0]) { + console.log("First content event keys:", Object.keys(events.contentEvents[0])); + } + generatedEvents = events; console.log("Tree factory result:", { @@ -225,15 +235,35 @@ import Asciidoctor from "asciidoctor"; function handlePublish() { if (!generatedEvents) return; - if (contentType === 'article' && generatedEvents.indexEvent) { - // Full article: publish both index event (30040) and content events (30041) - onPublishArticle(generatedEvents); - } else if (contentType === 'scattered-notes') { - // Only notes: publish just the content events (30041) - const notesOnly = { - contentEvents: generatedEvents.contentEvents - }; - onPublishScatteredNotes(notesOnly); + try { + // Deep clone the events to ensure they're fully serializable + // This prevents postMessage cloning errors + const serializableEvents = JSON.parse(JSON.stringify(generatedEvents)); + + if (contentType === 'article' && serializableEvents.indexEvent) { + // Full article: publish both index event (30040) and content events (30041) + onPublishArticle(serializableEvents); + } else if (contentType === 'scattered-notes') { + // Only notes: publish just the content events (30041) + const notesOnly = { + contentEvents: serializableEvents.contentEvents + }; + onPublishScatteredNotes(notesOnly); + } + } catch (error) { + console.error("Failed to serialize events:", error); + console.error("generatedEvents structure:", generatedEvents); + // Try to identify the non-serializable part + if (generatedEvents) { + console.error("Keys in generatedEvents:", Object.keys(generatedEvents)); + if (generatedEvents.indexEvent) { + console.error("indexEvent type:", typeof generatedEvents.indexEvent, generatedEvents.indexEvent?.constructor?.name); + } + if (generatedEvents.contentEvents?.[0]) { + console.error("First contentEvent type:", typeof generatedEvents.contentEvents[0], generatedEvents.contentEvents[0]?.constructor?.name); + } + } + alert("Error: Events contain non-serializable data. Check console for details."); } } @@ -826,4 +856,4 @@ Understanding the nature of knowledge... {/if} - \ No newline at end of file + diff --git a/src/lib/utils/asciidoc_publication_parser.ts b/src/lib/utils/asciidoc_publication_parser.ts index 00586ab..84d8ffc 100644 --- a/src/lib/utils/asciidoc_publication_parser.ts +++ b/src/lib/utils/asciidoc_publication_parser.ts @@ -109,23 +109,27 @@ async function buildTreeRelationships(result: ProcessorResult): Promise { export function exportEventsFromTree(result: PublicationTreeResult) { return { indexEvent: result.indexEvent ? eventToPublishableObject(result.indexEvent) : undefined, - contentEvents: result.contentEvents.map(eventToPublishableObject), - tree: result.tree + contentEvents: result.contentEvents.map(eventToPublishableObject) + // Note: Deliberately omitting 'tree' to ensure the object is serializable for postMessage }; } /** * Convert NDKEvent to publishable object format + * Ensures all properties are serializable for postMessage */ function eventToPublishableObject(event: any) { + // Extract only primitive values to ensure serializability return { - kind: event.kind, - content: event.content, - tags: event.tags, - created_at: event.created_at, - pubkey: event.pubkey, - id: event.id, - title: event.tags.find((t: string[]) => t[0] === "title")?.[1] || "Untitled" + kind: Number(event.kind), + content: String(event.content || ''), + tags: Array.isArray(event.tags) ? event.tags.map((tag: any) => + Array.isArray(tag) ? tag.map(t => String(t)) : [] + ) : [], + created_at: Number(event.created_at || Math.floor(Date.now() / 1000)), + pubkey: String(event.pubkey || ''), + id: String(event.id || ''), + title: event.tags?.find?.((t: string[]) => t[0] === "title")?.[1] || "Untitled" }; }