diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/prefetch.ts b/apps/sim/app/workspace/[workspaceId]/settings/[section]/prefetch.ts index b39acf3bf4..7ac50861e5 100644 --- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/prefetch.ts +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/prefetch.ts @@ -1,8 +1,8 @@ import type { QueryClient } from '@tanstack/react-query' import { headers } from 'next/headers' import { getInternalApiBaseUrl } from '@/lib/core/utils/urls' -import { generalSettingsKeys } from '@/hooks/queries/general-settings' -import { userProfileKeys } from '@/hooks/queries/user-profile' +import { generalSettingsKeys, mapGeneralSettingsResponse } from '@/hooks/queries/general-settings' +import { mapUserProfileResponse, userProfileKeys } from '@/hooks/queries/user-profile' /** * Forwards incoming request cookies so server-side API fetches authenticate correctly. @@ -29,17 +29,7 @@ export function prefetchGeneralSettings(queryClient: QueryClient) { }) if (!response.ok) throw new Error(`Settings prefetch failed: ${response.status}`) const { data } = await response.json() - return { - autoConnect: data.autoConnect ?? true, - showTrainingControls: data.showTrainingControls ?? false, - superUserModeEnabled: data.superUserModeEnabled ?? true, - theme: data.theme || 'system', - telemetryEnabled: data.telemetryEnabled ?? true, - billingUsageNotificationsEnabled: data.billingUsageNotificationsEnabled ?? true, - errorNotificationsEnabled: data.errorNotificationsEnabled ?? true, - snapToGridSize: data.snapToGridSize ?? 0, - showActionBar: data.showActionBar ?? true, - } + return mapGeneralSettingsResponse(data) }, staleTime: 60 * 60 * 1000, }) @@ -61,14 +51,7 @@ export function prefetchUserProfile(queryClient: QueryClient) { }) if (!response.ok) throw new Error(`Profile prefetch failed: ${response.status}`) const { user } = await response.json() - return { - id: user.id, - name: user.name || '', - email: user.email || '', - image: user.image || null, - createdAt: user.createdAt, - updatedAt: user.updatedAt, - } + return mapUserProfileResponse(user) }, staleTime: 5 * 60 * 1000, }) diff --git a/apps/sim/hooks/queries/general-settings.ts b/apps/sim/hooks/queries/general-settings.ts index d4015ddf43..db1cd864f3 100644 --- a/apps/sim/hooks/queries/general-settings.ts +++ b/apps/sim/hooks/queries/general-settings.ts @@ -28,6 +28,24 @@ export interface GeneralSettings { showActionBar: boolean } +/** + * Map raw API response data to GeneralSettings with defaults. + * Shared by both client fetch and server prefetch to prevent shape drift. + */ +export function mapGeneralSettingsResponse(data: Record): GeneralSettings { + return { + autoConnect: (data.autoConnect as boolean) ?? true, + showTrainingControls: (data.showTrainingControls as boolean) ?? false, + superUserModeEnabled: (data.superUserModeEnabled as boolean) ?? true, + theme: (data.theme as GeneralSettings['theme']) || 'system', + telemetryEnabled: (data.telemetryEnabled as boolean) ?? true, + billingUsageNotificationsEnabled: (data.billingUsageNotificationsEnabled as boolean) ?? true, + errorNotificationsEnabled: (data.errorNotificationsEnabled as boolean) ?? true, + snapToGridSize: (data.snapToGridSize as number) ?? 0, + showActionBar: (data.showActionBar as boolean) ?? true, + } +} + /** * Fetch general settings from API */ @@ -39,18 +57,7 @@ async function fetchGeneralSettings(signal?: AbortSignal): Promise): UserProfile { + return { + id: user.id as string, + name: (user.name as string) || '', + email: (user.email as string) || '', + image: (user.image as string) || null, + createdAt: user.createdAt as string, + updatedAt: user.updatedAt as string, + } +} + /** * Fetch user profile from API */ @@ -35,15 +50,7 @@ async function fetchUserProfile(signal?: AbortSignal): Promise { } const { user } = await response.json() - - return { - id: user.id, - name: user.name || '', - email: user.email || '', - image: user.image || null, - createdAt: user.createdAt, - updatedAt: user.updatedAt, - } + return mapUserProfileResponse(user) } /**