kodenique-game-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/dist/GameContext.d.ts +4 -0
  4. package/dist/GameContext.js +327 -0
  5. package/dist/GameDebug.d.ts +5 -0
  6. package/dist/GameDebug.js +172 -0
  7. package/dist/GamePlayer.d.ts +26 -0
  8. package/dist/GamePlayer.js +54 -0
  9. package/dist/SimplePlayer.d.ts +11 -0
  10. package/dist/SimplePlayer.js +41 -0
  11. package/dist/components/GamePlayerOverlays.d.ts +29 -0
  12. package/dist/components/GamePlayerOverlays.js +467 -0
  13. package/dist/components/GamePlayerVideo.d.ts +7 -0
  14. package/dist/components/GamePlayerVideo.js +86 -0
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/index.js +2 -0
  17. package/dist/config.d.ts +50 -0
  18. package/dist/config.js +46 -0
  19. package/dist/contexts/GameStreamContext.d.ts +24 -0
  20. package/dist/contexts/GameStreamContext.js +170 -0
  21. package/dist/examples/GameStreamExample.d.ts +26 -0
  22. package/dist/examples/GameStreamExample.js +92 -0
  23. package/dist/examples/SimpleAutoSubscribe.d.ts +9 -0
  24. package/dist/examples/SimpleAutoSubscribe.js +29 -0
  25. package/dist/hooks/index.d.ts +2 -0
  26. package/dist/hooks/index.js +1 -0
  27. package/dist/hooks/useGameStream.d.ts +29 -0
  28. package/dist/hooks/useGameStream.js +78 -0
  29. package/dist/hooks/useWebRTC.d.ts +21 -0
  30. package/dist/hooks/useWebRTC.js +555 -0
  31. package/dist/index.d.ts +13 -0
  32. package/dist/index.js +12 -0
  33. package/dist/lib/pusher.d.ts +50 -0
  34. package/dist/lib/pusher.js +137 -0
  35. package/dist/types.d.ts +87 -0
  36. package/dist/types.js +1 -0
  37. package/dist/useGames.d.ts +2 -0
  38. package/dist/useGames.js +73 -0
  39. package/package.json +66 -0
