@dialtribe/react-sdk 0.1.0-alpha.10

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