@maxtroost/use-websocket 1.0.0 → 1.1.1

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 CHANGED
@@ -1,238 +1,179 @@
1
- # @max-troost-io/use-websocket
1
+ # @maxtroost/use-websocket
2
2
 
3
3
  A robust WebSocket connection management package for React applications with automatic reconnection, heartbeat monitoring, URI-based message routing, and React integration via TanStack Store.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install @max-troost-io/use-websocket
8
+ npm install @maxtroost/use-websocket
9
9
  ```
10
10
 
11
- ## 📚 Navigation
11
+ **Peer dependencies:** React 18+, React DOM 18+
12
12
 
13
- ### Internal Sections
13
+ ### Message Format
14
14
 
15
- - [Features & Purpose](#-features--purpose)
16
- - [Code Structure](#-code-structure)
17
- - [Data Flow & Architecture](#-data-flow--architecture)
18
- - [Key Behaviors](#-key-behaviors)
19
- - [Usage & Integration](#-usage--integration)
20
- - [Testing Strategy](#-testing-strategy)
21
- - [Troubleshooting & Debugging](#-troubleshooting--debugging)
22
- - [Dependencies](#-dependencies)
15
+ All outgoing WebSocket messages share the same structure and are sent as JSON:
23
16
 
24
- ---
25
-
26
- ## 🎯 Features & Purpose
17
+ ```json
18
+ {
19
+ "method": "subscribe" | "unsubscribe" | "post",
20
+ "uri": "/path/to/endpoint",
21
+ "body": { ... }
22
+ }
23
+ ```
27
24
 
28
- This package provides a comprehensive WebSocket solution for React applications that require real-time data streaming and request/response messaging over a single connection.
25
+ | Field | Required | Description |
26
+ | ------- | -------- | --------------------------------------------------------------------------- |
27
+ | `method`| Optional | HTTP-like method: `subscribe`, `unsubscribe`, or `post` (default for custom messages) |
28
+ | `uri` | Yes | Path for routing; the server uses this to dispatch to the correct handler |
29
+ | `body` | Optional | Payload sent with the message |
29
30
 
30
- ### Problems Solved
31
+ **Examples:**
31
32
 
32
- - **Duplicate connections**: Prevents multiple WebSocket connections to the same URL
33
- - **Stale connections**: Detects and recovers from silent connection failures via heartbeat
34
- - **Reconnection complexity**: Handles reconnection with exponential backoff and browser online/offline detection
35
- - **Subscription sharing**: Multiple components can share the same subscription via a unique key
36
- - **Auth-aware URLs**: WebSocket URLs are built from the current auth context (region, role, user)
33
+ - **Subscribe** (streaming): `{ "method": "subscribe", "uri": "/notifications", "body": { "status": "active" } }`
34
+ - **Unsubscribe**: `{ "method": "unsubscribe", "uri": "/notifications" }`
35
+ - **Request/response** (e.g. validate, mark read): `{ "method": "post", "uri": "/voyages/modify/validate", "body": { ... } }`
37
36
 
38
- ### Key Features
37
+ You can add extra fields (e.g. auth headers) via `transformMessagePayload` in `WebsocketClient`.
39
38
 
40
- | Feature | Description |
41
- | ---------------------------- | -------------------------------------------------------------------------------------------------------- |
42
- | **Singleton Connection** | One connection per URL shared across all hooks |
43
- | **Key-Based API Management** | Subscription and Message APIs identified by unique keys; components with the same key share the instance |
44
- | **Automatic Reconnection** | Three-phase exponential backoff (4s → 30s → 90s) |
45
- | **Heartbeat Monitoring** | Ping/pong every 40 seconds to detect stale connections |
46
- | **URI-Based Routing** | Multiple subscriptions over a single connection |
47
- | **React Integration** | TanStack Store for reactive data updates |
48
- | **Online/Offline Detection** | Browser connectivity change handling |
49
- | **Two API Types** | **Subscription** for streaming data; **Message** for request/response commands |
39
+ ### Subscription vs Message
50
40
 
51
- ### Target Users
41
+ The package offers two patterns for different use cases:
52
42
 
53
- - **Developers** integrating real-time data (voyages, rotations, notifications) into React apps
54
- - **Applications** using `@mono-fleet/iam-provider` for region-based authentication
43
+ | | **Subscription** (`useWebsocketSubscription`) | **Message** (`useWebsocketMessage`) |
44
+ | --- | --- | --- |
45
+ | **Pattern** | Streaming — subscribe once, receive ongoing updates | Request/response — send a message, get one reply (or none) |
46
+ | **Use case** | Live data feeds (notifications, voyage list, real-time dashboards) | One-off commands (validate, modify, mark read) |
47
+ | **URI** | Fixed per hook — one URI per subscription | Any URI — send to different endpoints per call |
48
+ | **State** | TanStack Store — reactive `message`, `pendingSubscription`, `connected` | No store — returns a Promise or fire-and-forget |
49
+ | **Lifecycle** | Auto-subscribes when connection opens; unsubscribes when last component unmounts | No subscription — just send when needed |
55
50
 
56
51
  ---
57
52
 
58
- ## 🏗️ Code Structure
53
+ ## Basic Setup
59
54
 
60
- ```
61
- packages/use-websocket/
62
- ├── src/
63
- │ ├── index.ts # Public exports
64
- │ └── lib/
65
- │ ├── WebsocketHook.ts # React hooks (useWebsocketSubscription, useWebsocketMessage, useWebsocketSubscriptionByKey)
66
- │ ├── WebsocketConnection.ts # Connection lifecycle, reconnection, heartbeat
67
- │ ├── WebsocketSubscriptionApi.ts # Streaming subscription per URI
68
- │ ├── WebsocketMessageApi.ts # Request/response messaging (no subscription)
69
- │ ├── websocketStores.ts # Global TanStack stores (connections, listeners)
70
- │ ├── websocketStores.helpers.ts # findOrCreateWebsocketConnection, createWebsocketSubscriptionApi, etc.
71
- │ ├── types.ts # Types, options, store shapes
72
- │ ├── constants.ts # Timing, close codes, defaults
73
- │ ├── WebsocketConnection.helpers.ts # Reconnection, ping, notifications
74
- │ └── WEBSOCKET_CONNECTION.md # Detailed architecture and flows
75
- ├── README.md
76
- ├── CHART.md # Mermaid flow diagrams
77
- └── package.json
78
- ```
55
+ 1. Create a `WebsocketClient` and wrap your app with `WebsocketClientProvider`:
79
56
 
80
- ### Component Hierarchy
81
-
82
- ```mermaid
83
- graph TB
84
- subgraph "React Layer"
85
- Hook[useWebsocketSubscription / useWebsocketMessage]
86
- ByKey[useWebsocketSubscriptionByKey]
87
- Component[React Components]
88
- end
89
-
90
- subgraph "Connection Layer"
91
- Connection[WebsocketConnection<br/>Singleton per URL]
92
- SubApi[WebsocketSubscriptionApi<br/>One per key]
93
- MsgApi[WebsocketMessageApi<br/>One per key]
94
- end
95
-
96
- subgraph "WebSocket API"
97
- Socket[WebSocket]
98
- end
99
-
100
- Component -->|uses| Hook
101
- Component -->|uses| ByKey
102
- Hook -->|manages| Connection
103
- Hook -->|creates| SubApi
104
- Hook -->|creates| MsgApi
105
- Connection -->|manages| Socket
106
- Connection -->|routes messages to| SubApi
107
- Connection -->|routes messages to| MsgApi
108
- SubApi -->|TanStack Store| Component
109
- ```
57
+ ```tsx
58
+ import { WebsocketClient, WebsocketClientProvider } from "@maxtroost/use-websocket";
110
59
 
