import { lazy } from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import { createBrowserRouter, isRouteErrorResponse, redirect, RouterProvider, useRouteError, } from "react-router-dom"; import { ExclamationTriangleIcon } from "@heroicons/react/16/solid"; import { CLOUD_API, DEVICE_API } from "@/ui.config"; import api from "@/api"; import Root from "@/root"; import Card from "@components/Card"; import EmptyCard from "@components/EmptyCard"; import NotFoundPage from "@components/NotFoundPage"; import DeviceRoute, { LocalDevice } from "@routes/devices.$id"; import WelcomeRoute, { DeviceStatus } from "@routes/welcome-local"; import LoginLocalRoute from "@routes/login-local"; import WelcomeLocalModeRoute from "@routes/welcome-local.mode"; import WelcomeLocalPasswordRoute from "@routes/welcome-local.password"; import AdoptRoute from "@routes/adopt"; import SetupRoute from "@routes/devices.$id.setup"; import DevicesIdDeregister from "@routes/devices.$id.deregister"; import DeviceIdRename from "@routes/devices.$id.rename"; import DevicesRoute from "@routes/devices"; import SettingsIndexRoute from "@routes/devices.$id.settings._index"; import SettingsAccessIndexRoute from "@routes/devices.$id.settings.access._index"; const Notifications = lazy(() => import("@/notifications")); const SignupRoute = lazy(() => import("@routes/signup")); const LoginRoute = lazy(() => import("@routes/login")); const DevicesAlreadyAdopted = lazy(() => import("@routes/devices.already-adopted")); const OtherSessionRoute = lazy(() => import("@routes/devices.$id.other-session")); const MountRoute = lazy(() => import("./routes/devices.$id.mount")); const SettingsRoute = lazy(() => import("@routes/devices.$id.settings")); const SettingsMouseRoute = lazy(() => import("@routes/devices.$id.settings.mouse")); const SettingsKeyboardRoute = lazy(() => import("@routes/devices.$id.settings.keyboard")); const SettingsAdvancedRoute = lazy(() => import("@routes/devices.$id.settings.advanced")); const SettingsHardwareRoute = lazy(() => import("@routes/devices.$id.settings.hardware")); const SettingsVideoRoute = lazy(() => import("@routes/devices.$id.settings.video")); const SettingsAppearanceRoute = lazy(() => import("@routes/devices.$id.settings.appearance")); const SettingsGeneralIndexRoute = lazy(() => import("@routes/devices.$id.settings.general._index")); const SettingsGeneralRebootRoute = lazy(() => import("@routes/devices.$id.settings.general.reboot")); const SettingsGeneralUpdateRoute = lazy(() => import("@routes/devices.$id.settings.general.update")); const SettingsNetworkRoute = lazy(() => import("@routes/devices.$id.settings.network")); const SecurityAccessLocalAuthRoute = lazy(() => import("@routes/devices.$id.settings.access.local-auth")); const SettingsMacrosRoute = lazy(() => import("@routes/devices.$id.settings.macros")); const SettingsMacrosAddRoute = lazy(() => import("@routes/devices.$id.settings.macros.add")); const SettingsMacrosEditRoute = lazy(() => import("@routes/devices.$id.settings.macros.edit")); export const isOnDevice = import.meta.env.MODE === "device"; export const isInCloud = !isOnDevice; export async function checkCloudAuth() { const res = await fetch(`${CLOUD_API}/me`, { mode: "cors", credentials: "include", headers: { "Content-Type": "application/json" }, }); if (res.status === 401) { throw redirect(`/login?returnTo=${window.location.href}`); } return await res.json(); } export async function checkDeviceAuth() { const res = await api .GET(`${DEVICE_API}/device/status`) .then(res => res.json() as Promise); if (!res.isSetup) return redirect("/welcome"); const deviceRes = await api.GET(`${DEVICE_API}/device`); if (deviceRes.status === 401) return redirect("/login-local"); if (deviceRes.ok) { const device = (await deviceRes.json()) as LocalDevice; return { authMode: device.authMode }; } throw new Error("Error fetching device"); } export async function checkAuth() { return import.meta.env.MODE === "device" ? checkDeviceAuth() : checkCloudAuth(); } let router; if (isOnDevice) { router = createBrowserRouter([ { path: "/welcome/mode", element: , action: WelcomeLocalModeRoute.action, }, { path: "/welcome/password", element: , action: WelcomeLocalPasswordRoute.action, }, { path: "/welcome", element: , loader: WelcomeRoute.loader, }, { path: "/login-local", element: , action: LoginLocalRoute.action, loader: LoginLocalRoute.loader, }, { path: "/", errorElement: , element: , loader: DeviceRoute.loader, children: [ { path: "other-session", element: , }, { path: "mount", element: , }, { path: "settings", element: , children: [ { index: true, loader: SettingsIndexRoute.loader, }, { path: "general", children: [ { index: true, element: , }, { path: "reboot", element: , }, { path: "update", element: , }, ], }, { path: "mouse", element: , }, { path: "keyboard", element: , }, { path: "advanced", element: , }, { path: "hardware", element: , }, { path: "network", element: , }, { path: "access", children: [ { index: true, element: , loader: SettingsAccessIndexRoute.loader, }, { path: "local-auth", element: , }, ], }, { path: "video", element: , }, { path: "appearance", element: , }, { path: "macros", children: [ { index: true, element: , }, { path: "add", element: , }, { path: ":macroId/edit", element: , }, ], }, ], }, ], }, { path: "/adopt", element: , loader: AdoptRoute.loader, errorElement: , }, ]); } else { router = createBrowserRouter([ { errorElement: , children: [ { path: "signup", element: }, { path: "login", element: }, { path: "/", element: , children: [ { index: true, loader: async () => { await checkAuth(); return redirect(`/devices`); }, }, { path: "devices/:id/setup", element: , action: SetupRoute.action, loader: SetupRoute.loader, }, { path: "devices/already-adopted", element: , }, { path: "devices/:id", element: , loader: DeviceRoute.loader, children: [ { path: "other-session", element: , }, { path: "mount", element: , }, { path: "settings", element: , children: [ { index: true, loader: SettingsIndexRoute.loader, }, { path: "general", children: [ { index: true, element: , }, { path: "update", element: , }, ], }, { path: "mouse", element: , }, { path: "keyboard", element: , }, { path: "advanced", element: , }, { path: "hardware", element: , }, { path: "network", element: , }, { path: "access", children: [ { index: true, element: , loader: SettingsAccessIndexRoute.loader, }, { path: "local-auth", element: , }, ], }, { path: "video", element: , }, { path: "appearance", element: , }, { path: "macros", children: [ { index: true, element: , }, { path: "add", element: , }, { path: ":macroId/edit", element: , }, ], }, ], }, ], }, { path: "devices/:id/deregister", element: , loader: DevicesIdDeregister.loader, action: DevicesIdDeregister.action, }, { path: "devices/:id/rename", element: , loader: DeviceIdRename.loader, action: DeviceIdRename.action, }, { path: "devices", element: , loader: DevicesRoute.loader }, ], }, ], }, ]); } document.addEventListener("DOMContentLoaded", () => { ReactDOM.createRoot(document.getElementById("root")!).render( <> , ); }); // eslint-disable-next-line react-refresh/only-export-components function ErrorBoundary() { const error = useRouteError(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error const errorMessage = error?.data?.error?.message || error?.message; if (isRouteErrorResponse(error)) { if (error.status === 404) return ; } return (
{errorMessage}
) } />
); }