import { type ServerLifecycleWelcomePayload } from "@t3tools/contracts";
import { scopedProjectKey, scopeProjectRef } from "@t3tools/client-runtime";
import {
Outlet,
createRootRouteWithContext,
type ErrorComponentProps,
useLocation,
useNavigate,
} from "@tanstack/react-router";
import { useEffect, useEffectEvent, useRef } from "react";
import { QueryClient, useQueryClient } from "@tanstack/react-query";
import { APP_DISPLAY_NAME } from "../branding";
import { AppSidebarLayout } from "../components/AppSidebarLayout";
import { CommandPalette } from "../components/CommandPalette";
import { SshPasswordPromptDialog } from "../components/desktop/SshPasswordPromptDialog";
import { ProviderUpdateLaunchNotification } from "../components/ProviderUpdateLaunchNotification";
import {
SlowRpcAckToastCoordinator,
WebSocketConnectionCoordinator,
WebSocketConnectionSurface,
} from "../components/WebSocketConnectionSurface";
import { Button } from "../components/ui/button";
import {
AnchoredToastProvider,
stackedThreadToast,
ToastProvider,
toastManager,
} from "../components/ui/toast";
import { resolveAndPersistPreferredEditor } from "../editorPreferences";
import { readLocalApi } from "../localApi";
import { useSettings } from "../hooks/useSettings";
import {
deriveLogicalProjectKeyFromSettings,
derivePhysicalProjectKeyFromPath,
selectProjectGroupingSettings,
} from "../logicalProject";
import {
getServerConfigUpdatedNotification,
ServerConfigUpdatedNotification,
startServerStateSync,
useServerConfig,
useServerConfigUpdatedSubscription,
useServerWelcomeSubscription,
} from "../rpc/serverState";
import { useStore } from "../store";
import { useUiStateStore } from "../uiStateStore";
import { syncBrowserChromeTheme } from "../hooks/useTheme";
import {
ensureEnvironmentConnectionBootstrapped,
getPrimaryEnvironmentConnection,
listSavedEnvironmentRecords,
waitForSavedEnvironmentRegistryHydration,
startEnvironmentConnectionService,
useSavedEnvironmentRegistryStore,
} from "../environments/runtime";
import { configureClientTracing } from "../observability/clientTracing";
import {
ensurePrimaryEnvironmentReady,
getPrimaryKnownEnvironment,
resolveInitialServerAuthGateState,
updatePrimaryEnvironmentDescriptor,
} from "../environments/primary";
import { hasHostedPairingRequest, isHostedStaticApp } from "../hostedPairing";
export const Route = createRootRouteWithContext<{
queryClient: QueryClient;
}>()({
beforeLoad: async ({ location }) => {
if (location.pathname === "/pair" && hasHostedPairingRequest(new URL(window.location.href))) {
return {
authGateState: {
status: "hosted-pairing",
} as const,
};
}
if (isHostedStaticApp(new URL(window.location.href))) {
await waitForSavedEnvironmentRegistryHydration();
return {
authGateState: {
status: "hosted-static",
} as const,
};
}
const [, authGateState] = await Promise.all([
ensurePrimaryEnvironmentReady(),
resolveInitialServerAuthGateState(),
]);
return {
authGateState,
};
},
component: RootRouteView,
errorComponent: RootRouteErrorView,
head: () => ({
meta: [{ name: "title", content: APP_DISPLAY_NAME }],
}),
});
function RootRouteView() {
const pathname = useLocation({ select: (location) => location.pathname });
const { authGateState } = Route.useRouteContext();
const primaryEnvironmentAuthenticated = authGateState.status === "authenticated";
useEffect(() => {
const frame = window.requestAnimationFrame(() => {
syncBrowserChromeTheme();
});
return () => {
window.cancelAnimationFrame(frame);
};
}, [pathname]);
if (pathname === "/pair") {
return ;
}
if (authGateState.status !== "authenticated" && authGateState.status !== "hosted-static") {
return ;
}
const appShell = (
);
return (
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? : null}
{primaryEnvironmentAuthenticated ? (
{appShell}
) : (
appShell
)}
);
}
function HostedStaticEnvironmentBootstrap() {
const savedEnvironmentCount = useSavedEnvironmentRegistryStore(
(state) => Object.keys(state.byId).length,
);
useEffect(() => {
if (getPrimaryKnownEnvironment()) {
return;
}
const currentActiveEnvironmentId = useStore.getState().activeEnvironmentId;
if (currentActiveEnvironmentId) {
return;
}
const firstSavedEnvironment = listSavedEnvironmentRecords()[0];
if (!firstSavedEnvironment) {
return;
}
useStore.getState().setActiveEnvironmentId(firstSavedEnvironment.environmentId);
}, [savedEnvironmentCount]);
return null;
}
function RootRouteErrorView({ error, reset }: ErrorComponentProps) {
const message = errorMessage(error);
const details = errorDetails(error);
return (
{APP_DISPLAY_NAME}
Something went wrong.
{message}
Show error details
Hide error details
{details}
);
}
function errorMessage(error: unknown): string {
if (error instanceof Error && error.message.trim().length > 0) {
return error.message;
}
if (typeof error === "string" && error.trim().length > 0) {
return error;
}
return "An unexpected router error occurred.";
}
function errorDetails(error: unknown): string {
if (error instanceof Error) {
return error.stack ?? error.message;
}
if (typeof error === "string") {
return error;
}
try {
return JSON.stringify(error, null, 2);
} catch {
return "No additional error details are available.";
}
}
function ServerStateBootstrap() {
useEffect(() => {
if (!getPrimaryKnownEnvironment()) {
return;
}
return startServerStateSync(getPrimaryEnvironmentConnection().client.server);
}, []);
return null;
}
function AuthenticatedTracingBootstrap() {
useEffect(() => {
void configureClientTracing();
}, []);
return null;
}
function EnvironmentConnectionManagerBootstrap() {
const queryClient = useQueryClient();
useEffect(() => {
return startEnvironmentConnectionService(queryClient);
}, [queryClient]);
return null;
}
function EventRouter() {
const setActiveEnvironmentId = useStore((store) => store.setActiveEnvironmentId);
const navigate = useNavigate();
const pathname = useLocation({ select: (loc) => loc.pathname });
const projectGroupingSettings = useSettings(selectProjectGroupingSettings);
const readPathname = useEffectEvent(() => pathname);
const handledBootstrapThreadIdRef = useRef(null);
const seenServerConfigUpdateIdRef = useRef(getServerConfigUpdatedNotification()?.id ?? 0);
const lastKeybindingsSuccessToastAtRef = useRef(0);
const disposedRef = useRef(false);
const serverConfig = useServerConfig();
const handleWelcome = useEffectEvent((payload: ServerLifecycleWelcomePayload | null) => {
if (!payload) return;
updatePrimaryEnvironmentDescriptor(payload.environment);
setActiveEnvironmentId(payload.environment.environmentId);
void (async () => {
await ensureEnvironmentConnectionBootstrapped(payload.environment.environmentId);
if (disposedRef.current) {
return;
}
if (!payload.bootstrapProjectId || !payload.bootstrapThreadId) {
return;
}
const bootstrapEnvironmentState =
useStore.getState().environmentStateById[payload.environment.environmentId];
const bootstrapProject =
bootstrapEnvironmentState?.projectById[payload.bootstrapProjectId] ?? null;
const bootstrapProjectKey =
(bootstrapProject
? deriveLogicalProjectKeyFromSettings(bootstrapProject, projectGroupingSettings)
: null) ??
(serverConfig?.cwd
? derivePhysicalProjectKeyFromPath(payload.environment.environmentId, serverConfig.cwd)
: null) ??
scopedProjectKey(
scopeProjectRef(payload.environment.environmentId, payload.bootstrapProjectId),
);
useUiStateStore.getState().setProjectExpanded(bootstrapProjectKey, true);
if (readPathname() !== "/") {
return;
}
if (handledBootstrapThreadIdRef.current === payload.bootstrapThreadId) {
return;
}
await navigate({
to: "/$environmentId/$threadId",
params: {
environmentId: payload.environment.environmentId,
threadId: payload.bootstrapThreadId,
},
replace: true,
});
handledBootstrapThreadIdRef.current = payload.bootstrapThreadId;
})().catch(() => undefined);
});
const handleServerConfigUpdated = useEffectEvent(
(notification: ServerConfigUpdatedNotification | null) => {
if (!notification) return;
const { id, payload, source } = notification;
if (id <= seenServerConfigUpdateIdRef.current) {
return;
}
seenServerConfigUpdateIdRef.current = id;
if (source !== "keybindingsUpdated") {
return;
}
const issue = payload.issues.find((entry) => entry.kind.startsWith("keybindings."));
if (!issue) {
const now = Date.now();
if (now - lastKeybindingsSuccessToastAtRef.current < 2_000) {
return;
}
lastKeybindingsSuccessToastAtRef.current = now;
toastManager.add({
type: "success",
title: "Keybindings updated",
description: "Keybindings configuration reloaded successfully.",
});
return;
}
toastManager.add(
stackedThreadToast({
type: "warning",
title: "Invalid keybindings configuration",
description: issue.message,
actionVariant: "outline",
actionProps: {
children: "Open keybindings.json",
onClick: () => {
const api = readLocalApi();
if (!api) {
return;
}
void Promise.resolve(serverConfig ?? api.server.getConfig())
.then((config) => {
const editor = resolveAndPersistPreferredEditor(config.availableEditors);
if (!editor) {
throw new Error("No available editors found.");
}
return api.shell.openInEditor(config.keybindingsConfigPath, editor);
})
.catch((error) => {
toastManager.add(
stackedThreadToast({
type: "error",
title: "Unable to open keybindings file",
description:
error instanceof Error ? error.message : "Unknown error opening file.",
}),
);
});
},
},
}),
);
},
);
useEffect(() => {
if (!serverConfig) {
return;
}
updatePrimaryEnvironmentDescriptor(serverConfig.environment);
setActiveEnvironmentId(serverConfig.environment.environmentId);
}, [serverConfig, setActiveEnvironmentId]);
useEffect(() => {
disposedRef.current = false;
return () => {
disposedRef.current = true;
};
}, []);
useServerWelcomeSubscription(handleWelcome);
useServerConfigUpdatedSubscription(handleServerConfigUpdated);
return null;
}