111
- ---
60
+ const websocketClient = new WebsocketClient({
61
+ maxRetryAttempts: 20,
62
+ // Optional: customize heartbeat, timeouts, logging, etc.
63
+ });
112
64
 
113
- ## 🔄 Data Flow & Architecture
114
-
115
- ### Choosing the Right Hook
116
-
117
- | Hook | Use Case |
118
- | ------------------------------- | ----------------------------------------------------------------- |
119
- | `useWebsocketSubscription` | Streaming data (voyage list, notifications, live updates) |
120
- | `useWebsocketMessage` | One-off commands (validate, modify, mark read) — request/response |
121
- | `useWebsocketSubscriptionByKey` | Child component needs parent's subscription data |
122
-
123
- ### Message Flow: Subscription
124
-
125
- ```mermaid
126
- sequenceDiagram
127
- participant Component
128
- participant Hook as useWebsocketSubscription
129
- participant Connection as WebsocketConnection
130
- participant SubApi as WebsocketSubscriptionApi
131
- participant Socket as WebSocket
132
- participant Server
133
-
134
- Component->>Hook: useWebsocketSubscription(options)
135
- Hook->>Connection: findOrCreateWebsocketConnection(url)
136
- Hook->>Connection: addListener(SubApi)
137
- Connection->>Socket: new WebSocket(url)
138
-
139
- Socket-->>Connection: open event
140
- Connection->>SubApi: onOpen()
141
- SubApi->>Socket: subscribe message
142
- Socket->>Server: subscribe
143
-
144
- Server-->>Socket: message (uri, body)
145
- Socket-->>Connection: message event
146
- Connection->>Connection: Route by URI
147
- Connection->>SubApi: onMessage(body)
148
- SubApi->>SubApi: Update TanStack Store
149
- SubApi-->>Component: Store update triggers re-render
65
+ function App() {
66
+ return (
67
+ <WebsocketClientProvider client={websocketClient}>
68
+ <YourApp />
69
+ </WebsocketClientProvider>
70
+ );
71
+ }
150
72
  ```
