diff --git a/site/AGENTS.md b/site/AGENTS.md index 872a020a29..891a034f53 100644 --- a/site/AGENTS.md +++ b/site/AGENTS.md @@ -73,6 +73,7 @@ When investigating or editing TypeScript/React code, always use the TypeScript l directly. Do not prefix them with `window.` (e.g., write `location.href`, not `window.location.href`). They are globally available in every browser context. +- Do not use `typeof window`, `typeof document`, or similar runtime checks for browser globals. Coder is a pure SPA so these globals are always available. - Always use react-query for data fetching. Do not attempt to manage any data life cycle manually. Do not ever call an `API` function directly within a component. diff --git a/site/src/contexts/DiffsWorkerPoolProvider.tsx b/site/src/contexts/DiffsWorkerPoolProvider.tsx index 9a7cafc538..b184f9d7a9 100644 --- a/site/src/contexts/DiffsWorkerPoolProvider.tsx +++ b/site/src/contexts/DiffsWorkerPoolProvider.tsx @@ -22,8 +22,7 @@ const getPoolSize = (): number => { return Math.min(Math.max(1, cores - 1), 3); }; -const hasWorkerSupport = (): boolean => - typeof window !== "undefined" && typeof Worker !== "undefined"; +const hasWorkerSupport = (): boolean => typeof Worker !== "undefined"; export const DiffsWorkerPoolProvider: FC = ({ children, diff --git a/site/src/pages/AgentsPage/AgentChatPage.tsx b/site/src/pages/AgentsPage/AgentChatPage.tsx index a01233f2fb..eb694ecfb0 100644 --- a/site/src/pages/AgentsPage/AgentChatPage.tsx +++ b/site/src/pages/AgentsPage/AgentChatPage.tsx @@ -345,7 +345,7 @@ export function useConversationEditingState(deps: { : null; const [{ editorInitialValue, initialEditorState }, setDraftState] = useState( () => { - if (typeof window === "undefined" || !draftStorageKey) { + if (!draftStorageKey) { return { editorInitialValue: "", initialEditorState: undefined }; } const draft = parseStoredDraft(localStorage.getItem(draftStorageKey)); diff --git a/site/src/pages/AgentsPage/components/AgentChatInput.stories.tsx b/site/src/pages/AgentsPage/components/AgentChatInput.stories.tsx index 792530c4a6..0dfd26e701 100644 --- a/site/src/pages/AgentsPage/components/AgentChatInput.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentChatInput.stories.tsx @@ -95,7 +95,7 @@ export const MobileEnterInsertsNewline: Story = { }, play: async ({ canvasElement, args }) => { const originalMatchMedia = window.matchMedia; - window.matchMedia = ((query: string) => + window.matchMedia = (query: string) => ({ matches: query === "(max-width: 639px)", media: query, @@ -105,7 +105,7 @@ export const MobileEnterInsertsNewline: Story = { dispatchEvent: () => true, addListener: () => undefined, removeListener: () => undefined, - }) as MediaQueryList) as typeof window.matchMedia; + }) as MediaQueryList; try { const canvas = within(canvasElement); diff --git a/site/src/pages/AgentsPage/components/AgentPageHeader.stories.tsx b/site/src/pages/AgentsPage/components/AgentPageHeader.stories.tsx index 43d3b8ed85..1845f35cf0 100644 --- a/site/src/pages/AgentsPage/components/AgentPageHeader.stories.tsx +++ b/site/src/pages/AgentsPage/components/AgentPageHeader.stories.tsx @@ -51,7 +51,7 @@ const createMatchMediaController = (initialDesktop: boolean) => { } }; - const matchMedia = ((query: string): MediaQueryList => { + const matchMedia = (query: string): MediaQueryList => { const isDesktopQuery = /\(\s*min-width\s*:\s*640px\s*\)/.test(query); return { matches: isDesktopQuery ? desktop : false, @@ -94,7 +94,7 @@ const createMatchMediaController = (initialDesktop: boolean) => { } }, }; - }) as typeof window.matchMedia; + }; return { matchMedia, diff --git a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx index 605bf9f7ae..5906b1c514 100644 --- a/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceReadyPage.tsx @@ -106,7 +106,7 @@ export const WorkspaceReadyPage: FC = ({ const favicon = getFaviconByStatus(workspace.latest_build); const [faviconTheme, setFaviconTheme] = useState<"light" | "dark">("dark"); useEffect(() => { - if (typeof window === "undefined" || !window.matchMedia) { + if (!window.matchMedia) { return; } diff --git a/site/src/testHelpers/storybook.tsx b/site/src/testHelpers/storybook.tsx index 36342885e1..bea5436738 100644 --- a/site/src/testHelpers/storybook.tsx +++ b/site/src/testHelpers/storybook.tsx @@ -145,7 +145,7 @@ export const withWebSocket = (Story: FC, { parameters }: StoryContext) => { removeEventListener(_type: string, _callback: CallbackFn) {} close() {} - } as unknown as typeof window.WebSocket; + } as unknown as typeof WebSocket; return ; }; diff --git a/site/src/utils/mobile.ts b/site/src/utils/mobile.ts index 97e465efec..dfc278c1b9 100644 --- a/site/src/utils/mobile.ts +++ b/site/src/utils/mobile.ts @@ -5,9 +5,6 @@ * virtual keyboard to pop up unexpectedly. */ export const isMobileViewport = (): boolean => { - if (typeof window === "undefined" || !window.matchMedia) { - return false; - } return window.matchMedia("(max-width: 639px)").matches; }; @@ -20,8 +17,5 @@ export const isMobileViewport = (): boolean => { * mobile branch instead of the desktop flyout branch. */ export const isBelowMdViewport = (): boolean => { - if (typeof window === "undefined" || !window.matchMedia) { - return false; - } return window.matchMedia("(max-width: 767px)").matches; };