@@ -0,0 +1,24 @@
1
+ import React, { ReactNode } from "react";
2
+ import type { Game } from "../types";
3
+ interface GameStreamContextType {
4
+ activeGames: Game[];
5
+ subscribeToGame: (gameId: string) => void;
6
+ unsubscribeFromGame: (gameId: string) => void;
7
+ getGame: (gameId: string) => Game | undefined;
8
+ updateGame: (game: Game) => void;
9
+ isConnected: boolean;
10
+ subscribedGameIds: string[];
11
+ }
12
+ interface GameStreamProviderProps {
13
+ children: ReactNode;
14
+ socketToken?: string;
15
+ environment?: 'development' | 'staging' | 'production';
16
+ websocketUrl?: string;
17
+ pusherConfig?: {
18
+ key: string;
19
+ cluster: string;
20
+ };
21
+ }
22
+ export declare const GameStreamProvider: React.FC<GameStreamProviderProps>;
23
+ export declare const useGameStreamContext: () => GameStreamContextType;
24
+ export {};
@@ -0,0 +1,170 @@
1
+ import React, { createContext, useContext, useEffect, useState, useCallback } from "react";
2
+ import { GamePusherClient } from "../lib/pusher";
3
+ import { getWebSocketUrl } from "../config";
4
+ const GameStreamContext = createContext(undefined);
5
+ export const GameStreamProvider = ({ children, socketToken, environment = 'development', websocketUrl: customWebsocketUrl, pusherConfig, }) => {
6
+ const [activeGames, setActiveGames] = useState([]);
7
+ const [subscribedGameIds, setSubscribedGameIds] = useState([]);
8
+ const [isConnected, setIsConnected] = useState(false);
9
+ const [websocket, setWebsocket] = useState(null);
10
+ const [pusherClient, setPusherClient] = useState(null);
11
+ // Determine the WebSocket URL to use
12
+ const websocketUrl = customWebsocketUrl || (socketToken ? getWebSocketUrl(environment, socketToken) : undefined);
13
+ // Initialize Pusher connection
14
+ useEffect(() => {
15
+ if (!pusherConfig)
16
+ return;
17
+ console.log("[GameStreamContext] Initializing Pusher");
18
+ const client = new GamePusherClient(pusherConfig);
19
+ client.connect();
20
+ setPusherClient(client);
21
+ setIsConnected(client.isConnected());
22
+ return () => {
23
+ console.log("[GameStreamContext] Cleaning up Pusher");
24
+ client.disconnect();
25
+ };
26
+ }, [pusherConfig]);
27
+ // Initialize WebSocket connection
28
+ useEffect(() => {
29
+ if (!websocketUrl || pusherConfig)
30
+ return; // Skip if using Pusher
31
+ console.log("[GameStreamContext] Connecting to WebSocket:", websocketUrl);
32
+ const ws = new WebSocket(websocketUrl);
33
+ ws.onopen = () => {
34
+ console.log("[GameStreamContext] WebSocket connected");
35
+ setIsConnected(true);
36
+ };
37
+ ws.onclose = () => {
38
+ console.log("[GameStreamContext] WebSocket disconnected");
39
+ setIsConnected(false);
40
+ };
41
+ ws.onerror = (error) => {
42
+ console.error("[GameStreamContext] WebSocket error:", error);
43
+ setIsConnected(false);
44
+ };
45
+ ws.onmessage = (event) => {
46
+ try {
47
+ const data = JSON.parse(event.data);
48
+ console.log("[GameStreamContext] Received message:", data);
49
+ // Handle different message types
50
+ if (data.type === "game_update") {
51
+ updateGame(data.game);
52
+ }
53
+ else if (data.type === "game_ended") {
54
+ removeGame(data.gameId);
55
+ }
56
+ else if (data.type === "score_update") {
57
+ updateGameScore(data.gameId, data.scores);
58
+ }
59
+ }
60
+ catch (error) {
61
+ console.error("[GameStreamContext] Error parsing message:", error);
62
+ }
63
+ };
64
+ setWebsocket(ws);
65
+ return () => {
66
+ console.log("[GameStreamContext] Cleaning up WebSocket");
67
+ ws.close();
68
+ };
69
+ }, [websocketUrl, pusherConfig]);
70
+ // Subscribe to a game
71
+ const subscribeToGame = useCallback((gameId) => {
72
+ console.log("[GameStreamContext] Subscribing to game:", gameId);
73
+ setSubscribedGameIds((prev) => {
74
+ if (prev.includes(gameId))
75
+ return prev;
76
+ return [...prev, gameId];
77
+ });
78
+ // Use Pusher if available
79
+ if (pusherClient) {
80
+ pusherClient.subscribeToGame(gameId, {
81
+ onGameUpdate: updateGame,
82
+ onScoreUpdate: (scores) => updateGameScore(gameId, scores),
83
+ onStatusUpdate: (status) => {
84
+ // Update game status
85
+ setActiveGames((prev) => prev.map((g) => (g.id === gameId ? Object.assign(Object.assign({}, g), { status: status }) : g)));
86
+ },
87
+ onGameEnded: () => removeGame(gameId),
88
+ });
89
+ }
90
+ // Otherwise use WebSocket
91
+ else if (websocket && websocket.readyState === WebSocket.OPEN) {
92
+ websocket.send(JSON.stringify({
93
+ action: "subscribe",
94
+ gameId,
95
+ }));
96
+ }
97
+ }, [websocket, pusherClient]);
98
+ // Unsubscribe from a game
99
+ const unsubscribeFromGame = useCallback((gameId) => {
100
+ console.log("[GameStreamContext] Unsubscribing from game:", gameId);
101
+ setSubscribedGameIds((prev) => prev.filter((id) => id !== gameId));
102
+ // Use Pusher if available
103
+ if (pusherClient) {
104
+ pusherClient.unsubscribeFromGame(gameId);
105
+ }
106
+ // Otherwise use WebSocket
107
+ else if (websocket && websocket.readyState === WebSocket.OPEN) {
108
+ websocket.send(JSON.stringify({
109
+ action: "unsubscribe",
110
+ gameId,
111
+ }));
112
+ }
113
+ }, [websocket, pusherClient]);
114
+ // Get a specific game
115
+ const getGame = useCallback((gameId) => {
116
+ return activeGames.find((game) => game.id === gameId);
117
+ }, [activeGames]);
118
+ // Update game data
119
+ const updateGame = useCallback((game) => {
120
+ console.log("[GameStreamContext] Updating game:", game.id);
121
+ setActiveGames((prev) => {
122
+ const existingIndex = prev.findIndex((g) => g.id === game.id);
123
+ if (existingIndex >= 0) {
124
+ // Update existing game
125
+ const updated = [...prev];
126
+ updated[existingIndex] = game;
127
+ return updated;
128
+ }
129
+ else {
130
+ // Add new game
131
+ return [...prev, game];
132
+ }
133
+ });
134
+ }, []);
135
+ // Remove game (when ended)
136
+ const removeGame = useCallback((gameId) => {
137
+ console.log("[GameStreamContext] Removing game:", gameId);
138
+ setActiveGames((prev) => prev.filter((g) => g.id !== gameId));
139
+ }, []);
140
+ // Update game score only
141
+ const updateGameScore = useCallback((gameId, scores) => {
142
+ console.log("[GameStreamContext] Updating score for game:", gameId, scores);
143
+ setActiveGames((prev) => {
144
+ return prev.map((game) => {
145
+ if (game.id === gameId) {
146
+ return Object.assign(Object.assign({}, game), { teams: game.teams.map((team, index) => (Object.assign(Object.assign({}, team), { current_score: scores[index] || team.current_score }))) });
147
+ }
148
+ return game;
149
+ });
150
+ });
151
+ }, []);
152
+ const value = {
153
+ activeGames,
154
+ subscribeToGame,
155
+ unsubscribeFromGame,
156
+ getGame,
157
+ updateGame,
158
+ isConnected,
159
+ subscribedGameIds,
160
+ };
161
+ return (React.createElement(GameStreamContext.Provider, { value: value }, children));
162
+ };
163
+ // Custom hook to use game stream context
164
+ export const useGameStreamContext = () => {
165
+ const context = useContext(GameStreamContext);
166
+ if (!context) {
167
+ throw new Error("useGameStreamContext must be used within GameStreamProvider");
168
+ }
169
+ return context;
170
+ };
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ /**
3
+ * Example 1: Using GameProvider with WebSocket (Recommended)
4
+ * User only needs to pass their socket token!
5
+ */
6
+ export declare const GameStreamWithSocketTokenExample: () => React.JSX.Element;
7
+ /**
8
+ * Example 2: Using custom WebSocket URL (Advanced)
9
+ */
10
+ export declare const GameStreamWithCustomWebSocketExample: () => React.JSX.Element;
11
+ /**
12
+ * Example: Multiple games with subscriptions
13
+ */
14
+ export declare const MultipleGamesExample: () => React.JSX.Element;
15
+ /**
16
+ * Example: Manual subscription control
17
+ */
18
+ export declare const ManualSubscriptionExample: React.FC<{
19
+ gameId: string;
20
+ }>;
21
+ /**
22
+ * Example: Customizing overlay display
23
+ */
24
+ export declare const CustomOverlayExample: React.FC<{
25
+ gameId: string;
26
+ }>;
@@ -0,0 +1,92 @@
1
+ import React from "react";
2
+ import { GamePlayer } from "../GamePlayer";
3
+ import { GameProvider } from "../GameContext";
4
+ import { useGameStream } from "../hooks/useGameStream";
5
+ /**
6
+ * Example 1: Using GameProvider with WebSocket (Recommended)
7
+ * User only needs to pass their socket token!
8
+ */
9
+ export const GameStreamWithSocketTokenExample = () => {
10
+ return (React.createElement(GameProvider, { access_token: "your-api-access-token", socketToken: "your-socket-auth-token", environment: "production" // or 'staging' or 'development'
11
+ },
12
+ React.createElement(GamePlayerWithSubscription, { gameId: "game-123" })));
13
+ };
14
+ /**
15
+ * Example 2: Using custom WebSocket URL (Advanced)
16
+ */
17
+ export const GameStreamWithCustomWebSocketExample = () => {
18
+ return (React.createElement(GameProvider, { access_token: "your-api-access-token", websocketUrl: "wss://your-custom-websocket-server.com?token=abc123" },
19
+ React.createElement(GamePlayerWithSubscription, { gameId: "game-123" })));
20
+ };
21
+ /**
22
+ * Component that subscribes to game updates
23
+ */
24
+ const GamePlayerWithSubscription = ({ gameId }) => {
25
+ // Subscribe to game updates
26
+ const { game, isSubscribed, isConnected } = useGameStream({
27
+ gameId,
28
+ autoSubscribe: true,
29
+ });
30
+ return (React.createElement("div", null,
31
+ React.createElement("div", { className: "mb-4 flex items-center gap-2" },
32
+ React.createElement("div", { className: `h-3 w-3 rounded-full ${isConnected ? "bg-green-500" : "bg-red-500"}` }),
33
+ React.createElement("span", { className: "text-sm" }, isConnected ? "Connected" : "Disconnected"),
34
+ isSubscribed && (React.createElement("span", { className: "text-sm text-gray-500" },
35
+ "(Subscribed to ",
36
+ gameId,
37
+ ")"))),
38
+ React.createElement(GamePlayer, { streamUrl: "http://your-stream-server.com/stream", game: game, showScoreOverlay: true, showNetworkIndicator: true, showGameTitle: true, showRound: true, width: "100%", height: "600px" }),
39
+ game && (React.createElement("div", { className: "mt-4 rounded-lg bg-gray-100 p-4" },
40
+ React.createElement("h3", { className: "mb-2 text-lg font-bold" }, game.game_name),
41
+ React.createElement("div", { className: "flex gap-4" }, game.teams.map((team) => (React.createElement("div", { key: team.id, className: "flex-1" },
42
+ React.createElement("div", { className: "font-semibold", style: { color: team.team_color } }, team.team_name),
43
+ React.createElement("div", { className: "text-2xl font-bold" }, team.current_score))))),
44
+ React.createElement("div", { className: "mt-2 text-sm text-gray-600" },
45
+ "Status: ",
46
+ game.status)))));
47
+ };
48
+ /**
49
+ * Example: Multiple games with subscriptions
50
+ */
51
+ export const MultipleGamesExample = () => {
52
+ const gameIds = ["game-1", "game-2", "game-3"];
53
+ return (React.createElement(GameProvider, { access_token: "your-api-access-token", socketToken: "your-socket-auth-token", environment: "production" },
54
+ React.createElement("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3" }, gameIds.map((gameId) => (React.createElement(GamePlayerWithSubscription, { key: gameId, gameId: gameId }))))));
55
+ };
56
+ /**
57
+ * Example: Manual subscription control
58
+ */
59
+ export const ManualSubscriptionExample = ({ gameId, }) => {
60
+ const { game, isSubscribed, subscribe, unsubscribe } = useGameStream({
61
+ gameId,
62
+ autoSubscribe: false, // Don't auto-subscribe
63
+ });
64
+ return (React.createElement("div", null,
65
+ React.createElement("div", { className: "mb-4 flex gap-2" },
66
+ React.createElement("button", { onClick: subscribe, disabled: isSubscribed, className: "rounded bg-blue-500 px-4 py-2 text-white disabled:bg-gray-300" }, "Subscribe"),
67
+ React.createElement("button", { onClick: unsubscribe, disabled: !isSubscribed, className: "rounded bg-red-500 px-4 py-2 text-white disabled:bg-gray-300" }, "Unsubscribe"),
68
+ React.createElement("span", { className: "flex items-center text-sm" }, isSubscribed ? "✓ Subscribed" : "○ Not subscribed")),
69
+ game && (React.createElement(GamePlayer, { streamUrl: "http://your-stream-server.com/stream", game: game, showScoreOverlay: true, gameTitle: "Custom Game Title", showGameTitle: true, showRound: true }))));
70
+ };
71
+ /**
72
+ * Example: Customizing overlay display
73
+ */
74
+ export const CustomOverlayExample = ({ gameId, }) => {
75
+ const { game } = useGameStream({
76
+ gameId,
77
+ autoSubscribe: true,
78
+ });
79
+ return (React.createElement("div", { className: "space-y-6" },
80
+ React.createElement("div", null,
81
+ React.createElement("h3", { className: "mb-2 font-bold" }, "With Custom Title and Round"),
82
+ React.createElement(GamePlayer, { game: game, streamUrl: "http://your-stream-server.com/stream", showScoreOverlay: true, gameTitle: "Championship Finals", showGameTitle: true, showRound: true, width: "100%", height: "400px" })),
83
+ React.createElement("div", null,
84
+ React.createElement("h3", { className: "mb-2 font-bold" }, "Round and Scores Only"),
85
+ React.createElement(GamePlayer, { game: game, streamUrl: "http://your-stream-server.com/stream", showScoreOverlay: true, showGameTitle: false, showRound: true, width: "100%", height: "400px" })),
86
+ React.createElement("div", null,
87
+ React.createElement("h3", { className: "mb-2 font-bold" }, "Scores Only"),
88
+ React.createElement(GamePlayer, { game: game, streamUrl: "http://your-stream-server.com/stream", showScoreOverlay: true, showGameTitle: false, showRound: false, width: "100%", height: "400px" })),
89
+ React.createElement("div", null,
90
+ React.createElement("h3", { className: "mb-2 font-bold" }, "No Overlay"),
91
+ React.createElement(GamePlayer, { game: game, streamUrl: "http://your-stream-server.com/stream", showScoreOverlay: false, width: "100%", height: "400px" }))));
92
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Simple Auto-Subscribe Example
3
+ *
4
+ * This example shows the easiest way to use the Game SDK.
5
+ * Just pass the game object to GamePlayer - the SDK handles everything automatically!
6
+ */
7
+ import React from 'react';
8
+ declare function App(): React.JSX.Element;
9
+ export default App;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Simple Auto-Subscribe Example
3
+ *
4
+ * This example shows the easiest way to use the Game SDK.
5
+ * Just pass the game object to GamePlayer - the SDK handles everything automatically!
6
+ */
7
+ import React from 'react';
8
+ import { GameProvider, GamePlayer, useGames } from '../index';
9
+ function App() {
10
+ return (React.createElement(GameProvider, { access_token: "your-access-token", socketToken: "your-socket-token", environment: "production" // or "development" or "staging"
11
+ },
12
+ React.createElement(GamePage, null)));
13
+ }
14
+ function GamePage() {
15
+ // Fetch games from API
16
+ const { games, loading } = useGames({
17
+ access_token: 'your-access-token',
18
+ api_url: 'https://api.example.com/v1/external/games'
19
+ });
20
+ if (loading)
21
+ return React.createElement("div", null, "Loading games...");
22
+ const game = games[0]; // Or select specific game
23
+ return (React.createElement("div", null,
24
+ React.createElement("h1", null,
25
+ "Live Game: ", game === null || game === void 0 ? void 0 :
26
+ game.game_name),
27
+ React.createElement(GamePlayer, { game: game, showScoreOverlay: true, showGameTitle: false, showRound: true, autoPlay: true, muted: true, width: "100%", height: "600px" })));
28
+ }
29
+ export default App;
@@ -0,0 +1,2 @@
1
+ export { useWebRTC } from "./useWebRTC";
2
+ export type { UseWebRTCOptions, UseWebRTCReturn } from "./useWebRTC";
@@ -0,0 +1 @@
1
+ export { useWebRTC } from "./useWebRTC";
@@ -0,0 +1,29 @@
1
+ import type { Game } from "../types";
2
+ interface UseGameStreamOptions {
3
+ gameId?: string;
4
+ autoSubscribe?: boolean;
5
+ }
6
+ export interface UseGameStreamReturn {
7
+ game: Game | undefined;
8
+ isSubscribed: boolean;
9
+ isConnected: boolean;
10
+ subscribe: () => void;
11
+ unsubscribe: () => void;
12
+ updateGame: (game: Game) => void;
13
+ }
14
+ /**
15
+ * Hook to subscribe to a specific game's real-time updates
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * const { game, isSubscribed, subscribe } = useGameStream({
20
+ * gameId: "game-123",
21
+ * autoSubscribe: true
22
+ * });
23
+ *
24
+ * // Game data updates automatically via WebSocket
25
+ * console.log(game?.teams[0].current_score);
26
+ * ```
27
+ */
28
+ export declare function useGameStream(options?: UseGameStreamOptions): UseGameStreamReturn;
29
+ export {};
@@ -0,0 +1,78 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useGameContext } from "../GameContext";
3
+ /**
4
+ * Hook to subscribe to a specific game's real-time updates
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * const { game, isSubscribed, subscribe } = useGameStream({
9
+ * gameId: "game-123",
10
+ * autoSubscribe: true
11
+ * });
12
+ *
13
+ * // Game data updates automatically via WebSocket
14
+ * console.log(game?.teams[0].current_score);
15
+ * ```
16
+ */
17
+ export function useGameStream(options = {}) {
18
+ const { gameId, autoSubscribe = true } = options;
19
+ const { subscribeToGame, unsubscribeFromGame, getGame, updateGame: updateGameContext, isConnected, subscribedGameIds, activeGames, } = useGameContext();
20
+ const [game, setGame] = useState(undefined);
21
+ // Check if currently subscribed
22
+ const isSubscribed = gameId ? subscribedGameIds.includes(gameId) : false;
23
+ // Subscribe function
24
+ const subscribe = () => {
25
+ if (!gameId)
26
+ return;
27
+ subscribeToGame(gameId);
28
+ };
29
+ // Unsubscribe function
30
+ const unsubscribe = () => {
31
+ if (!gameId)
32
+ return;
33
+ unsubscribeFromGame(gameId);
34
+ };
35
+ // Auto-subscribe on mount if enabled, but wait for connection
36
+ useEffect(() => {
37
+ if (autoSubscribe && gameId && isConnected) {
38
+ console.log('[useGameStream] Auto-subscribing to game:', gameId);
39
+ subscribe();
40
+ }
41
+ return () => {
42
+ if (autoSubscribe && gameId) {
43
+ unsubscribe();
44
+ }
45
+ };
46
+ }, [gameId, autoSubscribe, isConnected]);
47
+ // Update local game state when context changes
48
+ useEffect(() => {
49
+ if (!gameId)
50
+ return;
51
+ const currentGame = getGame(gameId);
52
+ console.log('[useGameStream] Context activeGames changed, updating local game state');
53
+ console.log('[useGameStream] Current game from context:', currentGame);
54
+ if (currentGame) {
55
+ setGame(currentGame);
56
+ }
57
+ }, [gameId, activeGames, getGame]);
58
+ // Listen for game updates - poll every second
59
+ useEffect(() => {
60
+ if (!gameId || !isSubscribed)
61
+ return;
62
+ const interval = setInterval(() => {
63
+ const currentGame = getGame(gameId);
64
+ if (currentGame) {
65
+ setGame(currentGame);
66
+ }
67
+ }, 1000);
68
+ return () => clearInterval(interval);
69
+ }, [gameId, isSubscribed, getGame]);
70
+ return {
71
+ game,
72
+ isSubscribed,
73
+ isConnected,
74
+ subscribe,
75
+ unsubscribe,
76
+ updateGame: updateGameContext,
77
+ };
78
+ }
@@ -0,0 +1,21 @@
1
+ export interface UseWebRTCOptions {
2
+ streamUrl?: string;
3
+ serverUrl?: string;
4
+ streamName?: string;
5
+ autoPlay?: boolean;
6
+ muted?: boolean;
7
+ onLoad?: () => void;
8
+ onError?: (error: Error) => void;
9
+ onConnectionStateChange?: (state: RTCPeerConnectionState) => void;
10
+ }
11
+ export interface UseWebRTCReturn {
12
+ videoRef: React.RefObject<HTMLVideoElement>;
13
+ isLoading: boolean;
14
+ hasError: boolean;
15
+ errorMessage: string;
16
+ networkQuality: "good" | "fair" | "poor" | "bad";
17
+ latency: number;
18
+ bitrate: number;
19
+ retry: () => void;
20
+ }
21
+ export declare function useWebRTC(options: UseWebRTCOptions): UseWebRTCReturn;