Skip to content

Commit f225ad1

Browse files
committed
Enhance error handling in all package version routes
1 parent 5ac0d36 commit f225ad1

File tree

2 files changed

+298
-180
lines changed

2 files changed

+298
-180
lines changed

apps/cyberstorm-remix/app/p/packageVersion.tsx

Lines changed: 146 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,23 @@ import {
5353
formatInteger,
5454
formatToDisplayName,
5555
} from "@thunderstore/cyberstorm/src/utils/utils";
56-
import { DapperTs } from "@thunderstore/dapper-ts";
57-
import { getPackageVersionDetails } from "@thunderstore/dapper-ts/src/methods/packageVersion";
56+
import { type OutletContextShape } from "~/root";
57+
import { CopyButton } from "~/commonComponents/CopyButton/CopyButton";
58+
import { getPublicEnvVariables } from "cyberstorm/security/publicEnvVariables";
5859
import { getTeamDetails } from "@thunderstore/dapper-ts/src/methods/team";
60+
import { isPromise } from "cyberstorm/utils/typeChecks";
61+
import { getPackageVersionDetails } from "@thunderstore/dapper-ts/src/methods/packageVersion";
62+
import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse";
63+
import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError";
64+
import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings";
65+
import { getLoaderTools } from "cyberstorm/utils/getLoaderTools";
5966

60-
import "./packageListing.css";
67+
const packageVersionNotFoundMappings = [
68+
createNotFoundMapping(
69+
"Package version not found.",
70+
"We could not find the requested package version."
71+
),
72+
];
6173

6274
export async function loader({ params }: LoaderFunctionArgs) {
6375
if (
@@ -66,55 +78,81 @@ export async function loader({ params }: LoaderFunctionArgs) {
6678
params.packageId &&
6779
params.packageVersion
6880
) {
69-
const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]);
70-
const dapper = new DapperTs(() => {
81+
const { dapper } = getLoaderTools();
82+
try {
83+
const [community, version, team] = await Promise.all([
84+
dapper.getCommunity(params.communityId),
85+
dapper.getPackageVersionDetails(
86+
params.namespaceId,
87+
params.packageId,
88+
params.packageVersion
89+
),
90+
dapper.getTeamDetails(params.namespaceId),
91+
]);
92+
7193
return {
72-
apiHost: publicEnvVariables.VITE_API_URL,
73-
sessionId: undefined,
94+
communityId: params.communityId,
95+
community,
96+
version,
97+
team,
7498
};
75-
});
76-
77-
return {
78-
communityId: params.communityId,
79-
community: await dapper.getCommunity(params.communityId),
80-
version: await dapper.getPackageVersionDetails(
81-
params.namespaceId,
82-
params.packageId,
83-
params.packageVersion
84-
),
85-
team: await dapper.getTeamDetails(params.namespaceId),
86-
};
99+
} catch (error) {
100+
handleLoaderError(error, { mappings: packageVersionNotFoundMappings });
101+
}
87102
}
88-
throw new Response("Package not found", { status: 404 });
103+
throwUserFacingPayloadResponse({
104+
headline: "Package not found.",
105+
description: "We could not find the requested package.",
106+
category: "not_found",
107+
status: 404,
108+
});
89109
}
90110

