Files
WebChat/CLAUDE.md
molvqingtai 0bfaa07258 perf: optimize app positioning and message sending performance
- Change app button positioning from left-top to bottom-right anchor
- Add reverse mode to useDraggable for bottom-right coordinate system
- Reset button position to default on window resize
- Use useMemo to cache message list computation
- Use startTransition to prevent UI blocking when sending messages
- Add generic type parameters to useShareRef and useTriggerAway
- Add CLAUDE.md for repository guidance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-30 17:48:36 +08:00

7.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

WebChat is a decentralized, serverless browser extension that enables anonymous P2P chat on any website using WebRTC. Built with WXT framework for cross-browser support (Chrome, Firefox, Edge).

Key Technologies

  • WXT: Browser extension framework (config: wxt.config.ts)
  • Remesh: DDD framework for domain logic with true UI/logic separation (RxJS-based reactive state management)
  • Artico (@rtco/client): WebRTC P2P communication library (replaces previous trystero dependency)
  • React 19 with TypeScript
  • Tailwind CSS v4 with shadcn/ui components
  • Valibot: Runtime schema validation

Development Commands

# Development
npm run dev                  # Chrome dev mode with hot reload
npm run dev:firefox          # Firefox dev mode

# Type checking
npm run check                # Run TypeScript compiler without emitting files

# Linting
npm run lint                 # ESLint with auto-fix and cache

# Building
npm run build                # Production build for all browsers
npm run build:chrome         # Chrome production build only
npm run build:firefox        # Firefox production build only

# Packaging
npm run pack                 # Create zip files for all browsers
npm run pack:chrome          # Create Chrome zip only
npm run pack:firefox         # Create Firefox zip only

# Maintenance
npm run clear                # Remove .output directory
npm run prepare              # Setup husky git hooks
npm run postinstall          # WXT preparation (auto-runs after install)

Architecture

Extension Structure

WebChat uses WXT's app-based structure (not entrypoints):

  • src/app/content/ - Content script injected into web pages (main chat UI)
  • src/app/background/ - Service worker handling notifications and extension actions
  • src/app/options/ - Options page UI for user profile settings
  • Entry files: index.ts or index.tsx in each app directory

Domain-Driven Design (Remesh)

Business logic is fully decoupled from UI using Remesh domains:

Core Domains (src/domain/):

  • ChatRoom.ts - Site-specific P2P chat room (messages, users, sync)
  • VirtualRoom.ts - Global virtual room for cross-site user discovery
  • MessageList.ts - Message management and persistence
  • UserInfo.ts - User profile state
  • AppStatus.ts - Application state (open/minimized)
  • Danmaku.ts - Danmaku/bullet comments display
  • Notification.ts - Browser notifications
  • Toast.ts - In-app toast messages

Domain Pattern:

  • domain/ - Remesh domain definitions (pure logic, queries, commands, events)
  • domain/externs/ - External dependency interfaces (define contracts)
  • domain/impls/ - Concrete implementations of externs (WebRTC, storage, etc.)
  • domain/modules/ - Reusable domain sub-modules

P2P Communication Architecture

Two-Layer Room System:

  1. ChatRoom (Site-specific):

    • RoomId: Hash of current page's origin
    • Users on same site chat in isolated rooms
    • Message types: Text, Like, Hate, SyncUser, SyncHistory
    • History sync: Last 90 days (SYNC_HISTORY_MAX_DAYS)
    • Message size limit: 256KiB (WEB_RTC_MAX_MESSAGE_SIZE)
  2. VirtualRoom (Global):

    • RoomId: WEB_CHAT_VIRTUAL_ROOM constant
    • Cross-site user discovery
    • Shares online user presence across different websites
    • Message types: SyncUser only

Connection Flow:

  1. User joins VirtualRoom (global presence)
  2. User joins ChatRoom (site-specific, based on location.origin)
  3. On peer join: Exchange SyncUser messages
  4. Sync message history if peer's lastMessageTime is older
  5. WebRTC data channels handle all message transport

