pushstream-client 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dishu Mavi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # pushstream-js
2
+
3
+ A lightweight, zero-dependency JavaScript client for consuming Server-Sent Events (SSE) with automatic reconnection, event subscriptions, and connection state management.
4
+
5
+ ## Features
6
+
7
+ - **Zero dependencies** - Pure JavaScript, no external libraries
8
+ - **Tiny footprint** - Less than 5KB minified
9
+ - **Auto-reconnection** - Exponential backoff with jitter to prevent thundering herd
10
+ - **Event-driven API** - Familiar `on()`/`off()` subscription pattern
11
+ - **JSON parsing** - Automatic payload parsing
12
+ - **Connection state** - Track connection status with built-in events
13
+ - **Universal** - Works in browsers and Node.js
14
+
15
+ ## Installation
16
+
17
+ ### npm / yarn / pnpm
18
+
19
+ ```bash
20
+ npm install pushstream-js
21
+ # or
22
+ yarn add pushstream-js
23
+ # or
24
+ pnpm add pushstream-js
25
+ ```
26
+
27
+ ### CDN / Script Tag
28
+
29
+ ```html
30
+ <script src="https://unpkg.com/pushstream-js/dist/pushstream.min.js"></script>
31
+ <script>
32
+ const client = new PushStream.EventClient('/events');
33
+ </script>
34
+ ```
35
+
36
+ ## Quick Start
37
+
38
+ ```javascript
39
+ import { EventClient } from 'pushstream-js';
40
+
41
+ // Create client
42
+ const client = new EventClient('/events');
43
+
44
+ // Subscribe to events
45
+ client.on('task.progress', (data) => {
46
+ console.log(`Task ${data.taskId}: ${data.percentage}%`);
47
+ });
48
+
49
+ client.on('task.complete', (data) => {
50
+ console.log(`Task ${data.taskId} completed!`);
51
+ });
52
+
53
+ // Handle errors
54
+ client.on('stream.error', (error) => {
55
+ console.error('Connection error:', error.message);
56
+ });
57
+
58
+ // Connect
59
+ client.connect();
60
+
61
+ // Later: disconnect
62
+ client.disconnect();
63
+ ```
64
+
65
+ ## API Reference
66
+
67
+ ### `new EventClient(url, options?)`
68
+
69
+ Creates a new EventClient instance.
70
+
71
+ **Parameters:**
72
+ - `url` (string) - The SSE endpoint URL (relative or absolute)
73
+ - `options` (object, optional):
74
+ - `reconnect` (boolean, default: `true`) - Enable automatic reconnection
75
+ - `reconnectInterval` (number, default: `1000`) - Base delay in milliseconds
76
+ - `maxReconnectAttempts` (number, default: `10`) - Maximum retry attempts
77
+ - `maxReconnectDelay` (number, default: `30000`) - Maximum backoff delay
78
+ - `withCredentials` (boolean, default: `false`) - Include cookies in CORS requests
79
+
80
+ ```javascript
81
+ const client = new EventClient('/events', {
82
+ reconnect: true,
83
+ reconnectInterval: 2000,
84
+ maxReconnectAttempts: 5
85
+ });
86
+ ```
87
+
88
+ ### `connect()`
89
+
90
+ Establish an SSE connection to the server. This method is idempotent - calling it while already connected has no effect.
91
+
92
+ ```javascript
93
+ client.connect();
94
+ ```
95
+
96
+ ### `disconnect()`
97
+
98
+ Close the SSE connection. After calling `disconnect()`, no automatic reconnection will be attempted.
99
+
100
+ ```javascript
101
+ client.disconnect();
102
+ ```
103
+
104
+ ### `on(event, callback)`
105
+
106
+ Subscribe to an event. Returns the client instance for chaining.
107
+
108
+ ```javascript
109
+ client
110
+ .on('task.progress', handleProgress)
111
+ .on('task.complete', handleComplete);
112
+ ```
113
+
114
+ ### `off(event, callback?)`
115
+
116
+ Unsubscribe from an event. If `callback` is omitted, removes all listeners for that event.
117
+
118
+ ```javascript
119
+ // Remove specific callback
120
+ client.off('task.progress', handleProgress);
121
+
122
+ // Remove all callbacks for event
123
+ client.off('task.progress');
124
+ ```
125
+
126
+ ### `state` (property)
127
+
128
+ Get the current connection state.
129
+
130
+ ```javascript
131
+ console.log(client.state); // 'disconnected' | 'connecting' | 'connected'
132
+ ```
133
+
134
+ ## Built-in Events
135
+
136
+ | Event | Description | Payload |
137
+ |-------|-------------|---------|
138
+ | `stream.open` | Connection established | `{ url: string }` |
139
+ | `stream.close` | Connection closed | `{ manual: boolean }` |
140
+ | `stream.error` | Error occurred | `{ message: string, ... }` |
141
+ | `stream.statechange` | State changed | `{ previousState, currentState }` |
142
+
143
+ ```javascript
144
+ client.on('stream.open', () => {
145
+ console.log('Connected!');
146
+ });
147
+
148
+ client.on('stream.close', ({ manual }) => {
149
+ console.log(manual ? 'Disconnected by user' : 'Connection lost');
150
+ });
151
+
152
+ client.on('stream.error', ({ message }) => {
153
+ console.error('Error:', message);
154
+ });
155
+
156
+ client.on('stream.statechange', ({ previousState, currentState }) => {
157
+ console.log(`State: ${previousState} -> ${currentState}`);
158
+ });
159
+ ```
160
+
161
+ ## Connection States
162
+
163
+ | State | Description |
164
+ |-------|-------------|
165
+ | `disconnected` | Not connected to server |
166
+ | `connecting` | Attempting to establish connection |
167
+ | `connected` | Connected and receiving events |
168
+
169
+ ## Reconnection Behavior
170
+
171
+ By default, the client automatically reconnects when the connection is lost:
172
+
173
+ 1. Uses **exponential backoff**: delays increase with each failed attempt
174
+ 2. Adds **jitter** (random delay) to prevent all clients reconnecting simultaneously
175
+ 3. Respects **max attempts**: stops after `maxReconnectAttempts` failures
176
+ 4. **Preserves subscriptions**: no need to re-register event handlers after reconnection
177
+
178
+ To disable auto-reconnection:
179
+
180
+ ```javascript
181
+ const client = new EventClient('/events', { reconnect: false });
182
+ ```
183
+
184
+ ## Authentication
185
+
186
+ Since `EventSource` cannot send custom headers, use query parameters for authentication:
187
+
188
+ ```javascript
189
+ const client = new EventClient('/events?token=your-jwt-token');
190
+ client.connect();
191
+ ```
192
+
193
+ For cookie-based auth with CORS:
194
+
195
+ ```javascript
196
+ const client = new EventClient('https://api.example.com/events', {
197
+ withCredentials: true
198
+ });
199
+ ```
200
+
201
+ ## Browser Support
202
+
203
+ | Browser | Version |
204
+ |---------|---------|
205
+ | Chrome | 60+ |
206
+ | Firefox | 55+ |
207
+ | Safari | 11+ |
208
+ | Edge | 79+ |
209
+
210
+ ## Node.js Support
211
+
212
+ For Node.js 18+, use with an EventSource polyfill:
213
+
214
+ ```javascript
215
+ import { EventSource } from 'eventsource';
216
+ globalThis.EventSource = EventSource;
217
+
218
+ import { EventClient } from 'pushstream-js';
219
+ // ... use as normal
220
+ ```
221
+
222
+ ## Examples
223
+
224
+ ### Progress Tracking
225
+
226
+ ```javascript
227
+ const client = new EventClient('/api/upload/events?uploadId=abc123');
228
+
229
+ client.on('upload.progress', ({ percentage, bytesUploaded }) => {
230
+ updateProgressBar(percentage);
231
+ });
232
+
233
+ client.on('upload.complete', ({ fileUrl }) => {
234
+ showSuccess(fileUrl);
235
+ client.disconnect();
236
+ });
237
+
238
+ client.on('upload.error', ({ message }) => {
239
+ showError(message);
240
+ client.disconnect();
241
+ });
242
+
243
+ client.connect();
244
+ ```
245
+
246
+ ### Live Notifications
247
+
248
+ ```javascript
249
+ const client = new EventClient('/api/notifications');
250
+
251
+ client.on('notification', ({ title, body, type }) => {
252
+ showNotification(title, body, type);
253
+ });
254
+
255
+ client.on('stream.error', () => {
256
+ showOfflineIndicator();
257
+ });
258
+
259
+ client.on('stream.open', () => {
260
+ hideOfflineIndicator();
261
+ });
262
+
263
+ client.connect();
264
+ ```
265
+
266
+ ## TypeScript
267
+
268
+ TypeScript definitions are planned for a future release. For now, you can create a basic `.d.ts` file:
269
+
270
+ ```typescript
271
+ declare module 'pushstream-js' {
272
+ export class EventClient {
273
+ constructor(url: string, options?: EventClientOptions);
274
+ connect(): void;
275
+ disconnect(): void;
276
+ on(event: string, callback: (data: any) => void): this;
277
+ off(event: string, callback?: (data: any) => void): this;
278
+ readonly state: 'disconnected' | 'connecting' | 'connected';
279
+ }
280
+
281
+ export interface EventClientOptions {
282
+ reconnect?: boolean;
283
+ reconnectInterval?: number;
284
+ maxReconnectAttempts?: number;
285
+ maxReconnectDelay?: number;
286
+ withCredentials?: boolean;
287
+ }
288
+ }
289
+ ```
290
+
291
+ ## License
292
+
293
+ MIT
294
+