vue-streaming 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/README.md ADDED
@@ -0,0 +1,699 @@
1
+ # vue-streaming
2
+
3
+ <div align="center">
4
+ **Universal Vue 3 streaming component for real-time data and media**
5
+
6
+ [![npm version](https://img.shields.io/npm/v/vue-streaming.svg)](https://github.com/keroloszakaria/vue-streaming)
7
+ [![Vue 3](https://img.shields.io/badge/vue-3.3%2B-brightgreen.svg)](https://vuejs.org/)
8
+ [![TypeScript](https://img.shields.io/badge/typescript-ready-blue.svg)](https://www.typescriptlang.org/)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/vue-streaming)](https://bundlephobia.com/keroloszakaria/vue-streaming)
11
+
12
+ </div>
13
+
14
+ ## 🌟 Features
15
+
16
+ Vue Streaming provides a unified `<StreamPlayer>` component that handles **6 different streaming protocols** with a consistent, declarative API:
17
+
18
+ - 🔌 **WebSocket** - Real-time bidirectional communication
19
+ - 📡 **Server-Sent Events (SSE)** - Server-to-client event streams
20
+ - 🌊 **HTTP Streaming** - Chunked transfer encoding streams
21
+ - 🔄 **Long Polling** - HTTP-based persistent connections
22
+ - 📺 **HLS Video** - HTTP Live Streaming for adaptive video
23
+ - 🎥 **WebRTC** - Peer-to-peer real-time communication
24
+
25
+ ### ✨ Why Choose Vue Streaming?
26
+
27
+ - **One API, Many Protocols**: Switch between streaming types with just a prop change
28
+ - **Vue 3 Native**: Built for Composition API with full TypeScript support
29
+ - **Headless Design**: No imposed styling - complete UI control
30
+ - **Production Ready**: Auto-reconnection, error handling, and backoff strategies
31
+ - **Lightweight**: Thin wrapper around `js-streaming` core library
32
+ - **Extensible**: Custom slots and event system for any use case
33
+
34
+ ## 📦 Installation
35
+
36
+ ```bash
37
+ # npm
38
+ npm install vue-streaming js-streaming
39
+
40
+ # yarn
41
+ yarn add vue-streaming js-streaming
42
+
43
+ # pnpm
44
+ pnpm add vue-streaming js-streaming
45
+ ```
46
+
47
+ > **Note**: Both `vue-streaming` and `js-streaming` are required. Vue Streaming is a wrapper that leverages the core `js-streaming` library.
48
+
49
+ ### Requirements
50
+
51
+ - **Vue**: 3.3.0 or higher
52
+ - **Node**: 16+ (for build tools)
53
+ - **Build System**: Vite, Nuxt 3, or Vue CLI with TypeScript support
54
+
55
+ ## 🚀 Quick Start
56
+
57
+ ### Basic WebSocket Example
58
+
59
+ ```vue
60
+ <script setup lang="ts">
61
+ import { ref } from "vue";
62
+ import { StreamPlayer } from "vue-streaming";
63
+
64
+ const player = ref<InstanceType<typeof StreamPlayer>>();
65
+ const config = {
66
+ url: "wss://echo.websocket.events",
67
+ protocols: ["echo-protocol"],
68
+ };
69
+
70
+ function sendMessage() {
71
+ player.value?.send("Hello WebSocket!");
72
+ }
73
+ </script>
74
+
75
+ <template>
76
+ <div>
77
+ <h2>WebSocket Demo</h2>
78
+ <StreamPlayer
79
+ ref="player"
80
+ type="websocket"
81
+ :config="config"
82
+ :auto-open="true"
83
+ @message="console.log('Received:', $event)"
84
+ @status="console.log('Status:', $event)"
85
+ />
86
+ <button @click="sendMessage">Send Message</button>
87
+ </div>
88
+ </template>
89
+ ```
90
+
91
+ ### HLS Video Streaming
92
+
93
+ ```vue
94
+ <script setup lang="ts">
95
+ import { StreamPlayer } from "vue-streaming";
96
+
97
+ const hlsConfig = {
98
+ url: "https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8",
99
+ };
100
+ </script>
101
+
102
+ <template>
103
+ <StreamPlayer
104
+ type="hls"
105
+ :config="hlsConfig"
106
+ :auto-open="true"
107
+ :autoplay="true"
108
+ :controls="true"
109
+ :muted="false"
110
+ />
111
+ </template>
112
+ ```
113
+
114
+ ### Server-Sent Events
115
+
116
+ ```vue
117
+ <script setup lang="ts">
118
+ import { StreamPlayer } from "vue-streaming";
119
+
120
+ const sseConfig = {
121
+ url: "/api/events",
122
+ headers: { Authorization: "Bearer token" },
123
+ };
124
+ </script>
125
+
126
+ <template>
127
+ <StreamPlayer
128
+ type="sse"
129
+ :config="sseConfig"
130
+ :auto-open="true"
131
+ @message="handleServerEvent"
132
+ />
133
+ </template>
134
+ ```
135
+
136
+ ## 📚 API Reference
137
+
138
+ ### Props
139
+
140
+ | Prop | Type | Default | Description |
141
+ | ------------- | ------------ | ---------- | -------------------------------------------------------------------------- |
142
+ | `type` | `StreamType` | _required_ | Protocol type: `websocket`, `sse`, `http`, `long-polling`, `hls`, `webrtc` |
143
+ | `config` | `object` | _required_ | Protocol-specific configuration object |
144
+ | `autoOpen` | `boolean` | `false` | Automatically open connection on mount |
145
+ | `autoplay` | `boolean` | `false` | Auto-play for video streams (HLS/WebRTC) |
146
+ | `controls` | `boolean` | `true` | Show video controls |
147
+ | `playsInline` | `boolean` | `true` | Play video inline on mobile |
148
+ | `muted` | `boolean` | `false` | Start video muted |
149
+ | `logLimit` | `number` | `500` | Maximum messages to keep in memory |
150
+ | `videoAttrs` | `object` | `{}` | Additional HTML video element attributes |
151
+
152
+ ### Events
153
+
154
+ | Event | Payload | Description |
155
+ | ---------- | -------------- | ------------------------------------------------------------------------- |
156
+ | `@open` | `void` | Connection established |
157
+ | `@close` | `void` | Connection closed |
158
+ | `@status` | `StreamStatus` | Status change: `idle`, `connecting`, `open`, `closing`, `closed`, `error` |
159
+ | `@error` | `Error` | Error occurred |
160
+ | `@message` | `any` | New message/data received |
161
+
162
+ ### Exposed Methods & Properties
163
+
164
+ ```typescript
165
+ interface StreamPlayerInstance {
166
+ // Methods
167
+ open(): Promise<void>;
168
+ close(): Promise<void>;
169
+ send(data: unknown): void; // Available for WebSocket/WebRTC
170
+
171
+ // Reactive State
172
+ status: Ref<StreamStatus>;
173
+ isOpen: Ref<boolean>;
174
+ error: Ref<Error | null>;
175
+ messages: Ref<unknown[]>;
176
+ }
177
+ ```
178
+
179
+ ### Configuration Objects
180
+
181
+ Each stream type accepts different configuration options:
182
+
183
+ #### WebSocket Config
184
+
185
+ ```typescript
186
+ {
187
+ url: string
188
+ protocols?: string[]
189
+ headers?: Record<string, string>
190
+ binaryType?: 'blob' | 'arraybuffer'
191
+ }
192
+ ```
193
+
194
+ #### SSE Config
195
+
196
+ ```typescript
197
+ {
198
+ url: string
199
+ headers?: Record<string, string>
200
+ withCredentials?: boolean
201
+ eventSourceInitDict?: EventSourceInit
202
+ }
203
+ ```
204
+
205
+ #### HTTP Streaming Config
206
+
207
+ ```typescript
208
+ {
209
+ url: string
210
+ method?: string
211
+ headers?: Record<string, string>
212
+ body?: any
213
+ signal?: AbortSignal
214
+ }
215
+ ```
216
+
217
+ #### Long Polling Config
218
+
219
+ ```typescript
220
+ {
221
+ url: string
222
+ interval?: number
223
+ headers?: Record<string, string>
224
+ timeout?: number
225
+ }
226
+ ```
227
+
228
+ #### HLS Config
229
+
230
+ ```typescript
231
+ {
232
+ url: string
233
+ hlsConfig?: any // Passed to HLS.js
234
+ }
235
+ ```
236
+
237
+ #### WebRTC Config
238
+
239
+ ```typescript
240
+ {
241
+ configuration?: RTCConfiguration
242
+ attachVideo?: boolean // Auto-attach video stream
243
+ // Additional WebRTC-specific options
244
+ }
245
+ ```
246
+
247
+ ## 🎨 Customization with Slots
248
+
249
+ ### Custom Log Display
250
+
251
+ ```vue
252
+ <template>
253
+ <StreamPlayer type="websocket" :config="config">
254
+ <template #log="{ messages, status, error }">
255
+ <div class="custom-log">
256
+ <div class="status-bar">
257
+ Status: <span :class="status">{{ status }}</span>
258
+ </div>
259
+ <div v-if="error" class="error">{{ error.message }}</div>
260
+ <div class="messages">
261
+ <div v-for="(msg, i) in messages" :key="i" class="message">
262
+ {{ typeof msg === "string" ? msg : JSON.stringify(msg) }}
263
+ </div>
264
+ </div>
265
+ </div>
266
+ </template>
267
+ </StreamPlayer>
268
+ </template>
269
+
270
+ <style scoped>
271
+ .custom-log {
272
+ border: 2px solid #007acc;
273
+ border-radius: 8px;
274
+ padding: 16px;
275
+ background: #f8f9fa;
276
+ }
277
+ .status-bar {
278
+ font-weight: bold;
279
+ }
280
+ .status.open {
281
+ color: green;
282
+ }
283
+ .status.error {
284
+ color: red;
285
+ }
286
+ .messages {
287
+ max-height: 300px;
288
+ overflow-y: auto;
289
+ }
290
+ .message {
291
+ padding: 4px 0;
292
+ border-bottom: 1px solid #eee;
293
+ }
294
+ </style>
295
+ ```
296
+
297
+ ### Custom Action Buttons
298
+
299
+ ```vue
300
+ <template>
301
+ <StreamPlayer type="websocket" :config="config">
302
+ <template #actions="{ open, close, send, isOpen, status }">
303
+ <div class="action-bar">
304
+ <button @click="open" :disabled="isOpen">Connect</button>
305
+ <button @click="close" :disabled="!isOpen">Disconnect</button>
306
+ <button @click="send('ping')" :disabled="!isOpen">Ping</button>
307
+ <span class="status-indicator" :class="status">{{ status }}</span>
308
+ </div>
309
+ </template>
310
+ </StreamPlayer>
311
+ </template>
312
+ ```
313
+
314
+ ## 🛠️ Advanced Usage
315
+
316
+ ### Auto-Reconnection and Error Handling
317
+
318
+ ```vue
319
+ <script setup lang="ts">
320
+ import { ref } from "vue";
321
+ import { StreamPlayer } from "vue-streaming";
322
+
323
+ const config = ref({
324
+ url: "wss://api.example.com/ws",
325
+ // Auto-reconnection settings
326
+ autoReconnect: true,
327
+ maxRetries: 5,
328
+ heartbeatMs: 30000,
329
+ backoff: {
330
+ baseMs: 1000,
331
+ maxMs: 10000,
332
+ factor: 1.5,
333
+ jitter: true,
334
+ },
335
+ });
336
+
337
+ function handleError(error: Error) {
338
+ console.error("Stream error:", error);
339
+ // Custom error handling logic
340
+ }
341
+
342
+ function handleStatusChange(status: string) {
343
+ if (status === "error") {
344
+ // Handle connection errors
345
+ } else if (status === "open") {
346
+ console.log("Successfully connected!");
347
+ }
348
+ }
349
+ </script>
350
+
351
+ <template>
352
+ <StreamPlayer
353
+ type="websocket"
354
+ :config="config"
355
+ @error="handleError"
356
+ @status="handleStatusChange"
357
+ />
358
+ </template>
359
+ ```
360
+
361
+ ### Dynamic Configuration
362
+
363
+ ```vue
364
+ <script setup lang="ts">
365
+ import { ref, computed } from "vue";
366
+ import { StreamPlayer } from "vue-streaming";
367
+
368
+ const apiEndpoint = ref("wss://api.example.com");
369
+ const authToken = ref("");
370
+
371
+ const dynamicConfig = computed(() => ({
372
+ url: `${apiEndpoint.value}/ws`,
373
+ headers: {
374
+ Authorization: `Bearer ${authToken.value}`,
375
+ },
376
+ }));
377
+
378
+ // Configuration changes will automatically recreate the stream
379
+ </script>
380
+
381
+ <template>
382
+ <div>
383
+ <input v-model="apiEndpoint" placeholder="WebSocket URL" />
384
+ <input v-model="authToken" placeholder="Auth Token" />
385
+
386
+ <StreamPlayer
387
+ type="websocket"
388
+ :config="dynamicConfig"
389
+ :auto-open="!!authToken"
390
+ />
391
+ </div>
392
+ </template>
393
+ ```
394
+
395
+ ### Programmatic Control
396
+
397
+ ```vue
398
+ <script setup lang="ts">
399
+ import { ref, onMounted } from "vue";
400
+ import { StreamPlayer } from "vue-streaming";
401
+
402
+ const player = ref<InstanceType<typeof StreamPlayer>>();
403
+
404
+ onMounted(() => {
405
+ // Programmatic control
406
+ setTimeout(() => {
407
+ player.value?.open();
408
+ }, 1000);
409
+
410
+ // Send periodic messages
411
+ setInterval(() => {
412
+ if (player.value?.isOpen) {
413
+ player.value.send({
414
+ type: "heartbeat",
415
+ timestamp: Date.now(),
416
+ });
417
+ }
418
+ }, 10000);
419
+ });
420
+
421
+ // Access reactive state
422
+ const connectionStatus = computed(() => player.value?.status || "idle");
423
+ const messageCount = computed(() => player.value?.messages.length || 0);
424
+ </script>
425
+ ```
426
+
427
+ ## 🔧 TypeScript Support
428
+
429
+ Vue Streaming is fully typed. Import types for enhanced development experience:
430
+
431
+ ```typescript
432
+ import type {
433
+ StreamType,
434
+ StreamStatus,
435
+ StreamState,
436
+ StreamAPI,
437
+ } from "vue-streaming";
438
+
439
+ // Component instance type
440
+ import { StreamPlayer } from "vue-streaming";
441
+ type StreamPlayerInstance = InstanceType<typeof StreamPlayer>;
442
+
443
+ // Usage in composition function
444
+ function useStreamPlayer() {
445
+ const player = ref<StreamPlayerInstance>();
446
+ const status = computed(() => player.value?.status || "idle");
447
+
448
+ return { player, status };
449
+ }
450
+ ```
451
+
452
+ ## 🌐 Nuxt 3 / SSR Usage
453
+
454
+ For server-side rendering, wrap the component to prevent hydration issues:
455
+
456
+ ```vue
457
+ <template>
458
+ <div>
459
+ <ClientOnly>
460
+ <StreamPlayer type="websocket" :config="config" :auto-open="true" />
461
+ <template #fallback>
462
+ <div>Loading stream player...</div>
463
+ </template>
464
+ </ClientOnly>
465
+ </div>
466
+ </template>
467
+ ```
468
+
469
+ Or create an async component:
470
+
471
+ ```vue
472
+ <script setup lang="ts">
473
+ import { defineAsyncComponent } from "vue";
474
+
475
+ const StreamPlayer = defineAsyncComponent(() =>
476
+ import("vue-streaming").then((m) => m.StreamPlayer)
477
+ );
478
+ </script>
479
+ ```
480
+
481
+ ## 📱 Real-World Examples
482
+
483
+ ### Chat Application
484
+
485
+ ```vue
486
+ <script setup lang="ts">
487
+ import { ref } from "vue";
488
+ import { StreamPlayer } from "vue-streaming";
489
+
490
+ const message = ref("");
491
+ const chatPlayer = ref<InstanceType<typeof StreamPlayer>>();
492
+
493
+ const config = {
494
+ url: "wss://chat.example.com/ws",
495
+ protocols: ["chat-v1"],
496
+ };
497
+
498
+ function sendMessage() {
499
+ if (message.value.trim()) {
500
+ chatPlayer.value?.send({
501
+ type: "message",
502
+ content: message.value,
503
+ timestamp: new Date().toISOString(),
504
+ });
505
+ message.value = "";
506
+ }
507
+ }
508
+
509
+ function handleChatMessage(msg: any) {
510
+ if (msg.type === "message") {
511
+ // Handle incoming chat message
512
+ console.log(`${msg.user}: ${msg.content}`);
513
+ }
514
+ }
515
+ </script>
516
+
517
+ <template>
518
+ <div class="chat-container">
519
+ <StreamPlayer
520
+ ref="chatPlayer"
521
+ type="websocket"
522
+ :config="config"
523
+ :auto-open="true"
524
+ @message="handleChatMessage"
525
+ >
526
+ <template #log="{ messages }">
527
+ <div class="chat-messages">
528
+ <div v-for="msg in messages" :key="msg.id" class="message">
529
+ <strong>{{ msg.user }}:</strong> {{ msg.content }}
530
+ </div>
531
+ </div>
532
+ </template>
533
+
534
+ <template #actions="{ isOpen }">
535
+ <div class="chat-input">
536
+ <input
537
+ v-model="message"
538
+ @keyup.enter="sendMessage"
539
+ :disabled="!isOpen"
540
+ placeholder="Type a message..."
541
+ />
542
+ <button @click="sendMessage" :disabled="!isOpen">Send</button>
543
+ </div>
544
+ </template>
545
+ </StreamPlayer>
546
+ </div>
547
+ </template>
548
+ ```
549
+
550
+ ### Live Data Dashboard
551
+
552
+ ```vue
553
+ <script setup lang="ts">
554
+ import { ref, computed } from "vue";
555
+ import { StreamPlayer } from "vue-streaming";
556
+
557
+ const metrics = ref<any[]>([]);
558
+
559
+ const config = {
560
+ url: "/api/metrics/stream",
561
+ headers: { Accept: "text/event-stream" },
562
+ };
563
+
564
+ function handleMetricsUpdate(data: any) {
565
+ if (data.type === "metrics") {
566
+ metrics.value = [...metrics.value, data.payload].slice(-50); // Keep last 50
567
+ }
568
+ }
569
+
570
+ const latestMetrics = computed(
571
+ () => metrics.value[metrics.value.length - 1]?.payload || {}
572
+ );
573
+ </script>
574
+
575
+ <template>
576
+ <div class="dashboard">
577
+ <h1>Live Metrics Dashboard</h1>
578
+
579
+ <div class="metrics-grid">
580
+ <div class="metric-card">
581
+ <h3>CPU Usage</h3>
582
+ <div class="metric-value">{{ latestMetrics.cpu }}%</div>
583
+ </div>
584
+ <div class="metric-card">
585
+ <h3>Memory</h3>
586
+ <div class="metric-value">{{ latestMetrics.memory }}MB</div>
587
+ </div>
588
+ </div>
589
+
590
+ <StreamPlayer
591
+ type="sse"
592
+ :config="config"
593
+ :auto-open="true"
594
+ @message="handleMetricsUpdate"
595
+ >
596
+ <template #log="{ messages, status }">
597
+ <div class="connection-status">
598
+ Status: <span :class="status">{{ status }}</span> | Updates:
599
+ {{ messages.length }}
600
+ </div>
601
+ </template>
602
+ </StreamPlayer>
603
+ </div>
604
+ </template>
605
+ ```
606
+
607
+ ## 🐛 Troubleshooting
608
+
609
+ ### Common Issues
610
+
611
+ **Connection fails immediately**
612
+
613
+ ```typescript
614
+ // Check if the URL is correct and accessible
615
+ const config = {
616
+ url: "ws://localhost:3000/ws", // http:// for ws://, https:// for wss://
617
+ };
618
+ ```
619
+
620
+ **CORS issues with SSE/HTTP**
621
+
622
+ ```typescript
623
+ const config = {
624
+ url: "/api/stream",
625
+ headers: {
626
+ "Access-Control-Allow-Origin": "*",
627
+ },
628
+ };
629
+ ```
630
+
631
+ **Video not playing (HLS/WebRTC)**
632
+
633
+ ```vue
634
+ <StreamPlayer
635
+ type="hls"
636
+ :config="hlsConfig"
637
+ :autoplay="true"
638
+ :muted="true" <!-- Required for autoplay in most browsers -->
639
+ :plays-inline="true"
640
+ />
641
+ ```
642
+
643
+ **Messages not displaying**
644
+
645
+ ```javascript
646
+ // Check if logLimit is sufficient
647
+ <StreamPlayer :log-limit="1000" />
648
+
649
+ // Or handle messages manually
650
+ @message="msg => console.log('Received:', msg)"
651
+ ```
652
+
653
+ ### Browser Compatibility
654
+
655
+ - **WebSocket**: All modern browsers
656
+ - **SSE**: All modern browsers (IE/Edge requires polyfill)
657
+ - **HLS**: Requires HLS.js for non-Safari browsers
658
+ - **WebRTC**: Modern browsers (check specific API support)
659
+
660
+ ### Performance Tips
661
+
662
+ 1. **Limit message history**: Use reasonable `logLimit` values
663
+ 2. **Debounce rapid updates**: Use `shallowRef` for message arrays
664
+ 3. **Clean up properly**: Component handles cleanup automatically
665
+ 4. **Use object URLs**: For large binary data in WebRTC/HLS
666
+
667
+ ## 🤝 Contributing
668
+
669
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
670
+
671
+ ### Development Setup
672
+
673
+ ```bash
674
+ git clone https://github.com/yourusername/vue-streaming.git
675
+ cd vue-streaming
676
+ npm install
677
+ npm run dev
678
+ ```
679
+
680
+ ### Building
681
+
682
+ ```bash
683
+ npm run build
684
+ npm run test
685
+ ```
686
+
687
+ ## 📄 License
688
+
689
+ MIT © Vue Streaming Contributors
690
+
691
+ ---
692
+
693
+ <div align="center">
694
+
695
+ **[Documentation](https://github.com/yourusername/vue-streaming#readme) • [Examples](https://github.com/yourusername/vue-streaming/tree/main/examples) • [Issues](https://github.com/yourusername/vue-streaming/issues)**
696
+
697
+ Made with ❤️ for the Vue.js community
698
+
699
+ </div>