Storage Strategy

Three-tier storage implemented in src/domain/impls/Storage.ts:

  • LocalStorage - Fast, synchronous access (volatile)
  • IndexDB - Large data persistence (message history)
  • BrowserSyncStorage - Cross-device user profile sync (8kb limit per key)

Key storage keys in src/constants/config.ts:

  • USER_INFO_STORAGE_KEY - User profile (synced)
  • MESSAGE_LIST_STORAGE_KEY - Message history (IndexDB)
  • APP_STATUS_STORAGE_KEY - App UI state (local)

Message Sync Logic

Important sync behavior (documented in ChatRoom.ts:337-355):

  • New peer joins → existing peers with newer messages push history
  • Only messages newer than peer's lastMessageTime are synced
  • Messages chunked to respect WebRTC size limits
  • Incremental sync (not full 90-day diff) - may result in incomplete history for peers joining at different times

Code Organization

src/
├── app/              # WXT applications (content, background, options)
├── domain/           # Remesh domains (business logic)
│   ├── externs/      # External dependency interfaces
│   ├── impls/        # Concrete implementations
│   └── modules/      # Reusable domain modules
├── components/       # React UI components
│   ├── ui/           # shadcn/ui base components
│   └── magicui/      # Magic UI animated components
├── utils/            # Pure utility functions
├── constants/        # App constants and config
├── hooks/            # React hooks
├── messenger/        # Extension messaging (webext-bridge)
├── lib/              # Third-party library integrations
└── assets/           # Static assets (images, styles)

Path Aliases

TypeScript paths configured in tsconfig.json:

  • @/*./src/*

Import example: import { ChatRoomDomain } from '@/domain/ChatRoom'

Important Constants

In src/constants/config.ts:

  • MESSAGE_MAX_LENGTH = 500 - Max message length
  • MAX_AVATAR_SIZE = 5120 - Max avatar size (bytes) for sync storage
  • SYNC_HISTORY_MAX_DAYS = 90 - Message history retention
  • WEB_RTC_MAX_MESSAGE_SIZE = 262144 - 256KiB WebRTC limit
  • VIRTUAL_ROOM_ID = 'WEB_CHAT_VIRTUAL_ROOM' - Global room identifier

Browser Extension Specifics

Manifest configuration (wxt.config.ts):

  • Permissions: storage, notifications, tabs
  • Matches: https://*/*
  • Excludes: localhost, 127.0.0.1, csdn.net, csdn.com
  • Browser-specific manifests for Chrome and Firefox

Content Script Injection:

  • Shadow DOM mode: open
  • Position: inline in body (appended last)
  • CSS isolation with cssInjectionMode: 'ui'
  • Event isolation: keyup, keydown, keypress

Working with Remesh Domains

Creating/Using Domains:

// In content script
const store = Remesh.store({
  externs: [
    LocalStorageImpl,
    IndexDBStorageImpl,
    BrowserSyncStorageImpl,
    ChatRoomImpl,
    VirtualRoomImpl,
    // ... other implementations
  ]
})

// In React component
const send = domain.useRemeshSend()
const userList = domain.useRemeshQuery(chatRoomDomain.query.UserListQuery())

// Send command
send(chatRoomDomain.command.SendTextMessageCommand('Hello'))

// Subscribe to event
domain.useRemeshEvent(chatRoomDomain.event.OnTextMessageEvent, (message) => {
  console.log('New message:', message)
})

Validation with Valibot

All runtime message validation uses Valibot (not Zod):

import * as v from 'valibot'

const schema = v.object({ /* ... */ })
const isValid = v.safeParse(schema, data).success

Linting & Git Hooks

  • Husky pre-commit hooks configured
  • lint-staged auto-fixes JS/TS files on commit
  • commitlint enforces conventional commit messages

Node Version

Minimum Node.js version: >=20.0.0 (see engines in package.json)