@dialtribe/react-sdk 0.1.0-alpha.8 → 0.1.4

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.
@@ -0,0 +1,567 @@
1
+ import './dialtribe-player-CNriUtNi.js';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import React$1, { RefObject } from 'react';
4
+
5
+ /**
6
+ * Props for the DialtribeStreamer component.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * // Inside DialtribeProvider (recommended)
11
+ * <DialtribeProvider sessionToken={token}>
12
+ * <DialtribeStreamer
13
+ * streamKey={keyFromBackend}
14
+ * onDone={() => window.close()}
15
+ * />
16
+ * </DialtribeProvider>
17
+ *
18
+ * // Standalone (e.g., popup window)
19
+ * <DialtribeStreamer
20
+ * sessionToken={token}
21
+ * streamKey={keyFromBackend}
22
+ * onDone={() => window.close()}
23
+ * />
24
+ * ```
25
+ */
26
+ interface DialtribeStreamerProps {
27
+ /**
28
+ * Session token for API authentication.
29
+ *
30
+ * Required for permission checks. Can be provided via:
31
+ * 1. DialtribeProvider context (recommended for main app)
32
+ * 2. This prop (required for popup windows)
33
+ *
34
+ * Must include `broadcasts:stream` permission.
35
+ */
36
+ sessionToken?: string;
37
+ /**
38
+ * Stream key for broadcasting.
39
+ *
40
+ * **Production apps should always provide this from their backend.**
41
+ * The stream key authenticates the broadcaster with the encoder server.
42
+ *
43
+ * If omitted, a manual input form is shown. This is intended for
44
+ * development/testing only - end users should never see or handle stream keys.
45
+ *
46
+ * @example "w1_abc123def456..."
47
+ */
48
+ streamKey?: string;
49
+ /**
50
+ * Called when streaming ends (user stops, terminates, or clicks Done).
51
+ * Use this to close the popup or navigate away.
52
+ *
53
+ * @example () => window.close()
54
+ */
55
+ onDone?: () => void;
56
+ /**
57
+ * Called when the stream key changes (e.g., user edits it in preview mode).
58
+ * Useful for persisting the key or updating parent state.
59
+ */
60
+ onStreamKeyChange?: (key: string) => void;
61
+ /**
62
+ * Custom encoder server URL. Defaults to Dialtribe's production encoder.
63
+ * Only change this for self-hosted encoder deployments.
64
+ *
65
+ * @default "https://broadcastapi.dialtribe.com"
66
+ */
67
+ encoderServerUrl?: string;
68
+ /**
69
+ * Custom API base URL for broadcast availability checks.
70
+ * Only change this for self-hosted API deployments.
71
+ *
72
+ * @default "https://dialtribe.com/api/public/v1"
73
+ */
74
+ apiBaseUrl?: string;
75
+ /**
76
+ * When true, the streamer fills its parent container instead of the viewport.
77
+ * Use this when embedding the streamer inline within a page.
78
+ *
79
+ * @default false
80
+ */
81
+ inline?: boolean;
82
+ }
83
+ declare function DialtribeStreamer({ sessionToken: propSessionToken, streamKey: initialStreamKey, onDone, onStreamKeyChange, encoderServerUrl, apiBaseUrl, inline, }: DialtribeStreamerProps): react_jsx_runtime.JSX.Element;
84
+
85
+ interface StreamingPreviewProps {
86
+ videoRef: RefObject<HTMLVideoElement>;
87
+ isVideoKey: boolean;
88
+ isVideoEnabled: boolean;
89
+ mediaStream: MediaStream | null;
90
+ facingMode: "user" | "environment";
91
+ }
92
+ declare function StreamingPreview({ videoRef, isVideoKey, isVideoEnabled, mediaStream, facingMode, }: StreamingPreviewProps): react_jsx_runtime.JSX.Element;
93
+
94
+ type StreamingControlState = "previewing" | "connecting" | "live" | "stopping";
95
+ interface MediaDeviceInfo {
96
+ deviceId: string;
97
+ label: string;
98
+ }
99
+ interface StreamingControlsProps {
100
+ state: StreamingControlState;
101
+ isVideoKey: boolean;
102
+ isMuted: boolean;
103
+ isVideoEnabled: boolean;
104
+ facingMode: "user" | "environment";
105
+ hasMultipleCameras: boolean;
106
+ startTime: Date | null;
107
+ bytesSent: number;
108
+ showStopConfirm: boolean;
109
+ streamKey: string;
110
+ onStreamKeyChange?: (newKey: string) => void;
111
+ onStart: () => void;
112
+ onStop: () => void;
113
+ onConfirmStop: () => void;
114
+ onCancelStop: () => void;
115
+ onToggleMute: () => void;
116
+ onToggleVideo: () => void;
117
+ onFlipCamera: () => void;
118
+ onClose?: () => void;
119
+ showCloseConfirm?: boolean;
120
+ onConfirmClose?: () => void;
121
+ onCancelClose?: () => void;
122
+ videoDevices?: MediaDeviceInfo[];
123
+ audioDevices?: MediaDeviceInfo[];
124
+ selectedVideoDeviceId?: string;
125
+ selectedAudioDeviceId?: string;
126
+ onVideoDeviceChange?: (deviceId: string) => void;
127
+ onAudioDeviceChange?: (deviceId: string) => void;
128
+ mediaStream?: MediaStream | null;
129
+ }
130
+ declare function StreamingControls({ state, isVideoKey, isMuted, isVideoEnabled, facingMode: _facingMode, // Reserved for future use (e.g., showing camera direction)
131
+ hasMultipleCameras, startTime, bytesSent, showStopConfirm, streamKey, onStreamKeyChange, onStart, onStop, onConfirmStop, onCancelStop, onToggleMute, onToggleVideo, onFlipCamera, onClose, showCloseConfirm, onConfirmClose, onCancelClose, videoDevices, audioDevices, selectedVideoDeviceId, selectedAudioDeviceId, onVideoDeviceChange, onAudioDeviceChange, mediaStream, }: StreamingControlsProps): react_jsx_runtime.JSX.Element;
132
+
133
+ interface StreamKeyDisplayProps {
134
+ streamKey: string;
135
+ className?: string;
136
+ showLabel?: boolean;
137
+ showCopy?: boolean;
138
+ editable?: boolean;
139
+ onChange?: (newKey: string) => void;
140
+ size?: 'sm' | 'md' | 'lg';
141
+ layout?: 'vertical' | 'horizontal';
142
+ darkMode?: boolean;
143
+ }
144
+ /**
145
+ * Shared component for displaying stream keys with reveal/copy functionality
146
+ * Obscures the stream key by default, showing only first 6 and last 6 characters
147
+ * When revealed and editable, becomes an input field for editing
148
+ */
149
+ declare function StreamKeyDisplay({ streamKey, className, showLabel, showCopy, editable, onChange, size, layout, darkMode, }: StreamKeyDisplayProps): react_jsx_runtime.JSX.Element;
150
+
151
+ interface StreamKeyInputProps {
152
+ onSubmit: (key: string) => void;
153
+ /**
154
+ * When true, the input fills its parent container instead of the viewport.
155
+ * Use this when embedding inline within a page.
156
+ */
157
+ inline?: boolean;
158
+ }
159
+ /**
160
+ * Stream key input form for manual entry
161
+ * Validates stream key format before submission
162
+ */
163
+ declare function StreamKeyInput({ onSubmit, inline }: StreamKeyInputProps): react_jsx_runtime.JSX.Element;
164
+
165
+ /**
166
+ * WebSocket streaming client for sending media chunks to encoder server
167
+ * Based on prankcast reference implementation
168
+ */
169
+ /** Default encoder server URL */
170
+ declare const DEFAULT_ENCODER_SERVER_URL = "https://broadcastapi.dialtribe.com";
171
+ interface StreamDiagnostics {
172
+ mimeType: string | undefined;
173
+ chunksSent: number;
174
+ bytesSent: number;
175
+ elapsedMs: number;
176
+ closeCode?: number;
177
+ closeReason?: string;
178
+ lastError?: string;
179
+ }
180
+ interface WebSocketStreamerOptions {
181
+ streamKey: string;
182
+ mediaStream: MediaStream;
183
+ isVideo: boolean;
184
+ /** Optional custom encoder server URL (defaults to DEFAULT_ENCODER_SERVER_URL) */
185
+ encoderServerUrl?: string;
186
+ /** Disable canvas rendering (for debugging HLS issues). Disables seamless camera flips. */
187
+ disableCanvasRendering?: boolean;
188
+ onBytesUpdate?: (bytes: number) => void;
189
+ onStateChange?: (state: "connecting" | "live" | "stopped" | "terminated" | "error") => void;
190
+ onError?: (error: string, diagnostics?: StreamDiagnostics) => void;
191
+ }
192
+ declare class WebSocketStreamer {
193
+ private streamKey;
194
+ private mediaStream;
195
+ private isVideo;
196
+ private encoderServerUrl;
197
+ private disableCanvasRendering;
198
+ private websocket;
199
+ private mediaRecorder;
200
+ private bytesSent;
201
+ private chunksSent;
202
+ private userStopped;
203
+ private isHotSwapping;
204
+ private startTime;
205
+ private mimeType;
206
+ private onBytesUpdate?;
207
+ private onStateChange?;
208
+ private onError?;
209
+ private canvasState;
210
+ constructor(options: WebSocketStreamerOptions);
211
+ /**
212
+ * Calculate scaled dimensions for fitting video into canvas.
213
+ * @param mode - "contain" fits video inside canvas, "cover" fills canvas (cropping)
214
+ */
215
+ private calculateScaledDimensions;
216
+ /**
217
+ * Invalidate cached scaling dimensions (call when video source changes)
218
+ */
219
+ private invalidateScalingCache;
220
+ /**
221
+ * Validate stream key format
222
+ * Stream keys must follow format: {tierCode}{foreignId}_{randomKey}
223
+ * Tier codes: a (audio shared), b (audio VIP), v (video shared), w (video VIP)
224
+ */
225
+ private validateStreamKeyFormat;
226
+ /**
227
+ * Set up canvas-based rendering pipeline for video streams.
228
+ * This allows seamless camera flips by changing the video source
229
+ * without affecting MediaRecorder (which records from the canvas).
230
+ *
231
+ * This is async to ensure the video is producing frames before returning,
232
+ * which prevents black initial thumbnails.
233
+ */
234
+ private setupCanvasRendering;
235
+ /**
236
+ * Clean up canvas rendering resources
237
+ */
238
+ private cleanupCanvasRendering;
239
+ /**
240
+ * Build WebSocket URL from stream key
241
+ */
242
+ private buildWebSocketUrl;
243
+ /**
244
+ * Start streaming
245
+ */
246
+ start(): Promise<void>;
247
+ /**
248
+ * Stop streaming
249
+ */
250
+ stop(): void;
251
+ /**
252
+ * Get total bytes sent
253
+ */
254
+ getBytesSent(): number;
255
+ /**
256
+ * Get the current source media stream.
257
+ * This may change after replaceVideoTrack() is called.
258
+ */
259
+ getMediaStream(): MediaStream;
260
+ /**
261
+ * Get current diagnostics
262
+ */
263
+ private getDiagnostics;
264
+ /**
265
+ * Replace the video track for camera flips.
266
+ *
267
+ * When using canvas-based rendering (video streams), this preloads the new
268
+ * camera in a temporary video element, waits for it to be ready, then swaps
269
+ * it in. This ensures continuous frame output with no gaps.
270
+ *
271
+ * @param newVideoTrack - The new video track from the flipped camera
272
+ * @returns Promise that resolves when the swap is complete
273
+ */
274
+ replaceVideoTrack(newVideoTrack: MediaStreamTrack): Promise<void>;
275
+ /**
276
+ * Replace the audio track in the current MediaStream without stopping MediaRecorder.
277
+ *
278
+ * @param newAudioTrack - The new audio track
279
+ */
280
+ replaceAudioTrack(newAudioTrack: MediaStreamTrack): void;
281
+ /**
282
+ * Update the media stream (e.g., when switching devices from settings)
283
+ * This keeps the WebSocket connection alive while swapping the media source.
284
+ * Restarts the MediaRecorder with the new stream.
285
+ *
286
+ * Note: For camera flips, prefer replaceVideoTrack() which doesn't restart MediaRecorder.
287
+ * Note: Errors are thrown to the caller, not sent to onError callback.
288
+ */
289
+ updateMediaStream(newMediaStream: MediaStream): Promise<void>;
290
+ /**
291
+ * Set up WebSocket event handlers
292
+ */
293
+ private setupWebSocketHandlers;
294
+ /**
295
+ * Set up MediaRecorder event handlers
296
+ */
297
+ private setupMediaRecorderHandlers;
298
+ }
299
+
300
+ /**
301
+ * Media constraints for browser streaming
302
+ * Based on prankcast reference implementation
303
+ */
304
+ interface MediaConstraintsOptions {
305
+ isVideo: boolean;
306
+ facingMode?: "user" | "environment";
307
+ }
308
+ declare function getMediaConstraints(options: MediaConstraintsOptions): MediaStreamConstraints;
309
+ /**
310
+ * MediaRecorder options for encoding
311
+ */
312
+ declare function getMediaRecorderOptions(isVideo: boolean): MediaRecorderOptions;
313
+ /**
314
+ * Check browser compatibility
315
+ */
316
+ declare function checkBrowserCompatibility(): {
317
+ compatible: boolean;
318
+ error?: string;
319
+ };
320
+
321
+ /**
322
+ * Utility functions for opening broadcast streamer popup windows
323
+ */
324
+ interface PopupDimensions {
325
+ width: number;
326
+ height: number;
327
+ left: number;
328
+ top: number;
329
+ }
330
+ /**
331
+ * Calculate optimal popup dimensions based on screen size
332
+ * - Desktop/wider screens: 16:9 landscape ratio (e.g., 1280x720) to match modern webcams
333
+ * - Mobile/narrower screens: 9:16 portrait ratio (e.g., 720x1280) for vertical video
334
+ */
335
+ declare function calculatePopupDimensions(): PopupDimensions;
336
+ /**
337
+ * Options for opening a broadcast streamer popup window.
338
+ */
339
+ interface OpenDialtribeStreamerPopupOptions {
340
+ /**
341
+ * Session token for API authentication. **Required.**
342
+ * The token must include `broadcasts:stream` permission.
343
+ * Sent securely via postMessage (not in the URL).
344
+ */
345
+ sessionToken: string;
346
+ /**
347
+ * Stream key for broadcasting. **Required for production use.**
348
+ * Fetch this from your backend and pass it here.
349
+ * The key is sent securely via postMessage (not in the URL).
350
+ *
351
+ * @example "w1_abc123def456..."
352
+ */
353
+ streamKey: string;
354
+ /**
355
+ * URL path for the streamer page. **Required.**
356
+ * This is the route in your app where the popup page is hosted.
357
+ *
358
+ * @example "/broadcasts/new"
359
+ * @example "/stream/live"
360
+ */
361
+ streamerUrl: string;
362
+ /** Optional app ID to include in the postMessage payload */
363
+ appId?: number;
364
+ /** Additional URL parameters to pass to the popup page */
365
+ additionalParams?: Record<string, string>;
366
+ }
367
+ /**
368
+ * Open broadcast streamer popup window with credentials sent via postMessage
369
+ * This is more secure than passing sensitive data in the URL
370
+ *
371
+ * @example
372
+ * ```tsx
373
+ * import { openDialtribeStreamerPopup } from '@dialtribe/react-sdk/dialtribe-streamer';
374
+ *
375
+ * // Open popup for live streaming
376
+ * openDialtribeStreamerPopup({
377
+ * sessionToken: 'sess_xxx...',
378
+ * streamKey: 'w1_abc123...',
379
+ * streamerUrl: '/broadcasts/new',
380
+ * });
381
+ * ```
382
+ *
383
+ * @returns The popup window reference, or null if popup was blocked
384
+ */
385
+ declare function openDialtribeStreamerPopup(options: OpenDialtribeStreamerPopupOptions): Window | null;
386
+ /**
387
+ * Legacy function name for backwards compatibility
388
+ * @deprecated Use openDialtribeStreamerPopup instead
389
+ */
390
+ declare const openBroadcastPopup: typeof openDialtribeStreamerPopup;
391
+
392
+ /**
393
+ * Return value from useDialtribeStreamerPopup hook.
394
+ */
395
+ interface UseDialtribeStreamerPopupReturn {
396
+ /**
397
+ * Session token received from parent window.
398
+ * Will be null until credentials are received via postMessage.
399
+ */
400
+ sessionToken: string | null;
401
+ /**
402
+ * Stream key received from parent window.
403
+ * Will be null until credentials are received via postMessage.
404
+ */
405
+ streamKey: string | null;
406
+ /**
407
+ * API base URL received from parent window.
408
+ * Defaults to empty string (uses SDK default).
409
+ */
410
+ apiBaseUrl: string;
411
+ /**
412
+ * Function to update the stream key.
413
+ * Pass this to DialtribeStreamer's onStreamKeyChange prop.
414
+ */
415
+ setStreamKey: React.Dispatch<React.SetStateAction<string | null>>;
416
+ /**
417
+ * True if credentials have been received from the parent window.
418
+ */
419
+ isReady: boolean;
420
+ }
421
+ /**
422
+ * Hook for popup pages that receive streaming credentials via postMessage.
423
+ *
424
+ * Use this in your popup page component to handle the postMessage communication
425
+ * with the parent window that opened the popup via `openDialtribeStreamerPopup()`.
426
+ *
427
+ * @example
428
+ * ```tsx
429
+ * import { DialtribeStreamer, useDialtribeStreamerPopup } from '@dialtribe/react-sdk/dialtribe-streamer';
430
+ *
431
+ * export default function BroadcastPopupPage() {
432
+ * const { sessionToken, streamKey, apiBaseUrl, setStreamKey } = useDialtribeStreamerPopup();
433
+ *
434
+ * return (
435
+ * <DialtribeStreamer
436
+ * sessionToken={sessionToken}
437
+ * streamKey={streamKey}
438
+ * apiBaseUrl={apiBaseUrl}
439
+ * onDone={() => window.close()}
440
+ * onStreamKeyChange={setStreamKey}
441
+ * />
442
+ * );
443
+ * }
444
+ * ```
445
+ */
446
+ declare function useDialtribeStreamerPopup(): UseDialtribeStreamerPopupReturn;
447
+
448
+ /**
449
+ * Fallback behavior when popup is blocked by the browser.
450
+ */
451
+ type PopupFallbackMode = 'fullscreen' | 'newTab' | 'none';
452
+ /**
453
+ * Options for the useDialtribeStreamerLauncher hook.
454
+ */
455
+ interface UseDialtribeStreamerLauncherOptions {
456
+ /**
457
+ * Session token for API authentication.
458
+ */
459
+ sessionToken: string | null;
460
+ /**
461
+ * Stream key for broadcasting.
462
+ */
463
+ streamKey: string;
464
+ /**
465
+ * URL path for the streamer page (e.g., '/broadcasts/new').
466
+ */
467
+ streamerUrl: string;
468
+ /**
469
+ * API base URL for the streamer.
470
+ */
471
+ apiBaseUrl?: string;
472
+ /**
473
+ * What to do if the popup is blocked by the browser.
474
+ * - 'fullscreen': Show a fullscreen overlay in the current page
475
+ * - 'newTab': Open in a new browser tab (less likely to be blocked)
476
+ * - 'none': Do nothing, let the caller handle it
477
+ *
478
+ * @default 'fullscreen'
479
+ */
480
+ fallback?: PopupFallbackMode;
481
+ /**
482
+ * Callback when popup is blocked (called regardless of fallback mode).
483
+ */
484
+ onPopupBlocked?: () => void;
485
+ /**
486
+ * Callback when streaming ends (from fullscreen fallback mode).
487
+ */
488
+ onDone?: () => void;
489
+ /**
490
+ * Callback when stream key changes (from fallback streamer).
491
+ */
492
+ onStreamKeyChange?: (key: string) => void;
493
+ }
494
+ /**
495
+ * Return value from useDialtribeStreamerLauncher hook.
496
+ */
497
+ interface UseDialtribeStreamerLauncherReturn {
498
+ /**
499
+ * Launch the streamer. Tries popup first, falls back if blocked.
500
+ */
501
+ launch: () => void;
502
+ /**
503
+ * Portal component that renders the fallback overlay.
504
+ * Include this once in your JSX - it renders via portal to document.body.
505
+ *
506
+ * @example
507
+ * ```tsx
508
+ * const { launch, Fallback } = useDialtribeStreamerLauncher({...});
509
+ * return (
510
+ * <>
511
+ * <button onClick={launch}>Start</button>
512
+ * <Fallback />
513
+ * </>
514
+ * );
515
+ * ```
516
+ */
517
+ Fallback: React$1.FC;
518
+ /**
519
+ * Whether the fallback fullscreen overlay is currently shown.
520
+ * Use this for custom fallback rendering.
521
+ */
522
+ showFallback: boolean;
523
+ /**
524
+ * Close the fallback overlay.
525
+ * Use this for custom fallback rendering.
526
+ */
527
+ closeFallback: () => void;
528
+ /**
529
+ * Reference to the popup window (if successfully opened).
530
+ */
531
+ popupRef: Window | null;
532
+ /**
533
+ * Whether the last launch attempt was blocked.
534
+ */
535
+ wasBlocked: boolean;
536
+ }
537
+ /**
538
+ * Hook for launching the DialtribeStreamer with automatic popup fallback.
539
+ *
540
+ * This hook tries to open the streamer in a popup window first. If the popup
541
+ * is blocked by the browser, it automatically falls back to a fullscreen
542
+ * overlay or new tab (configurable).
543
+ *
544
+ * @example
545
+ * ```tsx
546
+ * import { useDialtribeStreamerLauncher } from '@dialtribe/react-sdk/dialtribe-streamer';
547
+ *
548
+ * function StreamButton({ sessionToken, streamKey }: Props) {
549
+ * const { launch, Fallback } = useDialtribeStreamerLauncher({
550
+ * sessionToken,
551
+ * streamKey,
552
+ * streamerUrl: '/broadcasts/new',
553
+ * fallback: 'fullscreen',
554
+ * });
555
+ *
556
+ * return (
557
+ * <>
558
+ * <button onClick={launch}>Start Streaming</button>
559
+ * <Fallback />
560
+ * </>
561
+ * );
562
+ * }
563
+ * ```
564
+ */
565
+ declare function useDialtribeStreamerLauncher(options: UseDialtribeStreamerLauncherOptions): UseDialtribeStreamerLauncherReturn;
566
+
567
+ export { DialtribeStreamer as D, type MediaConstraintsOptions as M, type OpenDialtribeStreamerPopupOptions as O, type PopupDimensions as P, StreamingPreview as S, type UseDialtribeStreamerPopupReturn as U, WebSocketStreamer as W, type DialtribeStreamerProps as a, type StreamingPreviewProps as b, StreamingControls as c, type StreamingControlsProps as d, type StreamingControlState as e, StreamKeyDisplay as f, type StreamKeyDisplayProps as g, StreamKeyInput as h, type StreamKeyInputProps as i, DEFAULT_ENCODER_SERVER_URL as j, type WebSocketStreamerOptions as k, type StreamDiagnostics as l, getMediaConstraints as m, getMediaRecorderOptions as n, checkBrowserCompatibility as o, openDialtribeStreamerPopup as p, openBroadcastPopup as q, calculatePopupDimensions as r, useDialtribeStreamerLauncher as s, type UseDialtribeStreamerLauncherOptions as t, useDialtribeStreamerPopup as u, type UseDialtribeStreamerLauncherReturn as v, type PopupFallbackMode as w };