@livepeer-frameworks/player-react 0.1.0 → 0.1.2

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.
Files changed (187) hide show
  1. package/README.md +7 -9
  2. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js +359 -0
  3. package/dist/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  4. package/dist/cjs/assets/logomark.svg.js +8 -0
  5. package/dist/cjs/assets/logomark.svg.js.map +1 -0
  6. package/dist/cjs/components/DevModePanel.js +826 -0
  7. package/dist/cjs/components/DevModePanel.js.map +1 -0
  8. package/dist/cjs/components/DvdLogo.js +200 -0
  9. package/dist/cjs/components/DvdLogo.js.map +1 -0
  10. package/dist/cjs/components/Icons.js +439 -0
  11. package/dist/cjs/components/Icons.js.map +1 -0
  12. package/dist/cjs/components/IdleScreen.js +587 -0
  13. package/dist/cjs/components/IdleScreen.js.map +1 -0
  14. package/dist/cjs/components/LoadingScreen.js +523 -0
  15. package/dist/cjs/components/LoadingScreen.js.map +1 -0
  16. package/dist/cjs/components/Player.js +420 -0
  17. package/dist/cjs/components/Player.js.map +1 -0
  18. package/dist/cjs/components/PlayerControls.js +798 -0
  19. package/dist/cjs/components/PlayerControls.js.map +1 -0
  20. package/dist/cjs/components/PlayerErrorBoundary.js +80 -0
  21. package/dist/cjs/components/PlayerErrorBoundary.js.map +1 -0
  22. package/dist/cjs/components/SeekBar.js +253 -0
  23. package/dist/cjs/components/SeekBar.js.map +1 -0
  24. package/dist/cjs/components/SkipIndicator.js +92 -0
  25. package/dist/cjs/components/SkipIndicator.js.map +1 -0
  26. package/dist/cjs/components/SpeedIndicator.js +43 -0
  27. package/dist/cjs/components/SpeedIndicator.js.map +1 -0
  28. package/dist/cjs/components/StatsPanel.js +202 -0
  29. package/dist/cjs/components/StatsPanel.js.map +1 -0
  30. package/dist/cjs/components/StreamStateOverlay.js +229 -0
  31. package/dist/cjs/components/StreamStateOverlay.js.map +1 -0
  32. package/dist/cjs/components/ThumbnailOverlay.js +86 -0
  33. package/dist/cjs/components/ThumbnailOverlay.js.map +1 -0
  34. package/dist/cjs/components/TitleOverlay.js +32 -0
  35. package/dist/cjs/components/TitleOverlay.js.map +1 -0
  36. package/dist/cjs/context/PlayerContext.js +46 -0
  37. package/dist/cjs/context/PlayerContext.js.map +1 -0
  38. package/dist/cjs/hooks/useMetaTrack.js +165 -0
  39. package/dist/cjs/hooks/useMetaTrack.js.map +1 -0
  40. package/dist/cjs/hooks/usePlaybackQuality.js +131 -0
  41. package/dist/cjs/hooks/usePlaybackQuality.js.map +1 -0
  42. package/dist/cjs/hooks/usePlayerController.js +518 -0
  43. package/dist/cjs/hooks/usePlayerController.js.map +1 -0
  44. package/dist/cjs/hooks/usePlayerSelection.js +90 -0
  45. package/dist/cjs/hooks/usePlayerSelection.js.map +1 -0
  46. package/dist/cjs/hooks/useStreamState.js +360 -0
  47. package/dist/cjs/hooks/useStreamState.js.map +1 -0
  48. package/dist/cjs/hooks/useTelemetry.js +120 -0
  49. package/dist/cjs/hooks/useTelemetry.js.map +1 -0
  50. package/dist/cjs/hooks/useViewerEndpoints.js +222 -0
  51. package/dist/cjs/hooks/useViewerEndpoints.js.map +1 -0
  52. package/dist/cjs/index.js +97 -1
  53. package/dist/cjs/index.js.map +1 -1
  54. package/dist/cjs/ui/badge.js +34 -0
  55. package/dist/cjs/ui/badge.js.map +1 -0
  56. package/dist/cjs/ui/button.js +74 -0
  57. package/dist/cjs/ui/button.js.map +1 -0
  58. package/dist/cjs/ui/context-menu.js +163 -0
  59. package/dist/cjs/ui/context-menu.js.map +1 -0
  60. package/dist/cjs/ui/slider.js +60 -0
  61. package/dist/cjs/ui/slider.js.map +1 -0
  62. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js +329 -0
  63. package/dist/esm/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  64. package/dist/esm/assets/logomark.svg.js +4 -0
  65. package/dist/esm/assets/logomark.svg.js.map +1 -0
  66. package/dist/esm/components/DevModePanel.js +822 -0
  67. package/dist/esm/components/DevModePanel.js.map +1 -0
  68. package/dist/esm/components/DvdLogo.js +196 -0
  69. package/dist/esm/components/DvdLogo.js.map +1 -0
  70. package/dist/esm/components/Icons.js +421 -0
  71. package/dist/esm/components/Icons.js.map +1 -0
  72. package/dist/esm/components/IdleScreen.js +582 -0
  73. package/dist/esm/components/IdleScreen.js.map +1 -0
  74. package/dist/esm/components/LoadingScreen.js +519 -0
  75. package/dist/esm/components/LoadingScreen.js.map +1 -0
  76. package/dist/esm/components/Player.js +416 -0
  77. package/dist/esm/components/Player.js.map +1 -0
  78. package/dist/esm/components/PlayerControls.js +794 -0
  79. package/dist/esm/components/PlayerControls.js.map +1 -0
  80. package/dist/esm/components/PlayerErrorBoundary.js +76 -0
  81. package/dist/esm/components/PlayerErrorBoundary.js.map +1 -0
  82. package/dist/esm/components/SeekBar.js +249 -0
  83. package/dist/esm/components/SeekBar.js.map +1 -0
  84. package/dist/esm/components/SkipIndicator.js +88 -0
  85. package/dist/esm/components/SkipIndicator.js.map +1 -0
  86. package/dist/esm/components/SpeedIndicator.js +39 -0
  87. package/dist/esm/components/SpeedIndicator.js.map +1 -0
  88. package/dist/esm/components/StatsPanel.js +198 -0
  89. package/dist/esm/components/StatsPanel.js.map +1 -0
  90. package/dist/esm/components/StreamStateOverlay.js +224 -0
  91. package/dist/esm/components/StreamStateOverlay.js.map +1 -0
  92. package/dist/esm/components/ThumbnailOverlay.js +82 -0
  93. package/dist/esm/components/ThumbnailOverlay.js.map +1 -0
  94. package/dist/esm/components/TitleOverlay.js +28 -0
  95. package/dist/esm/components/TitleOverlay.js.map +1 -0
  96. package/dist/esm/context/PlayerContext.js +41 -0
  97. package/dist/esm/context/PlayerContext.js.map +1 -0
  98. package/dist/esm/hooks/useMetaTrack.js +163 -0
  99. package/dist/esm/hooks/useMetaTrack.js.map +1 -0
  100. package/dist/esm/hooks/usePlaybackQuality.js +129 -0
  101. package/dist/esm/hooks/usePlaybackQuality.js.map +1 -0
  102. package/dist/esm/hooks/usePlayerController.js +516 -0
  103. package/dist/esm/hooks/usePlayerController.js.map +1 -0
  104. package/dist/esm/hooks/usePlayerSelection.js +88 -0
  105. package/dist/esm/hooks/usePlayerSelection.js.map +1 -0
  106. package/dist/esm/hooks/useStreamState.js +358 -0
  107. package/dist/esm/hooks/useStreamState.js.map +1 -0
  108. package/dist/esm/hooks/useTelemetry.js +118 -0
  109. package/dist/esm/hooks/useTelemetry.js.map +1 -0
  110. package/dist/esm/hooks/useViewerEndpoints.js +220 -0
  111. package/dist/esm/hooks/useViewerEndpoints.js.map +1 -0
  112. package/dist/esm/index.js +23 -1
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/ui/badge.js +31 -0
  115. package/dist/esm/ui/badge.js.map +1 -0
  116. package/dist/esm/ui/button.js +52 -0
  117. package/dist/esm/ui/button.js.map +1 -0
  118. package/dist/esm/ui/context-menu.js +132 -0
  119. package/dist/esm/ui/context-menu.js.map +1 -0
  120. package/dist/esm/ui/slider.js +38 -0
  121. package/dist/esm/ui/slider.js.map +1 -0
  122. package/dist/types/components/DvdLogo.d.ts +1 -1
  123. package/dist/types/components/Icons.d.ts +1 -1
  124. package/dist/types/components/Player.d.ts +1 -1
  125. package/dist/types/components/PlayerErrorBoundary.d.ts +2 -1
  126. package/dist/types/components/StreamStateOverlay.d.ts +2 -2
  127. package/dist/types/components/SubtitleRenderer.d.ts +2 -2
  128. package/dist/types/context/PlayerContext.d.ts +2 -2
  129. package/dist/types/context/index.d.ts +2 -2
  130. package/dist/types/hooks/useMetaTrack.d.ts +3 -3
  131. package/dist/types/hooks/usePlaybackQuality.d.ts +2 -2
  132. package/dist/types/hooks/usePlayerController.d.ts +26 -3
  133. package/dist/types/hooks/usePlayerSelection.d.ts +1 -1
  134. package/dist/types/hooks/useStreamState.d.ts +1 -1
  135. package/dist/types/hooks/useTelemetry.d.ts +1 -1
  136. package/dist/types/hooks/useViewerEndpoints.d.ts +3 -3
  137. package/dist/types/index.d.ts +28 -28
  138. package/dist/types/types.d.ts +3 -3
  139. package/dist/types/ui/select.d.ts +1 -1
  140. package/package.json +22 -14
  141. package/src/components/DevModePanel.tsx +244 -143
  142. package/src/components/DvdLogo.tsx +1 -1
  143. package/src/components/Icons.tsx +105 -25
  144. package/src/components/IdleScreen.tsx +262 -128
  145. package/src/components/LoadingScreen.tsx +169 -151
  146. package/src/components/LogoOverlay.tsx +3 -6
  147. package/src/components/Player.tsx +126 -59
  148. package/src/components/PlayerControls.tsx +384 -272
  149. package/src/components/PlayerErrorBoundary.tsx +7 -13
  150. package/src/components/SeekBar.tsx +96 -88
  151. package/src/components/SkipIndicator.tsx +2 -12
  152. package/src/components/SpeedIndicator.tsx +2 -11
  153. package/src/components/StatsPanel.tsx +31 -22
  154. package/src/components/StreamStateOverlay.tsx +105 -49
  155. package/src/components/SubtitleRenderer.tsx +29 -29
  156. package/src/components/ThumbnailOverlay.tsx +5 -6
  157. package/src/components/TitleOverlay.tsx +2 -8
  158. package/src/context/PlayerContext.tsx +4 -8
  159. package/src/context/index.ts +3 -3
  160. package/src/hooks/useMetaTrack.ts +27 -27
  161. package/src/hooks/usePlaybackQuality.ts +3 -3
  162. package/src/hooks/usePlayerController.ts +246 -138
  163. package/src/hooks/usePlayerSelection.ts +6 -6
  164. package/src/hooks/useStreamState.ts +51 -56
  165. package/src/hooks/useTelemetry.ts +18 -3
  166. package/src/hooks/useViewerEndpoints.ts +34 -23
  167. package/src/index.tsx +36 -28
  168. package/src/types.ts +8 -8
  169. package/src/ui/badge.tsx +6 -5
  170. package/src/ui/button.tsx +9 -8
  171. package/src/ui/context-menu.tsx +42 -61
  172. package/src/ui/select.tsx +13 -7
  173. package/src/ui/slider.tsx +18 -29
  174. package/dist/types/components/players/DashJsPlayer.d.ts +0 -18
  175. package/dist/types/components/players/HlsJsPlayer.d.ts +0 -18
  176. package/dist/types/components/players/MewsWsPlayer/index.d.ts +0 -18
  177. package/dist/types/components/players/MistPlayer.d.ts +0 -20
  178. package/dist/types/components/players/MistWebRTCPlayer/index.d.ts +0 -20
  179. package/dist/types/components/players/NativePlayer.d.ts +0 -19
  180. package/dist/types/components/players/VideoJsPlayer.d.ts +0 -18
  181. package/src/components/players/DashJsPlayer.tsx +0 -56
  182. package/src/components/players/HlsJsPlayer.tsx +0 -56
  183. package/src/components/players/MewsWsPlayer/index.tsx +0 -56
  184. package/src/components/players/MistPlayer.tsx +0 -60
  185. package/src/components/players/MistWebRTCPlayer/index.tsx +0 -59
  186. package/src/components/players/NativePlayer.tsx +0 -58
  187. package/src/components/players/VideoJsPlayer.tsx +0 -56
