mirror of
https://github.com/molvqingtai/WebChat.git
synced 2025-11-25 03:15:08 +08:00
218 lines
7.4 KiB
Markdown
218 lines
7.4 KiB
Markdown
|
|
# 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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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**:
|
||
|
|
```typescript
|
||
|
|
// 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):
|
||
|
|
```typescript
|
||
|
|
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)
|