fixed (i think)

This commit is contained in:
Michael Freno
2025-12-19 15:52:44 -05:00
parent 004ab5407f
commit bc90adf839
4 changed files with 101 additions and 92 deletions

View File

@@ -1,14 +1,6 @@
import { Typewriter } from "./Typewriter"; import { Typewriter } from "./Typewriter";
import { useBars } from "~/context/bars"; import { useBars } from "~/context/bars";
import { import { onMount, createEffect, createSignal, Show, For } from "solid-js";
onMount,
createEffect,
createSignal,
createResource,
Show,
For,
Suspense
} from "solid-js";
import { api } from "~/lib/api"; import { api } from "~/lib/api";
import { TerminalSplash } from "./TerminalSplash"; import { TerminalSplash } from "./TerminalSplash";
import { insertSoftHyphens } from "~/lib/client-utils"; import { insertSoftHyphens } from "~/lib/client-utils";
@@ -18,40 +10,47 @@ import { RecentCommits } from "./RecentCommits";
import { ActivityHeatmap } from "./ActivityHeatmap"; import { ActivityHeatmap } from "./ActivityHeatmap";
import { DarkModeToggle } from "./DarkModeToggle"; import { DarkModeToggle } from "./DarkModeToggle";
interface GitCommit {
sha: string;
message: string;
author: string;
date: string;
repo: string;
url: string;
}
interface ContributionDay {
date: string;
count: number;
}
export function RightBarContent() { export function RightBarContent() {
const [githubCommits] = createResource(async () => { const [githubCommits, setGithubCommits] = createSignal<GitCommit[]>([]);
try { const [giteaCommits, setGiteaCommits] = createSignal<GitCommit[]>([]);
return await api.gitActivity.getGitHubCommits.query({ limit: 3 }); const [githubActivity, setGithubActivity] = createSignal<ContributionDay[]>(
} catch (error) { []
console.error("Failed to fetch GitHub commits:", error); );
return []; const [giteaActivity, setGiteaActivity] = createSignal<ContributionDay[]>([]);
} const [loading, setLoading] = createSignal(true);
});
const [giteaCommits] = createResource(async () => { onMount(async () => {
// Fetch all data client-side only to avoid hydration mismatch
try { try {
return await api.gitActivity.getGiteaCommits.query({ limit: 3 }); const [ghCommits, gtCommits, ghActivity, gtActivity] = await Promise.all([
} catch (error) { api.gitActivity.getGitHubCommits.query({ limit: 3 }).catch(() => []),
console.error("Failed to fetch Gitea commits:", error); api.gitActivity.getGiteaCommits.query({ limit: 3 }).catch(() => []),
return []; api.gitActivity.getGitHubActivity.query().catch(() => []),
} api.gitActivity.getGiteaActivity.query().catch(() => [])
}); ]);
const [githubActivity] = createResource(async () => { setGithubCommits(ghCommits);
try { setGiteaCommits(gtCommits);
return await api.gitActivity.getGitHubActivity.query(); setGithubActivity(ghActivity);
setGiteaActivity(gtActivity);
} catch (error) { } catch (error) {
console.error("Failed to fetch GitHub activity:", error); console.error("Failed to fetch git activity:", error);
return []; } finally {
} setLoading(false);
});
const [giteaActivity] = createResource(async () => {
try {
return await api.gitActivity.getGiteaActivity.query();
} catch (error) {
console.error("Failed to fetch Gitea activity:", error);
return [];
} }
}); });
@@ -111,29 +110,27 @@ export function RightBarContent() {
</Typewriter> </Typewriter>
{/* Git Activity Section */} {/* Git Activity Section */}
<Suspense fallback={<TerminalSplash />}> <hr class="border-overlay0" />
<hr class="border-overlay0" /> <div class="flex min-w-0 flex-col gap-6 px-4 pt-6">
<div class="flex min-w-0 flex-col gap-6 px-4 pt-6"> <RecentCommits
<RecentCommits commits={githubCommits()}
commits={githubCommits()} title="Recent GitHub Commits"
title="Recent GitHub Commits" loading={loading()}
loading={githubCommits.loading} />
/> <ActivityHeatmap
<ActivityHeatmap contributions={githubActivity()}
contributions={githubActivity()} title="GitHub Activity"
title="GitHub Activity" />
/> <RecentCommits
<RecentCommits commits={giteaCommits()}
commits={giteaCommits()} title="Recent Gitea Commits"
title="Recent Gitea Commits" loading={loading()}
loading={giteaCommits.loading} />
/> <ActivityHeatmap
<ActivityHeatmap contributions={giteaActivity()}
contributions={giteaActivity()} title="Gitea Activity"
title="Gitea Activity" />
/> </div>
</div>
</Suspense>
</div> </div>
); );
} }