@@ -1,10 +1,5 @@
1
- import { useEffect, useState, useRef, useCallback } from 'react';
2
- import type {
3
- UseStreamStateOptions,
4
- StreamState,
5
- StreamStatus,
6
- MistStreamInfo,
7
- } from '../types';
1
+ import { useEffect, useState, useRef, useCallback } from "react";
2
+ import type { UseStreamStateOptions, StreamState, StreamStatus, MistStreamInfo } from "../types";
8
3
 
9
4
  /**
10
5
  * Parse MistServer error string into StreamStatus enum
@@ -12,14 +7,14 @@ import type {
12
7
  function parseErrorToStatus(error: string): StreamStatus {
13
8
  const lowerError = error.toLowerCase();
14
9
 
15
- if (lowerError.includes('offline')) return 'OFFLINE';
16
- if (lowerError.includes('initializing')) return 'INITIALIZING';
17
- if (lowerError.includes('booting')) return 'BOOTING';
18
- if (lowerError.includes('waiting for data')) return 'WAITING_FOR_DATA';
19
- if (lowerError.includes('shutting down')) return 'SHUTTING_DOWN';
20
- if (lowerError.includes('invalid')) return 'INVALID';
10
+ if (lowerError.includes("offline")) return "OFFLINE";
11
+ if (lowerError.includes("initializing")) return "INITIALIZING";
12
+ if (lowerError.includes("booting")) return "BOOTING";
13
+ if (lowerError.includes("waiting for data")) return "WAITING_FOR_DATA";
14
+ if (lowerError.includes("shutting down")) return "SHUTTING_DOWN";
15
+ if (lowerError.includes("invalid")) return "INVALID";
21
16
 
22
- return 'ERROR';
17
+ return "ERROR";
23
18
  }
24
19
 
25
20
  /**
@@ -27,25 +22,25 @@ function parseErrorToStatus(error: string): StreamStatus {
27
22
  */
