diff --git a/apps/docs/app/reference/[...slug]/page.tsx b/apps/docs/app/reference/[...slug]/page.tsx
index 0ed5497704c..560623c6408 100644
--- a/apps/docs/app/reference/[...slug]/page.tsx
+++ b/apps/docs/app/reference/[...slug]/page.tsx
@@ -46,7 +46,7 @@ export default async function ReferencePage(props: { params: Promise<{ slug: Arr
} else if (isCliReference) {
return
} else if (isApiReference) {
- return
+ return
} else if (isSelfHostingReference) {
return (
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
index b0b872ff4e7..08c99b5eed0 100644
--- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -3630,7 +3630,7 @@ export const references = [
label: 'Management API',
description: 'something about the reference',
icon: '/docs/img/icons/api-icon.svg',
- url: '/reference/management-api/start',
+ url: '/reference/api/introduction',
},
],
},
diff --git a/apps/docs/features/docs/Reference.apiPage.tsx b/apps/docs/features/docs/Reference.apiPage.tsx
index 3e77558f3e6..e8344cb3a85 100644
--- a/apps/docs/features/docs/Reference.apiPage.tsx
+++ b/apps/docs/features/docs/Reference.apiPage.tsx
@@ -1,13 +1,32 @@
+import { notFound, redirect } from 'next/navigation'
+
import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
import { reference_api } from '~/components/Navigation/NavigationMenu/NavigationMenu.constants'
-import { ClientLibIntroduction } from '~/features/docs/Reference.introduction'
+import { getSectionsBySlug } from '~/features/docs/Reference.generated.singleton'
import { ReferenceNavigation } from '~/features/docs/Reference.navigation'
import { ReferenceContentScrollHandler } from '~/features/docs/Reference.navigation.client'
-import { RefSections } from '~/features/docs/Reference.sections'
+import { SectionSwitch } from '~/features/docs/Reference.sections'
import { LayoutMainContent } from '~/layouts/DefaultLayout'
import { SidebarSkeleton } from '~/layouts/MainSkeleton'
-export async function ApiReferencePage() {
+export async function ApiReferencePage({ path }: { path: Array }) {
+ const operationSlug = path[0]
+
+ if (!operationSlug) {
+ redirect('/reference/api/introduction')
+ }
+
+ return
+}
+
+// DOCS-1268: one endpoint per page, reusing the same SectionSwitch (and
+// therefore the same ApiEndpointSection/MarkdownSection) that used to render
+// every operation on the single monolithic /reference/api page.
+async function ApiOperationPage({ operationSlug }: { operationSlug: string }) {
+ const sectionsBySlug = await getSectionsBySlug('api', 'latest')
+ const section = sectionsBySlug?.get(operationSlug)
+ if (!section) notFound()
+
return (
}
>
-
-
+
diff --git a/apps/docs/features/docs/Reference.navigation.client.tsx b/apps/docs/features/docs/Reference.navigation.client.tsx
index 4ddf294fd20..b676573baaf 100644
--- a/apps/docs/features/docs/Reference.navigation.client.tsx
+++ b/apps/docs/features/docs/Reference.navigation.client.tsx
@@ -239,11 +239,16 @@ export function RefLink({
section,
skipChildren = false,
className,
+ realNavigation,
}: {
basePath: string
section: AbbrevApiReferenceSection
skipChildren?: boolean
className?: string
+ // Spike (DOCS-1268): when true, this link does a real navigation instead of
+ // the scroll-hijack below — used only by the API reference, whose endpoints
+ // are now real pages. Undefined everywhere else preserves current behavior.
+ realNavigation?: boolean
}) {
const ref = useRef(null)
@@ -260,8 +265,11 @@ export function RefLink({
}, [isActive, className])
const onClick = useCallback(
- (evt: MouseEvent) => createReferenceSubsectionNavigator(href, section.slug)(evt),
- [href, section.slug]
+ (evt: MouseEvent) => {
+ if (realNavigation) return
+ createReferenceSubsectionNavigator(href, section.slug)(evt)
+ },
+ [href, section.slug, realNavigation]
)
if (!('title' in section)) return null
@@ -272,13 +280,13 @@ export function RefLink({
return (
<>
{isCompoundSection ? (
-
+
) : (
{
return (
-
+
)
})}
diff --git a/apps/docs/features/docs/Reference.navigation.tsx b/apps/docs/features/docs/Reference.navigation.tsx
index 51e594b2874..393624245c3 100644
--- a/apps/docs/features/docs/Reference.navigation.tsx
+++ b/apps/docs/features/docs/Reference.navigation.tsx
@@ -19,6 +19,10 @@ interface ReferenceNavigationProps {
libPath: string
version: string
isLatestVersion: boolean
+ // Spike (DOCS-1268): API reference sidebar links navigate to real pages
+ // instead of scrolling within one giant page. SDK/CLI/self-hosting callers
+ // never pass this, so their behavior is unchanged.
+ realNavigation?: boolean
}
export async function ReferenceNavigation({
@@ -28,6 +32,7 @@ export async function ReferenceNavigation({
libPath,
version,
isLatestVersion,
+ realNavigation,
}: ReferenceNavigationProps) {
const navSections = await getReferenceSections(libraryId, version)
const filteredNavSections = navSections?.filter((section) => section.title !== 'Auth')
@@ -46,11 +51,11 @@ export async function ReferenceNavigation({
{displayedNavSections?.map((section, index) =>
section.type === 'category' ? (
-
+
) : (
-
+
)
)}
@@ -64,9 +69,11 @@ const topLvlRefNavItemStyles = 'leading-5'
function RefCategory({
basePath,
section,
+ realNavigation,
}: {
basePath: string
section: AbbrevApiReferenceSection
+ realNavigation?: boolean
}) {
if (!('items' in section && section.items && section.items.length > 0)) return null
@@ -77,7 +84,7 @@ function RefCategory({
{section.items?.map((item) => (
-
-
+
))}
diff --git a/apps/docs/features/docs/Reference.utils.ts b/apps/docs/features/docs/Reference.utils.ts
index 5824f27901a..5fe986caaee 100644
--- a/apps/docs/features/docs/Reference.utils.ts
+++ b/apps/docs/features/docs/Reference.utils.ts
@@ -95,6 +95,21 @@ async function generateStaticParamsForSdkVersion(sdkId: string, version: string)
}))
}
+// Spike (DOCS-1268): one static page per Management API endpoint, in addition
+// to the existing bare `/reference/api` monolith. Deliberately does not reuse
+// generateStaticParamsForSdkVersion's output shape — that function bakes in a
+// 'crawlers' path segment for a separate crawler-only mechanism unrelated to
+// these human-facing per-operation URLs.
+async function generateStaticParamsForApi() {
+ const flattenedSections = await getFlattenedSections('api', 'latest')
+
+ return (flattenedSections || [])
+ .filter((section) => section.type !== 'category' && !!section.slug)
+ .map((section) => ({
+ slug: ['api', section.slug],
+ }))
+}
+
export async function generateReferenceStaticParams() {
const sdkPages = clientSdkIds
.flatMap((sdkId) =>
@@ -117,6 +132,7 @@ export async function generateReferenceStaticParams() {
{
slug: ['api'],
},
+ ...(await generateStaticParamsForApi()),
]
const selfHostingPages = selfHostingServices.map((service) => ({
@@ -178,9 +194,35 @@ export async function generateReferenceMetadata(
description: 'CLI reference for the Supabase CLI',
}
} else if (isApiReference) {
+ const { path } = parsedPath
+ const operationSlug = path[0]
+
+ const flattenedSections = operationSlug
+ ? await getFlattenedSections('api', 'latest')
+ : undefined
+ const sectionTitle = flattenedSections?.find((section) => section.slug === operationSlug)?.title
+
+ const url = [BASE_PATH, 'reference', 'api', operationSlug].filter(Boolean).join('/')
+ const images = generateOpenGraphImageMeta({
+ type: 'API Reference',
+ title: `Management API${sectionTitle ? `: ${sectionTitle}` : ''}`,
+ })
+
return {
- title: 'Management API Reference | Supabase Docs',
- description: 'Management API reference for the Supabase API',
+ title: `${sectionTitle ? `${sectionTitle} | ` : ''}Management API Reference | Supabase Docs`,
+ description: `Management API reference for the Supabase API${sectionTitle ? `: ${sectionTitle}` : ''}`,
+ ...(operationSlug
+ ? {
+ alternates: {
+ canonical: url,
+ },
+ }
+ : {}),
+ openGraph: {
+ ...parentOg,
+ url,
+ images,
+ },
}
} else if (isSelfHostingReference) {
return {
diff --git a/apps/docs/middleware.ts b/apps/docs/middleware.ts
index fd885725c23..cd31319d43f 100644
--- a/apps/docs/middleware.ts
+++ b/apps/docs/middleware.ts
@@ -63,7 +63,10 @@ export function middleware(request: NextRequest) {
return NextResponse.rewrite(new URL(rewritePath, request.url))
}
- if (lib === 'api') {
+ // Spike (DOCS-1268): only the bare /reference/api needs normalizing now.
+ // /reference/api/ has its own statically generated page — don't
+ // collapse it back to the monolith.
+ if (lib === 'api' && !maybeVersion) {
const rewritePath = [REFERENCE_PATH, 'api'].join('/')
return NextResponse.rewrite(new URL(rewritePath, request.url))
}
diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js
index 2ec7c41125d..866bef5ec9e 100644
--- a/apps/www/lib/redirects.js
+++ b/apps/www/lib/redirects.js
@@ -2081,7 +2081,17 @@ module.exports = [
{
permanent: true,
source: '/docs/reference/api',
- destination: '/docs/reference/api/start',
+ destination: '/docs/reference/api/introduction',
+ },
+ // 'start' was never a real API reference slug — it only ever worked because
+ // the old /reference/api/* routing collapsed every sub-path to the same
+ // monolith, and the bare /docs/reference/api redirect pointed here for years.
+ // Keep redirecting so external links and bookmarks don't 404 now that only
+ // real slugs resolve.
+ {
+ permanent: true,
+ source: '/docs/reference/api/start',
+ destination: '/docs/reference/api/introduction',
},
{
permanent: true,