sockr-client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # sockr-client
2
+
3
+ A WebSocket client SDK with React hooks for real-time messaging, authentication, presence tracking, and typing indicators. Built on [Socket.IO](https://socket.io) and designed to work with [sockr-server](../server).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install sockr-client
9
+ ```
10
+
11
+ **Optional peer dependency:** React 16.8+ is needed for the React hooks. The core `SocketClient` class works without React.
12
+
13
+ ## Quick Start
14
+
15
+ ### With React
16
+
17
+ ```tsx
18
+ import { SocketProvider, useSocket, useMessages, useSendMessage } from "sockr-client";
19
+
20
+ function App() {
21
+ return (
22
+ <SocketProvider
23
+ config={{ url: "http://localhost:3000" }}
24
+ token="my-auth-token"
25
+ >
26
+ <Chat />
27
+ </SocketProvider>
28
+ );
29
+ }
30
+
31
+ function Chat() {
32
+ const { isConnected, isAuthenticated } = useSocket();
33
+ const { messages } = useMessages();
34
+ const { sendMessage, isSending } = useSendMessage();
35
+
36
+ if (!isConnected) return <p>Connecting...</p>;
37
+ if (!isAuthenticated) return <p>Authenticating...</p>;
38
+
39
+ return (
40
+ <div>
41
+ {messages.map((msg) => (
42
+ <p key={msg.id}>
43
+ <strong>{msg.from}:</strong> {msg.content}
44
+ </p>
45
+ ))}
46
+ <button
47
+ disabled={isSending}
48
+ onClick={() => sendMessage("recipient-id", "Hello!")}
49
+ >
50
+ Send
51
+ </button>
52
+ </div>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ### Without React
58
+
59
+ ```typescript
60
+ import { SocketClient } from "sockr-client";
61
+
62
+ const client = new SocketClient({
63
+ url: "http://localhost:3000",
64
+ reconnection: true,
65
+ });
66
+
67
+ client.onStateChange((state) => {
68
+ console.log("Connection state:", state);
69
+ });
70
+
71
+ client.on("authenticated", ({ userId }) => {
72
+ console.log("Logged in as", userId);
73
+ client.sendMessage("bob", "Hey Bob!");
74
+ });
75
+
76
+ client.on("message", ({ from, content }) => {
77
+ console.log(`${from}: ${content}`);
78
+ });
79
+
80
+ client.connect();
81
+ client.authenticate("my-auth-token");
82
+ ```
83
+
84
+ ## API
85
+
86
+ ### `SocketClient`
87
+
88
+ The core client class for managing WebSocket connections, authentication, and messaging.
89
+
90
+ #### Constructor
91
+
92
+ ```typescript
93
+ new SocketClient(config: ClientConfig)
94
+ ```
95
+
96
+ `ClientConfig` options:
97
+
98
+ | Option | Type | Default | Description |
99
+ | --- | --- | --- | --- |
100
+ | `url` | `string` | _(required)_ | Server URL |
101
+ | `autoConnect` | `boolean` | `true` | Connect automatically on creation |
102
+ | `reconnection` | `boolean` | `true` | Auto-reconnect on disconnect |
103
+ | `reconnectionAttempts` | `number` | `5` | Max reconnection attempts |
104
+ | `reconnectionDelay` | `number` | `1000` | Base delay between attempts (ms) |
105
+ | `timeout` | `number` | `20000` | Connection timeout (ms) |
106
+ | `transports` | `string[]` | `["websocket", "polling"]` | Allowed transports |
107
+
108
+ #### Methods
109
+
110
+ | Method | Returns | Description |
111
+ | --- | --- | --- |
112
+ | `connect()` | `void` | Establish the WebSocket connection |
113
+ | `disconnect()` | `void` | Close the connection |
114
+ | `authenticate(token)` | `void` | Authenticate with the server |
115
+ | `sendMessage(to, content, metadata?)` | `void` | Send a direct message |
116
+ | `startTyping(to)` | `void` | Notify a user you are typing |
117
+ | `stopTyping(to)` | `void` | Clear typing indicator |
118
+ | `getOnlineStatus(userIds)` | `void` | Request online status for users |
119
+ | `isConnected()` | `boolean` | Check if connected |
120
+ | `isAuthenticated()` | `boolean` | Check if authenticated |
121
+ | `getConnectionState()` | `ConnectionState` | Get current connection state |
122
+ | `getUserId()` | `string \| null` | Get the authenticated user ID |
123
+ | `on(event, handler)` | `() => void` | Subscribe to events (returns cleanup) |
124
+ | `off(event, handler)` | `void` | Unsubscribe from events |
125
+ | `onStateChange(listener)` | `() => void` | Listen to state changes (returns cleanup) |
126
+
127
+ ### React Components & Hooks
128
+
129
+ #### `<SocketProvider>`
130
+
131
+ Provides socket context to your React tree.
132
+
133
+ ```tsx
134
+ <SocketProvider config={ClientConfig} token?: string>
135
+ {children}
136
+ </SocketProvider>
137
+ ```
138
+
139
+ | Prop | Type | Description |
140
+ | --- | --- | --- |
141
+ | `config` | `ClientConfig` | Connection configuration (required) |
142
+ | `token` | `string` | Auth token (auto-authenticates when connected) |
143
+
144
+ #### `useSocket()`
145
+
146
+ Access the socket client and connection state.
147
+
148
+ ```typescript
149
+ const { client, isConnected, isAuthenticated, connectionState, userId } = useSocket();
150
+ ```
151
+
152
+ #### `useMessages()`
153
+
154
+ Manage incoming messages.
155
+
156
+ ```typescript
157
+ const { messages, addMessage, clearMessages } = useMessages();
158
+ ```
159
+
160
+ #### `useSendMessage()`
161
+
162
+ Send messages with loading and error states.
163
+
164
+ ```typescript
165
+ const { sendMessage, isSending, error } = useSendMessage();
166
+ ```
167
+
168
+ #### `usePresence()`
169
+
170
+ Track which users are online.
171
+
172
+ ```typescript
173
+ const { onlineUsers, isUserOnline, checkOnlineStatus } = usePresence();
174
+ ```
175
+
176
+ #### `useTypingIndicator(timeout?)`
177
+
178
+ Manage typing indicators with auto-timeout.
179
+
180
+ ```typescript
181
+ const { startTyping, stopTyping, usersTyping } = useTypingIndicator(3000);
182
+ ```
183
+
184
+ #### `useSocketEvent(event, handler, deps?)`
185
+
186
+ Subscribe to any socket event within React lifecycle.
187
+
188
+ ```typescript
189
+ useSocketEvent("custom-event", (data) => {
190
+ console.log(data);
191
+ }, []);
192
+ ```
193
+
194
+ ### Connection States
195
+
196
+ ```typescript
197
+ enum ConnectionState {
198
+ DISCONNECTED = "disconnected",
199
+ CONNECTING = "connecting",
200
+ CONNECTED = "connected",
201
+ AUTHENTICATED = "authenticated",
202
+ ERROR = "error",
203
+ RECONNECTING = "reconnecting",
204
+ }
205
+ ```
206
+
207
+ ## Connection Lifecycle
208
+
209
+ ```text
210
+ SocketClient created (autoConnect: true)
211
+ -> State: CONNECTING
212
+ -> WebSocket established
213
+ -> State: CONNECTED
214
+ -> Client calls authenticate(token)
215
+ -> Server validates token
216
+ -> State: AUTHENTICATED
217
+ -> Client can send/receive messages
218
+ -> Connection lost
219
+ -> State: RECONNECTING (exponential backoff)
220
+ -> Reconnected -> State: CONNECTED
221
+ -> Client disconnects
222
+ -> State: DISCONNECTED
223
+ ```
224
+
225
+ ## Scripts
226
+
227
+ ```bash
228
+ npm run dev # Watch mode
229
+ npm run build # Production build
230
+ npm run clean # Remove dist/
231
+ ```
232
+
233
+ ## Documentation
234
+
235
+ See [Documentation.md](Documentation.md) for the full API reference.
236
+
237
+ ## License
238
+
239
+ MIT
@@ -0,0 +1,129 @@
1
+ import { ClientConfig } from 'sockr-shared';
2
+ export * from 'sockr-shared';
3
+ import React$1 from 'react';
4
+
5
+ declare enum ConnectionState {
6
+ DISCONNECTED = "disconnected",
7
+ CONNECTING = "connecting",
8
+ CONNECTED = "connected",
9
+ AUTHENTICATED = "authenticated",
10
+ ERROR = "error",
11
+ RECONNECTING = "reconnecting"
12
+ }
13
+ declare class ConnectionManager {
14
+ private state;
15
+ private listeners;
16
+ private reconnectAttempts;
17
+ private maxReconnectAttempts;
18
+ constructor(maxReconnectAttempts?: number);
19
+ getState(): ConnectionState;
20
+ setState(state: ConnectionState): void;
21
+ isConnected(): boolean;
22
+ isAuthenticated(): boolean;
23
+ onStateChange(listener: (state: ConnectionState) => void): () => void;
24
+ private notifyListeners;
25
+ incrementReconnectAttempts(): number;
26
+ resetReconnectAttempts(): void;
27
+ getReconnectAttempts(): number;
28
+ canReconnect(): boolean;
29
+ reset(): void;
30
+ }
31
+
32
+ declare class SocketClient {
33
+ private socket;
34
+ private config;
35
+ private eventEmitter;
36
+ private connectionManager;
37
+ private userId;
38
+ private reconnectTimer;
39
+ constructor(config: ClientConfig);
40
+ connect(): void;
41
+ private setupSocketListeners;
42
+ private shouldReconnect;
43
+ private scheduleReconnect;
44
+ authenticate(token: string): void;
45
+ sendMessage(to: string, content: string, metadata?: Record<string, any>): void;
46
+ getOnlineStatus(userIds: string[]): void;
47
+ startTyping(to: string): void;
48
+ stopTyping(to: string): void;
49
+ on(event: string, handler: (...args: any[]) => void): () => void;
50
+ off(event: string, handler: (...args: any[]) => void): void;
51
+ disconnect(): void;
52
+ isConnected(): boolean;
53
+ isAuthenticated(): boolean;
54
+ getConnectionState(): ConnectionState;
55
+ getUserId(): string | null;
56
+ onStateChange(listener: (state: ConnectionState) => void): () => void;
57
+ }
58
+
59
+ type EventHandler = (...args: any[]) => void;
60
+ declare class EventEmitter {
61
+ private events;
62
+ on(event: string, handler: EventHandler): () => void;
63
+ off(event: string, handler: EventHandler): void;
64
+ emit(event: string, ...args: any[]): void;
65
+ removeAllListeners(event?: string): void;
66
+ }
67
+
68
+ interface SocketContextValue {
69
+ client: SocketClient | null;
70
+ isConnected: boolean;
71
+ isAuthenticated: boolean;
72
+ connectionState: ConnectionState;
73
+ userId: string | null;
74
+ }
75
+ interface SocketProviderProps {
76
+ config: ClientConfig;
77
+ token?: string;
78
+ children: React$1.ReactNode;
79
+ }
80
+ declare const SocketProvider: React$1.FC<SocketProviderProps>;
81
+ declare const useSocketContext: () => SocketContextValue;
82
+
83
+ interface UseSocketReturn {
84
+ client: SocketClient | null;
85
+ isConnected: boolean;
86
+ isAuthenticated: boolean;
87
+ connectionState: ConnectionState;
88
+ userId: string | null;
89
+ }
90
+ declare const useSocket: () => UseSocketReturn;
91
+
92
+ declare const useSocketEvent: (event: string, handler: (...args: any[]) => void, deps?: React.DependencyList) => void;
93
+
94
+ interface Message {
95
+ id: string;
96
+ from: string;
97
+ content: string;
98
+ timestamp: number;
99
+ metadata?: Record<string, any>;
100
+ }
101
+ interface UseMessagesReturn {
102
+ messages: Message[];
103
+ addMessage: (message: Message) => void;
104
+ clearMessages: () => void;
105
+ }
106
+ declare const useMessages: () => UseMessagesReturn;
107
+
108
+ interface UseSendMessageReturn {
109
+ sendMessage: (to: string, content: string, metadata?: Record<string, any>) => void;
110
+ isSending: boolean;
111
+ error: string | null;
112
+ }
113
+ declare const useSendMessage: () => UseSendMessageReturn;
114
+
115
+ interface UsePresenceReturn {
116
+ onlineUsers: Set<string>;
117
+ isUserOnline: (userId: string) => boolean;
118
+ checkOnlineStatus: (userIds: string[]) => void;
119
+ }
120
+ declare const usePresence: () => UsePresenceReturn;
121
+
122
+ interface UseTypingIndicatorReturn {
123
+ startTyping: (to: string) => void;
124
+ stopTyping: (to: string) => void;
125
+ usersTyping: Set<string>;
126
+ }
127
+ declare const useTypingIndicator: (typingTimeout?: number) => UseTypingIndicatorReturn;
128
+
129
+ export { ConnectionManager, ConnectionState, EventEmitter, SocketClient, SocketProvider, useMessages, usePresence, useSendMessage, useSocket, useSocketContext, useSocketEvent, useTypingIndicator };
@@ -0,0 +1,129 @@
1
+ import { ClientConfig } from 'sockr-shared';
2
+ export * from 'sockr-shared';
3
+ import React$1 from 'react';
4
+
5
+ declare enum ConnectionState {
6
+ DISCONNECTED = "disconnected",
7
+ CONNECTING = "connecting",
8
+ CONNECTED = "connected",
9
+ AUTHENTICATED = "authenticated",
10
+ ERROR = "error",
11
+ RECONNECTING = "reconnecting"
12
+ }
13
+ declare class ConnectionManager {
14
+ private state;
15
+ private listeners;
16
+ private reconnectAttempts;
17
+ private maxReconnectAttempts;
18
+ constructor(maxReconnectAttempts?: number);
19
+ getState(): ConnectionState;
20
+ setState(state: ConnectionState): void;
21
+ isConnected(): boolean;
22
+ isAuthenticated(): boolean;
23
+ onStateChange(listener: (state: ConnectionState) => void): () => void;
24
+ private notifyListeners;
25
+ incrementReconnectAttempts(): number;
26
+ resetReconnectAttempts(): void;
27
+ getReconnectAttempts(): number;
28
+ canReconnect(): boolean;
29
+ reset(): void;
30
+ }
31
+
32
+ declare class SocketClient {
33
+ private socket;
34
+ private config;
35
+ private eventEmitter;
36
+ private connectionManager;
37
+ private userId;
38
+ private reconnectTimer;
39
+ constructor(config: ClientConfig);
40
+ connect(): void;
41
+ private setupSocketListeners;
42
+ private shouldReconnect;
43
+ private scheduleReconnect;
44
+ authenticate(token: string): void;
45
+ sendMessage(to: string, content: string, metadata?: Record<string, any>): void;
46
+ getOnlineStatus(userIds: string[]): void;
47
+ startTyping(to: string): void;
48
+ stopTyping(to: string): void;
49
+ on(event: string, handler: (...args: any[]) => void): () => void;
50
+ off(event: string, handler: (...args: any[]) => void): void;
51
+ disconnect(): void;
52
+ isConnected(): boolean;
53
+ isAuthenticated(): boolean;
54
+ getConnectionState(): ConnectionState;
55
+ getUserId(): string | null;
56
+ onStateChange(listener: (state: ConnectionState) => void): () => void;
57
+ }
58
+
59
+ type EventHandler = (...args: any[]) => void;
60
+ declare class EventEmitter {
61
+ private events;
62
+ on(event: string, handler: EventHandler): () => void;
63
+ off(event: string, handler: EventHandler): void;
64
+ emit(event: string, ...args: any[]): void;
65
+ removeAllListeners(event?: string): void;
66
+ }
67
+
68
+ interface SocketContextValue {
69
+ client: SocketClient | null;
70
+ isConnected: boolean;
71
+ isAuthenticated: boolean;
72
+ connectionState: ConnectionState;
73
+ userId: string | null;
74
+ }
75
+ interface SocketProviderProps {
76
+ config: ClientConfig;
77
+ token?: string;
78
+ children: React$1.ReactNode;
79
+ }
80
+ declare const SocketProvider: React$1.FC<SocketProviderProps>;
81
+ declare const useSocketContext: () => SocketContextValue;
82
+
83
+ interface UseSocketReturn {
84
+ client: SocketClient | null;
85
+ isConnected: boolean;
86
+ isAuthenticated: boolean;
87
+ connectionState: ConnectionState;
88
+ userId: string | null;
89
+ }
90
+ declare const useSocket: () => UseSocketReturn;
91
+
92
+ declare const useSocketEvent: (event: string, handler: (...args: any[]) => void, deps?: React.DependencyList) => void;
93
+
94
+ interface Message {
95
+ id: string;
96
+ from: string;
97
+ content: string;
98
+ timestamp: number;
99
+ metadata?: Record<string, any>;
100
+ }
101
+ interface UseMessagesReturn {
102
+ messages: Message[];
103
+ addMessage: (message: Message) => void;
104
+ clearMessages: () => void;
105
+ }
106
+ declare const useMessages: () => UseMessagesReturn;
107
+
108
+ interface UseSendMessageReturn {
109
+ sendMessage: (to: string, content: string, metadata?: Record<string, any>) => void;
110
+ isSending: boolean;
111
+ error: string | null;
112
+ }
113
+ declare const useSendMessage: () => UseSendMessageReturn;
114
+
115
+ interface UsePresenceReturn {
116
+ onlineUsers: Set<string>;
117
+ isUserOnline: (userId: string) => boolean;
118
+ checkOnlineStatus: (userIds: string[]) => void;
119
+ }
120
+ declare const usePresence: () => UsePresenceReturn;
121
+
122
+ interface UseTypingIndicatorReturn {
123
+ startTyping: (to: string) => void;
124
+ stopTyping: (to: string) => void;
125
+ usersTyping: Set<string>;
126
+ }
127
+ declare const useTypingIndicator: (typingTimeout?: number) => UseTypingIndicatorReturn;
128
+
129
+ export { ConnectionManager, ConnectionState, EventEmitter, SocketClient, SocketProvider, useMessages, usePresence, useSendMessage, useSocket, useSocketContext, useSocketEvent, useTypingIndicator };