Conversation
* feat: add PostHog analytics with reverse proxy - Initialize PostHog client in instrumentation-client.ts - Add server-side client with session ID support - Configure /ingest reverse proxy for ad-blocker resilience - Enable performance monitoring, error tracking, console logs * feat: add server-side PostHog tracking to AI API routes - Track ai_chat_requested and ai_structure_requested events - Use session-based distinct IDs for anonymous tracking * feat: add PostHog tracking to toolbar components - Track undo/redo actions with stack sizes - Track zoom changes (in/out/fit/reset) with zoom levels - Track selection formatting (fill, stroke, width, style changes) * feat: add PostHog tracking to board interactions - Track grid type, spacing, and major grid changes - Track pencil mode toggle - Track image insertions (source, target, dimensions) and fullscreen views - Track element deletions via eraser tool * feat: add PostHog tracking to image, eraser, and app actions - Track image insertions (source, target, dimensions) - Track image fullscreen views - Track element deletions via eraser tool - Track board lifecycle (created, deleted, renamed, switched) - Track file operations (save, open, export, clear) * chore: update gitignore and Next.js env types * chore: add .claude/ to .gitignore * fix: improve PostHog initialization safety and configuration - Validate POSTHOG_KEY before initialization to prevent crashes - Fix invalid defaults value (2026-01-30 -> 2025-11-30) - Make console log recording environment-aware (dev only) - Register process-level shutdown handlers instead of per-request - Batch events with flushAt: 10 and flushInterval: 5000ms - Handle missing PostHog key gracefully with warning * fix: extract duplicated model name resolution and handle null PostHog - Create shared resolveModelName utility function - Handle null PostHog client gracefully in API routes * fix: correct telemetry placement and state consistency - Move tool_selected capture after board null check - Fix toggleHanddrawn to use newMode in setState - Add resulting zoom level to zoom_fit_to_screen event
- Add @liveblocks/client, @liveblocks/react, @liveblocks/node for real-time collaboration - Add @dicebear/core, @dicebear/avataaars for avatar generation - Add unique-names-generator for anonymous user nicknames - Add posthog-js, posthog-node for product analytics
- Add provider-agnostic collaboration types (CollaborationUser, Cursor, UserPresence) - Add CollaborationProvider abstraction wrapping Liveblocks - Add hooks: useCollaborationContext, useRoomPresence, usePresence, useCursorTracking - Add cursor overlay and avatar components - Add user identity generation with DiceBear avatars and unique nicknames - Add cursor manager for presence tracking - Uses peerDependencies for React, Liveblocks to avoid duplication
- Define Presence types for cursor, selection, viewport, user - Define Storage schema for Plait elements - Define UserMeta for user info (name, color, avatar)
- POST /api/collaboration/auth authenticates users for room access - Validates required fields (userId, userName, userColor) - Creates Liveblocks session with full access to specified room - Returns authorized session token
- Add Room component with Liveblocks RoomProvider and ClientSideSuspense - Add CollaborativeBoard with cursor overlay and board sync - Add CollaborationStatusBar showing online users and share button - Integrate with @thinkix/collaboration package hooks and components
- Add server-side PostHog client with environment detection - Add instrumentation for PostHog initialization on server start - Support both client-side (posthog-js) and server-side (posthog-node)
- Add RemoteSyncHandler component for collaboration sync - Listen for thinkix:remote-elements-change custom events - Use Plait's useListRender to update board from remote changes - Dispatch thinkix:local-elements-change on local board changes
- Add collaboration prop for showing online status and controls - Add share board, change nickname, leave collaboration actions - Add nickname dialog for changing user name - Show collaboration options on mobile when enabled
- Add room detection from URL params (?room=xxx) - Add collaboration toggle with enable/disable functions - Wrap board in Room provider when collaboration enabled - Show Collaborate button and CollaborationStatusBar - Use Suspense boundary for useSearchParams
- Add @thinkix/collaboration to paths in tsconfig - Update vitest config to include collaboration package paths
- Add cursor manager unit tests for presence tracking - Add user identity tests for avatar and nickname generation - Add cursor collaboration integration tests - Add vitest snapshots for avatar generation
…ations - Add Yjs adapter package with Y.Map-based element storage - Replace O(n) findIndex operations with O(1) map lookups - Use transaction origin tracking to prevent sync echo loops - Add isLocalChange flag to distinguish local vs remote updates - Update collaborative-board.tsx to use new YjsProvider - Add yjs and @liveblocks/yjs dependencies
- Integrate getVisibleCursors to only render cursors in viewport - Add getActiveCursors to filter out idle cursors - Add maxCursors limit (default 50) to prevent DOM overload - Export cursor utilities from hooks index - Export CollaborationErrorBoundary from components
- Add CollaborationErrorBoundary class component - Add ConnectionIndicator for connection status display - Provides retry functionality on connection errors
- Add BoardLayoutSlots for positioned toolbar containers - Add CollaborateButton as standalone component - Add CollaborativeAppMenu to wrap AppMenu with collaboration context - Simplify page.tsx to only orchestrate components - Slots now render inside BoardCanvas for proper positioning context
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughIntroduces a complete real-time collaboration system with Liveblocks and Yjs integration. Adds a new Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client/Browser
participant Auth as Auth Endpoint
participant Liveblocks as Liveblocks Service
participant Yjs as Yjs Sync
participant Peer as Remote Peer
Client->>Auth: POST /api/collaboration/auth<br/>(userId, userName, userColor, room)
Auth->>Liveblocks: authorizeWithToken(sessionInfo)
Liveblocks-->>Auth: authorization token
Auth-->>Client: token response
Client->>Liveblocks: connectToRoom(roomId, token)
Client->>Yjs: initializeYjsDoc()
Yjs->>Liveblocks: subscribeLiveblocks
Client->>Client: renderRoom with YjsProvider + RoomProvider
Peer->>Yjs: updateRemoteElements
Yjs-->>Client: remoteElementsChanged
Client->>Client: updateLocalBoard(remoteElements)
Client->>Client: triggerRemoteSyncHandler
Client->>Client: localBoardChange
Client->>Yjs: emitLocalChange(elements)
Yjs->>Peer: broadcastUpdate
Peer->>Peer: applyRemoteChange
Client->>Client: pointerMove
Client->>Liveblocks: updatePresence(cursor)
Liveblocks->>Peer: broadcastPresenceUpdate
Peer->>Peer: renderRemoteCursor
sequenceDiagram
participant Board as Local Board
participant SyncBus as Sync Bus
participant RemoteSync as RemoteSyncHandler
participant Elements as Element State
Board->>Board: handleChange(newElements)
Board->>SyncBus: emitLocalChange(newElements)
SyncBus->>RemoteSync: notifyLocalChangeSubscribers
RemoteSync->>RemoteSync: onRemoteChange(newElements)
RemoteSync->>Elements: updateElements(newElements)
Elements->>Board: rerender(updatedElements)
rect rgba(100, 150, 200, 0.5)
Note over SyncBus,Elements: Remote peer emits change
end
RemoteSync->>SyncBus: subscribeToRemoteChanges
SyncBus->>RemoteSync: notifyRemoteChangeSubscribers
RemoteSync->>Elements: applyRemoteElements
Elements->>Board: refreshWithRemoteData
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
| Metric | Coverage |
|---|---|
| Lines | 0% |
| Functions | 96.32% |
| Branches | 84.91% |
| Statements | 94.82% |
| Average | 69.0% |
How to view coverage report
- Download the coverage artifact from the link above
- Extract the ZIP file
- Open
index.htmlin your browser
Commit: 04b6082ad6bbc225e90dbf29d686c5da8ee96d26
- Add viewport utilities (getViewport, screenToDocument, documentToScreen) - Add timing utilities (debounce, throttle) - Add SyncBus for type-safe event communication replacing window events
- Update CursorManager to use shared Viewport type - Update useCursorTracking to use shared getViewport function - Remove duplicate coordinate conversion code
- Debounce viewport recalculations (100ms default) for better performance - Reduce main thread blocking with 100+ cursors - Add configurable visibilityDebounceMs prop
- Use type-safe SyncBus pub/sub pattern instead of window.dispatchEvent - Improves testability and removes global event pollution - Enables proper cleanup with unsubscribe functions
- Export getSyncBus, resetSyncBus, and SyncBus type - Export utils module for direct access - Add tsconfig paths for @thinkix/collaboration/* sub-modules
- Update imports to use new sub-path exports - Fix assertions to use screenX/screenY instead of x/y - Align with shared viewport utilities
Replace removed 'randomUUID' import from 'crypto' with built-in crypto.randomUUID() which is available in modern Node.js
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/unit/liveblocks-hooks.test.ts`:
- Around line 4-22: Replace the static mock with a shared configurable mockState
and stable spy functions so tests can both mutate state per test and assert
calls: create a module-level mockState object holding myPresence, users,
connectionStatus, userCount and isConnected and expose stable spies for
updateCursor, updateSelection, updateViewport and updateUserInfo; have the
mocked hooks (usePresence, useRoomPresence, useRoomConnection) return values
that read from mockState and return the stable spy functions so vi.fn()
instances are not recreated; in tests reset mockState and call
vi.clearAllMocks() in beforeEach to restore defaults and allow verifying call
counts and different connection/user scenarios.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
tests/unit/collaboration-context.test.tsxtests/unit/liveblocks-hooks.test.tstests/unit/use-cursor-tracking.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/unit/use-cursor-tracking.test.tsx
- tests/unit/collaboration-context.test.tsx
- Introduce new unit tests for the useBoardSync hook, covering initialization, remote elements, and syncToRemote functionality - Update vitest configuration to include path aliases for collaboration-related files
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Add error isolation in sync-bus to prevent subscriber failures from propagating - Replace noop assertions with real verifications in liveblocks-hooks and collaboration-context tests - Use shared mock state for configurable test scenarios - Replace waitForTimeout with explicit Playwright wait conditions - Fix weak assertions to properly verify expected behavior
…ider - Remove redundant CollaborationProvider (duplicated YjsProvider logic) - Merge RoomProvider into provider.tsx - Delete room-provider.tsx - Update exports to use consolidated provider This reduces code duplication and simplifies the provider hierarchy.
- Replace unsafe `as (patch: object) => void` casts with typed Parameters<typeof> - Use proper type inference for updateMyPresence calls - Add explicit PresenceUpdate type for clarity This eliminates 8 unsafe type casts while maintaining Liveblocks compatibility.
- Replace `as (patch: unknown) => void` with Parameters<typeof> pattern - Add PresencePatch type for presence updates - Centralize type assertions at call sites Reduces unsafe casts from 15+ to 4 controlled assertions at Liveblocks boundaries.
…mance Offline handling: - Queue local changes when disconnected - Show warning banner 'Changes will sync when reconnected' - Auto-sync queued changes on reconnection - Prevents data loss during network drops Performance improvement: - Replace JSON.stringify comparison with hash-based approach - generateElementsHash only hashes element IDs and types - ~1000x less memory allocation on large boards - Prevents GC pressure with 100+ collaborating users
…dling - Introduce PresenceJson type for improved clarity in presence updates - Replace unsafe type casts with structured conversion functions (toCursor, toViewport, toUser) - Update presence handling logic to utilize new type definitions, reducing type assertion risks - Refactor presence mapping in useRoomPresence and useYjsPresence for consistency and safety
Summary by CodeRabbit
New Features
Tests