151
73
 
152
- ### Message Flow: Request/Response (useWebsocketMessage)
153
-
154
- ```mermaid
155
- sequenceDiagram
156
- participant Component
157
- participant MsgApi as WebsocketMessageApi
158
- participant Connection as WebsocketConnection
159
- participant Socket as WebSocket
160
- participant Server
161
-
162
- Component->>MsgApi: sendMessage(uri, method, body?)
163
- MsgApi->>Socket: Message with correlation ID
164
- Socket->>Server: message
165
-
166
- Server-->>Socket: response (same correlation)
167
- Socket-->>Connection: message event
168
- Connection->>MsgApi: deliverMessage(uri, data)
169
- MsgApi->>MsgApi: resolve Promise
170
- MsgApi-->>Component: await result
171
- ```
74
+ 2. Use the hooks in your components:
172
75
 
173
- ---
76
+ ```tsx
77
+ import { useWebsocketSubscription } from "@maxtroost/use-websocket";
78
+ import { useStore } from "@tanstack/react-store";
174
79
 
175
- ## ⚙️ Key Behaviors
80
+ function LiveNotifications() {
81
+ const api = useWebsocketSubscription<Notification[]>({
82
+ key: "notifications",
83
+ url: "wss://api.example.com/ws",
84
+ uri: "/notifications",
85
+ });
176
86
 
177
- ### Subscription Behavior
87
+ const notifications = useStore(api.store, (s) => s.message);
88
+ const loading = useStore(api.store, (s) => s.pendingSubscription);
89
+
90
+ if (loading) return <div>Connecting...</div>;
91
+ return (
92
+ <ul>
93
+ {notifications?.map((n) => (
94
+ <li key={n.id}>{n.text}</li>
95
+ ))}
96
+ </ul>
97
+ );
98
+ }
99
+ ```
178
100
 
