From d601e99c6c4c8ed29c8ea04ed3723628b9591620 Mon Sep 17 00:00:00 2001 From: Madison Date: Wed, 30 Jul 2025 13:18:17 -0500 Subject: [PATCH] init deeplink redirects (#804) Fix for a lot of the deep links that are causing 404 errors from old docs. ---- > [!IMPORTANT] > Adds dynamic redirection for documentation routes in multiple sections, redirecting to the correct page or an overview, with special handling for REST API routes. > > - **Behavior**: > - Adds dynamic redirection for documentation routes in `js`, `next`, `python`, `react`, and `rest-api` sections. > - Redirects to the correct documentation page or an overview if the page doesn't exist. > - For `rest-api`, redirects to `/api` instead of `/docs`. > - **Files**: > - `route.ts` in `js`, `next`, `python`, `react`, and `rest-api` sections handle the redirection logic. > - Uses `source.getPage()` or `apiSource.getPage()` to check page existence. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral) for 50c4b592a400f5b155c4b392f4131065bdc9a3db. You can [customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this summary. It will automatically update as commits are pushed. ---- ## Summary by CodeRabbit * **New Features** * Added dynamic redirection for documentation routes in JavaScript, Next.js, Python, React, and REST API sections. Users are now automatically redirected to the correct documentation page if it exists, or receive a 404 not found response if the page is missing. This improves navigation and error handling for documentation URLs. --------- Co-authored-by: Konsti Wohlwend --- docs/src/app/js/[...path]/route.ts | 31 ++++++++++++++++++++++++ docs/src/app/next/[...path]/route.ts | 31 ++++++++++++++++++++++++ docs/src/app/python/[...path]/route.ts | 31 ++++++++++++++++++++++++ docs/src/app/react/[...path]/route.ts | 31 ++++++++++++++++++++++++ docs/src/app/rest-api/[...path]/route.ts | 31 ++++++++++++++++++++++++ 5 files changed, 155 insertions(+) create mode 100644 docs/src/app/js/[...path]/route.ts create mode 100644 docs/src/app/next/[...path]/route.ts create mode 100644 docs/src/app/python/[...path]/route.ts create mode 100644 docs/src/app/react/[...path]/route.ts create mode 100644 docs/src/app/rest-api/[...path]/route.ts diff --git a/docs/src/app/js/[...path]/route.ts b/docs/src/app/js/[...path]/route.ts new file mode 100644 index 000000000..caeb4078e --- /dev/null +++ b/docs/src/app/js/[...path]/route.ts @@ -0,0 +1,31 @@ +import { source } from 'lib/source'; +import { notFound, redirect } from 'next/navigation'; +import { NextRequest } from 'next/server'; + +export function GET(request: NextRequest) { + const pathname = new URL(request.url).pathname; + + // Ensure we have the correct target path without double prefixes using proper URL construction + let targetPath: string; + if (pathname.startsWith('/docs')) { + targetPath = pathname; + } else { + // Remove leading slash and use as relative path to properly construct /docs prefix + targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname; + } + + // Extract slug by removing any '/docs' prefix and splitting by '/' + const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname; + const slug = cleanPath.substring(1).split('/').filter(Boolean); + + // Check if the target page exists + const page = source.getPage(slug); + + if (page) { + // Page exists, redirect to the full path + return redirect(targetPath); + } else { + // Page doesn't exist, return 404 + return notFound(); + } +} diff --git a/docs/src/app/next/[...path]/route.ts b/docs/src/app/next/[...path]/route.ts new file mode 100644 index 000000000..0e328050f --- /dev/null +++ b/docs/src/app/next/[...path]/route.ts @@ -0,0 +1,31 @@ +import { source } from 'lib/source'; +import { notFound, redirect } from 'next/navigation'; +import { NextRequest } from 'next/server'; + +export function GET(request: NextRequest) { + const pathname = new URL(request.url).pathname; + + // Ensure we have the correct target path without double prefixes using proper URL construction + let targetPath: string; + if (pathname.startsWith('/docs')) { + targetPath = pathname; + } else { + // Remove leading slash and use as relative path to properly construct /docs prefix + targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname; + } + + // Extract slug by removing any '/docs' prefix and splitting by '/' + const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname; + const slug = cleanPath.substring(1).split('/').filter(Boolean); + + // Check if the target page exists + const page = source.getPage(slug); + + if (page) { + // Page exists, redirect to the full path + return redirect(targetPath); + } else { + // Page doesn't exist, redirect to overview + return notFound(); + } +} diff --git a/docs/src/app/python/[...path]/route.ts b/docs/src/app/python/[...path]/route.ts new file mode 100644 index 000000000..0e328050f --- /dev/null +++ b/docs/src/app/python/[...path]/route.ts @@ -0,0 +1,31 @@ +import { source } from 'lib/source'; +import { notFound, redirect } from 'next/navigation'; +import { NextRequest } from 'next/server'; + +export function GET(request: NextRequest) { + const pathname = new URL(request.url).pathname; + + // Ensure we have the correct target path without double prefixes using proper URL construction + let targetPath: string; + if (pathname.startsWith('/docs')) { + targetPath = pathname; + } else { + // Remove leading slash and use as relative path to properly construct /docs prefix + targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname; + } + + // Extract slug by removing any '/docs' prefix and splitting by '/' + const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname; + const slug = cleanPath.substring(1).split('/').filter(Boolean); + + // Check if the target page exists + const page = source.getPage(slug); + + if (page) { + // Page exists, redirect to the full path + return redirect(targetPath); + } else { + // Page doesn't exist, redirect to overview + return notFound(); + } +} diff --git a/docs/src/app/react/[...path]/route.ts b/docs/src/app/react/[...path]/route.ts new file mode 100644 index 000000000..0e328050f --- /dev/null +++ b/docs/src/app/react/[...path]/route.ts @@ -0,0 +1,31 @@ +import { source } from 'lib/source'; +import { notFound, redirect } from 'next/navigation'; +import { NextRequest } from 'next/server'; + +export function GET(request: NextRequest) { + const pathname = new URL(request.url).pathname; + + // Ensure we have the correct target path without double prefixes using proper URL construction + let targetPath: string; + if (pathname.startsWith('/docs')) { + targetPath = pathname; + } else { + // Remove leading slash and use as relative path to properly construct /docs prefix + targetPath = new URL(pathname.substring(1), 'file:///docs/').pathname; + } + + // Extract slug by removing any '/docs' prefix and splitting by '/' + const cleanPath = pathname.startsWith('/docs') ? pathname.substring(5) : pathname; + const slug = cleanPath.substring(1).split('/').filter(Boolean); + + // Check if the target page exists + const page = source.getPage(slug); + + if (page) { + // Page exists, redirect to the full path + return redirect(targetPath); + } else { + // Page doesn't exist, redirect to overview + return notFound(); + } +} diff --git a/docs/src/app/rest-api/[...path]/route.ts b/docs/src/app/rest-api/[...path]/route.ts new file mode 100644 index 000000000..9653e7bfd --- /dev/null +++ b/docs/src/app/rest-api/[...path]/route.ts @@ -0,0 +1,31 @@ +import { apiSource } from 'lib/source'; +import { notFound, redirect } from 'next/navigation'; +import { NextRequest } from 'next/server'; + +export function GET(request: NextRequest) { + const pathname = new URL(request.url).pathname; + + // For rest-api, we redirect to /api not /docs using proper URL construction + let targetPath: string; + if (pathname.startsWith('/api')) { + targetPath = pathname; + } else { + // Remove leading slash and use as relative path to properly construct /api prefix + targetPath = new URL(pathname.substring(1), 'file:///api/').pathname; + } + + // Extract slug by removing any '/api' prefix and splitting by '/' + const cleanPath = pathname.startsWith('/api') ? pathname.substring(4) : pathname; + const slug = cleanPath.substring(1).split('/').filter(Boolean); + + // Check if the target page exists using apiSource for API docs + const page = apiSource.getPage(slug); + + if (page) { + // Page exists, redirect to the full path + return redirect(targetPath); + } else { + // Page doesn't exist, redirect to overview + return notFound(); + } +}