28
23
  function getStatusMessage(status: StreamStatus, percentage?: number): string {
29
24
  switch (status) {
30
- case 'ONLINE':
31
- return 'Stream is online';
32
- case 'OFFLINE':
33
- return 'Stream is offline';
34
- case 'INITIALIZING':
25
+ case "ONLINE":
26
+ return "Stream is online";
27
+ case "OFFLINE":
28
+ return "Stream is offline";
29
+ case "INITIALIZING":
35
30
  return percentage !== undefined
36
31
  ? `Initializing... ${Math.round(percentage * 10) / 10}%`
37
- : 'Stream is initializing';
38
- case 'BOOTING':
39
- return 'Stream is starting up';
40
- case 'WAITING_FOR_DATA':
41
- return 'Waiting for stream data';
42
- case 'SHUTTING_DOWN':
43
- return 'Stream is shutting down';
44
- case 'INVALID':
45
- return 'Stream status is invalid';
46
- case 'ERROR':
32
+ : "Stream is initializing";
33
+ case "BOOTING":
34
+ return "Stream is starting up";
35
+ case "WAITING_FOR_DATA":
36
+ return "Waiting for stream data";
37
+ case "SHUTTING_DOWN":
38
+ return "Stream is shutting down";
39
+ case "INVALID":
40
+ return "Stream status is invalid";
41
+ case "ERROR":
47
42
  default:
48
- return 'Stream error';
43
+ return "Stream error";
49
44
  }
50
45
  }
