sockress-client 0.1.5 → 0.1.6
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 +359 -61
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,61 +1,359 @@
|
|
|
1
|
-
# Sockress Client SDK
|
|
2
|
-
|
|
3
|
-
sockress-client is the companion SDK for Sockress-powered backends. It automatically prefers
|
|
4
|
-
|
|
5
|
-
Created by
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
1
|
+
# Sockress Client SDK
|
|
2
|
+
|
|
3
|
+
[`sockress-client`](https://www.npmjs.com/package/sockress-client) is the companion SDK for Sockress-powered backends. It automatically prefers the WebSocket transport (sharing the same request/response semantics as HTTP) and silently falls back to `fetch` when a socket is unavailable. Multipart uploads (`FormData`) are serialized over the wire, so you can use a single API surface for avatars, profile forms, and realtime commands.
|
|
4
|
+
|
|
5
|
+
**Created by [Also Coder](https://alsocoder.com) · GitHub [@alsocoders](https://github.com/alsocoders)**
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Socket-first requests with automatic HTTP fallback
|
|
12
|
+
- `FormData`, `Blob`, and JSON serialization handled automatically
|
|
13
|
+
- Familiar API: `api.request()`, `api.get()`, `api.post()`, `api.put()`, `api.patch()`, `api.delete()`
|
|
14
|
+
- Built-in event emitters for `open`, `close`, `error`, and `reconnect`
|
|
15
|
+
- Works in browsers and Node.js (inject custom `fetch` / `wsFactory`)
|
|
16
|
+
- Automatic cookie handling (browser only)
|
|
17
|
+
- Request queuing when socket is not yet connected
|
|
18
|
+
- Automatic reconnection with exponential backoff
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install sockress-client
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Sockress Client supports both ESM and CommonJS:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// ESM
|
|
32
|
+
import { sockressClient } from 'sockress-client';
|
|
33
|
+
|
|
34
|
+
// CommonJS
|
|
35
|
+
const { sockressClient } = require('sockress-client');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { sockressClient } from 'sockress-client';
|
|
44
|
+
|
|
45
|
+
const api = sockressClient({
|
|
46
|
+
baseUrl: 'http://localhost:5051',
|
|
47
|
+
autoConnect: true,
|
|
48
|
+
preferSocket: true
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// GET request
|
|
52
|
+
const users = await api.get('/api/users');
|
|
53
|
+
console.log(users.body);
|
|
54
|
+
|
|
55
|
+
// POST request
|
|
56
|
+
const response = await api.post('/api/auth/login', {
|
|
57
|
+
body: { email: 'user@example.com', password: 'secret' }
|
|
58
|
+
});
|
|
59
|
+
console.log(response.body.token);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## API Methods
|
|
65
|
+
|
|
66
|
+
### `api.request(options)`
|
|
67
|
+
|
|
68
|
+
Make a request with full control:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const response = await api.request({
|
|
72
|
+
path: '/api/users',
|
|
73
|
+
method: 'GET',
|
|
74
|
+
headers: { 'Authorization': 'Bearer token' },
|
|
75
|
+
query: { page: 1, limit: 10 },
|
|
76
|
+
body: { name: 'John' },
|
|
77
|
+
timeout: 5000,
|
|
78
|
+
signal: abortController.signal,
|
|
79
|
+
disableHttpFallback: false
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `api.get(path, options?)`
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const response = await api.get('/api/users', {
|
|
87
|
+
query: { page: 1 },
|
|
88
|
+
headers: { 'Authorization': 'Bearer token' }
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### `api.post(path, options?)`
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const response = await api.post('/api/users', {
|
|
96
|
+
body: { name: 'John', email: 'john@example.com' }
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `api.put(path, options?)`
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
const response = await api.put('/api/users/123', {
|
|
104
|
+
body: { name: 'Jane' }
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `api.patch(path, options?)`
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const response = await api.patch('/api/users/123', {
|
|
112
|
+
body: { email: 'jane@example.com' }
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### `api.delete(path, options?)`
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const response = await api.delete('/api/users/123');
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Response Object
|
|
125
|
+
|
|
126
|
+
All methods return a `SockressClientResponse`:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
interface SockressClientResponse<T> {
|
|
130
|
+
status: number; // HTTP status code
|
|
131
|
+
ok: boolean; // true if status is 200-299
|
|
132
|
+
headers: Record<string, string>; // response headers
|
|
133
|
+
body: T; // parsed response body
|
|
134
|
+
json: <R = T>() => R; // get body as JSON (type-safe)
|
|
135
|
+
text: () => string; // get body as string
|
|
136
|
+
raw: () => T; // get raw body
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const response = await api.get('/api/users');
|
|
144
|
+
console.log(response.status); // 200
|
|
145
|
+
console.log(response.ok); // true
|
|
146
|
+
console.log(response.body); // parsed JSON
|
|
147
|
+
console.log(response.json()); // same as body
|
|
148
|
+
console.log(response.text()); // JSON string
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## File Uploads
|
|
154
|
+
|
|
155
|
+
Upload files using `FormData`:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const formData = new FormData();
|
|
159
|
+
formData.append('avatar', file);
|
|
160
|
+
formData.append('name', 'John Doe');
|
|
161
|
+
|
|
162
|
+
const response = await api.post('/api/profile/avatar', {
|
|
163
|
+
body: formData,
|
|
164
|
+
headers: { 'Authorization': 'Bearer token' }
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
console.log(response.body.avatarUrl);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The client automatically serializes `FormData` for socket transport and uses native `FormData` for HTTP fallback.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Events
|
|
175
|
+
|
|
176
|
+
Listen to socket events:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
// Socket opened
|
|
180
|
+
api.on('open', () => {
|
|
181
|
+
console.log('Socket connected');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Socket closed
|
|
185
|
+
api.on('close', ({ code, reason }) => {
|
|
186
|
+
console.log('Socket closed', code, reason);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Error occurred
|
|
190
|
+
api.on('error', (error) => {
|
|
191
|
+
console.error('Socket error:', error);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Reconnection attempt
|
|
195
|
+
api.on('reconnect', ({ attempt }) => {
|
|
196
|
+
console.log('Reconnecting, attempt:', attempt);
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Remove listeners:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
const unsubscribe = api.on('open', () => {
|
|
204
|
+
console.log('Connected');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Later
|
|
208
|
+
api.off('open', handler);
|
|
209
|
+
// or
|
|
210
|
+
unsubscribe();
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Configuration
|
|
216
|
+
|
|
217
|
+
Create a client with custom options:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
const api = sockressClient({
|
|
221
|
+
baseUrl: 'http://localhost:5051', // required
|
|
222
|
+
socketPath: '/sockress', // WebSocket path (default: '/sockress')
|
|
223
|
+
headers: { 'X-Custom': 'value' }, // default headers
|
|
224
|
+
timeout: 15_000, // request timeout in ms (default: 15000)
|
|
225
|
+
reconnectInterval: 1_000, // initial reconnect delay (default: 1000)
|
|
226
|
+
maxReconnectInterval: 15_000, // max reconnect delay (default: 15000)
|
|
227
|
+
autoConnect: true, // auto-connect on creation (default: true)
|
|
228
|
+
preferSocket: true, // prefer socket over HTTP (default: true)
|
|
229
|
+
credentials: 'include', // fetch credentials (default: 'include')
|
|
230
|
+
fetchImpl: fetch, // custom fetch implementation
|
|
231
|
+
wsFactory: (url) => new WebSocket(url) // custom WebSocket factory
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Node.js Usage
|
|
238
|
+
|
|
239
|
+
In Node.js, you may need to provide custom implementations:
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import fetch from 'node-fetch';
|
|
243
|
+
import WebSocket from 'ws';
|
|
244
|
+
|
|
245
|
+
const api = sockressClient({
|
|
246
|
+
baseUrl: 'https://api.example.com',
|
|
247
|
+
fetchImpl: fetch as any,
|
|
248
|
+
wsFactory: (url) => new WebSocket(url) as any
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Manual Connection Management
|
|
255
|
+
|
|
256
|
+
Control socket connection manually:
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const api = sockressClient({
|
|
260
|
+
baseUrl: 'http://localhost:5051',
|
|
261
|
+
autoConnect: false // don't auto-connect
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// Connect manually
|
|
265
|
+
await api.connect();
|
|
266
|
+
|
|
267
|
+
// Close manually
|
|
268
|
+
api.close();
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The client automatically closes the socket on process exit (Node.js) or page unload (browser).
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## Request Options
|
|
276
|
+
|
|
277
|
+
### `path` (required)
|
|
278
|
+
Request path (e.g., `'/api/users'`)
|
|
279
|
+
|
|
280
|
+
### `method` (optional)
|
|
281
|
+
HTTP method: `'GET'`, `'POST'`, `'PUT'`, `'PATCH'`, `'DELETE'`, `'HEAD'`, `'OPTIONS'` (default: `'GET'`)
|
|
282
|
+
|
|
283
|
+
### `headers` (optional)
|
|
284
|
+
Request headers object
|
|
285
|
+
|
|
286
|
+
### `query` (optional)
|
|
287
|
+
Query parameters object (values can be strings, numbers, booleans, or arrays)
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
await api.get('/api/users', {
|
|
291
|
+
query: {
|
|
292
|
+
page: 1,
|
|
293
|
+
limit: 10,
|
|
294
|
+
tags: ['js', 'ts'],
|
|
295
|
+
active: true
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### `body` (optional)
|
|
301
|
+
Request body. Can be:
|
|
302
|
+
- Plain object (serialized as JSON)
|
|
303
|
+
- `FormData` (for file uploads)
|
|
304
|
+
- `Blob` or `ArrayBuffer`
|
|
305
|
+
- `URLSearchParams`
|
|
306
|
+
- String
|
|
307
|
+
|
|
308
|
+
### `timeout` (optional)
|
|
309
|
+
Request timeout in milliseconds (overrides default)
|
|
310
|
+
|
|
311
|
+
### `signal` (optional)
|
|
312
|
+
`AbortSignal` for canceling requests
|
|
313
|
+
|
|
314
|
+
### `disableHttpFallback` (optional)
|
|
315
|
+
If `true`, throws an error if socket is unavailable instead of falling back to HTTP (default: `false`)
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Error Handling
|
|
320
|
+
|
|
321
|
+
Handle errors with try/catch:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
try {
|
|
325
|
+
const response = await api.post('/api/users', {
|
|
326
|
+
body: { name: 'John' }
|
|
327
|
+
});
|
|
328
|
+
console.log(response.body);
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error('Request failed:', error);
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## TypeScript Support
|
|
337
|
+
|
|
338
|
+
Sockress Client is written in TypeScript and provides full type safety:
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
interface User {
|
|
342
|
+
id: number;
|
|
343
|
+
name: string;
|
|
344
|
+
email: string;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const response = await api.get<User[]>('/api/users');
|
|
348
|
+
const users: User[] = response.body;
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Links
|
|
354
|
+
|
|
355
|
+
- Website: [https://alsocoder.com](https://alsocoder.com)
|
|
356
|
+
- GitHub: [https://github.com/alsocoders/sockress](https://github.com/alsocoders/sockress)
|
|
357
|
+
- Issues: [https://github.com/alsocoders/sockress/issues](https://github.com/alsocoders/sockress/issues)
|
|
358
|
+
|
|
359
|
+
PRs and feedback welcome!
|
package/package.json
CHANGED