import { useMemo, useEffect, useState, useCallback } from "react" import { TLStoreSnapshot } from "@tldraw/tldraw" import { CloudflareNetworkAdapter } from "./CloudflareAdapter" import { useAutomergeStoreV2, useAutomergePresence } from "./useAutomergeStoreV2" import { TLStoreWithStatus } from "@tldraw/tldraw" import { Repo } from "@automerge/automerge-repo" interface AutomergeSyncConfig { uri: string assets?: any shapeUtils?: any[] bindingUtils?: any[] user?: { id: string name: string } } export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus { const { uri, user } = config // Extract roomId from URI (e.g., "https://worker.com/connect/room123" -> "room123") const roomId = useMemo(() => { const match = uri.match(/\/connect\/([^\/]+)$/) return match ? match[1] : "default-room" }, [uri]) // Extract worker URL from URI (remove /connect/roomId part) const workerUrl = useMemo(() => { return uri.replace(/\/connect\/.*$/, '') }, [uri]) const [repo] = useState(() => new Repo({ network: [new CloudflareNetworkAdapter(workerUrl, roomId)] })) const [handle, setHandle] = useState(null) const [isLoading, setIsLoading] = useState(true) // Initialize Automerge document handle useEffect(() => { let mounted = true const initializeHandle = async () => { try { console.log("🔌 Initializing Automerge Repo with NetworkAdapter") if (mounted) { // Create a new document - Automerge will generate the proper document ID // Force refresh to clear cache const handle = repo.create() console.log("Created Automerge handle via Repo:", { handleId: handle.documentId, isReady: handle.isReady() }) // Wait for the handle to be ready await handle.whenReady() console.log("Automerge handle is ready:", { hasDoc: !!handle.doc(), docKeys: handle.doc() ? Object.keys(handle.doc()).length : 0 }) setHandle(handle) setIsLoading(false) } } catch (error) { console.error("Error initializing Automerge handle:", error) if (mounted) { setIsLoading(false) } } } initializeHandle() return () => { mounted = false } }, [repo, roomId]) // Auto-save to Cloudflare on every change (with debouncing to prevent excessive calls) useEffect(() => { if (!handle) return let saveTimeout: NodeJS.Timeout const scheduleSave = () => { // Clear existing timeout if (saveTimeout) clearTimeout(saveTimeout) // Schedule save with a short debounce (500ms) to batch rapid changes saveTimeout = setTimeout(async () => { try { // With Repo, we don't need manual saving - the NetworkAdapter handles sync console.log("🔍 Automerge changes detected - NetworkAdapter will handle sync") } catch (error) { console.error('Error in change-triggered save:', error) } }, 500) } // Listen for changes to the Automerge document const changeHandler = (payload: any) => { console.log('🔍 Automerge document changed:', { hasPatches: !!payload.patches, patchCount: payload.patches?.length || 0, patches: payload.patches?.map((p: any) => ({ action: p.action, path: p.path, value: p.value ? (typeof p.value === 'object' ? 'object' : p.value) : 'undefined' })) }) scheduleSave() } handle.on('change', changeHandler) return () => { handle.off('change', changeHandler) if (saveTimeout) clearTimeout(saveTimeout) } }, [handle]) // Get the store from the Automerge document const store = useMemo(() => { if (!handle?.doc()) { return null } const doc = handle.doc() if (!doc.store) { return null } return doc.store }, [handle]) // Get the store with status const storeWithStatus = useMemo((): TLStoreWithStatus => { if (!store) { return { status: 'loading' as const } } return { status: 'synced-remote' as const, connectionStatus: 'online' as const, store } }, [store, isLoading]) // Get presence data (only when handle is ready) const userMetadata: { userId: string; name: string; color: string } = (() => { if (user && 'userId' in user) { return { userId: (user as { userId: string; name: string; color?: string }).userId, name: (user as { userId: string; name: string; color?: string }).name, color: (user as { userId: string; name: string; color?: string }).color || '#000000' } } return { userId: user?.id || 'anonymous', name: user?.name || 'Anonymous', color: '#000000' } })() const presence = useAutomergePresence({ handle: handle || null, store: store || null, userMetadata }) return { ...storeWithStatus, presence } as TLStoreWithStatus & { presence: typeof presence } }