diff --git a/src/app/[...parts]/page.tsx b/src/app/[...parts]/page.tsx deleted file mode 100644 index f51ce0ee..00000000 --- a/src/app/[...parts]/page.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { redirect } from "next/navigation"; -import { type ViewType } from "react-diff-view"; -import { createSimplePackageSpec } from "^/lib/createSimplePackageSpec"; -import { DEFAULT_DIFF_FILES_GLOB } from "^/lib/default-diff-files"; -import destination from "^/lib/destination"; -import { parseQuery, type QueryParams } from "^/lib/query"; -import { simplePackageSpecToString } from "^/lib/SimplePackageSpec"; -import decodeParts from "^/lib/utils/decodeParts"; -import specsToDiff from "^/lib/utils/specsToDiff"; -import splitParts from "^/lib/utils/splitParts"; -import BundlephobiaDiff from "./_page/BundlephobiaDiff"; -import DiffIntro from "./_page/DiffIntro"; -import NpmDiff from "./_page/NpmDiff"; -import PackagephobiaDiff from "./_page/PackagephobiaDiff"; -import { type DIFF_TYPE_PARAM_NAME } from "./_page/paramNames"; - -export interface DiffPageProps { - params: { parts: string | string[] }; - searchParams: QueryParams & { [DIFF_TYPE_PARAM_NAME]: ViewType }; -} - -export function generateMetadata({ params: { parts } }: DiffPageProps) { - const specs = splitParts(decodeParts(parts)); - - const [a, b] = specs.map((spec) => createSimplePackageSpec(spec)); - - return { - title: `Comparing ${simplePackageSpecToString(a)}...${simplePackageSpecToString(b)}`, - description: `A diff between the npm packages "${simplePackageSpecToString(a)}" and "${simplePackageSpecToString(b)}"`, - }; -} - -const DiffPage = async ({ - params: { parts }, - searchParams, -}: DiffPageProps): Promise => { - const { diffFiles, ...optionsQuery } = searchParams; - - const specsOrVersions = splitParts(decodeParts(parts)); - const { redirect: redirectTarget, canonicalSpecs } = - await destination(specsOrVersions); - - if (redirectTarget !== false) { - const specsStr = specsToDiff(canonicalSpecs); - const searchStr = Object.entries(searchParams) - .map(([key, value]) => `${key}=${value}`) - .join("&"); - - redirect( - `/${specsStr}` + (searchStr?.length > 0 ? `?${searchStr}` : ""), - ); - } else { - const options = parseQuery({ - // If no diffFiles is passed, use the default. - // This is done here, since we don't want a fall back in the API - diffFiles: diffFiles ?? DEFAULT_DIFF_FILES_GLOB, - ...optionsQuery, - }); - - const [a, b] = canonicalSpecs.map((spec) => - createSimplePackageSpec(spec), - ); - - return ( - <> - - - - - } - options={options} - /> - - - ); - } -}; - -export default DiffPage; diff --git a/src/app/api/-/destination/route.ts b/src/app/api/-/destination/route.ts new file mode 100644 index 00000000..c0109e3b --- /dev/null +++ b/src/app/api/-/destination/route.ts @@ -0,0 +1,23 @@ +import { type NextRequest, NextResponse } from "next/server"; +import destination from "^/lib/destination"; + +function assureArrayLength(specs: string[]) { + if (specs.length < 3) { + return specs as [string] | [string, string]; + } + throw new Error("Too many specs"); +} + +export async function GET(req: NextRequest, {}: { params: {} }) { + const { searchParams } = new URL(req.url); + + const specsOrVersions = assureArrayLength( + searchParams.getAll("specs") ?? "", + ); + + console.log("[api/-/destination] running", specsOrVersions); + + const result = await destination(specsOrVersions); + + return NextResponse.json(result); +} diff --git a/src/app/[...parts]/_error/ErrorBox.tsx b/src/app/diff/[a]/[b]/_error/ErrorBox.tsx similarity index 100% rename from src/app/[...parts]/_error/ErrorBox.tsx rename to src/app/diff/[a]/[b]/_error/ErrorBox.tsx diff --git a/src/app/[...parts]/_page/BundlephobiaDiff.tsx b/src/app/diff/[a]/[b]/_page/BundlephobiaDiff.tsx similarity index 100% rename from src/app/[...parts]/_page/BundlephobiaDiff.tsx rename to src/app/diff/[a]/[b]/_page/BundlephobiaDiff.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlags.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlags.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlags.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlags.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlagsSkeleton.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlagsSkeleton.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlagsSkeleton.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/BundlePhobiaFlagsSkeleton.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/Flag.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/Flag.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/Flag.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/Flag.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/assets/SideeffectIcon.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/assets/SideeffectIcon.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/assets/SideeffectIcon.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/assets/SideeffectIcon.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/assets/TreeshakeIcon.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/assets/TreeshakeIcon.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/assets/TreeshakeIcon.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/assets/TreeshakeIcon.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/index.ts b/src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/index.ts similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/BundlePhobiaFlags/index.ts rename to src/app/diff/[a]/[b]/_page/DiffIntro/BundlePhobiaFlags/index.ts diff --git a/src/app/[...parts]/_page/DiffIntro/Command.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/Command.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/Command.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/Command.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/DiffIntro.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/DiffIntro.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/DiffIntro.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/DiffIntro.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/Halfs.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/Halfs.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/Halfs.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/Halfs.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/Options.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/Options.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/Options.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/Options.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/PublishDate.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/PublishDate.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/PublishDate.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/PublishDate.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/ServiceLink.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/ServiceLink.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/ServiceLink.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/ServiceLink.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/ServiceLinks.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/ServiceLinks.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/ServiceLinks.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/ServiceLinks.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/ServiceTooltip.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/ServiceTooltip.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/ServiceTooltip.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/ServiceTooltip.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/SpecBox.tsx b/src/app/diff/[a]/[b]/_page/DiffIntro/SpecBox.tsx similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/SpecBox.tsx rename to src/app/diff/[a]/[b]/_page/DiffIntro/SpecBox.tsx diff --git a/src/app/[...parts]/_page/DiffIntro/index.ts b/src/app/diff/[a]/[b]/_page/DiffIntro/index.ts similarity index 100% rename from src/app/[...parts]/_page/DiffIntro/index.ts rename to src/app/diff/[a]/[b]/_page/DiffIntro/index.ts diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.skeleton.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.skeleton.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.skeleton.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.skeleton.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFile.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFileHeader.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFileHeader.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffFileHeader.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffFileHeader.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffHunk.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffHunk.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffHunk.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffHunk.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffPlaceholder.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffPlaceholder.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/DiffPlaceholder.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/DiffPlaceholder.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/index.ts b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/index.ts similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/index.ts rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/index.ts diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.css b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.css similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.css rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.css diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFile/react-diff-view.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFiles.skeleton.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFiles.skeleton.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFiles.skeleton.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFiles.skeleton.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFiles.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFiles.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/DiffFiles.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/DiffFiles.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/DiffFiles/index.ts b/src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/index.ts similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/DiffFiles/index.ts rename to src/app/diff/[a]/[b]/_page/NpmDiff/DiffFiles/index.ts diff --git a/src/app/[...parts]/_page/NpmDiff/NoDiff.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/NoDiff.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/NoDiff.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/NoDiff.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/NpmDiff.skeleton.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/NpmDiff.skeleton.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/NpmDiff.skeleton.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/NpmDiff.skeleton.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/NpmDiff.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/NpmDiff.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/NpmDiff.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/NpmDiff.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/ViewTypeSwitch.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/ViewTypeSwitch.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/ViewTypeSwitch.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/ViewTypeSwitch.tsx diff --git a/src/app/[...parts]/_page/NpmDiff/index.tsx b/src/app/diff/[a]/[b]/_page/NpmDiff/index.tsx similarity index 100% rename from src/app/[...parts]/_page/NpmDiff/index.tsx rename to src/app/diff/[a]/[b]/_page/NpmDiff/index.tsx diff --git a/src/app/[...parts]/_page/PackagephobiaDiff.tsx b/src/app/diff/[a]/[b]/_page/PackagephobiaDiff.tsx similarity index 100% rename from src/app/[...parts]/_page/PackagephobiaDiff.tsx rename to src/app/diff/[a]/[b]/_page/PackagephobiaDiff.tsx diff --git a/src/app/[...parts]/_page/ServiceIcon.tsx b/src/app/diff/[a]/[b]/_page/ServiceIcon.tsx similarity index 100% rename from src/app/[...parts]/_page/ServiceIcon.tsx rename to src/app/diff/[a]/[b]/_page/ServiceIcon.tsx diff --git a/src/app/[...parts]/_page/SizeComparison/SizeComparison.tsx b/src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparison.tsx similarity index 100% rename from src/app/[...parts]/_page/SizeComparison/SizeComparison.tsx rename to src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparison.tsx diff --git a/src/app/[...parts]/_page/SizeComparison/SizeComparisonHeading.tsx b/src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparisonHeading.tsx similarity index 100% rename from src/app/[...parts]/_page/SizeComparison/SizeComparisonHeading.tsx rename to src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparisonHeading.tsx diff --git a/src/app/[...parts]/_page/SizeComparison/SizeComparisonSkeleton.tsx b/src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparisonSkeleton.tsx similarity index 100% rename from src/app/[...parts]/_page/SizeComparison/SizeComparisonSkeleton.tsx rename to src/app/diff/[a]/[b]/_page/SizeComparison/SizeComparisonSkeleton.tsx diff --git a/src/app/[...parts]/_page/SizeComparison/index.ts b/src/app/diff/[a]/[b]/_page/SizeComparison/index.ts similarity index 100% rename from src/app/[...parts]/_page/SizeComparison/index.ts rename to src/app/diff/[a]/[b]/_page/SizeComparison/index.ts diff --git a/src/app/[...parts]/_page/paramNames.ts b/src/app/diff/[a]/[b]/_page/paramNames.ts similarity index 100% rename from src/app/[...parts]/_page/paramNames.ts rename to src/app/diff/[a]/[b]/_page/paramNames.ts diff --git a/src/app/[...parts]/error.tsx b/src/app/diff/[a]/[b]/error.tsx similarity index 100% rename from src/app/[...parts]/error.tsx rename to src/app/diff/[a]/[b]/error.tsx diff --git a/src/app/diff/[a]/[b]/page.tsx b/src/app/diff/[a]/[b]/page.tsx new file mode 100644 index 00000000..da957a9f --- /dev/null +++ b/src/app/diff/[a]/[b]/page.tsx @@ -0,0 +1,87 @@ +import { type ViewType } from "react-diff-view"; +import { createSimplePackageSpec } from "^/lib/createSimplePackageSpec"; +import { DEFAULT_DIFF_FILES_GLOB } from "^/lib/default-diff-files"; +import { parseQuery, type QueryParams } from "^/lib/query"; +import { simplePackageSpecToString } from "^/lib/SimplePackageSpec"; +import BundlephobiaDiff from "./_page/BundlephobiaDiff"; +import DiffIntro from "./_page/DiffIntro"; +import NpmDiff from "./_page/NpmDiff"; +import PackagephobiaDiff from "./_page/PackagephobiaDiff"; +import { type DIFF_TYPE_PARAM_NAME } from "./_page/paramNames"; + +export interface DiffPageProps { + params: { + a: string; + b: string; + }; + searchParams: QueryParams & { + [DIFF_TYPE_PARAM_NAME]: ViewType; + }; +} + +export function generateMetadata({ params: { a: _a, b: _b } }: DiffPageProps) { + const a = createSimplePackageSpec(decodeURIComponent(_a)); + const b = createSimplePackageSpec(decodeURIComponent(_b)); + + return { + title: `Comparing ${simplePackageSpecToString(a)}...${simplePackageSpecToString(b)}`, + description: `A diff between the npm packages "${simplePackageSpecToString(a)}" and "${simplePackageSpecToString(b)}"`, + }; +} + +const DiffPage = async ({ + params: { a: _a, b: _b }, + searchParams, +}: DiffPageProps): Promise => { + const { diffFiles, ...optionsQuery } = searchParams; + + const options = parseQuery({ + // If no diffFiles is passed, use the default. + // This is done here, since we don't want a fall back in the API + diffFiles: diffFiles ?? DEFAULT_DIFF_FILES_GLOB, + ...optionsQuery, + }); + + _a = decodeURIComponent(_a); + _b = decodeURIComponent(_b); + + const specs = [_a, _b] as [string, string]; + const a = createSimplePackageSpec(_a); + const b = createSimplePackageSpec(_b); + + return ( + <> + + + + + } + options={options} + /> + + + ); +}; + +export default DiffPage; diff --git a/src/lib/utils/useViewType.ts b/src/lib/utils/useViewType.ts index 1bb11343..8e864975 100644 --- a/src/lib/utils/useViewType.ts +++ b/src/lib/utils/useViewType.ts @@ -1,7 +1,7 @@ import { useSearchParams } from "next/navigation"; import { type ViewType } from "react-diff-view"; import { useMedia } from "react-use"; -import { DIFF_TYPE_PARAM_NAME } from "^/app/[...parts]/_page/paramNames"; +import { DIFF_TYPE_PARAM_NAME } from "^/app/diff/[a]/[b]/_page/paramNames"; export default function useViewType(): ViewType { const searchParams = useSearchParams(); diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 00000000..7f071bb0 --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,51 @@ +import { type NextRequest, NextResponse } from "next/server"; +import type { Destination } from "./lib/destination"; +import specsToDiff from "./lib/utils/specsToDiff"; +import splitParts from "./lib/utils/splitParts"; + +enum STATUS_CODES { + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, +} + +export const config = { + matcher: "/((?!(?:about|api|_next|diff)(?:/.*)?|favicon.ico|icon.png).+)", +}; + +export async function middleware(request: NextRequest) { + console.log("[middleware]", request.nextUrl.pathname); + + const parts = request.nextUrl.pathname.split("/")[1]; + + const specsOrVersions = splitParts(parts); + + const url = new URL(`/api/-/destination`, request.url); + specsOrVersions.forEach((spec) => url.searchParams.append("specs", spec)); + + console.log("[middleware] fetching", url.toString()); + + const { redirect: red, canonicalSpecs }: Destination = await fetch( + url.toString(), + ).then((res) => res.json()); + + if (red) { + console.log("[middleware] redirecting to", red); + return NextResponse.redirect( + new URL(`/${specsToDiff(canonicalSpecs)}`, request.nextUrl), + red === "permanent" + ? STATUS_CODES.PERMANENT_REDIRECT + : STATUS_CODES.TEMPORARY_REDIRECT, + ); + } else { + const url = new URL( + `/diff/${encodeURIComponent( + canonicalSpecs[0], + )}/${encodeURIComponent(canonicalSpecs[1])}`, + request.url, + ); + console.log("[middleware] rewriting", url.toString()); + return NextResponse.rewrite(url.toString()); + } + + return NextResponse.next(); +}