{"version":3,"sources":["components/Game.tsx","utils/api.tsx","utils/Message.tsx","components/StateTable.tsx","components/VideoPlayer.tsx","components/MainPage.tsx","components/App.tsx","scripts/serviceWorker.ts","index.tsx"],"names":["GameState","PingStatus","isMissing","e","undefined","Api","params","id","server","endpoint","this","host","port","fetch","method","response","text","status","json","message","statusText","commandResult","state","commandOptions","handleGameStatusResponse","request","headers","body","JSON","stringify","leaderboard","Object","entries","TIMEOUT_ERROR","TIMEOUT_SUCCESS","Message","Toaster","create","position","Position","BOTTOM","usePortal","canEscapeKeyClear","maxToasts","StateTable","render","stateMap","props","stateKeys","keys","length","map","stateKey","React","Component","VideoPlayer","playAudio","videoPlaying","setState","videoUrl","className","onClick","url","playing","CLASSES","classNames","Classes","CARD","ELEVATION_4","Game","api","tryCreateGame","a","createGame","show","timeout","icon","intent","Intent","DANGER","gameState","REQUEST_FAILED","errorMessage","SUCCESS","REDIRECTING","redirectId","tryDeleteGame","deleteGame","tryPing","ping","pingStatus","FAILED","WARNING","SUCCEEDED","tryLoadInstance","IN_PROGRESS","commandName","commandValue","getGame","tryPerformCommand","playerName","newCommandResult","performCommand","componentDidMount","PING","LOADING_INSTANCE","setPlayerName","target","value","commandClicked","command","commandVal","toggleLeaderboard","leaderboardEntries","leaderboardVisible","fetchLeaderboard","newGameClicked","renderRedirecting","location","to","pathname","search","renderLoadingInstance","OVERLAY_CONTAINER","isOpen","NONE","renderRequestFailed","renderPing","SENDING","renderInProgress","imageUrl","commandKeys","Array","from","src","alt","style","whiteSpace","commandValues","minimal","vertical","i","key","disabled","active","dotenv","config","process","REACT_APP_HOST","REACT_APP_PORT","parseQueryParams","queryString","parse","MainPage","exact","path","Number","parseInt","match","App","DARK","width","height","Boolean","window","hostname","ReactDOM","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.72075caa.chunk.js","sourcesContent":["import React from \"react\";\r\nimport { CommandResult, Error, Server } from \"types/adventure\";\r\nimport Api from \"utils/api\";\r\nimport { ProgressBar, Overlay, Intent, Classes, Text, H1, ButtonGroup, Button, FormGroup, InputGroup } from \"@blueprintjs/core\";\r\nimport classNames from \"classnames\";\r\nimport Message, { TIMEOUT_ERROR, TIMEOUT_SUCCESS } from 'utils/Message';\r\n\r\nimport 'styles/Game.css';\r\nimport { RouteComponentProps, Redirect } from \"react-router\";\r\nimport StateTable from 'components/StateTable';\r\nimport VideoPlayer from 'components/VideoPlayer';\r\nimport LeaderboardTable from \"./LeaderboardTable\";\r\n\r\nenum GameState {\r\n PING,\r\n IN_PROGRESS,\r\n REQUEST_FAILED,\r\n REDIRECTING,\r\n LOADING_INSTANCE,\r\n};\r\n\r\nenum PingStatus {\r\n SENDING,\r\n FAILED,\r\n SUCCEEDED,\r\n WARNING,\r\n};\r\n\r\ninterface Props extends RouteComponentProps {\r\n id: number | null;\r\n server: Server;\r\n commandResult: CommandResult | null;\r\n}\r\n\r\ntype State = {\r\n commandResult: CommandResult | null;\r\n pingStatus: PingStatus;\r\n gameState: GameState;\r\n errorMessage: string | null;\r\n commandName: string | null;\r\n commandValue: string | null;\r\n redirectId: number | null;\r\n playerName: string;\r\n leaderboardVisible: boolean;\r\n leaderboardEntries: [string, number][];\r\n};\r\n\r\nconst CLASSES = classNames(\r\n Classes.CARD,\r\n Classes.ELEVATION_4,\r\n 'ping-overlay',\r\n);\r\n\r\n\r\n\r\nclass Game extends React.Component {\r\n api: Api;\r\n\r\n constructor(props: Props) {\r\n super(props);\r\n\r\n const { id, server } = props;\r\n this.api = new Api({\r\n id,\r\n server,\r\n });\r\n\r\n const { commandResult } = props;\r\n this.state = {\r\n commandResult,\r\n gameState: id !== null ? GameState.LOADING_INSTANCE : GameState.PING,\r\n pingStatus: PingStatus.SENDING,\r\n errorMessage: null,\r\n commandName: null,\r\n commandValue: null,\r\n redirectId: null,\r\n playerName: \"Anonymous\",\r\n leaderboardVisible: false,\r\n leaderboardEntries: [],\r\n };\r\n }\r\n\r\n /**\r\n * Attempts to create a new game.\r\n */\r\n tryCreateGame = async () => {\r\n let commandResult = null;\r\n try {\r\n commandResult = await this.api.createGame();\r\n } catch (error) {\r\n const { message } = error as Error;\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `POST /create failed: ${message}`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n return this.setState({\r\n gameState: GameState.REQUEST_FAILED,\r\n errorMessage: 'Failed to create game',\r\n });\r\n }\r\n\r\n const { id } = commandResult;\r\n Message.show({\r\n timeout: TIMEOUT_SUCCESS,\r\n message: 'POST /create succeeded!',\r\n icon: 'tick',\r\n intent: Intent.SUCCESS,\r\n });\r\n return this.setState({\r\n gameState: GameState.REDIRECTING,\r\n redirectId: id,\r\n });\r\n };\r\n\r\n /**\r\n * Attempts to delete the current game.\r\n */\r\n tryDeleteGame = async () => {\r\n try {\r\n await this.api.deleteGame();\r\n } catch (error) {\r\n const { message } = error as Error;\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `DELETE /instance/:id failed: ${message}`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n return this.setState({\r\n gameState: GameState.REQUEST_FAILED,\r\n errorMessage: 'Failed to delete game',\r\n });\r\n }\r\n\r\n Message.show({\r\n timeout: TIMEOUT_SUCCESS,\r\n message: 'DELETE /create succeeded!',\r\n icon: 'tick',\r\n intent: Intent.SUCCESS,\r\n });\r\n };\r\n\r\n /**\r\n * Attempts to ping the server.\r\n */\r\n tryPing = async () => {\r\n let text = null;\r\n try {\r\n text = await this.api.ping();\r\n } catch (error) {\r\n const { message } = error as Error;\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `GET /ping failed: ${message}`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n return this.setState({\r\n pingStatus: PingStatus.FAILED,\r\n errorMessage: 'Could not ping the server',\r\n });\r\n }\r\n\r\n if (text !== 'pong') {\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `GET /ping returned '${text}' instead of 'pong'`,\r\n icon: 'warning-sign',\r\n intent: Intent.WARNING,\r\n });\r\n return this.setState({\r\n pingStatus: PingStatus.WARNING,\r\n errorMessage: 'Server ping not set up correctly',\r\n });\r\n }\r\n\r\n Message.show({\r\n timeout: TIMEOUT_SUCCESS,\r\n message: 'GET /ping succeeded!',\r\n icon: 'tick',\r\n intent: Intent.SUCCESS,\r\n });\r\n return this.setState(\r\n { pingStatus: PingStatus.SUCCEEDED },\r\n () => this.tryCreateGame(),\r\n );\r\n };\r\n\r\n tryLoadInstance = async () => {\r\n let { commandResult } = this.state;\r\n if (commandResult !== null) return this.setState({\r\n commandResult,\r\n gameState: GameState.IN_PROGRESS,\r\n commandName: null,\r\n commandValue: null,\r\n });\r\n\r\n try {\r\n commandResult = await this.api.getGame();\r\n } catch (error) {\r\n const { message } = error as Error;\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `GET /instance/:id failed: ${message}\\nPossibly, the API is not running; you might also need to follow the instructions in the assignment doc to bypass the browser security measures.`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n return this.setState({\r\n gameState: GameState.REQUEST_FAILED,\r\n errorMessage: 'Could not load game',\r\n });\r\n }\r\n\r\n Message.show({\r\n timeout: TIMEOUT_SUCCESS,\r\n message: 'GET /instance/:id succeeded!',\r\n icon: 'tick',\r\n intent: Intent.SUCCESS,\r\n });\r\n return this.setState({\r\n gameState: GameState.IN_PROGRESS,\r\n commandResult,\r\n commandName: null,\r\n commandValue: null,\r\n });\r\n };\r\n\r\n tryPerformCommand = async () => {\r\n const { commandName, commandValue, playerName } = this.state;\r\n\r\n if (commandName === null || commandValue === null) {\r\n return this.setState({\r\n gameState: GameState.REQUEST_FAILED,\r\n errorMessage: 'Could not complete command',\r\n });\r\n }\r\n\r\n let newCommandResult = null;\r\n try {\r\n newCommandResult = await this.api.performCommand({ commandName, commandValue, playerName });\r\n } catch (error) {\r\n const { message } = error as Error;\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `POST /command failed: ${message}`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n return this.setState({\r\n gameState: GameState.REQUEST_FAILED,\r\n errorMessage: `Could not ${commandName}`,\r\n });\r\n }\r\n\r\n Message.show({\r\n timeout: TIMEOUT_SUCCESS,\r\n message: `POST /command succeeded!`,\r\n icon: 'tick',\r\n intent: Intent.SUCCESS,\r\n });\r\n return this.setState({\r\n gameState: GameState.IN_PROGRESS,\r\n commandResult: newCommandResult,\r\n commandName: null,\r\n commandValue: null,\r\n });\r\n }\r\n\r\n componentDidMount = () => {\r\n const { gameState } = this.state;\r\n\r\n switch (gameState) {\r\n case GameState.PING: return this.tryPing();\r\n case GameState.LOADING_INSTANCE: return this.tryLoadInstance();\r\n }\r\n };\r\n\r\n setPlayerName = (e: any) => {\r\n this.setState({\r\n playerName: e.target.value || \"Anonymous\"\r\n })\r\n }\r\n\r\n commandClicked = (command: string, commandVal: string) => {\r\n const { commandName } = this.state;\r\n\r\n // The user already clicked a button.\r\n if (commandName !== null) return;\r\n\r\n return this.setState(\r\n {\r\n commandName: command,\r\n commandValue: commandVal,\r\n },\r\n () => this.tryPerformCommand(),\r\n );\r\n };\r\n\r\n toggleLeaderboard = async () => {\r\n let leaderboardEntries: [string, number][] = [];\r\n if (!this.state.leaderboardVisible) {\r\n try {\r\n leaderboardEntries = await this.api.fetchLeaderboard();\r\n } catch (error) {\r\n Message.show({\r\n timeout: TIMEOUT_ERROR,\r\n message: `POST /leaderboard failed: ${error.message}`,\r\n icon: 'error',\r\n intent: Intent.DANGER,\r\n });\r\n }\r\n\r\n }\r\n this.setState({\r\n leaderboardVisible: !this.state.leaderboardVisible,\r\n leaderboardEntries\r\n })\r\n }\r\n\r\n newGameClicked = () => {\r\n const { gameState } = this.state;\r\n // The user already clicked this button.\r\n if (gameState === GameState.REDIRECTING) return;\r\n\r\n return this.setState(\r\n { gameState: GameState.REDIRECTING, redirectId: null },\r\n () => this.tryDeleteGame(),\r\n );\r\n };\r\n\r\n\r\n renderRedirecting = () => {\r\n const { redirectId, commandResult } = this.state;\r\n const { location } = this.props;\r\n if (redirectId === null) {\r\n return (\r\n \r\n );\r\n }\r\n return (\r\n \r\n );\r\n };\r\n\r\n renderLoadingInstance = () => (\r\n \r\n
\r\n

Loading game ...

\r\n \r\n
\r\n
\r\n );\r\n\r\n renderRequestFailed = () => {\r\n const { errorMessage } = this.state;\r\n return (\r\n \r\n
\r\n

{errorMessage}

\r\n \r\n
\r\n
\r\n );\r\n };\r\n\r\n renderPing = () => {\r\n const { pingStatus, errorMessage } = this.state;\r\n const message = {\r\n [PingStatus.SENDING]: 'Sending ping ...',\r\n [PingStatus.FAILED]: errorMessage,\r\n [PingStatus.WARNING]: errorMessage,\r\n [PingStatus.SUCCEEDED]: 'Pong received!',\r\n }[pingStatus];\r\n const intent = {\r\n [PingStatus.SENDING]: Intent.NONE,\r\n [PingStatus.FAILED]: Intent.DANGER,\r\n [PingStatus.WARNING]: Intent.WARNING,\r\n [PingStatus.SUCCEEDED]: Intent.SUCCESS,\r\n }[pingStatus];\r\n return (\r\n \r\n
\r\n

{message}

\r\n \r\n
\r\n
\r\n );\r\n };\r\n\r\n renderInProgress = () => {\r\n const { commandResult, commandName, commandValue, leaderboardEntries } = this.state;\r\n const { imageUrl, videoUrl, message, commandOptions, state } = commandResult!;\r\n const commandKeys = Array.from(Object.keys(commandOptions));\r\n\r\n const leaderboardCardClasses = classNames(\r\n Classes.CARD,\r\n Classes.ELEVATION_4,\r\n \"leaderboard-overlay\"\r\n );\r\n\r\n return (\r\n
\r\n
\r\n

Adventure v2.0

\r\n
\r\n
\r\n {imageUrl && \"new\"}\r\n
\r\n
\r\n \r\n Message: \r\n {message}\r\n \r\n
\r\n {/* \r\n \r\n \r\n */}\r\n\r\n {/* \r\n
\r\n

Leaderboard

\r\n \r\n \r\n
\r\n
*/}\r\n
\r\n {\r\n commandKeys.map(command => {\r\n // @ts-ignore\r\n const commandValues = commandOptions[command];\r\n\r\n return (commandValues && {\r\n // @ts-ignore\r\n commandValues.map((value, i) => (\r\n this.commandClicked(command, value)}\r\n >\r\n {`${command} ${value}`}\r\n \r\n ))\r\n }\r\n )\r\n })\r\n }\r\n
\r\n {state && }\r\n {videoUrl && }\r\n
\r\n );\r\n };\r\n\r\n render = () => {\r\n const { gameState } = this.state;\r\n\r\n switch (gameState) {\r\n case GameState.REDIRECTING: return this.renderRedirecting();\r\n case GameState.LOADING_INSTANCE: return this.renderLoadingInstance();\r\n case GameState.REQUEST_FAILED: return this.renderRequestFailed();\r\n case GameState.PING: return this.renderPing();\r\n case GameState.IN_PROGRESS: return this.renderInProgress();\r\n }\r\n };\r\n}\r\n\r\nexport default Game;","/* eslint-disable no-throw-literal */\r\nimport { Server, CommandResult, Error, Command } from 'types/adventure';\r\n\r\nconst isMissing = (e: any) => e === undefined || e === null;\r\n\r\nexport type ApiParams = {\r\n id: number | null;\r\n server: Server;\r\n};\r\n\r\ninterface Leaderboard {\r\n [name: string]: number\r\n}\r\n\r\nexport default class Api {\r\n id: number | null;\r\n server: Server;\r\n endpoint: string;\r\n\r\n constructor(params: ApiParams) {\r\n const { id, server } = params;\r\n this.id = id !== undefined ? id : null;\r\n this.server = server;\r\n\r\n const { host, port } = server;\r\n this.endpoint = `https://${host}:${port}/adventure/v1`;\r\n }\r\n\r\n async ping() {\r\n const response = await fetch(`${this.endpoint}/ping`, {\r\n method: 'GET',\r\n });\r\n\r\n return response.text();\r\n }\r\n\r\n async handleGameStatusResponse(response: Response) {\r\n if (response.status === 400) {\r\n const error: Error = await response.json();\r\n throw error;\r\n }\r\n\r\n if (response.status !== 200) {\r\n const error: Error = { message: `${response.status}-${response.statusText}` };\r\n throw error;\r\n }\r\n const commandResult: CommandResult = await response.json();\r\n\r\n // Validation.\r\n if (isMissing(commandResult.id)) throw { message: `'id' field is not in response` } as Error;\r\n if (isMissing(commandResult.message)) throw { message: `'message' field is not in response` } as Error;\r\n if (isMissing(commandResult.state)) throw { message: `'state' field is not in response` } as Error;\r\n if (isMissing(commandResult.commandOptions)) throw { message: `'commandOptions' field is not in response` } as Error;\r\n\r\n this.id = commandResult.id;\r\n return commandResult;\r\n }\r\n\r\n async createGame() {\r\n const response = await fetch(`${this.endpoint}/create`, {\r\n method: 'POST',\r\n });\r\n\r\n return this.handleGameStatusResponse(response);\r\n }\r\n\r\n async getGame() {\r\n if (this.id === null) throw { message: 'no id set' } as Error;\r\n\r\n const response = await fetch(`${this.endpoint}/instance/${this.id}`, {\r\n method: 'GET',\r\n });\r\n\r\n return this.handleGameStatusResponse(response);\r\n }\r\n\r\n async deleteGame() {\r\n if (this.id === null) throw { message: 'no id set' } as Error;\r\n\r\n const response = await fetch(`${this.endpoint}/instance/${this.id}`, {\r\n method: 'DELETE',\r\n });\r\n\r\n if (response.status === 400) {\r\n const error: Error = await response.json();\r\n throw error;\r\n }\r\n\r\n if (response.status !== 200) {\r\n const error: Error = { message: `${response.status}-${response.statusText}` };\r\n throw error;\r\n }\r\n }\r\n\r\n async performCommand(request: Command) {\r\n if (this.id === null) throw { message: 'no id set' } as Error;\r\n\r\n const response = await fetch(`${this.endpoint}/instance/${this.id}/command/`, {\r\n method: 'POST',\r\n headers: {\r\n 'Accept': 'application/json',\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(request),\r\n });\r\n\r\n return this.handleGameStatusResponse(response);\r\n }\r\n\r\n async fetchLeaderboard() {\r\n const response = await fetch(`${this.endpoint}/leaderboard/`, {\r\n method: 'GET',\r\n });\r\n\r\n const leaderboard: Leaderboard = await response.json();\r\n return Object.entries(leaderboard);\r\n }\r\n}","import { Position, Toaster } from '@blueprintjs/core';\r\n\r\n\r\nexport const TIMEOUT_ERROR = 30000;\r\nexport const TIMEOUT_SUCCESS = 2000;\r\n\r\nconst MAX_TOASTS = 3;\r\n\r\nconst Message = Toaster.create({\r\n position: Position.BOTTOM,\r\n usePortal: true,\r\n canEscapeKeyClear: true,\r\n maxToasts: MAX_TOASTS,\r\n});\r\n\r\nexport default Message;","import React from \"react\";\r\nimport 'styles/Game.css';\r\n\r\ntype Props = {\r\n stateMap: object;\r\n}\r\n\r\nclass StateTable extends React.Component {\r\n render = () => {\r\n const { stateMap } = this.props;\r\n const stateKeys = Object.keys(stateMap); \r\n\r\n return stateKeys.length > 0 && (\r\n
\r\n \r\n \r\n \r\n \r\n \r\n {\r\n stateKeys.map((stateKey) => {\r\n return (\r\n \r\n \r\n )\r\n })\r\n }\r\n
KeyValue
{stateKey}{\r\n // @ts-ignore\r\n stateMap[stateKey]\r\n }
\r\n
\r\n )\r\n };\r\n}\r\n\r\nexport default StateTable;","import React from \"react\";\r\nimport ReactPlayer from \"react-player\";\r\nimport {Button} from \"@blueprintjs/core\";\r\nimport 'styles/Game.css';\r\n\r\ntype Props = {\r\n videoUrl: string;\r\n}\r\n\r\ntype State = {\r\n videoPlaying: boolean;\r\n}\r\n\r\nclass VideoPlayer extends React.Component {\r\n\r\n constructor(props: Props) {\r\n super(props);\r\n\r\n this.state = {\r\n videoPlaying: false,\r\n }\r\n }\r\n\r\n playAudio = () => {\r\n const { videoPlaying } = this.state;\r\n\r\n this.setState({\r\n videoPlaying: !videoPlaying,\r\n })\r\n };\r\n\r\n render = () => {\r\n const { videoPlaying } = this.state;\r\n const { videoUrl } = this.props;\r\n\r\n return (\r\n
\r\n \r\n \r\n
\r\n )\r\n };\r\n}\r\n\r\nexport default VideoPlayer;","import React from 'react';\r\nimport { HashRouter as Router, Route, RouteComponentProps } from 'react-router-dom';\r\nimport dotenv from 'dotenv';\r\nimport queryString from 'query-string';\r\n\r\nimport Game from 'components/Game';\r\nimport { Server } from 'types/adventure';\r\n\r\n\r\ndotenv.config();\r\n\r\nconst { REACT_APP_HOST = 'localhost', REACT_APP_PORT = 8080 } = process.env;\r\nconst SIEBEL_JSON = 'https://courses.grainger.illinois.edu/cs126/sp2020/resources/siebel.json';\r\n\r\ninterface MatchParams {\r\n id: string;\r\n};\r\n\r\ninterface Props extends RouteComponentProps { };\r\n\r\nconst parseQueryParams = (params: string) => {\r\n const {\r\n host = REACT_APP_HOST,\r\n port = REACT_APP_PORT,\r\n url = SIEBEL_JSON,\r\n } = queryString.parse(params);\r\n\r\n return { host, port, url } as Server;\r\n};\r\n\r\nconst MainPage = () => (\r\n \r\n {\r\n const id = Number.parseInt(props.match.params.id, 10);\r\n const server = parseQueryParams(props.location.search);\r\n const { commandResult = null } = props.location.state || { };\r\n return ;\r\n }} />\r\n {\r\n const server = parseQueryParams(props.location.search);\r\n return ;\r\n }} />\r\n \r\n);\r\n\r\nexport default MainPage;","import React from 'react';\r\nimport { Classes } from '@blueprintjs/core';\r\n\r\nimport '@blueprintjs/core/lib/css/blueprint.css';\r\n\r\nimport MainPage from 'components/MainPage';\r\n\r\nimport 'styles/App.css';\r\n\r\n\r\nconst App = () => (\r\n \r\n \r\n \r\n);\r\n\r\nexport default App;","// This optional code is used to register a service worker.\r\n// register() is not called by default.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on subsequent visits to a page, after all the\r\n// existing tabs open on the page have been closed, since previously cached\r\n// resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model and instructions on how to\r\n// opt-in, read https://bit.ly/CRA-PWA\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\ntype Config = {\r\n onSuccess?: (registration: ServiceWorkerRegistration) => void;\r\n onUpdate?: (registration: ServiceWorkerRegistration) => void;\r\n};\r\n\r\nexport function register(config?: Config) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(\r\n (process as { env: { [key: string]: string } }).env.PUBLIC_URL,\r\n window.location.href\r\n );\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Let's check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, config);\r\n\r\n // Add some additional logging to localhost, pointing developers to the\r\n // service worker/PWA documentation.\r\n navigator.serviceWorker.ready.then(() => {\r\n console.log(\r\n 'This web app is being served cache-first by a service ' +\r\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\r\n );\r\n });\r\n } else {\r\n // Is not localhost. Just register service worker\r\n registerValidSW(swUrl, config);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW(swUrl: string, config?: Config) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n if (installingWorker == null) {\r\n return;\r\n }\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the updated precached content has been fetched,\r\n // but the previous service worker will still serve the older\r\n // content until all client tabs are closed.\r\n console.log(\r\n 'New content is available and will be used when all ' +\r\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\r\n );\r\n\r\n // Execute callback\r\n if (config && config.onUpdate) {\r\n config.onUpdate(registration);\r\n }\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n\r\n // Execute callback\r\n if (config && config.onSuccess) {\r\n config.onSuccess(registration);\r\n }\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker(swUrl: string, config?: Config) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n const contentType = response.headers.get('content-type');\r\n if (\r\n response.status === 404 ||\r\n (contentType != null && contentType.indexOf('javascript') === -1)\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, config);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister() {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import React from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport dotenv from 'dotenv';\r\n\r\nimport App from 'components/App';\r\nimport * as serviceWorker from 'scripts/serviceWorker';\r\n\r\nimport 'styles/index.css';\r\n\r\n\r\ndotenv.config();\r\n\r\nReactDOM.render(, document.getElementById('root'));\r\n\r\n// If you want your app to work offline and load faster, you can change\r\n// unregister() to register() below. Note this comes with some pitfalls.\r\n// Learn more about service workers: https://bit.ly/CRA-PWA\r\nserviceWorker.unregister();"],"sourceRoot":""}