diff --git a/src/App.tsx b/src/App.tsx index 158b3ab..8e83645 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,12 @@ -import { useAuth0 } from '@auth0/auth0-react'; -import { lazy, Suspense, useEffect } from 'react'; +import {useAuth0} from '@auth0/auth0-react'; +import {lazy, Suspense, useEffect} from 'react'; import {BrowserRouter, Routes, Route} from 'react-router-dom'; import Layout from './Layout'; -const Home = lazy(() => import('@/pages/Home')); +const Home = lazy(async () => import('@/pages/Home')); const App = () : JSX.Element => { - const { loginWithRedirect, isAuthenticated, isLoading} = useAuth0(); + const {loginWithRedirect, isAuthenticated, isLoading} = useAuth0(); useEffect(() => { if (!isAuthenticated && !isLoading) { loginWithRedirect(); @@ -14,7 +14,7 @@ const App = () : JSX.Element => { }, [isAuthenticated, isLoading]); if (isLoading) { - return Loading.... + return Loading....; } return ( diff --git a/src/Layout.tsx b/src/Layout.tsx index ecf8b23..6434ea6 100644 --- a/src/Layout.tsx +++ b/src/Layout.tsx @@ -1,22 +1,22 @@ +import {useAuth0} from '@auth0/auth0-react'; import AppBar from '@mui/material/AppBar'; import Button from '@mui/material/Button'; import Toolbar from '@mui/material/Toolbar'; import Typography from '@mui/material/Typography'; import {Outlet} from 'react-router-dom'; -import { useAuth0 } from "@auth0/auth0-react"; const Layout = () : JSX.Element => { - const { logout } = useAuth0(); + const {logout} = useAuth0(); return ( <> - diff --git a/src/components/AuthProvider.tsx b/src/components/AuthProvider.tsx index 784bb95..572d65e 100644 --- a/src/components/AuthProvider.tsx +++ b/src/components/AuthProvider.tsx @@ -1,6 +1,7 @@ -import { Auth0Provider } from "@auth0/auth0-react"; -import { ReactNode, useContext } from "react"; -import { tivoContext } from "./TivoContext"; +import {Auth0Provider} from '@auth0/auth0-react'; +import type {ReactNode} from 'react'; +import {useContext} from 'react'; +import {tivoContext} from './TivoContext'; type Props = { children : ReactNode; @@ -10,7 +11,7 @@ export const AuthProvider = ({children} : Props) => { const context = useContext(tivoContext); if (!context) { - return <>Loading config... + return <>Loading config...; } return { audience={context.audience} > {children} - -} \ No newline at end of file + ; +}; diff --git a/src/components/ChannelComponent.tsx b/src/components/ChannelComponent.tsx index d5f2480..9d529f7 100644 --- a/src/components/ChannelComponent.tsx +++ b/src/components/ChannelComponent.tsx @@ -1,149 +1,153 @@ -import Typography from '@mui/material/Typography'; -import { forwardRef, ReactElement, Ref, useContext, useEffect, useState } from 'react'; import CloseIcon from '@mui/icons-material/Close'; - -import type { Channel } from '@/types/Tivo'; -import Dialog from '@mui/material/Dialog'; import AppBar from '@mui/material/AppBar'; -import Toolbar from '@mui/material/Toolbar'; -import IconButton from '@mui/material/IconButton'; import Button from '@mui/material/Button'; -import type { TransitionProps } from '@mui/material/transitions'; -import Slide from '@mui/material/Slide'; import VideoJS from './VideoJS'; import Container from '@mui/material/Container'; -import { useFetch } from '@/util/api'; -import { tivoContext } from './TivoContext'; +import Dialog from '@mui/material/Dialog'; +import IconButton from '@mui/material/IconButton'; +import Slide from '@mui/material/Slide'; +import Toolbar from '@mui/material/Toolbar'; +import type {TransitionProps} from '@mui/material/transitions'; +import Typography from '@mui/material/Typography'; +import {forwardRef, useContext, useEffect, useState} from 'react'; +import type {ReactElement, Ref} from 'react'; import type videojs from 'video.js'; +import {tivoContext} from './TivoContext'; +import type {Channel} from '@/types/Tivo'; +import {useFetch} from '@/util/api'; type Props = { openState : boolean; close : () => void; channel : Channel | null; -} +}; type Stream = { - hlsSession: { + hlsSession : { clientUuid : string; hlsSessionId : string; playlistUri : string; type : string; isLocal : boolean; - } - errorCode : string|undefined; + }; + errorCode : string | undefined; type : string; IsFinal : boolean; -} +}; const Transition = forwardRef(function Transition( - props: TransitionProps & { - children: ReactElement; + props : TransitionProps & { + children : ReactElement; }, - ref: Ref, - ) { - return ; - }); + ref : Ref, +) { + return ; +}); const ChannelComponent = ({openState, close, channel} : Props) : JSX.Element => { - const [stream, setStream] = useState(null); + const [stream, setStream] = useState(null); const fetch = useFetch(); const context = useContext(tivoContext); - const clearSession = async (hlsSessionId : string) => { return await fetch(`/stream/stop/${encodeURIComponent(hlsSessionId)}`); - } + }; const getSession = async (stbChannelId : string) => { - if (stream && stream.hlsSession?.hlsSessionId) { - clearSession(stream.hlsSession?.hlsSessionId); + if (stream && stream.hlsSession.hlsSessionId) { + clearSession(stream.hlsSession.hlsSessionId); } - const rsp = await fetch(`/stream/startChannel/${encodeURIComponent(stbChannelId)}`) + + const rsp = await fetch(`/stream/startChannel/${encodeURIComponent(stbChannelId)}`); const strm = await rsp.json(); return strm; - } + }; const closeWindow = () => { - if (stream && stream.hlsSession?.hlsSessionId) { - clearSession(stream.hlsSession?.hlsSessionId); + if (stream && stream.hlsSession.hlsSessionId) { + clearSession(stream.hlsSession.hlsSessionId); } + setStream(null); close(); - } + }; useEffect(() => { if (channel?.stbChannelId) { - getSession(channel?.stbChannelId).then(async (newStream) => { + getSession(channel.stbChannelId).then(async newStream => { await new Promise(r => setTimeout(r, 2000)); setStream(newStream); }); } + return () => { - if (!stream || !stream.hlsSession?.hlsSessionId) { + if (!stream || !stream.hlsSession.hlsSessionId) { console.log('skipping unmount clear'); return; } - clearSession(stream.hlsSession?.hlsSessionId); - } + + clearSession(stream.hlsSession.hlsSessionId); + }; }, [channel]); + if (!channel) { return <>; } + return ( - - - - - - - {channel.affiliate} - - - - - {stream && stream.hlsSession?.playlistUri && ( - <> - - )} - {stream && stream.errorCode === undefined && ( - <> - {stream.errorCode} - - )} - - - - + fullScreen + open={openState} + onClose={closeWindow} + TransitionComponent={Transition} + > + + + + + + + {channel.affiliate} + + + + + {stream && stream.hlsSession.playlistUri && ( + <> + + )} + {stream && stream.errorCode === undefined && ( + <> + {stream.errorCode} + + )} + + + + ); }; - -export default ChannelComponent; \ No newline at end of file +export default ChannelComponent; diff --git a/src/components/Playback.tsx b/src/components/Playback.tsx index 60ec2c0..e9501da 100644 --- a/src/components/Playback.tsx +++ b/src/components/Playback.tsx @@ -1,172 +1,178 @@ -import Typography from '@mui/material/Typography'; -import { forwardRef, ReactElement, Ref, useContext, useEffect, useState } from 'react'; import CloseIcon from '@mui/icons-material/Close'; - -import type { MyShows, Recording } from '@/types/Tivo'; -import Dialog from '@mui/material/Dialog'; import AppBar from '@mui/material/AppBar'; -import Toolbar from '@mui/material/Toolbar'; -import IconButton from '@mui/material/IconButton'; import Button from '@mui/material/Button'; -import type { TransitionProps } from '@mui/material/transitions'; -import Slide from '@mui/material/Slide'; import VideoJS from './VideoJS'; import Container from '@mui/material/Container'; -import { useFetch } from '@/util/api'; -import { tivoContext } from './TivoContext'; +import Dialog from '@mui/material/Dialog'; +import IconButton from '@mui/material/IconButton'; +import Slide from '@mui/material/Slide'; +import Toolbar from '@mui/material/Toolbar'; +import type {TransitionProps} from '@mui/material/transitions'; +import Typography from '@mui/material/Typography'; +import {forwardRef, useContext, useEffect, useState} from 'react'; +import type {ReactElement, Ref} from 'react'; import type videojs from 'video.js'; +import {tivoContext} from './TivoContext'; +import type {MyShows, Recording} from '@/types/Tivo'; +import {useFetch} from '@/util/api'; type Props = { openState : boolean; close : () => void; recording : Recording | null; -} +}; type Stream = { - hlsSession: { + hlsSession : { clientUuid : string; hlsSessionId : string; playlistUri : string; type : string; isLocal : boolean; - } - errorCode : string|undefined; + }; + errorCode : string | undefined; type : string; IsFinal : boolean; -} +}; const Transition = forwardRef(function Transition( - props: TransitionProps & { - children: ReactElement; + props : TransitionProps & { + children : ReactElement; }, - ref: Ref, - ) { - return ; - }); + ref : Ref, +) { + return ; +}); const Playback = ({openState, close, recording} : Props) : JSX.Element => { - const [stream, setStream] = useState(null); + const [stream, setStream] = useState(null); const fetch = useFetch(); const context = useContext(tivoContext); - const clearSession = async (hlsSessionId : string) => { return await fetch(`/stream/stop/${encodeURIComponent(hlsSessionId)}`); - } + }; const getSession = async (recordingId : string) => { - if (stream && stream.hlsSession?.hlsSessionId) { - clearSession(stream.hlsSession?.hlsSessionId); + if (stream && stream.hlsSession.hlsSessionId) { + clearSession(stream.hlsSession.hlsSessionId); } - const rsp = await fetch(`/stream/start/${encodeURIComponent(recordingId)}`) + + const rsp = await fetch(`/stream/start/${encodeURIComponent(recordingId)}`); const strm = await rsp.json(); return strm; - } + }; const closeWindow = () => { - if (stream && stream.hlsSession?.hlsSessionId) { - clearSession(stream.hlsSession?.hlsSessionId); + if (stream && stream.hlsSession.hlsSessionId) { + clearSession(stream.hlsSession.hlsSessionId); } + setStream(null); close(); - } + }; useEffect(() => { if (recording?.recordingId) { - getSession(recording?.recordingId).then((newStream) => { + getSession(recording.recordingId).then(newStream => { setStream(newStream); }); } + return () => { - if (!stream || !stream.hlsSession?.hlsSessionId) { + if (!stream || !stream.hlsSession.hlsSessionId) { console.log('skipping unmount clear'); return; } - clearSession(stream.hlsSession?.hlsSessionId); - } + + clearSession(stream.hlsSession.hlsSessionId); + }; }, [recording]); + if (!recording) { return <>; } - const episode = recording.episodeNum?.length > 0 ? `S${recording.seasonNumber} E${recording.episodeNum.join(',')} ` : ``; + + const episode = recording.episodeNum.length > 0 ? `S${recording.seasonNumber} E${recording.episodeNum.join(',')} ` : ''; const secondary = `${episode}${recording.subtitle}`; return ( - - - - - - - {recording?.shortTitle} - - - - - {recording?.shortTitle} {episode} - {secondary} - {stream && stream.hlsSession?.playlistUri && ( - <> - - )} - {stream && stream.errorCode === undefined && ( - <> - {stream.errorCode} - - )} - {recording.description} - - - - + fullScreen + open={openState} + onClose={closeWindow} + TransitionComponent={Transition} + > + + + + + + + {recording.shortTitle} + + + + + {recording.shortTitle} {episode} - {secondary} + {stream && stream.hlsSession.playlistUri && ( + <> + + )} + {stream && stream.errorCode === undefined && ( + <> + {stream.errorCode} + + )} + {recording.description} + + + + ); }; - -export default Playback; \ No newline at end of file +export default Playback; diff --git a/src/components/TivoContext.tsx b/src/components/TivoContext.tsx index 4b7c3f6..ff53ef0 100644 --- a/src/components/TivoContext.tsx +++ b/src/components/TivoContext.tsx @@ -1,5 +1,6 @@ -import { createContext, ReactNode, useEffect, useState } from "react"; -import { z } from "zod"; +import type {ReactNode} from 'react'; +import {createContext, useEffect, useState} from 'react'; +import {z} from 'zod'; type Props = { children ?: ReactNode; @@ -10,9 +11,9 @@ export type TivoContextType = { domain : string; clientID : string; audience : string; -} +}; -export const tivoContext = createContext(null); +export const tivoContext = createContext(null); const fetchValidator = z.object({ apiBaseUrl: z.string(), @@ -21,28 +22,26 @@ const fetchValidator = z.object({ audience: z.string(), }); - export const TivoContextComponent = ({children} : Props) => { - const [ctx, setCtx] = useState(null); + const [ctx, setCtx] = useState(null); useEffect(() => { fetch('config.json').then(rsp => { - rsp.json().then( data => { - console.log('data', data); - const validatedData = fetchValidator.parse(data) - setCtx({ - apiBaseUrl : validatedData.apiBaseUrl, - domain : validatedData.domain, - clientID : validatedData.clientID, - audience : validatedData.audience, - }) - } - ) - }) - }, []) - + rsp.json().then(data => { + console.log('data', data); + const validatedData = fetchValidator.parse(data); + setCtx({ + apiBaseUrl: validatedData.apiBaseUrl, + domain: validatedData.domain, + clientID: validatedData.clientID, + audience: validatedData.audience, + }); + }); + }); + }, []); + return ( - - {children} - + + {children} + ); - } \ No newline at end of file +}; diff --git a/src/components/VideoJS.tsx b/src/components/VideoJS.tsx index 30cfeb5..929dd6b 100644 --- a/src/components/VideoJS.tsx +++ b/src/components/VideoJS.tsx @@ -5,59 +5,58 @@ import 'video.js/dist/video-js.css'; type Props = { options : videojs.PlayerOptions; onReady ?: (player : videojs.Player) => void; -} +}; export const VideoJS = (props : Props) => { - const videoRef = React.useRef(null); - const playerRef = React.useRef(null); - const {options, onReady} = props; - - React.useEffect(() => { - - // Make sure Video.js player is only initialized once - if (!playerRef.current) { - const videoElement = videoRef.current; - - if (!videoElement) return; - - const player = playerRef.current = videojs(videoElement, options, () => { - videojs.log('player is ready'); - onReady && onReady(player); - }); - - // You could update an existing player in the `else` block here - // on prop change, for example: - } else { - // const player = playerRef.current; - - // player.autoplay(options.autoplay); - // player.src(options.sources); - } - }, [options, videoRef]); - - // Dispose the Video.js player when the functional component unmounts - React.useEffect(() => { - const player = playerRef.current; - - return () => { - if (player) { - player.dispose(); - playerRef.current = null; - } - }; - }, [playerRef]); - - return ( -
-
- ); -} - -export default VideoJS; \ No newline at end of file + const videoRef = React.useRef(null); + const playerRef = React.useRef(null); + const {options, onReady} = props; + + React.useEffect(() => { + // Make sure Video.js player is only initialized once + if (!playerRef.current) { + const videoElement = videoRef.current; + + if (!videoElement) return; + + const player = playerRef.current = videojs(videoElement, options, () => { + videojs.log('player is ready'); + onReady && onReady(player); + }); + + // You could update an existing player in the `else` block here + // on prop change, for example: + } else { + // const player = playerRef.current; + + // player.autoplay(options.autoplay); + // player.src(options.sources); + } + }, [options, videoRef]); + + // Dispose the Video.js player when the functional component unmounts + React.useEffect(() => { + const player = playerRef.current; + + return () => { + if (player) { + player.dispose(); + playerRef.current = null; + } + }; + }, [playerRef]); + + return ( +
+
+ ); +}; + +export default VideoJS; diff --git a/src/main.tsx b/src/main.tsx index 6cadac6..735aef0 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -7,8 +7,8 @@ import {ThemeProvider} from '@mui/material/styles'; import {StrictMode} from 'react'; import {render} from 'react-dom'; import App from './App'; -import { AuthProvider } from './components/AuthProvider'; -import { TivoContextComponent } from './components/TivoContext'; +import {AuthProvider} from './components/AuthProvider'; +import {TivoContextComponent} from './components/TivoContext'; const theme = createTheme(); diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 8aa2992..f802da5 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,145 +1,145 @@ -import Typography from '@mui/material/Typography'; +import ChevronRightIcon from '@mui/icons-material/ChevronRight'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import {Box, Tabs, Tab, Chip} from '@mui/material'; +import Accordion from '@mui/material/Accordion'; +import AccordionDetails from '@mui/material/AccordionDetails'; +import AccordionSummary from '@mui/material/AccordionSummary'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ListItemButton from '@mui/material/ListItemButton'; import ListItemText from '@mui/material/ListItemText'; -import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; -import ChevronRightIcon from "@mui/icons-material/ChevronRight"; -import Accordion from '@mui/material/Accordion'; -import AccordionSummary from '@mui/material/AccordionSummary'; -import AccordionDetails from '@mui/material/AccordionDetails'; -import type { Channel, Recording } from '@/types/Tivo'; -import { useFetch } from '@/util/api'; -import { lazy, useEffect, useState, Suspense} from 'react'; -import { Box, Tabs, Tab, Chip} from '@mui/material'; +import Typography from '@mui/material/Typography'; import Container from '@mui/system/Container'; +import {lazy, useEffect, useState, Suspense} from 'react'; +import type {Channel, Recording} from '@/types/Tivo'; +import {useFetch} from '@/util/api'; -const Playback = lazy(() => import('@/components/Playback')); -const ChannelComponent = lazy(() => import('@/components/ChannelComponent')); +const Playback = lazy(async () => import('@/components/Playback')); +const ChannelComponent = lazy(async () => import('@/components/ChannelComponent')); -interface TabPanelProps { - children?: React.ReactNode; - index: number; - value: number; - } +type TabPanelProps = { + children ?: React.ReactNode; + index : number; + value : number; +}; + +function TabPanel(props : TabPanelProps) { + const {children, value, index, ...other} = props; -function TabPanel(props: TabPanelProps) { - const { children, value, index, ...other } = props; - return ( - + ); - } +} const Home = () : JSX.Element => { const [recordings, setRecordings] = useState([]); const [uniqueCollections, setUniqueCollections] = useState([]); const [channels, setChannels] = useState([]); - const [selectedRecording, setSelectedRecording] = useState(null); - const [selectedChannel, setSelectedChannel] = useState(null); + const [selectedRecording, setSelectedRecording] = useState(null); + const [selectedChannel, setSelectedChannel] = useState(null); const [tab, setTab] = useState(0); const fetch = useFetch(); - const changeTab = (event: React.SyntheticEvent, newValue: number) => { + const changeTab = (event : React.SyntheticEvent, newValue : number) => { setSelectedChannel(null); setSelectedRecording(null); setTab(newValue); }; useEffect(() => { - fetch('/getMyShows').then(async (rec) => { + fetch('/getMyShows').then(async rec => { const rawRecordings = await rec.json() as Recording[]; setUniqueCollections(rawRecordings.filter((r, i) => rawRecordings.findIndex(or => or.collectionId === r.collectionId) === i)); setRecordings(rawRecordings); }); - fetch('/getMyLineup').then(async (rec) => { + fetch('/getMyLineup').then(async rec => { const allChannels = await rec.json(); const channelList = allChannels.channel as Channel[]; - setChannels(channelList.filter((c) => c.isReceived)); - console.log('channels', channelList.filter((c) => c.isReceived)); + setChannels(channelList.filter(c => c.isReceived)); + console.log('channels', channelList.filter(c => c.isReceived)); }); - },[]); + }, []); console.log('uniqueCollections', uniqueCollections); return ( <> Home - - - - - + + + + + - - {uniqueCollections.map((c, i) => { - const collectionRecordings = recordings.filter(r => r.collectionId === c.collectionId).reverse(); - const latestRecording = collectionRecordings.length ? - new Date(collectionRecordings[0].actualStartTime).toLocaleDateString() : - ''; - return - } - aria-controls="panel1a-content" - id="panel1a-header" - > - - {c.collectionTitle} {latestRecording} - - - - {collectionRecordings.map(recording => { - const recordingStart = new Date(recording.scheduledStartTime).toLocaleString(); - const episode = recording.episodeNum?.length > 0 ? `S${recording.seasonNumber} E${recording.episodeNum.join(',')} ` : ``; - const secondary = `${episode}${recording.subtitle}`; - return - { - console.log('recording', recording); - setSelectedRecording(recording); - }} - > - - - - })} - - - - })} + + {uniqueCollections.map((c, i) => { + const collectionRecordings = recordings.filter(r => r.collectionId === c.collectionId).reverse(); + const latestRecording = collectionRecordings.length + ? new Date(collectionRecordings[0].actualStartTime).toLocaleDateString() + : ''; + return + } + aria-controls="panel1a-content" + id="panel1a-header" + > + + {c.collectionTitle} {latestRecording} + + + + {collectionRecordings.map(recording => { + const recordingStart = new Date(recording.scheduledStartTime).toLocaleString(); + const episode = recording.episodeNum.length > 0 ? `S${recording.seasonNumber} E${recording.episodeNum.join(',')} ` : ''; + const secondary = `${episode}${recording.subtitle}`; + return + { + console.log('recording', recording); + setSelectedRecording(recording); + }} + > + + + ; + })} + + + ; + })} - {channels.map((channel) => { + {channels.map(channel => { return - { - console.log('channel', channel); - setSelectedChannel(channel); - }} - > - - - + { + console.log('channel', channel); + setSelectedChannel(channel); + }} + > + + + ; })} @@ -147,18 +147,22 @@ const Home = () : JSX.Element => { }> {setSelectedRecording(null)}} + close={() => { + setSelectedRecording(null); + }} recording={selectedRecording} /> }> {setSelectedChannel(null)}} + close={() => { + setSelectedChannel(null); + }} channel={selectedChannel} /> - + ); }; diff --git a/src/types/Tivo.ts b/src/types/Tivo.ts index 05e8419..01b6eec 100644 --- a/src/types/Tivo.ts +++ b/src/types/Tivo.ts @@ -3,7 +3,7 @@ export type Recording = { isNew : boolean; shortTitle : string; subtitle : string; - description: string; + description : string; seasonNumber : number; collectionTitle : string; @@ -16,7 +16,7 @@ export type Recording = { isEpisode : boolean; duration : number; - hdtv: boolean; + hdtv : boolean; size : number; actualStartTime : string; @@ -33,7 +33,7 @@ export type Recording = { recordingPlaybackPolicy : string; tivoToGo : boolean; type : string; - } + }; }; export type MyShows = { @@ -42,25 +42,25 @@ export type MyShows = { type : string; IsFinal : boolean; isBottom : boolean; -} +}; export type Channel = { - affiliate: string; - callSign: string; - channelId: string; - channelNumber: string; - isKidZone: boolean; - isReceived: boolean; - name: string; - sourceType: string; - stationId: string; + affiliate : string; + callSign : string; + channelId : string; + channelNumber : string; + isKidZone : boolean; + isReceived : boolean; + name : string; + sourceType : string; + stationId : string; isDigital ?: boolean; logoIndex ?: number; - isBlocked: boolean; - objectIdAndType: string; - isHdtv: boolean; - isEntitled: boolean; - videoResolution: string; - type: string; - stbChannelId: string; -} \ No newline at end of file + isBlocked : boolean; + objectIdAndType : string; + isHdtv : boolean; + isEntitled : boolean; + videoResolution : string; + type : string; + stbChannelId : string; +}; diff --git a/src/util/api.ts b/src/util/api.ts index d7ddf6f..951078b 100644 --- a/src/util/api.ts +++ b/src/util/api.ts @@ -1,18 +1,20 @@ -import { tivoContext } from '@/components/TivoContext'; -import { useAuth0 } from '@auth0/auth0-react'; -import { useContext } from 'react'; +import {useAuth0} from '@auth0/auth0-react'; +import {useContext} from 'react'; +import {tivoContext} from '@/components/TivoContext'; export const useFetch = () => { - const { getAccessTokenSilently } = useAuth0(); + const {getAccessTokenSilently} = useAuth0(); const context = useContext(tivoContext); - + return async (url : string | URL, options : RequestInit | undefined = {}) => { const token = await getAccessTokenSilently(); + if (!options) { options = {}; } + options.headers = new Headers(options.headers); options.headers.append('Authorization', 'Bearer ' + token); return await fetch((context?.apiBaseUrl ?? '') + url.toString(), options); - } -} \ No newline at end of file + }; +}; diff --git a/vite.config.ts b/vite.config.ts index f925726..289c478 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,4 @@ -import { Output } from '@mui/icons-material'; +import {Output} from '@mui/icons-material'; import react from '@vitejs/plugin-react'; import {visualizer} from 'rollup-plugin-visualizer'; import {defineConfig} from 'vite'; @@ -26,6 +26,6 @@ export default defineConfig({ '^/session-streaming/.*': { target: 'http://localhost:8000', }, - } - } + }, + }, });