179
- Subscriptions automatically subscribe when the WebSocket connection opens.
101
+ ---
180
102
 
181
- ### Store Shape (WebsocketSubscriptionStore)
103
+ ## Features
182
104
 
183
- ```typescript
184
- interface WebsocketSubscriptionStore<TData> {
185
- message: TData | undefined; // Latest data from server
186
- subscribed: boolean; // Subscription confirmed
187
- pendingSubscription: boolean; // Subscribe sent, waiting for first response (for loading UI)
188
- subscribedAt: number | undefined;
189
- receivedAt: number | undefined;
190
- connected: boolean; // WebSocket open
191
- messageError: WebsocketTransportError | undefined;
192
- serverError: WebsocketServerError<unknown> | undefined;
193
- }
194
- ```
105
+ - **Automatic reconnection** — Exponential backoff (4s → 30s → 90s) with configurable max attempts
106
+ - **Heartbeat monitoring** — Ping/pong to detect stale connections
107
+ - **URI-based routing** — Messages routed by URI; one connection per URL shared across subscriptions
108
+ - **TanStack Store integration** — Reactive state for subscriptions; components re-render on updates
109
+ - **Two patterns** `useWebsocketSubscription` for streaming data, `useWebsocketMessage` for request/response
110
+ - **Shared stores** — Child components access parent subscriptions via `useWebsocketSubscriptionByKey`
111
+ - **Conditional subscriptions** — `enabled` option to pause when unauthenticated or feature-flagged off
112
+ - **Lifecycle callbacks** `onSubscribe`, `onMessage`, `onError`, `onClose` for logging and side effects
113
+ - **Connection events** — `connectionEvent` callback for reconnection status, logging, or custom notifications
195
114
 
196
- ### Reconnection Backoff
115
+ ---
197
116
 
198
- | Attempt Range | Wait Time |
199
- | ------------- | ---------- |
200
- | 0–4 attempts | 4 seconds |
201
- | 5–9 attempts | 30 seconds |
202
- | 10+ attempts | 90 seconds |
117
+ ## API Reference
203
118
 
204
- User notifications are shown after 10 failed attempts. Reconnection stops after 20 attempts (~18 minutes); users can retry manually via the notification action.
119
+ | Export | Description |
120
+ | ------ | ----------- |
121
+ | `useWebsocketSubscription` | Subscribe to a URI and receive streaming data via a reactive store |
122
+ | `useWebsocketSubscriptionByKey` | Access the store of a subscription created elsewhere (by key) |
123
+ | `useWebsocketMessage` | Send request/response messages to any URI |
124
+ | `WebsocketClient` | Client configuration; instantiate and pass to `WebsocketClientProvider`; `reconnectAllConnections()` for manual retry |
125
+ | `WebsocketClientProvider` | Context provider; wrap your app to enable hooks |
126
+ | `WebsocketConnection` | Low-level connection class; `setCustomLogger` for debugging |
127
+ | `ReadyState`, `WebsocketSubscriptionStore`, `WebsocketTransportError`, `WebsocketServerError` | Types |
205
128
 
206
129
  ---
207
130
 
208
- ## 🔧 Usage & Integration
131
+ ## Examples
209
132
 
210
133
  ### Subscription (Streaming Data)
211
134
 
212
- ```typescript
213
- import { useWebsocketSubscription } from "@max-troost-io/use-websocket";
135
+ Subscribe to a URI and receive streaming data via a reactive TanStack Store.
136
+
137
+ ```tsx
138
+ import { useWebsocketSubscription } from "@maxtroost/use-websocket";
214
139
  import { useStore } from "@tanstack/react-store";
215
140
 
