The CRDT auto-persist was broadcasting state-refresh after each save, causing
other clients to fetch from DB and overwrite their local variables/characters
with stale values. Since CRDT already syncs nodes/edges via yjs-update
broadcasts, the state-refresh from auto-persist was redundant and destructive.
Manual save still broadcasts state-refresh as intended.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add connection timeout (15s) to handle stale initial subscribes, inactivity
pause (5min) to save resources when idle, and automatic resume on user activity
or tab focus. The heartbeat now detects unhealthy channel states and consecutive
failures to trigger reconnects. Unexpected CLOSED status also triggers reconnect
instead of staying disconnected silently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of relying on Yjs broadcast serialization (which has delivery
issues), use a lightweight state-refresh broadcast event. When any
client persists (manual save or CRDT auto-persist), it broadcasts
state-refresh. Other clients fetch the latest flowchart_data from the
database and update their local state and CRDT.
Added isSuppressed flag to CRDTManager to prevent broadcast/persist
loops during initialization and refresh operations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a user saves, the full Yjs document state is broadcast so all
connected clients converge, even if they missed incremental updates.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The yjs-update broadcast listener was added after the Supabase channel
was already subscribed, which meant it never received messages. Moved
the listener registration to the builder chain before .subscribe()
(matching how cursor/node-lock listeners work), and removed the broken
isRemoteUpdateRef guard that caused ReferenceErrors preventing local
changes from reaching the CRDT.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The merge at bcbad57 lost utility functions, type definitions, and
handlers from the developing branch. This restores: imports (useRef,
useEffect, ConditionalEdge, ContextMenu), constants (AUTOSAVE_DEBOUNCE_MS),
types (ContextMenuState, ConditionEditorState), utility functions
(fromReactFlowNodes, fromReactFlowEdges, saveDraft, loadDraft, clearDraft,
flowchartDataEquals, isValidFlowchartData, convertToRenpyFormat), context
menu handlers, proper FlowchartEditorProps (userId, userDisplayName,
isOwner), ReactFlow container height (h-screen), and fixes stale closure
dependency arrays for characters/variables.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace the variableName text input in edge conditions with a
Combobox-based variable selector. Adds ConditionEditor modal
that opens on edge click, with type-aware operators (comparison
for numeric, == and != for string/boolean) and type-adaptive
value inputs (number, text, or boolean toggle).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Next.js App Router requires components using useSearchParams() to be
wrapped in a Suspense boundary for static generation. Split login and
signup pages into server component wrappers with Suspense and client
form components.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>