diff --git a/apps/cyberstorm-remix/app/p/packageListing.tsx b/apps/cyberstorm-remix/app/p/packageListing.tsx index a28757665..e04e61be6 100644 --- a/apps/cyberstorm-remix/app/p/packageListing.tsx +++ b/apps/cyberstorm-remix/app/p/packageListing.tsx @@ -55,6 +55,7 @@ import { import { PackageLikeAction } from "@thunderstore/cyberstorm-forms"; import type { CurrentUser } from "@thunderstore/dapper/types"; import { DapperTs, type DapperTsInterface } from "@thunderstore/dapper-ts"; +import { getDapperForRequest } from "cyberstorm/utils/dapperSingleton"; import { getPublicListing, getPrivateListing } from "./listingUtils"; import { ManagementTools } from "./components/PackageListing/ManagementTools"; @@ -132,7 +133,7 @@ async function getPackageListingStatus( return undefined; } -export async function clientLoader({ params }: LoaderFunctionArgs) { +export async function clientLoader({ params, request }: LoaderFunctionArgs) { const { communityId, namespaceId, packageId } = params; if (!communityId || !namespaceId || !packageId) { @@ -140,11 +141,7 @@ export async function clientLoader({ params }: LoaderFunctionArgs) { } const tools = getSessionTools(); - const config = tools.getConfig(); - const dapper = new DapperTs(() => ({ - apiHost: config.apiHost, - sessionId: config.sessionId, - })); + const dapper = getDapperForRequest(request); const listing = await getPrivateListing(dapper, { communityId, diff --git a/apps/cyberstorm-remix/app/p/packageListingVersion.tsx b/apps/cyberstorm-remix/app/p/packageListingVersion.tsx index 26a070927..ef9418478 100644 --- a/apps/cyberstorm-remix/app/p/packageListingVersion.tsx +++ b/apps/cyberstorm-remix/app/p/packageListingVersion.tsx @@ -40,10 +40,8 @@ import { import { DapperTs } from "@thunderstore/dapper-ts"; import { type OutletContextShape } from "~/root"; import { CopyButton } from "~/commonComponents/CopyButton/CopyButton"; -import { - getPublicEnvVariables, - getSessionTools, -} from "cyberstorm/security/publicEnvVariables"; +import { getPublicEnvVariables } from "cyberstorm/security/publicEnvVariables"; +import { getDapperForRequest } from "cyberstorm/utils/dapperSingleton"; import { getPrivateListing, getPublicListing } from "./listingUtils"; import { type PackageListingDetails, @@ -77,19 +75,14 @@ export async function loader({ params }: LoaderFunctionArgs) { }; } -export async function clientLoader({ params }: LoaderFunctionArgs) { +export async function clientLoader({ params, request }: LoaderFunctionArgs) { const { communityId, namespaceId, packageId, packageVersion } = params; if (!communityId || !namespaceId || !packageId || !packageVersion) { throw new Response("Package not found", { status: 404 }); } - const tools = getSessionTools(); - const config = tools.getConfig(); - const dapper = new DapperTs(() => ({ - apiHost: config.apiHost, - sessionId: config.sessionId, - })); + const dapper = getDapperForRequest(request); const listing = await getPrivateListing(dapper, { communityId, diff --git a/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionRequired.tsx b/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionRequired.tsx deleted file mode 100644 index bd8d99c21..000000000 --- a/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionRequired.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Suspense } from "react"; -import { type LoaderFunctionArgs } from "react-router"; -import { useLoaderData, Await } from "react-router"; -import { DapperTs } from "@thunderstore/dapper-ts"; -import { SkeletonBox } from "@thunderstore/cyberstorm"; -import { PaginatedDependencies } from "~/commonComponents/PaginatedDependencies/PaginatedDependencies"; -import { - getPublicEnvVariables, - getSessionTools, -} from "cyberstorm/security/publicEnvVariables"; - -export async function loader({ params, request }: 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, - }; - }); - const searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - - return { - version: await dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - params.packageVersion - ), - dependencies: await dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - params.packageVersion, - page === null ? undefined : Number(page) - ), - }; - } - throw new Response("Package version dependencies not found", { status: 404 }); -} - -export async function clientLoader({ params, request }: 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 searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - - return { - version: dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - params.packageVersion - ), - dependencies: dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - params.packageVersion, - page === null ? undefined : Number(page) - ), - }; - } - throw new Response("Package version dependencies not found", { status: 404 }); -} - -export default function PackageVersionRequired() { - const { dependencies } = useLoaderData(); - - return ( - } - > - Error occurred while loading required dependencies - } - > - {(resolvedDependencies) => ( - - )} - - - ); -} diff --git a/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionWithoutCommunityRequired.tsx b/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionWithoutCommunityRequired.tsx deleted file mode 100644 index af6cdd0ac..000000000 --- a/apps/cyberstorm-remix/app/p/tabs/Required/PackageVersionWithoutCommunityRequired.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { Suspense } from "react"; -import { type LoaderFunctionArgs } from "react-router"; -import { useLoaderData, Await } from "react-router"; -import { DapperTs } from "@thunderstore/dapper-ts"; -import { SkeletonBox } from "@thunderstore/cyberstorm"; -import { PaginatedDependencies } from "~/commonComponents/PaginatedDependencies/PaginatedDependencies"; -import { - getPublicEnvVariables, - getSessionTools, -} from "cyberstorm/security/publicEnvVariables"; - -export async function loader({ params, request }: 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, - }; - }); - const searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - - return { - version: await dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - params.packageVersion - ), - dependencies: await dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - params.packageVersion, - page === null ? undefined : Number(page) - ), - }; - } - throw new Response("Package version dependencies not found", { status: 404 }); -} - -export async function clientLoader({ params, request }: 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 searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - - return { - version: dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - params.packageVersion - ), - dependencies: dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - params.packageVersion, - page === null ? undefined : Number(page) - ), - }; - } - throw new Response("Package version dependencies not found", { status: 404 }); -} - -export default function PackageVersionWithoutCommunityRequired() { - const { dependencies } = useLoaderData(); - - return ( - } - > - Error occurred while loading required dependencies - } - > - {(resolvedDependencies) => ( - - )} - - - ); -} diff --git a/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx b/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx index 64d76108c..d2fcace55 100644 --- a/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx +++ b/apps/cyberstorm-remix/app/p/tabs/Required/Required.tsx @@ -1,84 +1,108 @@ import { Suspense } from "react"; -import { type LoaderFunctionArgs } from "react-router"; -import { useLoaderData, Await } from "react-router"; -import { DapperTs } from "@thunderstore/dapper-ts"; +import { Await, type LoaderFunctionArgs, useLoaderData } from "react-router"; + import { SkeletonBox } from "@thunderstore/cyberstorm"; -import { PaginatedDependencies } from "~/commonComponents/PaginatedDependencies/PaginatedDependencies"; -import { - getPublicEnvVariables, - getSessionTools, -} from "cyberstorm/security/publicEnvVariables"; +import { DapperTs } from "@thunderstore/dapper-ts"; + +import { PaginatedDependencies } from "app/commonComponents/PaginatedDependencies/PaginatedDependencies"; +import { getPrivateListing, getPublicListing } from "app/p/listingUtils"; +import { getPublicEnvVariables } from "cyberstorm/security/publicEnvVariables"; +import { getDapperForRequest } from "cyberstorm/utils/dapperSingleton"; + +const Dependency404 = new Response("Package dependencies not found", { + status: 404, +}); + +const getPageFromUrl = (url: string): number | undefined => { + const searchParams = new URL(url).searchParams; + const maybePage = searchParams.get("page"); + return maybePage ? Number(maybePage) : undefined; +}; export async function loader({ params, request }: LoaderFunctionArgs) { - if (params.communityId && params.namespaceId && params.packageId) { - const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]); - const dapper = new DapperTs(() => { - return { - apiHost: publicEnvVariables.VITE_API_URL, - sessionId: undefined, - }; - }); - const searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - const listing = await dapper.getPackageListingDetails( - params.communityId, - params.namespaceId, - params.packageId - ); - - return { - version: await dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - listing.latest_version_number - ), - dependencies: await dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - listing.latest_version_number, - page === null ? undefined : Number(page) - ), - }; + const { communityId, namespaceId, packageId, packageVersion } = params; + + // Either communityId or packageVersion is required depending on route. + if (!namespaceId || !packageId || (!communityId && !packageVersion)) { + throw Dependency404; + } + + const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]); + const dapper = new DapperTs(() => ({ + apiHost: publicEnvVariables.VITE_API_URL, + sessionId: undefined, + })); + + let version: string; + + if (packageVersion) { + version = packageVersion; + } else if (communityId) { + const listingArgs = { communityId, namespaceId, packageId }; + const listing = await getPublicListing(dapper, listingArgs); + + // Listing that's not available on unauthenticated SSR request + // might be available for authenticated user on client. Return + // undefined rather than throw error to allow refetch on client. + if (!listing) { + return { dependencies: undefined }; + } + + version = listing.latest_version_number; + } else { + throw Dependency404; // Can't happen, satisfies TypeScript } - throw new Response("Package version dependencies not found", { status: 404 }); + + return { + dependencies: await dapper.getPackageVersionDependencies( + namespaceId, + packageId, + version, + getPageFromUrl(request.url) + ), + }; } export async function clientLoader({ params, request }: LoaderFunctionArgs) { - if (params.communityId && params.namespaceId && params.packageId) { - const tools = getSessionTools(); - const dapper = new DapperTs(() => { - return { - apiHost: tools?.getConfig().apiHost, - sessionId: tools?.getConfig().sessionId, - }; - }); - const searchParams = new URL(request.url).searchParams; - const page = searchParams.get("page"); - const listing = await dapper.getPackageListingDetails( - params.communityId, - params.namespaceId, - params.packageId - ); - - return { - version: dapper.getPackageVersionDetails( - params.namespaceId, - params.packageId, - listing.latest_version_number - ), - dependencies: dapper.getPackageVersionDependencies( - params.namespaceId, - params.packageId, - listing.latest_version_number, - page === null ? undefined : Number(page) - ), - }; + const { communityId, namespaceId, packageId, packageVersion } = params; + + // Either communityId or packageVersion is required depending on route. + if (!namespaceId || !packageId || (!communityId && !packageVersion)) { + throw Dependency404; } - throw new Response("Package version dependencies not found", { status: 404 }); + + const dapper = getDapperForRequest(request); + let version: string; + + if (packageVersion) { + version = packageVersion; + } else if (communityId) { + const listingArgs = { communityId, namespaceId, packageId }; + const listing = await getPrivateListing(dapper, listingArgs); + version = listing.latest_version_number; + } else { + throw Dependency404; // Can't happen, satisfies TypeScript + } + + return { + dependencies: dapper.getPackageVersionDependencies( + namespaceId, + packageId, + version, + getPageFromUrl(request.url) + ), + }; } +clientLoader.hydrate = true; + export default function PackageVersionRequired() { - const { dependencies } = useLoaderData(); + const { dependencies } = useLoaderData(); + + // SSR failed to fetch, retry as authenticated user on client. + if (dependencies === undefined) { + return ; + } return (