@dialtribe/react-sdk 0.1.0-alpha.5

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,517 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1, { Component, ReactNode, ErrorInfo } from 'react';
3
+
4
+ /**
5
+ * DialTribe SDK Context
6
+ * Manages session token and auto-refresh across all SDK components
7
+ */
8
+ interface DialTribeContextValue {
9
+ /** Current session token */
10
+ sessionToken: string | null;
11
+ /** Update the session token (called automatically on refresh) */
12
+ setSessionToken: (token: string, expiresAt?: string) => void;
13
+ /** Whether the session token is expired/invalid */
14
+ isExpired: boolean;
15
+ /** Mark token as expired */
16
+ markExpired: () => void;
17
+ }
18
+ interface DialTribeProviderProps {
19
+ /** Session token from your backend (required) */
20
+ sessionToken: string;
21
+ /** Called when the API returns a refreshed token via X-Session-Token header */
22
+ onTokenRefresh?: (newToken: string, expiresAt: string) => void;
23
+ /** Called when the session token expires or becomes invalid */
24
+ onTokenExpired?: () => void;
25
+ /** Your React app */
26
+ children: React$1.ReactNode;
27
+ }
28
+ /**
29
+ * DialTribe Provider
30
+ *
31
+ * Wraps your app to provide session token authentication to all SDK components.
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * <DialTribeProvider
36
+ * sessionToken="sess_xxx..."
37
+ * onTokenRefresh={(newToken) => {
38
+ * // Save to state/localStorage
39
+ * setToken(newToken);
40
+ * }}
41
+ * onTokenExpired={() => {
42
+ * // Redirect to login or refresh
43
+ * router.push('/login');
44
+ * }}
45
+ * >
46
+ * <App />
47
+ * </DialTribeProvider>
48
+ * ```
49
+ */
50
+ declare function DialTribeProvider({ sessionToken: initialToken, onTokenRefresh, onTokenExpired, children, }: DialTribeProviderProps): react_jsx_runtime.JSX.Element;
51
+ /**
52
+ * Hook to access DialTribe context
53
+ *
54
+ * @throws Error if used outside DialTribeProvider
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * const { sessionToken, setSessionToken } = useDialTribe();
59
+ * ```
60
+ */
61
+ declare function useDialTribe(): DialTribeContextValue;
62
+
63
+ /**
64
+ * DialTribe API Client
65
+ *
66
+ * Handles all API communication with fixed DialTribe endpoints.
67
+ * Automatically manages session token refresh via X-Session-Token headers.
68
+ */
69
+ /** DialTribe API base URL (production only) */
70
+ declare const DIALTRIBE_API_BASE = "https://dialtribe.com/api/public/v1";
71
+ /** API endpoints (fixed, not configurable) */
72
+ declare const ENDPOINTS: {
73
+ readonly broadcasts: "https://dialtribe.com/api/public/v1/broadcasts";
74
+ readonly broadcast: (id: number) => string;
75
+ readonly contentPlay: "https://dialtribe.com/api/public/v1/content/play";
76
+ readonly presignedUrl: "https://dialtribe.com/api/public/v1/media/presigned-url";
77
+ readonly sessionStart: "https://dialtribe.com/api/public/v1/session/start";
78
+ readonly sessionPing: "https://dialtribe.com/api/public/v1/session/ping";
79
+ };
80
+ interface ApiClientConfig {
81
+ /** Session token for authentication */
82
+ sessionToken: string;
83
+ /** Called when API returns a refreshed token */
84
+ onTokenRefresh?: (newToken: string, expiresAt: string) => void;
85
+ /** Called when token expires or becomes invalid */
86
+ onTokenExpired?: () => void;
87
+ }
88
+ /**
89
+ * DialTribe API Client
90
+ *
91
+ * Low-level client for making authenticated requests to DialTribe API.
92
+ * Handles session token auto-refresh automatically.
93
+ */
94
+ declare class DialTribeClient {
95
+ private config;
96
+ constructor(config: ApiClientConfig);
97
+ /**
98
+ * Make an authenticated request to DialTribe API
99
+ *
100
+ * Automatically:
101
+ * - Adds Authorization header with session token
102
+ * - Checks for X-Session-Token header in response (token refresh)
103
+ * - Calls onTokenRefresh if new token is provided
104
+ * - Calls onTokenExpired on 401 errors
105
+ */
106
+ fetch(url: string, options?: RequestInit): Promise<Response>;
107
+ /**
108
+ * Update the session token
109
+ * Called automatically when token is refreshed, or manually by user
110
+ */
111
+ setSessionToken(token: string): void;
112
+ /**
113
+ * Get list of broadcasts for the authenticated app
114
+ */
115
+ getBroadcasts(params?: {
116
+ page?: number;
117
+ limit?: number;
118
+ broadcastStatus?: 1 | 2;
119
+ search?: string;
120
+ includeDeleted?: boolean;
121
+ }): Promise<any>;
122
+ /**
123
+ * Get a single broadcast by ID
124
+ */
125
+ getBroadcast(id: number): Promise<any>;
126
+ /**
127
+ * Get presigned URL for media playback
128
+ *
129
+ * @param broadcastId - Broadcast ID
130
+ * @param hash - Broadcast hash (optional if using session token)
131
+ * @param action - 'download' to force download, otherwise streams
132
+ */
133
+ getPlaybackUrl(params: {
134
+ broadcastId: number;
135
+ hash?: string;
136
+ action?: 'download';
137
+ }): Promise<string>;
138
+ /**
139
+ * Refresh a presigned URL before it expires
140
+ *
141
+ * @param broadcastId - Broadcast ID
142
+ * @param hash - Broadcast hash
143
+ * @param fileType - Type of media file
144
+ */
145
+ refreshPresignedUrl(params: {
146
+ broadcastId: number;
147
+ hash: string;
148
+ fileType: 'mp4' | 'mp3' | 'hls';
149
+ }): Promise<{
150
+ url: string;
151
+ expiresAt: string;
152
+ expiresIn: number;
153
+ }>;
154
+ /**
155
+ * Start a new audience tracking session
156
+ *
157
+ * @returns audienceId and optional resumePosition
158
+ */
159
+ startSession(params: {
160
+ contentId: number;
161
+ broadcastId: number;
162
+ appId: string;
163
+ foreignId?: string | null;
164
+ foreignTier?: string;
165
+ sessionId: string;
166
+ fileType: string;
167
+ platform: string;
168
+ userAgent: string | null;
169
+ origin: string | null;
170
+ country?: string | null;
171
+ region?: string | null;
172
+ }): Promise<{
173
+ audienceId: string;
174
+ resumePosition?: number;
175
+ }>;
176
+ /**
177
+ * Send a session ping event
178
+ *
179
+ * Event types:
180
+ * - 0: PAUSE/STOP
181
+ * - 1: PLAY/START
182
+ * - 2: HEARTBEAT
183
+ * - 3: UNMOUNT
184
+ */
185
+ sendSessionPing(params: {
186
+ audienceId: string;
187
+ sessionId: string;
188
+ eventType: 0 | 1 | 2 | 3;
189
+ currentTime: number;
190
+ duration: number;
191
+ }): Promise<any>;
192
+ }
193
+
194
+ /**
195
+ * Broadcast data structure
196
+ * Matches the response from /api/public/v1/broadcasts
197
+ */
198
+ interface Broadcast {
199
+ id: number;
200
+ hash: string | null;
201
+ platformBroadcastId: string | null;
202
+ streamKey: string;
203
+ broadcastStatus: number;
204
+ recordingStatus: number;
205
+ isVideo: boolean;
206
+ saveRecordings: boolean;
207
+ startedAt: string;
208
+ endedAt: string | null;
209
+ durationSeconds: number | null;
210
+ s3FolderUrl: string | null;
211
+ hlsPlaylistUrl: string | null;
212
+ recordingMp4Url: string | null;
213
+ recordingMp3Url: string | null;
214
+ mp4Size: string;
215
+ mp3Size: string;
216
+ terminatedBy: string | null;
217
+ terminationReason: string | null;
218
+ transcriptStatus?: number;
219
+ transcriptUrl?: string | null;
220
+ transcriptPreview?: string | null;
221
+ transcriptDuration?: number | null;
222
+ transcriptLanguage?: string | null;
223
+ transcriptError?: string | null;
224
+ transcriptSize?: string;
225
+ app?: {
226
+ s3Hash: string | null;
227
+ };
228
+ content?: {
229
+ id: number;
230
+ hash: string;
231
+ } | null;
232
+ streamKeyRecord?: {
233
+ foreignId: string;
234
+ foreignName: string | null;
235
+ } | null;
236
+ }
237
+ /**
238
+ * Transcript word interface (from OpenAI Whisper API)
239
+ */
240
+ interface TranscriptWord {
241
+ word: string;
242
+ start: number;
243
+ end: number;
244
+ }
245
+ /**
246
+ * Transcript segment interface
247
+ */
248
+ interface TranscriptSegment {
249
+ id: number;
250
+ start: number;
251
+ end: number;
252
+ text: string;
253
+ words: TranscriptWord[];
254
+ }
255
+ /**
256
+ * Full transcript data structure
257
+ */
258
+ interface TranscriptData {
259
+ text: string;
260
+ segments?: TranscriptSegment[];
261
+ words?: TranscriptWord[];
262
+ }
263
+
264
+ interface BroadcastPlayerProps {
265
+ /** Broadcast data from DialTribe API */
266
+ broadcast: Broadcast;
267
+ /** Optional: App ID for tracking */
268
+ appId?: string;
269
+ /** Optional: Content ID for tracking */
270
+ contentId?: number;
271
+ /** Foreign user ID from partner system (any tier) */
272
+ foreignId?: string;
273
+ /** Tier name from partner system (e.g., 'guest', 'member', 'subscriber_gold') */
274
+ foreignTier?: string;
275
+ /**
276
+ * Optional render prop for clip creator
277
+ * If provided, the "Create Clip" button will be shown and this will be called when clicked
278
+ */
279
+ renderClipCreator?: (props: {
280
+ isOpen: boolean;
281
+ onClose: () => void;
282
+ sourceVideoUrl?: string;
283
+ sourceAudioUrl?: string;
284
+ sourceDuration: number;
285
+ onPauseParent: () => void;
286
+ }) => React.ReactNode;
287
+ /** Optional: Called when player encounters error */
288
+ onError?: (error: Error) => void;
289
+ /** Optional: Custom CSS classes */
290
+ className?: string;
291
+ /** Optional: Enable keyboard shortcuts (Space, arrows, M, F, etc.). Default: false */
292
+ enableKeyboardShortcuts?: boolean;
293
+ }
294
+ /**
295
+ * BroadcastPlayer - Core media player component (no modal wrapper)
296
+ *
297
+ * Plays video/audio broadcasts with transcript, waveform visualization, and clip creation.
298
+ * Uses DialTribeClient for authenticated API calls.
299
+ *
300
+ * @example
301
+ * ```tsx
302
+ * <BroadcastPlayer
303
+ * broadcast={broadcast}
304
+ * appId="app_123"
305
+ * contentId={456}
306
+ * />
307
+ * ```
308
+ */
309
+ declare function BroadcastPlayer({ broadcast, appId, contentId, foreignId, foreignTier, renderClipCreator, onError, className, enableKeyboardShortcuts, }: BroadcastPlayerProps): react_jsx_runtime.JSX.Element;
310
+
311
+ interface BroadcastPlayerModalProps {
312
+ /** Broadcast data from DialTribe API */
313
+ broadcast: Broadcast;
314
+ /** Whether modal is open */
315
+ isOpen: boolean;
316
+ /** Called when modal should close */
317
+ onClose: () => void;
318
+ /** Optional: App ID for tracking */
319
+ appId?: string;
320
+ /** Optional: Content ID for tracking */
321
+ contentId?: number;
322
+ /** Foreign user ID from partner system (any tier) */
323
+ foreignId?: string;
324
+ /** Tier name from partner system (e.g., 'guest', 'member', 'subscriber_gold') */
325
+ foreignTier?: string;
326
+ /**
327
+ * Optional render prop for clip creator
328
+ * If provided, the "Create Clip" button will be shown and this will be called when clicked
329
+ */
330
+ renderClipCreator?: (props: {
331
+ isOpen: boolean;
332
+ onClose: () => void;
333
+ sourceVideoUrl?: string;
334
+ sourceAudioUrl?: string;
335
+ sourceDuration: number;
336
+ onPauseParent: () => void;
337
+ }) => React.ReactNode;
338
+ /** Optional: Custom CSS classes for the player */
339
+ className?: string;
340
+ /** Optional: Enable keyboard shortcuts (Space, arrows, M, F, etc.). Default: false */
341
+ enableKeyboardShortcuts?: boolean;
342
+ }
343
+ /**
344
+ * BroadcastPlayerModal - Modal wrapper for BroadcastPlayer
345
+ *
346
+ * Provides a modal overlay with ESC key handling and backdrop click to close.
347
+ * Uses the new BroadcastPlayer component for all player functionality.
348
+ *
349
+ * @example
350
+ * ```tsx
351
+ * <BroadcastPlayerModal
352
+ * broadcast={broadcast}
353
+ * isOpen={showModal}
354
+ * onClose={() => setShowModal(false)}
355
+ * appId="app_123"
356
+ * contentId={456}
357
+ * />
358
+ * ```
359
+ */
360
+ declare function BroadcastPlayerModal({ broadcast, isOpen, onClose, appId, contentId, foreignId, foreignTier, renderClipCreator, className, enableKeyboardShortcuts, }: BroadcastPlayerModalProps): react_jsx_runtime.JSX.Element | null;
361
+
362
+ interface Props {
363
+ children: ReactNode;
364
+ /** Callback when modal needs to be closed */
365
+ onClose?: () => void;
366
+ /** Broadcast ID for logging purposes */
367
+ broadcastId?: number;
368
+ }
369
+ interface State {
370
+ hasError: boolean;
371
+ error: Error | null;
372
+ errorInfo: ErrorInfo | null;
373
+ }
374
+ /**
375
+ * Error Boundary for Broadcast Player Modal
376
+ *
377
+ * Catches and handles React errors that occur during:
378
+ * - Rendering
379
+ * - Lifecycle methods
380
+ * - Constructors of the whole tree below them
381
+ *
382
+ * Does NOT catch errors in:
383
+ * - Event handlers (use try-catch)
384
+ * - Asynchronous code (use try-catch)
385
+ * - Server-side rendering
386
+ * - Errors thrown in the error boundary itself
387
+ *
388
+ * Benefits:
389
+ * - Prevents white screen of death
390
+ * - Provides user-friendly error UI
391
+ * - Logs errors for debugging
392
+ * - Allows graceful recovery
393
+ */
394
+ declare class BroadcastPlayerErrorBoundary extends Component<Props, State> {
395
+ constructor(props: Props);
396
+ static getDerivedStateFromError(error: Error): Partial<State>;
397
+ componentDidCatch(error: Error, errorInfo: ErrorInfo): void;
398
+ handleReset: () => void;
399
+ handleClose: () => void;
400
+ render(): string | number | boolean | Iterable<ReactNode> | react_jsx_runtime.JSX.Element | null | undefined;
401
+ }
402
+
403
+ interface AudioWaveformProps {
404
+ /** Audio/video element for playback visualization */
405
+ audioElement?: HTMLMediaElement | null;
406
+ /** Media stream for live streaming visualization */
407
+ mediaStream?: MediaStream | null;
408
+ /** Whether the audio is currently playing (for playback mode) */
409
+ isPlaying?: boolean;
410
+ /** Whether this is currently a live stream (for HLS streams) */
411
+ isLive?: boolean;
412
+ }
413
+ /**
414
+ * Shared audio waveform visualization component
415
+ * Can be used for both live streaming (MediaStream) and playback (HTMLVideoElement)
416
+ */
417
+ declare function AudioWaveform({ audioElement, mediaStream, isPlaying, isLive, }: AudioWaveformProps): react_jsx_runtime.JSX.Element;
418
+
419
+ /**
420
+ * Shared Loading Spinner Component
421
+ */
422
+ interface LoadingSpinnerProps {
423
+ /**
424
+ * Optional text to display below the spinner
425
+ */
426
+ text?: string;
427
+ /**
428
+ * Size variant of the spinner
429
+ * @default "md"
430
+ */
431
+ size?: "sm" | "md" | "lg";
432
+ /**
433
+ * Color scheme
434
+ * @default "default"
435
+ */
436
+ variant?: "default" | "primary" | "white";
437
+ }
438
+ /**
439
+ * Loading spinner component with optional text
440
+ *
441
+ * @example
442
+ * <LoadingSpinner />
443
+ * <LoadingSpinner text="Loading broadcasts..." size="lg" />
444
+ * <LoadingSpinner variant="white" />
445
+ */
446
+ declare function LoadingSpinner({ text, size, variant, }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
447
+
448
+ /**
449
+ * Format seconds to time string (HH:MM:SS or MM:SS)
450
+ *
451
+ * @param seconds - Number of seconds
452
+ * @param includeHours - Whether to always include hours (default: auto-detect)
453
+ * @returns Formatted time string
454
+ *
455
+ * Examples:
456
+ * - formatTime(45) → "0:45"
457
+ * - formatTime(125) → "2:05"
458
+ * - formatTime(3665) → "1:01:05"
459
+ */
460
+ declare function formatTime(seconds: number, includeHours?: boolean): string;
461
+
462
+ /**
463
+ * CDN domain for broadcast content
464
+ * Can be overridden via environment variable CONTENT_CDN_DOMAIN
465
+ */
466
+ declare const CDN_DOMAIN: string;
467
+ /**
468
+ * Build S3 key prefix for broadcast files
469
+ *
470
+ * @param appHash - App S3 hash
471
+ * @param broadcastHash - Broadcast hash
472
+ * @returns S3 key prefix with trailing slash
473
+ */
474
+ declare function buildBroadcastS3KeyPrefix(appHash: string, broadcastHash: string): string;
475
+ /**
476
+ * Build CDN URL for a broadcast file (HLS)
477
+ *
478
+ * @param appHash - App S3 hash
479
+ * @param broadcastHash - Broadcast hash
480
+ * @param filename - File name (e.g., "index.m3u8", "seg-0-000001.ts")
481
+ * @returns CDN URL
482
+ */
483
+ declare function buildBroadcastCdnUrl(appHash: string, broadcastHash: string, filename: string): string;
484
+
485
+ declare const HTTP_STATUS: {
486
+ readonly OK: 200;
487
+ readonly CREATED: 201;
488
+ readonly ACCEPTED: 202;
489
+ readonly NO_CONTENT: 204;
490
+ readonly MOVED_PERMANENTLY: 301;
491
+ readonly FOUND: 302;
492
+ readonly SEE_OTHER: 303;
493
+ readonly NOT_MODIFIED: 304;
494
+ readonly TEMPORARY_REDIRECT: 307;
495
+ readonly PERMANENT_REDIRECT: 308;
496
+ readonly BAD_REQUEST: 400;
497
+ readonly UNAUTHORIZED: 401;
498
+ readonly PAYMENT_REQUIRED: 402;
499
+ readonly FORBIDDEN: 403;
500
+ readonly NOT_FOUND: 404;
501
+ readonly METHOD_NOT_ALLOWED: 405;
502
+ readonly NOT_ACCEPTABLE: 406;
503
+ readonly CONFLICT: 409;
504
+ readonly GONE: 410;
505
+ readonly PAYLOAD_TOO_LARGE: 413;
506
+ readonly UNSUPPORTED_MEDIA_TYPE: 415;
507
+ readonly UNPROCESSABLE_ENTITY: 422;
508
+ readonly TOO_MANY_REQUESTS: 429;
509
+ readonly INTERNAL_SERVER_ERROR: 500;
510
+ readonly NOT_IMPLEMENTED: 501;
511
+ readonly BAD_GATEWAY: 502;
512
+ readonly SERVICE_UNAVAILABLE: 503;
513
+ readonly GATEWAY_TIMEOUT: 504;
514
+ };
515
+ type HttpStatusCode = typeof HTTP_STATUS[keyof typeof HTTP_STATUS];
516
+
517
+ export { type ApiClientConfig, AudioWaveform, type Broadcast, BroadcastPlayer, BroadcastPlayerErrorBoundary, BroadcastPlayerModal, type BroadcastPlayerModalProps, type BroadcastPlayerProps, CDN_DOMAIN, DIALTRIBE_API_BASE, DialTribeClient, type DialTribeContextValue, DialTribeProvider, type DialTribeProviderProps, ENDPOINTS, HTTP_STATUS, type HttpStatusCode, LoadingSpinner, type TranscriptData, type TranscriptSegment, type TranscriptWord, buildBroadcastCdnUrl, buildBroadcastS3KeyPrefix, formatTime, useDialTribe };