eny.space Landingpage
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add 404 page and improve signup network error handling

- Add space-themed 404 page with heliopause headline
- Catch network/timeout errors in signUp action and return readable messages instead of letting fetch failures surface raw to the client
- Add try/catch in SignUpForm transition as a safety net

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+71 -26
+23 -11
app/actions/auth.ts
··· 13 13 const email = formData.get("email") as string; 14 14 const password = formData.get("password") as string; 15 15 16 - const { error } = await supabase.auth.signUp({ 17 - email, 18 - password, 19 - options: { 20 - emailRedirectTo: `${ 21 - process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000" 22 - }/auth/callback`, 23 - }, 24 - }); 16 + try { 17 + const { error } = await supabase.auth.signUp({ 18 + email, 19 + password, 20 + options: { 21 + emailRedirectTo: `${ 22 + process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000" 23 + }/auth/callback`, 24 + }, 25 + }); 25 26 26 - if (error) { 27 - return { error: error.message }; 27 + if (error) { 28 + return { error: error.message }; 29 + } 30 + } catch (err) { 31 + const cause = (err as any)?.cause; 32 + const isTimeout = 33 + cause?.code === "UND_ERR_CONNECT_TIMEOUT" || 34 + (err as Error)?.message === "fetch failed"; 35 + return { 36 + error: isTimeout 37 + ? "Could not reach the server. Please check your connection and try again." 38 + : "An unexpected error occurred. Please try again.", 39 + }; 28 40 } 29 41 30 42 return { success: true };
+18 -13
app/api/pds/service/route.ts
··· 37 37 const failedRequestsLast24h = 42; 38 38 const successfulRequestsLast24h = requestsPerHourLast24h.reduce( 39 39 (sum, p) => sum + p.count, 40 - 0, 40 + 0 41 41 ); 42 42 43 43 return { ··· 102 102 error: 103 103 "Missing PDS_API_TOKEN env variable for authenticating with PDS API", 104 104 }, 105 - { status: 500 }, 105 + { status: 500 } 106 106 ); 107 107 } 108 108 ··· 121 121 .eq("user_id", user.id) 122 122 .maybeSingle(); 123 123 124 - const forcedServiceIdRaw = process.env.PDS_FORCE_SERVICE_ID === "true" 125 - ? process.env.PDS_TEST_SERVICE_ID 126 - : undefined; 127 - const forcedServiceId = forcedServiceIdRaw ? Number(forcedServiceIdRaw) : null; 124 + const forcedServiceIdRaw = 125 + process.env.PDS_FORCE_SERVICE_ID === "true" 126 + ? process.env.PDS_TEST_SERVICE_ID 127 + : undefined; 128 + const forcedServiceId = forcedServiceIdRaw 129 + ? Number(forcedServiceIdRaw) 130 + : null; 128 131 129 - const pdsServiceId = (forcedServiceId !== null && Number.isFinite(forcedServiceId) 130 - ? forcedServiceId 131 - : pdsServiceRow?.pds_service_id) as number | null | undefined; 132 + const pdsServiceId = ( 133 + forcedServiceId !== null && Number.isFinite(forcedServiceId) 134 + ? forcedServiceId 135 + : pdsServiceRow?.pds_service_id 136 + ) as number | null | undefined; 132 137 133 138 if (!pdsServiceId) { 134 139 return NextResponse.json( 135 140 { message: "No provisioned PDS found for this user yet" }, 136 - { status: 404 }, 141 + { status: 404 } 137 142 ); 138 143 } 139 144 ··· 171 176 status: res.status, 172 177 body: data, 173 178 }, 174 - { status: 502 }, 179 + { status: 502 } 175 180 ); 176 181 } 177 182 ··· 204 209 contentType, 205 210 bodyPreview: bodyText.slice(0, 500), 206 211 }, 207 - { status: 502 }, 212 + { status: 502 } 208 213 ); 209 214 } catch (error) { 210 215 console.error("Error proxying PDS service request", error); ··· 213 218 error: "Failed to reach PDS service endpoint", 214 219 detail: error instanceof Error ? error.message : String(error), 215 220 }, 216 - { status: 500 }, 221 + { status: 500 } 217 222 ); 218 223 } 219 224 }
+24
app/not-found.tsx
··· 1 + import { Heading } from "@/components/heading"; 2 + import { ButtonLink } from "@/components/button-link"; 3 + 4 + export default function NotFound() { 5 + return ( 6 + <div className="flex flex-col items-center justify-center gap-6 py-32 text-center"> 7 + <Heading className="text-5xl tracking-tight text-white sm:text-6xl md:text-7xl"> 8 + you've drifted past the heliopause. 9 + </Heading> 10 + <Heading as="h2" className="text-2xl text-white/50"> 11 + 404 12 + </Heading> 13 + <p className="text-muted-foreground max-w-sm"> 14 + you've gone too far into the unknown. this page doesn't exist. 15 + </p> 16 + <ButtonLink 17 + href="/" 18 + className="bg-primary text-primary-foreground hover:bg-primary/90" 19 + > 20 + Go home 21 + </ButtonLink> 22 + </div> 23 + ); 24 + }
+6 -2
app/signup/signup-form.tsx
··· 28 28 e.preventDefault(); 29 29 const formData = new FormData(e.currentTarget); 30 30 startTransition(async () => { 31 - const result = await signUp(null, formData); 32 - setState(result); 31 + try { 32 + const result = await signUp(null, formData); 33 + setState(result); 34 + } catch { 35 + setState({ error: "An unexpected error occurred. Please try again." }); 36 + } 33 37 }); 34 38 } 35 39