141
+ interface Voyage {
142
+ id: string;
143
+ name: string;
144
+ status: string;
145
+ }
146
+
216
147
  function VoyageList() {
217
- const voyageApi = useWebsocketSubscription<Voyage[], VoyageFilters>({
148
+ const voyageApi = useWebsocketSubscription<Voyage[], { status: string }>({
218
149
  key: "voyages-list",
219
- url: "/api",
150
+ url: "wss://api.example.com/ws",
220
151
  uri: "/api/voyages",
221
152
  body: { status: "active" },
222
153
  });
223
154
 
224
155
  const voyages = useStore(voyageApi.store, (s) => s.message);
225
156
  const pending = useStore(voyageApi.store, (s) => s.pendingSubscription);
157
+ const connected = useStore(voyageApi.store, (s) => s.connected);
226
158
 
227
159
  if (pending) return <Skeleton />;
228
- return <div>{/* Render voyages */}</div>;
160
+ return (
161
+ <div>
162
+ {!connected && <span>Reconnecting...</span>}
163
+ {voyages?.map((v) => (
164
+ <div key={v.id}>{v.name}</div>
165
+ ))}
166
+ </div>
167
+ );
229
168
  }
230
169
  ```
231
170
 
232
171
  ### Access Store by Key (Child Components)
233
172
 
234
- ```typescript
235
- import { useWebsocketSubscriptionByKey } from "@max-troost-io/use-websocket";
173
+ When a parent creates the subscription, children can access the same store by key.
174
+
175
+ ```tsx
176
+ import { useWebsocketSubscriptionByKey } from "@maxtroost/use-websocket";
236
177
  import { useStore } from "@tanstack/react-store";
237
178
 
238
179
  function VoyageCount() {
@@ -244,13 +185,15 @@ function VoyageCount() {
244
185
 
245
186
  ### Message API (Request/Response)
246
187
 
247
- ```typescript
248
- import { useWebsocketMessage } from "@max-troost-io/use-websocket";
188
+ For one-off commands (validate, modify, mark read) — send a message and optionally await a response.
189
+
190
+ ```tsx
191
+ import { useWebsocketMessage } from "@maxtroost/use-websocket";
249
192
 
250
193
  function VoyageActions() {
251
- const api = useWebsocketMessage<ModifyVoyageUim, ModifyVoyageUim>({
194
+ const api = useWebsocketMessage<ValidationResult, FormValues>({
252
195
  key: "voyages/modify",
253
- url: "/api",
196
+ url: "wss://api.example.com/ws",
254
197
  responseTimeoutMs: 5000,
255
198
  });
256
199
 
@@ -260,91 +203,135 @@ function VoyageActions() {
260
203
  "post",
261
204
  formValues
262
205
  );
263
- // ...
206
+ if (result.valid) {
207
+ // proceed
208
+ }
264
209
  };
265
210
 
266
211
  const handleMarkRead = () => {
267
212
  api.sendMessageNoWait(`notifications/${id}/read`, "post");
268
213
  };
214
+
215
+ return (
216
+ <>
217
+ <button onClick={handleValidate}>Validate</button>
218
+ <button onClick={handleMarkRead}>Mark Read</button>
219
+ </>
220
+ );
269
221
  }
270
222
  ```
271
223
 
272
- ### Options Reference
224
+ ### Conditional Subscription
273
225
 
274
- #### WebsocketSubscriptionOptions
226
+ Disable the subscription when the user is not authenticated or when a feature flag is off.
275
227
 
276
- | Option | Type | Description |
277
- | ------------------------------------------------------------------ | --------- | ---------------------------------------------------------------------- |
278
- | `key` | `string` | Unique identifier; components with same key share the API |
279
- | `url` | `string` | Base WebSocket path (full URL; apps typically build from auth context) |
280
- | `uri` | `string` | URI endpoint for this subscription |
281
- | `body` | `TBody` | Optional payload for subscription |
282
- | `enabled` | `boolean` | When `false`, disconnects (default: `true`) |
283
- | `onMessage`, `onSubscribe`, `onError`, `onMessageError`, `onClose` | callbacks | Lifecycle callbacks |
284
-
285
- #### WebsocketMessageOptions
286
-
287
- | Option | Type | Description |
288
- | ------------------- | --------- | -------------------------------------------------- |
289
- | `key` | `string` | Unique identifier |
290
- | `url` | `string` | Base WebSocket path |
291
- | `enabled` | `boolean` | When `false`, disconnects |
292
- | `responseTimeoutMs` | `number` | Default timeout for `sendMessage` (default: 10000) |
228
+ ```tsx
229
+ function VoyageList({ isAuthenticated }: { isAuthenticated: boolean }) {
230
+ const api = useWebsocketSubscription<Voyage[]>({
231
+ key: "voyages-list",
232
+ url: "wss://api.example.com/ws",
233
+ uri: "/api/voyages",
234
+ enabled: isAuthenticated,
235
+ });
236
+ // ...
237
+ }
238
+ ```
293
239
 
294
240
  ---
295
241
 
296
- ## 🐛 Troubleshooting & Debugging
297
-
298
- ### Common Issues
242
+ ## Advanced Examples
243
+
244
+ ### Custom WebsocketClient Configuration
245
+
246
+ ```tsx
247
+ const websocketClient = new WebsocketClient({
248
+ maxRetryAttempts: 10,
249
+ notificationThreshold: 5,
250
+ messageResponseTimeoutMs: 5000,
251
+ heartbeat: { enabled: true, intervalMs: 30000 },
252
+ connectionEvent: (event) => {
253
+ if (event.type === "reconnecting") {
254
+ analytics.track("websocket_reconnecting", { url: event.url });
255
+ }
256
+ },
257
+ });
258
+ ```
299
259
 
300
- #### Subscription Never Receives Data
260
+ ### Auth Token in WebSocket URL
301
261
 
302
- - **Symptoms**: `message` stays `undefined`, `pendingSubscription` remains `true`
303
- - **Possible causes**: Wrong `uri`, server not sending to that URI, connection not open
304
- - **Debugging**: Check `connected` in store; verify server logs for incoming subscribe; ensure `useWebsocketConnectionConfig` and `useReconnectWebsocketConnections` are called at app root inside auth provider
305
- - **Solution**: Confirm `uri` matches server route; check network tab for WebSocket frames
262
+ When the WebSocket URL includes an auth token, pass the full URL to the hook. When the token changes, the hook automatically calls `replaceUrl` to reconnect with the new URL.
306
263
 
307
- #### Connection Drops Repeatedly
264
+ ```tsx
265
+ function VoyageList() {
266
+ const { token } = useAuth();
267
+ const wsUrl = token ? `wss://api.example.com/ws?token=${token}` : null;
308
268
 
309
- - **Symptoms**: Frequent reconnects, notifications after 10 attempts
310
- - **Possible causes**: Auth token expiry, CORS, wrong URL, server rejecting connection
311
- - **Debugging**: `WebsocketConnection.setCustomLogger` to log events; check `connectionFailed` callback (token refresh triggered after 5 retries)
312
- - **Solution**: Pass WebSocket secret via `useWebsocketConnectionConfig` for local dev; verify auth context provides valid region/role for URL construction
269
+ const api = useWebsocketSubscription<Voyage[]>({
270
+ key: "voyages",
271
+ url: wsUrl ?? "", // Hook handles URL changes via replaceUrl
272
+ uri: "/api/voyages",
273
+ enabled: !!token,
274
+ });
275
+ // ...
276
+ }
277
+ ```
313
278
 
314
- #### Child Component Gets Empty Store
279
+ To manually retry after reconnection stops (e.g. user clicks "Retry"): `websocketClient.reconnectAllConnections()`.
315
280
 
316
- - **Symptoms**: `useWebsocketSubscriptionByKey` returns fallback store with `message: undefined`
317
- - **Possible causes**: Parent with `useWebsocketSubscription` not mounted yet; different `key` used
318
- - **Debugging**: Ensure parent mounts first; verify `key` string matches exactly
319
- - **Solution**: Use same `key` in parent and child; consider lifting subscription higher in tree
281
+ ### Transform Outgoing Messages (e.g. Add Auth Header)
320
282
 
321
- ### Debugging Tools
283
+ ```tsx
284
+ const websocketClient = new WebsocketClient({
285
+ transformMessagePayload: (payload) => ({
286
+ ...payload,
287
+ headers: {
288
+ ...payload.headers,
289
+ Authorization: `Bearer ${getAuthToken()}`,
290
+ },
291
+ }),
292
+ });
293
+ ```
322
294
 
323
- - **Browser DevTools**: Network tab → WS filter for WebSocket frames
324
- - **Debugging**: `WebsocketConnection.setCustomLogger` to log events; check `connectionFailed` callback (token refresh triggered after 5 retries)
325
- - **Store inspection**: `useStore(api.store)` to read full state
295
+ ### Lifecycle Callbacks
296
+
297
+ ```tsx
298
+ const api = useWebsocketSubscription<Voyage[]>({
299
+ key: "voyages",
300
+ url: "wss://api.example.com/ws",
301
+ uri: "/api/voyages",
302
+ onSubscribe: ({ uri }) => console.log("Subscribed to", uri),
303
+ onMessage: ({ data }) => console.log("Received", data),
304
+ onError: (error) => {
305
+ if (error.type === "transport")
306
+ console.error("Connection error", error.event);
307
+ },
308
+ onMessageError: (error) => {
309
+ if (error.type === "server")
310
+ console.error("Server error", error.message);
311
+ },
312
+ onClose: (event) => console.log("Connection closed", event.code),
313
+ });
314
+ ```
326
315
 
327
- ### Error Types
316
+ ### Per-Call Timeout Override
328
317
 
329
- - **WebsocketTransportError**: Connection failure, network issues (`error.type === 'transport'`)
330
- - **WebsocketServerError**: Server-sent error message (`error.type === 'server'`, body in `error.message`)
318
+ ```tsx
319
+ const result = await api.sendMessage("/api/command", "post", body, {
320
+ timeout: 3000,
321
+ });
322
+ ```
331
323
 
332
324
  ---
333
325
 
334
- ## 📦 Dependencies
326
+ ## Documentation
327
+
328
+ For contributors and deeper architecture details:
335
329
 
336
- | Dependency | Purpose |
337
- | ----------------------- | ---------------------------------------- |
338
- | `@tanstack/react-store` | Reactive state for components |
339
- | `@tanstack/store` | Core store implementation |
340
- | `notistack` | User notifications (reconnection errors) |
341
- | `uuid` | Correlation IDs |
342
- | `fast-equals` | Deep equality for options |
343
- | `usehooks-ts` | `useIsomorphicLayoutEffect` |
330
+ - **[WEBSOCKET_CONNECTION.md](https://github.com/max-troost-io/mt-use-websockets/blob/main/src/lib/WEBSOCKET_CONNECTION.md)** — Connection lifecycle, class diagrams, URI API lifecycle, browser online/offline handling, full API reference
331
+ - **[CHART.md](https://github.com/max-troost-io/mt-use-websockets/blob/main/src/lib/CHART.md)** Mermaid flow diagrams for hooks, connection, and error flows
344
332
 
345
333
  ---
346
334
 
347
- ## Learn More
335
+ ## License
348
336
 
349
- - **[WEBSOCKET_CONNECTION.md](src/lib/WEBSOCKET_CONNECTION.md)** — Detailed architecture, class diagrams, connection lifecycle, URI API lifecycle, browser online/offline handling, full API reference
350
- - **[CHART.md](CHART.md)** — Mermaid flow diagrams for hooks, connection, and error flows
337
+ MIT