51
46
 
@@ -53,9 +48,9 @@ function getStatusMessage(status: StreamStatus, percentage?: number): string {
53
48
  * Initial stream state
54
49
  */
55
50
  const initialState: StreamState = {
56
- status: 'OFFLINE',
51
+ status: "OFFLINE",
57
52
  isOnline: false,
58
- message: 'Connecting...',
53
+ message: "Connecting...",
59
54
  lastUpdate: 0,
60
55
  };
61
56
 
@@ -115,7 +110,7 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
115
110
  const status = parseErrorToStatus(data.error);
116
111
  const message = data.on_error || getStatusMessage(status, data.perc);
117
112
 
118
- setState(prev => ({
113
+ setState((prev) => ({
119
114
  status,
120
115
  isOnline: false,
121
116
  message,
@@ -128,10 +123,10 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
128
123
  // Stream is online with valid metadata
129
124
  // Merge new data with existing streamInfo to preserve source/tracks from initial fetch
130
125
  // WebSocket updates may not include source array - only status updates
131
- setState(prev => {
126
+ setState((prev) => {
132
127
  const mergedStreamInfo: MistStreamInfo = {
133
- ...prev.streamInfo, // Keep existing source/meta if present
134
- ...data, // Override with new data
128
+ ...prev.streamInfo, // Keep existing source/meta if present
129
+ ...data, // Override with new data
135
130
  // Explicitly preserve source if not in new data
136
131
  source: data.source || prev.streamInfo?.source,
137
132
  // Merge meta to preserve tracks
@@ -144,9 +139,9 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
144
139
  };
145
140
 
146
141
  return {
147
- status: 'ONLINE',
142
+ status: "ONLINE",
148
143
  isOnline: true,
149
- message: 'Stream is online',
144
+ message: "Stream is online",
150
145
  lastUpdate: Date.now(),
151
146
  streamInfo: mergedStreamInfo,
152
147
  };
@@ -163,11 +158,11 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
163
158
 
164
159
  try {
165
160
  // Build URL with MistPlayer-style params
166
- const baseUrl = `${mistBaseUrl.replace(/\/$/, '')}/json_${encodeURIComponent(streamName)}.js`;
161
+ const baseUrl = `${mistBaseUrl.replace(/\/$/, "")}/json_${encodeURIComponent(streamName)}.js`;
167
162
  const url = `${baseUrl}?metaeverywhere=1&inclzero=1`;
168
163
  const response = await fetch(url, {
169
- method: 'GET',
170
- headers: { 'Accept': 'application/json' },
164
+ method: "GET",
165
+ headers: { Accept: "application/json" },
171
166
  });
172
167
 
173
168
  if (!response.ok) {
@@ -187,13 +182,13 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
187
182
  } catch (error) {
188
183
  if (!mountedRef.current) return;
189
184
 
190
- setState(prev => ({
185
+ setState((prev) => ({
191
186
  ...prev,
192
- status: 'ERROR',
187
+ status: "ERROR",
193
188
  isOnline: false,
194
- message: error instanceof Error ? error.message : 'Connection failed',
189
+ message: error instanceof Error ? error.message : "Connection failed",
195
190
  lastUpdate: Date.now(),
196
- error: error instanceof Error ? error.message : 'Unknown error',
191
+ error: error instanceof Error ? error.message : "Unknown error",
197
192
  }));
198
193
  }
199
194
 
@@ -222,9 +217,9 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
222
217
  try {
223
218
  // Convert http(s) to ws(s)
224
219
  const wsUrl = mistBaseUrl
225
- .replace(/^http:/, 'ws:')
226
- .replace(/^https:/, 'wss:')
227
- .replace(/\/$/, '');
220
+ .replace(/^http:/, "ws:")
221
+ .replace(/^https:/, "wss:")
222
+ .replace(/\/$/, "");
228
223
 
229
224
  // Build URL with MistPlayer-style params
230
225
  const url = `${wsUrl}/json_${encodeURIComponent(streamName)}.js?metaeverywhere=1&inclzero=1`;
@@ -235,7 +230,7 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
235
230
  wsTimeoutRef.current = setTimeout(() => {
236
231
  if (ws.readyState <= WebSocket.OPEN) {
237
232
  if (debug) {
238
- console.debug('[useStreamState] WebSocket timeout (5s), falling back to HTTP polling');
233
+ console.debug("[useStreamState] WebSocket timeout (5s), falling back to HTTP polling");
239
234
  }
240
235
  ws.close();
241
236
  pollHttp();
@@ -244,7 +239,7 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
244
239
 
245
240
  ws.onopen = () => {
246
241
  if (debug) {
247
- console.debug('[useStreamState] WebSocket connected');
242
+ console.debug("[useStreamState] WebSocket connected");
248
243
  }
249
244
  setSocketReady(true);
250
245
  };
@@ -260,12 +255,12 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
260
255
  const data = JSON.parse(event.data) as MistStreamInfo;
261
256
  processStreamInfo(data);
262
257
  } catch (e) {
263
- console.warn('[useStreamState] Failed to parse WebSocket message:', e);
258
+ console.warn("[useStreamState] Failed to parse WebSocket message:", e);
264
259
  }
265
260
  };
266
261
 
267
262
  ws.onerror = (_event) => {
268
- console.warn('[useStreamState] WebSocket error, falling back to HTTP polling');
263
+ console.warn("[useStreamState] WebSocket error, falling back to HTTP polling");
269
264
  if (wsTimeoutRef.current) {
270
265
  clearTimeout(wsTimeoutRef.current);
271
266
  wsTimeoutRef.current = null;
@@ -281,12 +276,12 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
281
276
 
282
277
  // Fallback to HTTP polling or reconnect
283
278
  if (debug) {
284
- console.debug('[useStreamState] WebSocket closed, starting HTTP polling');
279
+ console.debug("[useStreamState] WebSocket closed, starting HTTP polling");
285
280
  }
286
281
  pollHttp();
287
282
  };
288
283
  } catch (error) {
289
- console.warn('[useStreamState] WebSocket connection failed:', error);
284
+ console.warn("[useStreamState] WebSocket connection failed:", error);
290
285
  // Fallback to HTTP polling
291
286
  pollHttp();
292
287
  }
@@ -320,7 +315,7 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
320
315
  // Reset state when stream changes
321
316
  setState({
322
317
  ...initialState,
323
- message: 'Connecting...',
318
+ message: "Connecting...",
324
319
  lastUpdate: Date.now(),
325
320
  });
326
321
 
@@ -342,7 +337,7 @@ export function useStreamState(options: UseStreamStateOptions): UseStreamStateRe
342
337
  // Set mounted=false FIRST before any other cleanup
343
338
  mountedRef.current = false;
344
339
  if (debug) {
345
- console.debug('[useStreamState] cleanup starting, mountedRef set to false');
340
+ console.debug("[useStreamState] cleanup starting, mountedRef set to false");
346
341
  }
347
342
 
348
343
  // Cleanup WebSocket timeout
@@ -1,5 +1,10 @@
1
- import { useEffect, useRef, useCallback } from 'react';
2
- import { TelemetryReporter, type TelemetryOptions, type PlaybackQuality, type ContentType } from '@livepeer-frameworks/player-core';
1
+ import { useEffect, useRef, useCallback } from "react";
2
+ import {
3
+ TelemetryReporter,
4
+ type TelemetryOptions,
5
+ type PlaybackQuality,
6
+ type ContentType,
7
+ } from "@livepeer-frameworks/player-core";
3
8
 
4
9
  export interface UseTelemetryOptions extends TelemetryOptions {
5
10
  /** Video element to monitor */
@@ -87,7 +92,17 @@ export function useTelemetry(options: UseTelemetryOptions) {
87
92
  reporterRef.current?.stop();
88
93
  reporterRef.current = null;
89
94
  };
90
- }, [enabled, endpoint, authToken, interval, batchSize, contentId, contentType, playerType, protocol]);
95
+ }, [
96
+ enabled,
97
+ endpoint,
98
+ authToken,
99
+ interval,
100
+ batchSize,
101
+ contentId,
102
+ contentType,
103
+ playerType,
104
+ protocol,
105
+ ]);
91
106
 
92
107
  // Start/stop reporting when video element changes
93
108
  useEffect(() => {
@@ -1,6 +1,6 @@
1
- import { useEffect, useState, useRef } from 'react';
2
- import type { ContentType } from '@livepeer-frameworks/player-core';
3
- import type { ContentEndpoints } from '../types';
1
+ import { useEffect, useState, useRef } from "react";
2
+ import type { ContentType } from "@livepeer-frameworks/player-core";
3
+ import type { ContentEndpoints } from "../types";
4
4
 
5
5
  const MAX_RETRIES = 3;
6
6
  const INITIAL_DELAY_MS = 500;
@@ -25,7 +25,7 @@ async function fetchWithRetry(
25
25
  const response = await fetch(url, options);
26
26
  return response;
27
27
  } catch (e) {
28
- lastError = e instanceof Error ? e : new Error('Fetch failed');
28
+ lastError = e instanceof Error ? e : new Error("Fetch failed");
29
29
 
30
30
  // Don't retry on abort
31
31
  if (options.signal?.aborted) {
@@ -35,24 +35,31 @@ async function fetchWithRetry(
35
35
  // Wait before retrying (exponential backoff)
36
36
  if (attempt < maxRetries - 1) {
37
37
  const delay = initialDelay * Math.pow(2, attempt);
38
- console.warn(`[useViewerEndpoints] Retry ${attempt + 1}/${maxRetries - 1} after ${delay}ms`);
39
- await new Promise(resolve => setTimeout(resolve, delay));
38
+ console.warn(
39
+ `[useViewerEndpoints] Retry ${attempt + 1}/${maxRetries - 1} after ${delay}ms`
40
+ );
41
+ await new Promise((resolve) => setTimeout(resolve, delay));
40
42
  }
41
43
  }
42
44
  }
43
45
 
44
- throw lastError ?? new Error('Gateway unreachable after retries');
46
+ throw lastError ?? new Error("Gateway unreachable after retries");
45
47
  }
46
48
 
47
- export function useViewerEndpoints({ gatewayUrl, contentType: _contentType, contentId, authToken }: Params) {
49
+ export function useViewerEndpoints({
50
+ gatewayUrl,
51
+ contentType: _contentType,
52
+ contentId,
53
+ authToken,
54
+ }: Params) {
48
55
  const [endpoints, setEndpoints] = useState<ContentEndpoints | null>(null);
49
- const [status, setStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle');
56
+ const [status, setStatus] = useState<"idle" | "loading" | "ready" | "error">("idle");
50
57
  const [error, setError] = useState<string | null>(null);
51
58
  const abortRef = useRef<AbortController | null>(null);
52
59
 
53
60
  useEffect(() => {
54
61
  if (!gatewayUrl || !contentId) return;
55
- setStatus('loading');
62
+ setStatus("loading");
56
63
  setError(null);
57
64
  abortRef.current?.abort();
58
65
  const ac = new AbortController();
@@ -60,7 +67,7 @@ export function useViewerEndpoints({ gatewayUrl, contentType: _contentType, cont
60
67
 
61
68
  (async () => {
62
69
  try {
63
- const graphqlEndpoint = gatewayUrl.replace(/\/$/, '');
70
+ const graphqlEndpoint = gatewayUrl.replace(/\/$/, "");
64
71
  const query = `
65
72
  query ResolveViewer($contentId: String!) {
66
73
  resolveViewerEndpoint(contentId: $contentId) {
@@ -71,9 +78,9 @@ export function useViewerEndpoints({ gatewayUrl, contentType: _contentType, cont
71
78
  }
72
79
  `;
73
80
  const res = await fetchWithRetry(graphqlEndpoint, {
74
- method: 'POST',
81
+ method: "POST",
75
82
  headers: {
76
- 'Content-Type': 'application/json',
83
+ "Content-Type": "application/json",
77
84
  ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
78
85
  },
79
86
  body: JSON.stringify({ query, variables: { contentId } }),
@@ -81,32 +88,36 @@ export function useViewerEndpoints({ gatewayUrl, contentType: _contentType, cont
81
88
  });
82
89
  if (!res.ok) throw new Error(`Gateway GQL error ${res.status}`);
83
90
  const payload = await res.json();
84
- if (payload.errors?.length) throw new Error(payload.errors[0]?.message || 'GraphQL error');
91
+ if (payload.errors?.length) throw new Error(payload.errors[0]?.message || "GraphQL error");
85
92
  const resp = payload.data?.resolveViewerEndpoint;
86
93
  const primary = resp?.primary;
87
94
  const fallbacks = Array.isArray(resp?.fallbacks) ? resp.fallbacks : [];
88
- if (!primary) throw new Error('No endpoints');
95
+ if (!primary) throw new Error("No endpoints");
89
96
 
90
97
  // Parse outputs JSON string (GraphQL returns JSON scalar as string)
91
- if (primary.outputs && typeof primary.outputs === 'string') {
92
- try { primary.outputs = JSON.parse(primary.outputs); } catch {}
98
+ if (primary.outputs && typeof primary.outputs === "string") {
99
+ try {
100
+ primary.outputs = JSON.parse(primary.outputs);
101
+ } catch {}
93
102
  }
94
103
  if (fallbacks) {
95
104
  fallbacks.forEach((fb: any) => {
96
- if (fb.outputs && typeof fb.outputs === 'string') {
97
- try { fb.outputs = JSON.parse(fb.outputs); } catch {}
105
+ if (fb.outputs && typeof fb.outputs === "string") {
106
+ try {
107
+ fb.outputs = JSON.parse(fb.outputs);
108
+ } catch {}
98
109
  }
99
110
  });
100
111
  }
101
112
 
102
113
  setEndpoints({ primary, fallbacks, metadata: resp?.metadata });
103
- setStatus('ready');
114
+ setStatus("ready");
104
115
  } catch (e) {
105
116
  if (ac.signal.aborted) return;
106
- const message = e instanceof Error ? e.message : 'Unknown gateway error';
107
- console.error('[useViewerEndpoints] Gateway resolution failed:', message);
117
+ const message = e instanceof Error ? e.message : "Unknown gateway error";
118
+ console.error("[useViewerEndpoints] Gateway resolution failed:", message);
108
119
  setError(message);
109
- setStatus('error');
120
+ setStatus("error");
110
121
  }
111
122
  })();
112
123
 
package/src/index.tsx CHANGED
@@ -5,48 +5,56 @@
5
5
  */
6
6
 
7
7
  // Main player component
8
- export { default as Player } from './components/Player';
9
- export { default as PlayerControls } from './components/PlayerControls';
8
+ export { default as Player } from "./components/Player";
9
+ export { default as PlayerControls } from "./components/PlayerControls";
10
10
 
11
11
  // Overlay components
12
- export { default as LoadingScreen } from './components/LoadingScreen';
13
- export { default as IdleScreen } from './components/IdleScreen';
14
- export { default as ThumbnailOverlay } from './components/ThumbnailOverlay';
15
- export { default as TitleOverlay } from './components/TitleOverlay';
16
- export { default as StreamStateOverlay } from './components/StreamStateOverlay';
17
- export { default as StatsPanel } from './components/StatsPanel';
18
- export { default as DevModePanel } from './components/DevModePanel';
19
- export { default as PlayerErrorBoundary } from './components/PlayerErrorBoundary';
12
+ export { default as LoadingScreen } from "./components/LoadingScreen";
13
+ export { default as IdleScreen } from "./components/IdleScreen";
14
+ export { default as ThumbnailOverlay } from "./components/ThumbnailOverlay";
15
+ export { default as TitleOverlay } from "./components/TitleOverlay";
16
+ export { default as StreamStateOverlay } from "./components/StreamStateOverlay";
17
+ export { default as StatsPanel } from "./components/StatsPanel";
18
+ export { default as DevModePanel } from "./components/DevModePanel";
19
+ export { default as PlayerErrorBoundary } from "./components/PlayerErrorBoundary";
20
20
 
21
21
  // Icon components
22
- export * from './components/Icons';
22
+ export * from "./components/Icons";
23
23
 
24
24
  // UI primitives
25
- export { Button } from './ui/button';
26
- export { Badge } from './ui/badge';
27
- export { Slider } from './ui/slider';
25
+ export { Button } from "./ui/button";
26
+ export { Badge } from "./ui/badge";
27
+ export { Slider } from "./ui/slider";
28
28
 
29
29
  // Context
30
- export { PlayerProvider, usePlayerContext, usePlayerContextOptional, PlayerContext } from './context/PlayerContext';
31
- export type { PlayerContextValue } from './context/PlayerContext';
30
+ export {
31
+ PlayerProvider,
32
+ usePlayerContext,
33
+ usePlayerContextOptional,
34
+ PlayerContext,
35
+ } from "./context/PlayerContext";
36
+ export type { PlayerContextValue } from "./context/PlayerContext";
32
37
 
33
38
  // Hooks
34
- export { useStreamState } from './hooks/useStreamState';
35
- export { usePlaybackQuality } from './hooks/usePlaybackQuality';
36
- export { useViewerEndpoints } from './hooks/useViewerEndpoints';
37
- export { useMetaTrack } from './hooks/useMetaTrack';
38
- export { useTelemetry } from './hooks/useTelemetry';
39
- export { usePlayerSelection } from './hooks/usePlayerSelection';
40
- export type { UsePlayerSelectionOptions, UsePlayerSelectionReturn } from './hooks/usePlayerSelection';
41
- export { usePlayerController } from './hooks/usePlayerController';
39
+ export { useStreamState } from "./hooks/useStreamState";
40
+ export { usePlaybackQuality } from "./hooks/usePlaybackQuality";
41
+ export { useViewerEndpoints } from "./hooks/useViewerEndpoints";
42
+ export { useMetaTrack } from "./hooks/useMetaTrack";
43
+ export { useTelemetry } from "./hooks/useTelemetry";
44
+ export { usePlayerSelection } from "./hooks/usePlayerSelection";
45
+ export type {
46
+ UsePlayerSelectionOptions,
47
+ UsePlayerSelectionReturn,
48
+ } from "./hooks/usePlayerSelection";
49
+ export { usePlayerController } from "./hooks/usePlayerController";
42
50
  export type {
43
51
  UsePlayerControllerConfig,
44
52
  UsePlayerControllerReturn,
45
53
  PlayerControllerState,
46
- } from './hooks/usePlayerController';
54
+ } from "./hooks/usePlayerController";
47
55
 
48
56
  // Types
49
- export * from './types';
57
+ export * from "./types";
50
58
 
51
59
  // Re-export commonly used core items
52
60
  export {
@@ -57,7 +65,7 @@ export {
57
65
  StreamStateClient,
58
66
  QualityMonitor,
59
67
  cn,
60
- } from '@livepeer-frameworks/player-core';
68
+ } from "@livepeer-frameworks/player-core";
61
69
 
62
70
  export type {
63
71
  PlayerState,
@@ -72,4 +80,4 @@ export type {
72
80
  PlayerSelection,
73
81
  PlayerCombination,
74
82
  PlayerManagerEvents,
75
- } from '@livepeer-frameworks/player-core';
83
+ } from "@livepeer-frameworks/player-core";
package/src/types.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * React-specific types for FrameWorks player
3
3
  */
4
- import type React from 'react';
5
- import type {
6
- PlayerOptions,
7
- PlayerState,
8
- PlayerStateContext,
4
+ import type React from "react";
5
+ import type {
6
+ PlayerOptions,
7
+ PlayerState,
8
+ PlayerStateContext,
9
9
  ContentEndpoints,
10
10
  MetaTrackSubscription,
11
11
  PlaybackQuality,
12
12
  QualityThresholds,
13
- ContentType
14
- } from '@livepeer-frameworks/player-core';
13
+ ContentType,
14
+ } from "@livepeer-frameworks/player-core";
15
15
 
16
16
  export interface PlayerProps {
17
17
  /** Content identifier or stream name */
@@ -132,4 +132,4 @@ export type {
132
132
  StreamStatus,
133
133
  EndpointInfo,
134
134
  ContentMetadata,
135
- } from '@livepeer-frameworks/player-core';
135
+ } from "@livepeer-frameworks/player-core";
package/src/ui/badge.tsx CHANGED
@@ -9,16 +9,17 @@ const badgeVariants = cva(
9
9
  variant: {
10
10
  default: "bg-primary text-primary-foreground hover:bg-primary/80",
11
11
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
12
- outline: "border-border text-foreground"
13
- }
12
+ outline: "border-border text-foreground",
13
+ },
14
14
  },
15
15
  defaultVariants: {
16
- variant: "default"
17
- }
16
+ variant: "default",
17
+ },
18
18
  }
19
19
  );
20
20
 
21
- export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
21
+ export interface BadgeProps
22
+ extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
22
23
 
23
24
  function Badge({ className, variant, ...props }: BadgeProps) {
24
25
  return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
package/src/ui/button.tsx CHANGED
@@ -14,32 +14,33 @@ const buttonVariants = cva(
14
14
  outline: "border border-border bg-transparent hover:bg-accent hover:text-accent-foreground",
15
15
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
16
16
  subtle: "bg-muted text-muted-foreground hover:bg-muted/80",
17
- link: "text-primary underline-offset-4 hover:underline"
17
+ link: "text-primary underline-offset-4 hover:underline",
18
18
  },
19
19
  size: {
20
20
  default: "h-10 px-4 py-2",
21
21
  sm: "h-9 rounded-md px-3",
22
22
  lg: "h-11 rounded-md px-8",
23
- icon: "h-9 w-9"
24
- }
23
+ icon: "h-9 w-9",
24
+ },
25
25
  },
26
26
  defaultVariants: {
27
27
  variant: "default",
28
- size: "default"
29
- }
28
+ size: "default",
29
+ },
30
30
  }
31
31
  );
32
32
 
33
33
  export interface ButtonProps
34
- extends React.ButtonHTMLAttributes<HTMLButtonElement>,
35
- VariantProps<typeof buttonVariants> {
34
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
36
35
  asChild?: boolean;
37
36
  }
38
37
 
39
38
  const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
40
39
  ({ className, variant, size, asChild = false, ...props }, ref) => {
41
40
  const Comp = asChild ? Slot : "button";
42
- return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
41
+ return (
42
+ <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
43
+ );
43
44
  }
44
45
  );
45
46
  Button.displayName = "Button";