View File

@@ -6,18 +6,18 @@ const spinnerChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "
export function TerminalSplash() { export function TerminalSplash() {
const [showing, setShowing] = createSignal(0); const [showing, setShowing] = createSignal(0);
// Only run animation on client onMount(() => {
if (!isServer) { // Only run animation on client
onMount(() => { if (isServer) return;
const interval = setInterval(() => {
setShowing((prev) => (prev + 1) % spinnerChars.length);
}, 50);
onCleanup(() => { const interval = setInterval(() => {
clearInterval(interval); setShowing((prev) => (prev + 1) % spinnerChars.length);
}); }, 50);
onCleanup(() => {
clearInterval(interval);
}); });
} });
return ( return (
<div class="bg-base flex min-h-screen w-full flex-col items-center justify-center overflow-hidden"> <div class="bg-base flex min-h-screen w-full flex-col items-center justify-center overflow-hidden">

51
src/env/server.ts vendored
View File

@@ -177,29 +177,42 @@ export const validateClientEnv = (
} }
}; };
// Environment validation for server startup with better error reporting // Lazy environment validation - only validates when accessed
export const env = (() => { let _cachedEnv: ServerEnv | null = null;
try { let _validationAttempted = false;
// Validate server environment variables using process.env
const validatedServerEnv = validateServerEnv(process.env);
console.log("✅ Environment validation successful"); export const env = new Proxy({} as ServerEnv, {
return validatedServerEnv; get(_target, prop: string) {
} catch (error) { // Only validate once
if (error instanceof EnvironmentError) { if (!_validationAttempted) {
console.error("❌ Environment validation failed:", error.message); _validationAttempted = true;
if (error.errors) { try {
console.error( // Validate server environment variables using process.env
"Detailed errors:", _cachedEnv = validateServerEnv(process.env);
JSON.stringify(error.errors, null, 2) console.log("✅ Environment validation successful");
); } catch (error) {
if (error instanceof EnvironmentError) {
console.error("❌ Environment validation failed:", error.message);
if (error.errors) {
console.error(
"Detailed errors:",
JSON.stringify(error.errors, null, 2)
);
}
throw new Error(`Environment validation failed: ${error.message}`);
}
console.error("❌ Unexpected environment validation error:", error);
throw new Error("Unexpected environment validation error occurred");
} }
throw new Error(`Environment validation failed: ${error.message}`);
} }
console.error("❌ Unexpected environment validation error:", error);
throw new Error("Unexpected environment validation error occurred"); if (!_cachedEnv) {
throw new Error("Environment validation has not been performed yet");
}
return _cachedEnv[prop as keyof ServerEnv];
} }
})(); });
// For client-side validation (useful in components) // For client-side validation (useful in components)
export const getClientEnvValidation = () => { export const getClientEnvValidation = () => {

View File

@@ -1,5 +1,4 @@
import { createTRPCProxyClient, httpBatchLink, loggerLink } from "@trpc/client"; import { createTRPCProxyClient, httpBatchLink, loggerLink } from "@trpc/client";
import { env } from "~/env/server";
import { AppRouter } from "~/server/api/root"; import { AppRouter } from "~/server/api/root";
export const api = createTRPCProxyClient<AppRouter>({ export const api = createTRPCProxyClient<AppRouter>({
@@ -7,6 +6,6 @@ export const api = createTRPCProxyClient<AppRouter>({
// will print out helpful logs when using client // will print out helpful logs when using client
loggerLink(), loggerLink(),
// identifies what url will handle trpc requests // identifies what url will handle trpc requests
httpBatchLink({ url: `${env.VITE_DOMAIN}/api/trpc` }) httpBatchLink({ url: `${import.meta.env.VITE_DOMAIN}/api/trpc` })
] ]
}); });