91-
export async function clientLoader({ params }: LoaderFunctionArgs) {
111+
export function clientLoader({ params }: LoaderFunctionArgs) {
92112
if (
93113
params.communityId &&
94114
params.namespaceId &&
95115
params.packageId &&
96116
params.packageVersion
97117
) {
98-
const tools = getSessionTools();
99-
const dapper = new DapperTs(() => {
100-
return {
101-
apiHost: tools?.getConfig().apiHost,
102-
sessionId: tools?.getConfig().sessionId,
103-
};
104-
});
105-
106-
return {
107-
communityId: params.communityId,
108-
community: dapper.getCommunity(params.communityId),
109-
version: dapper.getPackageVersionDetails(
118+
const { dapper } = getLoaderTools();
119+
const community = dapper
120+
.getCommunity(params.communityId)
121+
.catch((error) =>
122+
handleLoaderError(error, { mappings: packageVersionNotFoundMappings })
123+
);
124+
const version = dapper
125+
.getPackageVersionDetails(
110126
params.namespaceId,
111127
params.packageId,
112128
params.packageVersion
113-
),
114-
team: dapper.getTeamDetails(params.namespaceId),
129+
)
130+
.catch((error) =>
131+
handleLoaderError(error, { mappings: packageVersionNotFoundMappings })
132+
);
133+
const team = dapper
134+
.getTeamDetails(params.namespaceId)
135+
.catch((error) =>
136+
handleLoaderError(error, { mappings: packageVersionNotFoundMappings })
137+
);
138+
139+
return {
140+
communityId: params.communityId,
141+
community,
142+
version,
143+
team,
115144
};
116145
}
117-
throw new Response("Package not found", { status: 404 });
146+
throwUserFacingPayloadResponse({
147+
headline: "Package not found.",
148+
description: "We could not find the requested package.",
149+
category: "not_found",
150+
status: 404,
151+
});
152+
}
153+
154+
export function ErrorBoundary() {
155+
return <NimbusDefaultRouteErrorBoundary />;
118156
}
119157

120158
export function shouldRevalidate(arg: ShouldRevalidateFunctionArgs) {
@@ -154,39 +192,65 @@ export default function PackageVersion() {
154192
// If strict mode is removed from the entry.client.tsx, this should only run once
155193
useEffect(() => {
156194
if (!startsHydrated.current && isHydrated) return;
157-
if (isPromise(version)) {
158-
version.then((versionData) => {
159-
setFirstUploaded(
160-
<RelativeTime
161-
time={versionData.datetime_created}
162-
suppressHydrationWarning
163-
/>
164-
);
165-
});
166-
} else {
195+
if (!isPromise(version)) {
167196
setFirstUploaded(
168197
<RelativeTime
169198
time={version.datetime_created}
170199
suppressHydrationWarning
171200
/>
172201
);
202+
return;
173203
}
174-
}, []);
204+
205+
let isCancelled = false;
206+
207+
const resolveVersionTimes = async () => {
208+
try {
209+
const versionData = await version;
210+
if (isCancelled) {
211+
return;
212+
}
213+
214+
setFirstUploaded(
215+
<RelativeTime
216+
time={versionData.datetime_created}
217+
suppressHydrationWarning
218+
/>
219+
);
220+
} catch (error) {
221+
if (!isCancelled) {
222+
console.error("Failed to resolve version metadata", error);
223+
}
224+
}
225+
};
226+
227+
resolveVersionTimes();
228+
229+
return () => {
230+
isCancelled = true;
231+
};
232+
}, [isHydrated, version]);
175233
// END: For sidebar meta dates
176234

177235
const currentTab = location.pathname.split("/")[8] || "details";
178236

179237
const versionAndCommunityPromise = useMemo(
180238
() => Promise.all([version, community]),
181-
[]
239+
[version, community]
182240
);
183241

184-
const versionAndTeamPromise = useMemo(() => Promise.all([version, team]), []);
242+
const versionAndTeamPromise = useMemo(
243+
() => Promise.all([version, team]),
244+
[version, team]
245+
);
185246

186247
return (
187248
<>
188249
<Suspense>
189-
<Await resolve={versionAndCommunityPromise}>
250+
<Await
251+
resolve={versionAndCommunityPromise}
252+
errorElement={<NimbusAwaitErrorElement />}
253+
>
190254
{(resolvedValue) => (
191255
<>
192256
<meta
@@ -235,7 +299,10 @@ export default function PackageVersion() {
235299
</NewAlert>
236300
}
237301
>
238-
<Await resolve={version}>
302+
<Await
303+
resolve={version}
304+
errorElement={<NimbusAwaitErrorElement />}
305+
>
239306
{(resolvedValue) => (
240307
<NewAlert csVariant="warning">
241308
You are viewing a potentially older version of this
@@ -259,7 +326,10 @@ export default function PackageVersion() {
259326
<SkeletonBox className="package-listing__page-header-skeleton" />
260327
}
261328
>
262-
<Await resolve={version}>
329+
<Await
330+
resolve={version}
331+
errorElement={<NimbusAwaitErrorElement />}
332+
>
263333
{(resolvedValue) => (
264334
<PageHeader
265335
headingLevel="1"
@@ -325,15 +395,21 @@ export default function PackageVersion() {
325395
rootClasses="package-listing__drawer"
326396
>
327397
<Suspense fallback={<p>Loading...</p>}>
328-
<Await resolve={version}>
398+
<Await
399+
resolve={version}
400+
errorElement={<NimbusAwaitErrorElement />}
401+
>
329402
{(resolvedValue) => (
330403
<>{packageMeta(firstUploaded, resolvedValue)}</>
331404
)}
332405
</Await>
333406
</Suspense>
334407
</Drawer>
335408
<Suspense fallback={<p>Loading...</p>}>
336-
<Await resolve={versionAndTeamPromise}>
409+
<Await
410+
resolve={versionAndTeamPromise}
411+
errorElement={<NimbusAwaitErrorElement />}
412+
>
337413
{(resolvedValue) => (
338414
<Actions
339415
team={resolvedValue[1]}
@@ -348,7 +424,10 @@ export default function PackageVersion() {
348424
<SkeletonBox className="package-listing__nav-skeleton" />
349425
}
350426
>
351-
<Await resolve={version}>
427+
<Await
428+
resolve={version}
429+
errorElement={<NimbusAwaitErrorElement />}
430+
>
352431
{(resolvedValue) => (
353432
<>
354433
<Tabs>
@@ -418,7 +497,10 @@ export default function PackageVersion() {
418497
<SkeletonBox className="package-listing-sidebar__install-skeleton" />
419498
}
420499
>
421-
<Await resolve={version}>
500+
<Await
501+
resolve={version}
502+
errorElement={<NimbusAwaitErrorElement />}
503+
>
422504
{(resolvedValue) => (
423505
<NewButton
424506
csVariant="accent"
@@ -442,7 +524,10 @@ export default function PackageVersion() {
442524
<SkeletonBox className="package-listing-sidebar__actions-skeleton" />
443525
}
444526
>
445-
<Await resolve={versionAndTeamPromise}>
527+
<Await
528+
resolve={versionAndTeamPromise}
529+
errorElement={<NimbusAwaitErrorElement />}
530+
>
446531
{(resolvedValue) => (
447532
<Actions
448533
team={resolvedValue[1]}
@@ -456,7 +541,10 @@ export default function PackageVersion() {
456541
<SkeletonBox className="package-listing-sidebar__skeleton" />
457542
}
458543
>
459-
<Await resolve={version}>
544+
<Await
545+
resolve={version}
546+
errorElement={<NimbusAwaitErrorElement />}
547+
>
460548
{(resolvedValue) => (
461549
<>{packageMeta(firstUploaded, resolvedValue)}</>
462550
)}

0 commit comments

Comments
 (0)