Scope the site preview cookie to the preview route so customization/theme persists on navigation (RND-12191) (#4481)

Co-authored-by: Peter White <1788320+peterwhite@users.noreply.github.com>
This commit is contained in:
Zeno Kapitein
2026-10-07 09:53:30 +02:00
committed by GitHub
parent 2137c2df7b
commit ad6262b6f9
3 changed files with 63 additions and 3 deletions
+43 -1
View File
@@ -1,6 +1,8 @@
import { describe, expect, it } from 'bun:test';
import { getPreviewRequestIdentifier, isPreviewRequest } from './preview';
import type { PublishedSiteContent } from '@gitbook/api';
import { getPreviewCookieResponse, getPreviewRequestIdentifier, isPreviewRequest } from './preview';
describe('isPreviewRequest', () => {
it('should return true for preview requests', () => {
@@ -23,3 +25,43 @@ describe('getPreviewRequestIdentifier', () => {
expect(getPreviewRequestIdentifier(previewRequestURL)).toBe('site_foo');
});
});
describe('getPreviewCookieResponse', () => {
// The site's canonical base path — deliberately different from the preview route prefix so the
// test fails if the cookie is scoped to it instead of the preview route.
const siteURLData = { siteBasePath: '/docs/' } as unknown as PublishedSiteContent;
it('scopes the cookie to the preview route prefix in url-host mode, not the site base path', () => {
const cookie = getPreviewCookieResponse({
name: 'gitbook-customization',
value: 'v',
mode: 'url-host',
siteRequestURL: new URL('https://sites.gitbook.com/preview/site_foo/hello/world'),
siteURLData,
});
expect(cookie.options?.path).toBe('/preview/site_foo');
expect(cookie.options?.sameSite).toBe('lax');
});
it('scopes the cookie to the proxied preview route prefix in url mode', () => {
const cookie = getPreviewCookieResponse({
name: 'gitbook-customization',
value: 'v',
mode: 'url',
siteRequestURL: new URL('https://sites.gitbook.com/preview/site_foo/hello/world'),
siteURLData,
});
expect(cookie.options?.path).toBe('/url/sites.gitbook.com/preview/site_foo');
});
it('falls back to the site base path for a non-preview url-host request', () => {
const cookie = getPreviewCookieResponse({
name: 'gitbook-customization',
value: 'v',
mode: 'url-host',
siteRequestURL: new URL('https://example.com/docs/hello/world'),
siteURLData,
});
expect(cookie.options?.path).toBe('/docs/');
});
});
+15 -2
View File
@@ -51,8 +51,21 @@ export function getPreviewCookieResponse(args: {
gitbookPreviewBaseURL.host + gitbookPreviewBaseURL.pathname.replace(/\/$/, '');
return `/url/${gitbookPreviewHostPath}/${getPreviewRequestIdentifier(siteRequestURL)}`;
}
case 'url-host':
return siteURLData.siteBasePath;
case 'url-host': {
// The whole site preview (all variants/sections/pages) is served under the preview
// route prefix `<previewBasePath>/<siteId>` (e.g. `/preview/<siteId>`). Scope the
// cookie to that prefix, derived from the request, so it is resent on every
// in-preview navigation. The resolved `siteBasePath` is the site's canonical base
// path and does not prefix the preview route, so relying on it makes the browser
// drop the cookie on the next page — the actual cause of the override being lost.
// Mirrors getVisitorAuthBasePath, which uses the request identifier for proxy
// requests. Fall back to `siteBasePath` for any preview not served under the route.
if (!isPreviewRequest(siteRequestURL)) {
return siteURLData.siteBasePath;
}
const gitbookPreviewBaseURL = new URL(GITBOOK_PREVIEW_BASE_URL);
return `${gitbookPreviewBaseURL.pathname.replace(/\/$/, '')}/${getPreviewRequestIdentifier(siteRequestURL)}`;
}
default:
assertNever(mode);
}