mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
fix(proxy): remove first-referrer cookie stamping from Studio and Docs middleware (#43190)
Summary - Reverts the middleware changes to `apps/studio` and `apps/docs` from #43153 that caused full page reloads on every client-side navigation in Studio - Root cause: broadening the `middleware` matchers to match all routes and returning `NextResponse.next()` unconditionally interferes with client-side navigation in the multi-zone production setup (`www` proxies `/dashboard/*` → Studio, `/docs/*` → Docs) - Cookie stamping is unnecessary in Studio and Docs because `apps/www` sits in front of both apps in production and already handles first-referrer cookie attribution for all incoming traffic - The `apps/www` middleware, packages/common cookie utilities, and telemetry changes from #43153 are left intact Test plan - Verify client-side navigation works without full page reloads in Studio (production or preview deploy) - Verify first-referrer cookie is still stamped via `www` middleware on initial visit
This commit is contained in:
1 parent
fc35630951
commit
87ee98ed3d
2 files changed
+23
-79
No files matched your search
+11
-33
@@ -1,23 +1,17 @@
|
||||
import { clientSdkIds } from '~/content/navigation.references'
|
||||
import { BASE_PATH } from '~/lib/constants'
|
||||
import { stampFirstReferrerCookie } from 'common/first-referrer-cookie'
|
||||
import { isbot } from 'isbot'
|
||||
import { NextResponse, type NextRequest } from 'next/server'
|
||||
|
||||
import { clientSdkIds } from '~/content/navigation.references'
|
||||
import { BASE_PATH } from '~/lib/constants'
|
||||
|
||||
const REFERENCE_PATH = `${BASE_PATH ?? ''}/reference`
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const url = new URL(request.url)
|
||||
|
||||
// Non-reference paths: just handle the first-referrer cookie and pass through
|
||||
if (!url.pathname.startsWith(REFERENCE_PATH)) {
|
||||
const response = NextResponse.next()
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
// Reference paths: existing rewrite logic with cookie stamping on every response
|
||||
|
||||
if (isbot(request.headers.get('user-agent'))) {
|
||||
let [, lib, maybeVersion, ...slug] = url.pathname.replace(REFERENCE_PATH, '').split('/')
|
||||
|
||||
@@ -30,9 +24,7 @@ export function middleware(request: NextRequest) {
|
||||
if (slug.length > 0) {
|
||||
const rewriteUrl = new URL(url)
|
||||
rewriteUrl.pathname = (BASE_PATH ?? '') + '/api/crawlers'
|
||||
const response = NextResponse.rewrite(rewriteUrl)
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.rewrite(rewriteUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,42 +33,28 @@ export function middleware(request: NextRequest) {
|
||||
|
||||
if (lib === 'cli') {
|
||||
const rewritePath = [REFERENCE_PATH, 'cli'].join('/')
|
||||
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
}
|
||||
|
||||
if (lib === 'api') {
|
||||
const rewritePath = [REFERENCE_PATH, 'api'].join('/')
|
||||
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
}
|
||||
|
||||
if (lib?.startsWith('self-hosting-')) {
|
||||
const rewritePath = [REFERENCE_PATH, lib].join('/')
|
||||
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
}
|
||||
|
||||
if (clientSdkIds.includes(lib)) {
|
||||
const version = /v\d+/.test(maybeVersion) ? maybeVersion : null
|
||||
const rewritePath = [REFERENCE_PATH, lib, version].filter(Boolean).join('/')
|
||||
const response = NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.rewrite(new URL(rewritePath, request.url))
|
||||
}
|
||||
|
||||
const response = NextResponse.next()
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
// Broadened from `/reference/:path*` to stamp first-referrer cookies on all
|
||||
// docs pages, not just reference paths. Excludes Next.js internals and static files.
|
||||
'/((?!api|_next/static|_next/image|_next/data|favicon.ico|__nextjs).*)',
|
||||
],
|
||||
matcher: '/reference/:path*',
|
||||
}
|
||||
+12
-46
@@ -1,12 +1,9 @@
|
||||
import {
|
||||
FIRST_REFERRER_COOKIE_NAME,
|
||||
shouldRefreshCookie,
|
||||
stampFirstReferrerCookie,
|
||||
} from 'common/first-referrer-cookie'
|
||||
import { NextResponse } from 'next/server'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import type { NextRequest } from 'next/server'
|
||||
|
||||
import { IS_PLATFORM } from '@/lib/constants'
|
||||
export const config = {
|
||||
matcher: '/api/:function*',
|
||||
}
|
||||
|
||||
// [Joshen] Return 404 for all next.js API endpoints EXCEPT the ones we use in hosted:
|
||||
const HOSTED_SUPPORTED_API_URLS = [
|
||||
@@ -32,44 +29,13 @@ const HOSTED_SUPPORTED_API_URLS = [
|
||||
]
|
||||
|
||||
export function proxy(request: NextRequest) {
|
||||
// API route filtering for hosted platform
|
||||
if (request.nextUrl.pathname.startsWith('/api/')) {
|
||||
if (
|
||||
IS_PLATFORM &&
|
||||
!HOSTED_SUPPORTED_API_URLS.some((url) => request.nextUrl.pathname.endsWith(url))
|
||||
) {
|
||||
return Response.json(
|
||||
{ success: false, message: 'Endpoint not supported on hosted' },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
// Valid API route — pass through without middleware interference
|
||||
return
|
||||
}
|
||||
|
||||
// Belt & suspenders: stamp first-referrer cookie for direct Studio visits.
|
||||
// Primary stamping happens in www/docs middleware; this catches edge cases
|
||||
// like bookmarked Studio URLs with UTMs or direct-to-Studio paid traffic.
|
||||
//
|
||||
// IMPORTANT: Only return NextResponse.next() when we actually need to set a
|
||||
// cookie. In the multi-zone production setup (www proxies /dashboard/* → Studio),
|
||||
// returning an explicit NextResponse.next() unconditionally causes the response
|
||||
// to flow through Next.js's middleware response pipeline, which interferes with
|
||||
// client-side navigation and triggers full page reloads. Returning undefined
|
||||
// lets Next.js handle the request completely untouched.
|
||||
const referrer = request.headers.get('referer') ?? ''
|
||||
const { stamp } = shouldRefreshCookie(request.cookies.has(FIRST_REFERRER_COOKIE_NAME), {
|
||||
referrer,
|
||||
url: request.url,
|
||||
})
|
||||
|
||||
if (stamp) {
|
||||
const response = NextResponse.next()
|
||||
stampFirstReferrerCookie(request, response)
|
||||
return response
|
||||
if (
|
||||
IS_PLATFORM &&
|
||||
!HOSTED_SUPPORTED_API_URLS.some((url) => request.nextUrl.pathname.endsWith(url))
|
||||
) {
|
||||
return Response.json(
|
||||
{ success: false, message: 'Endpoint not supported on hosted' },
|
||||
{ status: 404 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: ['/((?!_next/static|_next/image|_next/data|favicon.ico|__nextjs).*)'],
|
||||
}
|
||||
Reference in new issue
Block a user