Prettier 2: Electric Boogaloo (#6113)

# Description of Changes
When I added Prettier formatting in #6052, my aim was to use just the
default settings in Prettier. Turns out, Prettier looks _really hard_
for any config files if it's not explicitly given one, which means that
if a developer has some sort of Prettier config file lying around on
their system, Prettier might find it and use it. Also, Prettier changes
its defaults based on stuff in `.editorconfig` without any good way of
disabling that behaviour explicitly in its config file.

To solve both of these issues, I've introduced a `.prettierrc` file
which sets Prettier's defaults explicitly, and then reformatted all our
code _again_ in Prettier's actual default settings. This should achieve
the aim of #6052 and remove the possibility for it breaking on different
dev computers.
This commit is contained in:
James Brunton
2026-04-17 09:50:16 +00:00
committed by GitHub
parent de8c483054
commit 8ab060a4be
1207 changed files with 52646 additions and 15352 deletions
+150 -40
View File
@@ -1,10 +1,32 @@
import { createContext, useContext, useEffect, useState, ReactNode, useCallback } from "react";
import {
createContext,
useContext,
useEffect,
useState,
ReactNode,
useCallback,
} from "react";
import { supabase } from "@app/auth/supabase";
import type { Session, User as SupabaseUser, AuthError } from "@supabase/supabase-js";
import { CreditSummary, SubscriptionInfo, CreditCheckResult, ApiCredits } from "@app/types/credits";
import apiClient, { setGlobalCreditUpdateCallback } from "@app/services/apiClient";
import type {
Session,
User as SupabaseUser,
AuthError,
} from "@supabase/supabase-js";
import {
CreditSummary,
SubscriptionInfo,
CreditCheckResult,
ApiCredits,
} from "@app/types/credits";
import apiClient, {
setGlobalCreditUpdateCallback,
} from "@app/services/apiClient";
import { synchronizeUserUpgrade } from "@app/services/userService";
import { syncOAuthAvatar, getProfilePictureMetadata, type ProfilePictureMetadata } from "@app/services/avatarSyncService";
import {
syncOAuthAvatar,
getProfilePictureMetadata,
type ProfilePictureMetadata,
} from "@app/services/avatarSyncService";
// Extend Supabase User to include optional username for compatibility
export type User = SupabaseUser & { username?: string };
@@ -55,7 +77,11 @@ const AuthContext = createContext<AuthContextType>({
profilePictureMetadata: null,
signOut: async () => {},
refreshSession: async () => {},
hasSufficientCredits: () => ({ hasSufficientCredits: false, currentBalance: 0, requiredCredits: 0 }),
hasSufficientCredits: () => ({
hasSufficientCredits: false,
currentBalance: 0,
requiredCredits: 0,
}),
updateCredits: () => {},
refreshCredits: async () => {},
refreshProStatus: async () => {},
@@ -69,12 +95,19 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState<AuthError | null>(null);
const [creditBalance, setCreditBalance] = useState<number | null>(null);
const [subscription, setSubscription] = useState<SubscriptionInfo | null>(null);
const [creditSummary, setCreditSummary] = useState<CreditSummary | null>(null);
const [subscription, setSubscription] = useState<SubscriptionInfo | null>(
null,
);
const [creditSummary, setCreditSummary] = useState<CreditSummary | null>(
null,
);
const [isPro, setIsPro] = useState<boolean | null>(null);
const [trialStatus, setTrialStatus] = useState<TrialStatus | null>(null);
const [profilePictureUrl, setProfilePictureUrl] = useState<string | null>(null);
const [profilePictureMetadata, setProfilePictureMetadata] = useState<ProfilePictureMetadata | null>(null);
const [profilePictureUrl, setProfilePictureUrl] = useState<string | null>(
null,
);
const [profilePictureMetadata, setProfilePictureMetadata] =
useState<ProfilePictureMetadata | null>(null);
const fetchCredits = useCallback(
async (sessionToUse?: Session | null) => {
@@ -89,14 +122,18 @@ export function AuthProvider({ children }: { children: ReactNode }) {
}
try {
console.debug("[Auth Debug] Fetching credits for user:", currentSession.user.id);
console.debug(
"[Auth Debug] Fetching credits for user:",
currentSession.user.id,
);
const response = await apiClient.get<ApiCredits>("/api/v1/credits");
const apiCredits = response.data;
// Map server payload to app CreditSummary
const credits: CreditSummary = {
currentCredits: apiCredits.totalAvailableCredits,
maxCredits: apiCredits.weeklyCreditsAllocated + apiCredits.totalBoughtCredits,
maxCredits:
apiCredits.weeklyCreditsAllocated + apiCredits.totalBoughtCredits,
creditsUsed:
apiCredits.weeklyCreditsAllocated -
apiCredits.weeklyCreditsRemaining +
@@ -139,13 +176,18 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const currentSession = sessionToUse ?? session;
if (!currentSession?.user) {
console.debug("[Auth Debug] No user session, skipping pro status fetch");
console.debug(
"[Auth Debug] No user session, skipping pro status fetch",
);
setIsPro(null);
return;
}
try {
console.debug("[Auth Debug] Fetching pro status for user:", currentSession.user.id);
console.debug(
"[Auth Debug] Fetching pro status for user:",
currentSession.user.id,
);
const { data: proStatus, error } = await supabase.rpc("is_pro");
if (error) {
@@ -173,16 +215,23 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const currentSession = sessionToUse ?? session;
if (!currentSession?.user) {
console.debug("[Auth Debug] No user session, skipping trial status fetch");
console.debug(
"[Auth Debug] No user session, skipping trial status fetch",
);
setTrialStatus(null);
return;
}
try {
console.debug("[Auth Debug] Fetching trial status for user:", currentSession.user.id);
console.debug(
"[Auth Debug] Fetching trial status for user:",
currentSession.user.id,
);
const { data, error } = await supabase
.from("billing_subscriptions")
.select("status, trial_end, has_payment_method, scheduled_subscription_id")
.select(
"status, trial_end, has_payment_method, scheduled_subscription_id",
)
.in("status", ["trialing", "incomplete_expired", "canceled"])
.order("created_at", { ascending: false })
.limit(1)
@@ -197,7 +246,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (data?.trial_end) {
const trialEnd = new Date(data.trial_end);
const now = new Date();
const daysRemaining = Math.ceil((trialEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
const daysRemaining = Math.ceil(
(trialEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),
);
setTrialStatus({
isTrialing: data.status === "trialing" && daysRemaining > 0,
@@ -233,7 +284,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const currentSession = sessionToUse ?? session;
if (!currentSession?.user) {
console.debug("[Auth Debug] No user session, skipping profile picture fetch");
console.debug(
"[Auth Debug] No user session, skipping profile picture fetch",
);
setProfilePictureUrl(null);
return;
}
@@ -242,16 +295,26 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const PROFILE_BUCKET = "profile-pictures";
const profilePath = `${currentSession.user.id}/avatar`;
console.debug("[Auth Debug] Fetching profile picture for user:", currentSession.user.id);
const { data, error } = await supabase.storage.from(PROFILE_BUCKET).createSignedUrl(profilePath, 60 * 60);
console.debug(
"[Auth Debug] Fetching profile picture for user:",
currentSession.user.id,
);
const { data, error } = await supabase.storage
.from(PROFILE_BUCKET)
.createSignedUrl(profilePath, 60 * 60);
if (error) {
// Profile picture not found is expected for users without uploads
console.debug("[Auth Debug] Profile picture not available:", error.message);
console.debug(
"[Auth Debug] Profile picture not available:",
error.message,
);
setProfilePictureUrl(null);
} else {
setProfilePictureUrl(data.signedUrl);
console.debug("[Auth Debug] Profile picture URL fetched successfully");
console.debug(
"[Auth Debug] Profile picture URL fetched successfully",
);
}
} catch (error: unknown) {
console.debug("[Auth Debug] Failed to fetch profile picture:", error);
@@ -270,18 +333,31 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const currentSession = sessionToUse ?? session;
if (!currentSession?.user) {
console.debug("[Auth Debug] No user session, skipping profile picture metadata fetch");
console.debug(
"[Auth Debug] No user session, skipping profile picture metadata fetch",
);
setProfilePictureMetadata(null);
return;
}
try {
console.debug("[Auth Debug] Fetching profile picture metadata for user:", currentSession.user.id);
const metadata = await getProfilePictureMetadata(currentSession.user.id);
console.debug(
"[Auth Debug] Fetching profile picture metadata for user:",
currentSession.user.id,
);
const metadata = await getProfilePictureMetadata(
currentSession.user.id,
);
setProfilePictureMetadata(metadata);
console.debug("[Auth Debug] Profile picture metadata fetched:", metadata);
console.debug(
"[Auth Debug] Profile picture metadata fetched:",
metadata,
);
} catch (error: unknown) {
console.debug("[Auth Debug] Failed to fetch profile picture metadata:", error);
console.debug(
"[Auth Debug] Failed to fetch profile picture metadata:",
error,
);
setProfilePictureMetadata(null);
}
},
@@ -294,7 +370,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const updateCredits = useCallback(
(newBalance: number) => {
console.debug("[Auth Debug] Updating credit balance:", { from: creditBalance, to: newBalance });
console.debug("[Auth Debug] Updating credit balance:", {
from: creditBalance,
to: newBalance,
});
setCreditBalance(newBalance);
// Also update the creditSummary if it exists
if (creditSummary) {
@@ -313,7 +392,11 @@ export function AuthProvider({ children }: { children: ReactNode }) {
(requiredCredits: number): CreditCheckResult => {
const currentBalance = creditBalance ?? 0;
const hasSufficient = currentBalance >= requiredCredits;
console.debug("[Auth Debug] Credit check:", { requiredCredits, currentBalance, hasSufficient });
console.debug("[Auth Debug] Credit check:", {
requiredCredits,
currentBalance,
hasSufficient,
});
return {
hasSufficientCredits: hasSufficient,
@@ -340,7 +423,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
setSession(data.session);
}
} catch (err) {
console.error("[Auth Debug] Unexpected error during session refresh:", err);
console.error(
"[Auth Debug] Unexpected error during session refresh:",
err,
);
setError(err as AuthError);
} finally {
setLoading(false);
@@ -396,7 +482,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
if (data.session?.user) {
// Sync OAuth avatar in background
syncOAuthAvatar(data.session.user).catch((err) => {
console.debug("[Auth Debug] Failed to sync OAuth avatar on init:", err);
console.debug(
"[Auth Debug] Failed to sync OAuth avatar on init:",
err,
);
});
await fetchCredits(data.session);
@@ -411,7 +500,10 @@ export function AuthProvider({ children }: { children: ReactNode }) {
}
}
} catch (err) {
console.error("[Auth Debug] Unexpected error during auth initialization:", err);
console.error(
"[Auth Debug] Unexpected error during auth initialization:",
err,
);
if (mounted) {
setError(err as AuthError);
}
@@ -477,7 +569,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
setTimeout(() => {
fetchProfilePicture(newSession).finally(() => {
setLoading(false);
console.debug("[Auth Debug] User data fully loaded after sign in");
console.debug(
"[Auth Debug] User data fully loaded after sign in",
);
});
}, 500);
});
@@ -493,7 +587,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
fetchProfilePictureMetadata(newSession),
fetchProfilePicture(newSession),
]).then(() => {
console.debug("[Auth Debug] User data refreshed after token refresh");
console.debug(
"[Auth Debug] User data refreshed after token refresh",
);
});
}
} else if (event === "USER_UPDATED") {
@@ -503,8 +599,15 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const pendingUpgrade = sessionStorage.getItem("pendingUpgrade");
const upgradeProvider = sessionStorage.getItem("upgradeProvider");
if (pendingUpgrade && newSession?.user && newSession.user.is_anonymous === false) {
console.debug("[Auth Debug] Processing pending OAuth upgrade:", upgradeProvider);
if (
pendingUpgrade &&
newSession?.user &&
newSession.user.is_anonymous === false
) {
console.debug(
"[Auth Debug] Processing pending OAuth upgrade:",
upgradeProvider,
);
// Clear the flags first to prevent loops
sessionStorage.removeItem("pendingUpgrade");
@@ -513,7 +616,9 @@ export function AuthProvider({ children }: { children: ReactNode }) {
// Synchronize with backend
synchronizeUserUpgrade(upgradeProvider || undefined)
.then(() => {
console.debug("[Auth Debug] User upgrade synchronized successfully");
console.debug(
"[Auth Debug] User upgrade synchronized successfully",
);
// Refresh credits, pro status, trial status, profile picture metadata, and profile picture after upgrade
if (newSession?.user) {
@@ -527,10 +632,15 @@ export function AuthProvider({ children }: { children: ReactNode }) {
}
})
.then(() => {
console.debug("[Auth Debug] User data refreshed after upgrade");
console.debug(
"[Auth Debug] User data refreshed after upgrade",
);
})
.catch((err) => {
console.error("[Auth Debug] Failed to synchronize user upgrade:", err);
console.error(
"[Auth Debug] Failed to synchronize user upgrade:",
err,
);
});
}
}
+11 -3
View File
@@ -22,7 +22,9 @@ if (!config.url) {
}
if (!config.key) {
throw new Error("Missing VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY environment variable");
throw new Error(
"Missing VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY environment variable",
);
}
export const supabase = createClient(config.url, config.key, {
@@ -95,7 +97,10 @@ export const linkEmailIdentity = async (email: string, password?: string) => {
const { error: refreshError } = await supabase.auth.refreshSession();
if (refreshError) {
console.warn("[Supabase] Session refresh after email linking failed:", refreshError);
console.warn(
"[Supabase] Session refresh after email linking failed:",
refreshError,
);
// Don't throw - linking was successful, refresh is just for consistency
} else {
console.log("[Supabase] Session refreshed after email linking");
@@ -113,7 +118,10 @@ export const linkEmailIdentity = async (email: string, password?: string) => {
}
};
export const linkOAuthIdentity = async (provider: "google" | "github" | "apple" | "azure", redirectTo?: string) => {
export const linkOAuthIdentity = async (
provider: "google" | "github" | "apple" | "azure",
redirectTo?: string,
) => {
try {
const { data, error } = await supabase.auth.linkIdentity({
provider: provider,