{#if typingUsers.length > 0}
{/if}
{$chatStore.connection.status}
{#if $chatStore.connection.status === 'connected'}
{:else}
{/if}
```
---
## WEBSOCKET MANAGER
**Purpose**: Low-level WebSocket management for custom implementations.
### API
```typescript
import {
WebSocketManager,
createWebSocketManager,
type WebSocketConfig
} from '@composable-svelte/chat';
const config: WebSocketConfig = {
url: 'wss://api.example.com/chat',
reconnect: true,
reconnectInterval: 1000,
maxReconnectAttempts: 10,
heartbeatInterval: 30000
};
const manager = createWebSocketManager(config);
// Connect
manager.connect();
// Send message
manager.send({ type: 'message', content: 'Hello' });
// Listen for messages
manager.onMessage((message) => {
console.log('Received:', message);
});
// Listen for connection changes
manager.onConnectionChange((state) => {
console.log('Connection:', state.status);
});
// Disconnect
manager.disconnect();
```
---
## MOCK UTILITIES
**Purpose**: Testing and development without backend.
```typescript
import { createMockStreamingChat } from '@composable-svelte/chat';
const chatStore = createStore({
initialState: createInitialStreamingChatState(),
reducer: streamingChatReducer,
dependencies: createMockStreamingChat({
responseDelay: 50, // Delay between chunks (ms)
mockResponses: [
'This is a mock response.',
'It simulates streaming behavior.'
]
})
});
```
---
## COMPONENT SELECTION GUIDE
**When to use each variant**:
**MinimalStreamingChat**:
- Embedded chat
- Minimal UI needed
- Custom chrome/header
**StandardStreamingChat** (recommended):
- Most use cases
- Balanced features
- Good defaults
**FullStreamingChat**:
- Feature-rich chat app
- Need reactions
- Need attachments
- Need voice input
**Collaborative Features**:
- Multi-user chat
- Team collaboration
- Need presence/typing
- Real-time sync required
---
## CROSS-REFERENCES
**Related Skills**:
- **composable-svelte-core**: Store, reducer, Effect system
- **composable-svelte-media**: VoiceInput (can integrate with chat)
- **composable-svelte-code**: Syntax highlighting in messages
- **composable-svelte-components**: UI components
**When to Use Each Package**:
- **chat**: Real-time chat, streaming responses, LLM interfaces
- **media**: Audio players, video embeds, standalone voice input
- **code**: Code editors, syntax highlighting
- **core**: Base architecture (Store, reducer, effects)
---
## TESTING PATTERNS
### StreamingChat Testing
```typescript
import { TestStore } from '@composable-svelte/core';
import {
streamingChatReducer,
createInitialStreamingChatState,
createMockStreamingChat
} from '@composable-svelte/chat';
const store = new TestStore({
initialState: createInitialStreamingChatState(),
reducer: streamingChatReducer,
dependencies: createMockStreamingChat()
});
// Test message send
await store.send({
type: 'sendMessage',
content: 'Hello',
attachments: []
});
await store.receive({ type: 'streamingStarted' }, (state) => {
expect(state.isStreaming).toBe(true);
});
await store.receive({ type: 'streamingChunk', chunk: 'Hi' }, (state) => {
expect(state.streamingMessage).toBe('Hi');
});
await store.receive({ type: 'streamingCompleted' }, (state) => {
expect(state.isStreaming).toBe(false);
expect(state.messages.length).toBe(2); // User + assistant
});
```
### Collaborative Testing
```typescript
import { TestStore } from '@composable-svelte/core';
import {
collaborativeReducer,
createInitialCollaborativeState
} from '@composable-svelte/chat';
const store = new TestStore({
initialState: createInitialCollaborativeState(),
reducer: collaborativeReducer,
dependencies: {
sendMessage: async function*() {
yield 'Test response';
},
connectWebSocket: vi.fn(),
sendWebSocketMessage: vi.fn()
}
});
// Test user join
await store.send({
type: 'userJoined',
user: {
id: 'user-2',
name: 'Alice',
color: '#3b82f6',
presence: 'active'
}
}, (state) => {
expect(state.users.size).toBe(1);
expect(state.users.get('user-2')?.name).toBe('Alice');
});
// Test typing indicator
await store.send({
type: 'userStartedTyping',
userId: 'user-2',
info: {
target: 'message',
startedAt: Date.now(),
lastUpdate: Date.now()
}
}, (state) => {
expect(state.users.get('user-2')?.typing).toBeTruthy();
});
```
---
## TROUBLESHOOTING
**Streaming not working**:
- Check sendMessage generator function returns AsyncGenerator
- Verify yield statements send string chunks
- Ensure signal.aborted is checked for cancellation
- Check network tab for response streaming
**WebSocket connection failing**:
- Verify WebSocket URL (wss:// for HTTPS, ws:// for HTTP)
- Check CORS/authentication headers
- Ensure reconnect logic is enabled
- Check browser console for errors
**Markdown not rendering**:
- Verify message content is valid markdown
- Check syntax highlighting CSS is loaded
- Ensure code blocks use supported languages
**Collaborative features not syncing**:
- Verify WebSocket connection is active
- Check message format matches expected schema
- Ensure user IDs are unique and consistent
- Check heartbeat/presence update intervals