From 8d1a78f226dec957443b1bff9c5707f3075a2aaf Mon Sep 17 00:00:00 2001 From: Oksamies Date: Wed, 19 Nov 2025 14:26:56 +0200 Subject: [PATCH] Enhance error handling in all package readme routes --- .../p/tabs/Readme/PackageVersionReadme.tsx | 109 ++++++++++-------- .../PackageVersionWithoutCommunityReadme.tsx | 101 ++++++++-------- .../app/p/tabs/Readme/Readme.css | 13 +++ .../app/p/tabs/Readme/Readme.tsx | 101 +++++++++------- 4 files changed, 181 insertions(+), 143 deletions(-) diff --git a/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionReadme.tsx b/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionReadme.tsx index d0c5de923..4f1025600 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionReadme.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionReadme.tsx @@ -10,78 +10,87 @@ import { SkeletonBox } from "@thunderstore/cyberstorm"; import { DapperTs } from "@thunderstore/dapper-ts"; import "./Readme.css"; +import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError"; +import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings"; +import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse"; +import { + NimbusAwaitErrorElement, + NimbusDefaultRouteErrorBoundary, +} from "cyberstorm/utils/errors/NimbusErrorBoundary"; +import { getLoaderTools } from "cyberstorm/utils/getLoaderTools"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId && params.packageVersion) { - const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]); - const dapper = new DapperTs(() => { - return { - apiHost: publicEnvVariables.VITE_API_URL, - sessionId: undefined, - }; - }); - return { - readme: await dapper.getPackageReadme( + const { dapper } = getLoaderTools(); + try { + const readme = await dapper.getPackageReadme( params.namespaceId, params.packageId, params.packageVersion - ), - }; + ); + + return { + readme, + }; + } catch (error) { + handleLoaderError(error, { + mappings: [ + createNotFoundMapping( + "Readme not available.", + "We could not find a readme for this package version." + ), + ], + }); + } } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package version.", + category: "not_found", + status: 404, + }); } -export async function clientLoader({ params }: LoaderFunctionArgs) { +export function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId && params.packageVersion) { - const tools = getSessionTools(); - const dapper = new DapperTs(() => { - return { - apiHost: tools?.getConfig().apiHost, - sessionId: tools?.getConfig().sessionId, - }; - }); + const { dapper } = getLoaderTools(); + const readme = dapper.getPackageReadme( + params.namespaceId, + params.packageId, + params.packageVersion + ); + return { - readme: dapper.getPackageReadme( - params.namespaceId, - params.packageId, - params.packageVersion - ), + readme, }; } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package version.", + category: "not_found", + status: 404, + }); } export default function PackageVersionReadme() { - const { status, message, readme } = useLoaderData< - typeof loader | typeof clientLoader - >(); + const { readme } = useLoaderData(); - if (status === "error") return
{message}
; return ( }> - Error occurred while loading description} - > + }> {(resolvedValue) => ( - <> -
-
-
- +
+
+
)} ); } + +export function ErrorBoundary() { + return ; +} diff --git a/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionWithoutCommunityReadme.tsx b/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionWithoutCommunityReadme.tsx index d0c5de923..0309948d2 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionWithoutCommunityReadme.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Readme/PackageVersionWithoutCommunityReadme.tsx @@ -10,78 +10,79 @@ import { SkeletonBox } from "@thunderstore/cyberstorm"; import { DapperTs } from "@thunderstore/dapper-ts"; import "./Readme.css"; +import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError"; +import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse"; +import { + NimbusAwaitErrorElement, + NimbusDefaultRouteErrorBoundary, +} from "cyberstorm/utils/errors/NimbusErrorBoundary"; +import { getLoaderTools } from "cyberstorm/utils/getLoaderTools"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId && params.packageVersion) { - const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]); - const dapper = new DapperTs(() => { - return { - apiHost: publicEnvVariables.VITE_API_URL, - sessionId: undefined, - }; - }); - return { - readme: await dapper.getPackageReadme( + const { dapper } = getLoaderTools(); + try { + const readme = await dapper.getPackageReadme( params.namespaceId, params.packageId, params.packageVersion - ), - }; + ); + + return { + readme, + }; + } catch (error) { + handleLoaderError(error); + } } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package version.", + category: "not_found", + status: 404, + }); } -export async function clientLoader({ params }: LoaderFunctionArgs) { +export function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId && params.packageVersion) { - const tools = getSessionTools(); - const dapper = new DapperTs(() => { - return { - apiHost: tools?.getConfig().apiHost, - sessionId: tools?.getConfig().sessionId, - }; - }); + const { dapper } = getLoaderTools(); + const readme = dapper.getPackageReadme( + params.namespaceId, + params.packageId, + params.packageVersion + ); + return { - readme: dapper.getPackageReadme( - params.namespaceId, - params.packageId, - params.packageVersion - ), + readme, }; } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package version.", + category: "not_found", + status: 404, + }); } export default function PackageVersionReadme() { - const { status, message, readme } = useLoaderData< - typeof loader | typeof clientLoader - >(); + const { readme } = useLoaderData(); - if (status === "error") return
{message}
; return ( }> - Error occurred while loading description
} - > + }> {(resolvedValue) => ( - <> -
-
-
- +
+
+
)} ); } + +export function ErrorBoundary() { + return ; +} diff --git a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.css b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.css index c51359af4..6132053de 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.css +++ b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.css @@ -2,4 +2,17 @@ .package-readme__skeleton { height: 500px; } + + .package-readme__error { + display: flex; + flex-direction: column; + gap: 1rem; + align-items: flex-start; + padding: 3rem 0; + } + + .package-readme__error-description { + max-width: 40rem; + color: var(--Color-text-muted, rgb(180 189 255 / 0.8)); + } } diff --git a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx index c8ca63f0d..5b0c6f177 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Readme/Readme.tsx @@ -10,70 +10,85 @@ import { SkeletonBox } from "@thunderstore/cyberstorm"; import { DapperTs } from "@thunderstore/dapper-ts"; import "./Readme.css"; +import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError"; +import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings"; +import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse"; +import { + NimbusAwaitErrorElement, + NimbusDefaultRouteErrorBoundary, +} from "cyberstorm/utils/errors/NimbusErrorBoundary"; +import { getLoaderTools } from "cyberstorm/utils/getLoaderTools"; export async function loader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { - const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]); - const dapper = new DapperTs(() => { + const { dapper } = getLoaderTools(); + try { + const readme = await dapper.getPackageReadme( + params.namespaceId, + params.packageId + ); + return { - apiHost: publicEnvVariables.VITE_API_URL, - sessionId: undefined, + readme, }; - }); - return { - readme: dapper.getPackageReadme(params.namespaceId, params.packageId), - }; + } catch (error) { + handleLoaderError(error, { + mappings: [ + createNotFoundMapping( + "Readme not available.", + "We could not find a readme for this package." + ), + ], + }); + } } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package.", + category: "not_found", + status: 404, + }); } -export async function clientLoader({ params }: LoaderFunctionArgs) { +export function clientLoader({ params }: LoaderFunctionArgs) { if (params.namespaceId && params.packageId) { - const tools = getSessionTools(); - const dapper = new DapperTs(() => { - return { - apiHost: tools?.getConfig().apiHost, - sessionId: tools?.getConfig().sessionId, - }; - }); + const { dapper } = getLoaderTools(); + const readme = dapper.getPackageReadme( + params.namespaceId, + params.packageId + ); + return { - readme: dapper.getPackageReadme(params.namespaceId, params.packageId), + readme, }; } - return { - status: "error", - message: "Failed to load readme", - readme: { html: "" }, - }; + throwUserFacingPayloadResponse({ + headline: "Readme not available.", + description: "We could not find a readme for this package.", + category: "not_found", + status: 404, + }); } export default function Readme() { - const { status, message, readme } = useLoaderData< - typeof loader | typeof clientLoader - >(); + const { readme } = useLoaderData(); - if (status === "error") return
{message}
; return ( }> - Error occurred while loading description
} - > + }> {(resolvedValue) => ( - <> -
-
-
- +
+
+
)} ); } + +export function ErrorBoundary() { + return ; +}