Image Handling in Web Comment Editor

    Problem

      When users insert images into the web comment editor, we currently use data URLs (base64 encoding) to store images in drafts. This allows unauthenticated users to create drafts with images that persist across sessions without uploading to IPFS until the comment is published. However, the current data URL approach has significant UX issues:

      Browser Freezing: Base64 encoding blocks the main thread, causing the editor to freeze, especially with larger images (>1MB)

      Performance: Data URLs are 33% larger than the original files, slowing down draft serialization and deserialization

      Poor Mobile Experience: The encoding delay is even more noticeable on mobile devices

      Why We Can't Just Upload Immediately

        Unauthenticated Access: Anyone can create comment drafts without an account

        Orphaned Uploads: If we upload images immediately, users who add images but never publish would create orphaned IPFS data

        Resource Abuse: Malicious users could paste many images and waste daemon resources

    Solution

      I asked AI as suggested and this is what it came up with:

      Option 1: Blob URLs ❌ NOT GOOD for your use case

        const displaySrc = URL.createObjectURL(img) // "blob:http://..."

        Problems:

          Blob URLs are temporary - they die when the page reloads

          Can't be serialized to localStorage/IndexedDB

          Lost when user closes the tab

          Your cached drafts would lose images!

        Verdict: Won't work for persistent drafts.

      Option 2: IndexedDB with Blob Storage ✅ BEST for your use case

        Store the actual File/Blob in IndexedDB, not the base64:

        // Store original file in IndexedDB
        const imageId = `draft-img-${Date.now()}`
        await indexedDB.put('draft-images', img, imageId)
        
        // Create blob URL for display (fast!)
        const displaySrc = URL.createObjectURL(img)
        
        node.create({
          displaySrc: displaySrc,     // Temporary display (fast)
          imageId: imageId,           // Reference to IndexedDB
          name: name,
        })
        
        // On mount/reload: recreate blob URL from IndexedDB
        const storedBlob = await indexedDB.get('draft-images', imageId)
        if (storedBlob) {
          const displaySrc = URL.createObjectURL(storedBlob)
          // Update block with new blob URL
        }

        Pros:

          Fast - no base64 encoding

          Persistent - survives page reload

          Secure - stays in user's browser, no server upload

          Efficient - stores binary, not base64

          Cleanup - can delete IndexedDB entries when draft is published/discarded

        Cons:

          More code complexity

          Need to handle IndexedDB lifecycle

      Option 3: Data URLs (Current approach) ⚠️ Works but slow

        const dataUrl = await readAsDataURL(img) // "data:image/jpeg;base64,..."

        Pros:

          Serializable (can store in localStorage)

          Persistent

          Simple

        Cons:

          Very slow - base64 encoding blocks UI

          33% larger than original file

          Freezes browser for large images

      Option 4: Upload Immediately ⚠️ Orphan problem

        Cons:

          Creates orphaned IPFS uploads

          Wastes daemon resources

          Security issue - unauthenticated users can fill your IPFS

      My Recommendation: IndexedDB (Option 2)

        Here's why:

          Solves the freezing problem - no base64 encoding

          Keeps drafts secure - client-side only until published

          Persists across sessions - user can reload and continue

          Clean architecture - natural place to store draft data

          Easy cleanup - delete from IndexedDB when draft published/discarded