Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V2: search and ask AI #2889

Merged
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Iterate
  • Loading branch information
SamyPesse committed Mar 2, 2025
commit 3bd9b3757840c9b041c853cdb6b9011ac917754c
24 changes: 9 additions & 15 deletions packages/gitbook-v2/src/app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { fetchSiteContextByURL, getBaseContext } from '@v2/lib/context';
import { GITBOOK_API_TOKEN, GITBOOK_API_URL } from '@v2/lib/env';
import { MiddlewareHeaders } from '@v2/lib/middleware';
import { headers } from 'next/headers';
import {
fetchSiteContextByURL,
fetchSiteContextByURLLookup,
getBaseContext,
} from '@v2/lib/context';
import { getSiteURLDataFromMiddleware } from '@v2/lib/middleware';

export type RouteParamMode = 'url-host' | 'url';

@@ -40,22 +42,14 @@ export function getStaticSiteContext(params: RouteLayoutParams) {
*/
export async function getDynamicSiteContext(params: RouteLayoutParams) {
const siteURL = getSiteURLFromParams(params);
const headersSet = await headers();
const siteURLData = await getSiteURLDataFromMiddleware();

return fetchSiteContextByURL(
return fetchSiteContextByURLLookup(
getBaseContext({
siteURL,
urlMode: getModeFromParams(params.mode),
apiToken: headersSet.get(MiddlewareHeaders.APIToken) ?? GITBOOK_API_TOKEN,
apiEndpoint: headersSet.get(MiddlewareHeaders.APIEndpoint) ?? GITBOOK_API_URL,
}),
{
url: siteURL.toString(),
visitorAuthToken: headersSet.get(MiddlewareHeaders.VisitorToken),

// TODO: set it only when the token comes from the cookies.
redirectOnError: true,
}
siteURLData
);
}

35 changes: 17 additions & 18 deletions packages/gitbook-v2/src/lib/context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getSiteStructureSections } from '@/lib/sites';
import type {
ChangeRequest,
PublishedSiteContentLookup,
RevisionPage,
RevisionPageDocument,
Site,
@@ -17,7 +18,7 @@ import { redirect } from 'next/navigation';
import { assert } from 'ts-essentials';
import { GITBOOK_API_TOKEN, GITBOOK_API_URL, GITBOOK_URL } from './env';
import { type ImageResizer, createImageResizer } from './images';
import { type GitBookSpaceLinker, appendBasePathToLinker, createLinker } from './links';
import { type GitBookSpaceLinker, createLinker } from './links';

/**
* Generic context when rendering content.
@@ -91,9 +92,6 @@ export type GitBookSiteContext = GitBookSpaceContext & {

/** Scripts to load for the site. */
scripts: SiteIntegrationScript[];

/** Visitor token used to fetch the site */
visitorAuthToken: string | null;
};

/**
@@ -125,12 +123,12 @@ export function getBaseContext(input: {
urlMode === 'url-host'
? createLinker({
host: url.host,
pathname: '/',
pathname: url.pathname,
})
: createLinker({
protocol: gitbookURL.protocol,
host: gitbookURL.host,
pathname: `/url/${url.host}`,
pathname: `/url/${url.host}${url.pathname}`,
});

if (urlMode === 'url') {
@@ -146,7 +144,7 @@ export function getBaseContext(input: {

// To ensure image resizing work for proxied sites,
// we serve images from the root of the site.
linker: appendBasePathToLinker(linker, url.pathname),
linker: linker,
});

return {
@@ -174,11 +172,22 @@ export async function fetchSiteContextByURL(
redirectOnError: input.redirectOnError,
});

return fetchSiteContextByURLLookup(baseContext, data);
}

/**
* Fetch the context of a site using the resolution of a URL
*/
export async function fetchSiteContextByURLLookup(
baseContext: GitBookBaseContext,
data: PublishedSiteContentLookup
): Promise<GitBookSiteContext> {
const { dataFetcher } = baseContext;
if ('redirect' in data) {
redirect(data.redirect);
}

const context = await fetchSiteContextByIds(
return await fetchSiteContextByIds(
{
...baseContext,
dataFetcher: dataFetcher.withToken({
@@ -194,16 +203,8 @@ export async function fetchSiteContextByURL(
shareKey: data.shareKey,
changeRequest: data.changeRequest,
revision: data.revision,
visitorAuthToken: input.visitorAuthToken,
}
);

const siteContext = {
...context,
linker: appendBasePathToLinker(context.linker, data.basePath),
};

return siteContext;
}

/**
@@ -220,7 +221,6 @@ export async function fetchSiteContextByIds(
shareKey: string | undefined;
changeRequest: string | undefined;
revision: string | undefined;
visitorAuthToken: string | null;
}
): Promise<GitBookSiteContext> {
const { dataFetcher } = baseContext;
@@ -286,7 +286,6 @@ export async function fetchSiteContextByIds(
structure: siteStructure,
sections,
scripts,
visitorAuthToken: ids.visitorAuthToken,
};
}

50 changes: 39 additions & 11 deletions packages/gitbook-v2/src/lib/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CustomizationThemeMode } from '@gitbook/api';
import { CustomizationThemeMode, type PublishedSiteContent } from '@gitbook/api';
import { headers } from 'next/headers';

export enum MiddlewareHeaders {
@@ -12,6 +12,11 @@ export enum MiddlewareHeaders {
*/
SiteURL = 'x-gitbook-site-url',

/**
* The data associated with the URL.
*/
SiteURLData = 'x-gitbook-site-url-data',

/**
* The mode of the URL (url or url-host)
*/
@@ -27,24 +32,15 @@ export enum MiddlewareHeaders {
*/
Customization = 'x-gitbook-customization',

/**
* The visitor token used for authentication.
*/
VisitorToken = 'x-gitbook-visitor-token',

/**
* Token to use for the API.
*/
APIToken = 'x-gitbook-token',

/**
* Endpoint to use for the API.
*/
APIEndpoint = 'x-gitbook-api',
}

/**
* Get the URL mode from the middleware headers.
* This function should only be called in a server action or a dynamic route.
*/
export async function getURLModeFromMiddleware(): Promise<'url' | 'url-host'> {
const headersList = await headers();
@@ -56,8 +52,40 @@ export async function getURLModeFromMiddleware(): Promise<'url' | 'url-host'> {
return mode as 'url' | 'url-host';
}

/**
* Get the site URL data from the middleware headers.
* This function should only be called in a server action or a dynamic route.
*/
export async function getSiteURLDataFromMiddleware(): Promise<PublishedSiteContent> {
const headersList = await headers();
const siteURLData = headersList.get(MiddlewareHeaders.SiteURLData);

if (!siteURLData) {
throw new Error(
'Site URL data is not set by the middleware. This should only be called in a server action or a dynamic route.'
);
}

return JSON.parse(siteURLData);
}

/**
* Get the URL from the middleware headers.
* This function should only be called in a server action or a dynamic route.
*/
export async function getSiteURLFromMiddleware(): Promise<string> {
const headersList = await headers();
const siteURL = headersList.get(MiddlewareHeaders.SiteURL);
if (!siteURL) {
throw new Error('URL mode is not set by the middleware');
}

return siteURL;
}

/**
* For preview, the theme can be set via query string (?theme=light).
* This function should only be called in a dynamic route.
*/
export async function getThemeFromMiddleware() {
const headersList = await headers();
39 changes: 13 additions & 26 deletions packages/gitbook-v2/src/lib/server-actions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import { headers } from 'next/headers';
import { type GitBookBaseContext, fetchSiteContextByURL, getBaseContext } from './context';
import { GITBOOK_API_TOKEN, GITBOOK_API_URL } from './env';
import { MiddlewareHeaders, getURLModeFromMiddleware } from './middleware';
import { type GitBookBaseContext, fetchSiteContextByURLLookup, getBaseContext } from './context';
import { GITBOOK_API_TOKEN } from './env';
import {
getSiteURLDataFromMiddleware,
getSiteURLFromMiddleware,
getURLModeFromMiddleware,
} from './middleware';

/**
* Get the base context for a server action.
*/
export async function getServerActionBaseContext() {
const headersSet = await headers();
const siteURL = headersSet.get(MiddlewareHeaders.SiteURL);

if (!siteURL) {
throw new Error('Site URL is not set by the middleware');
}

const siteURL = await getSiteURLFromMiddleware();
const siteURLData = await getSiteURLDataFromMiddleware();
const urlMode = await getURLModeFromMiddleware();

return getBaseContext({
siteURL,
urlMode,
apiToken: headersSet.get(MiddlewareHeaders.APIToken) ?? GITBOOK_API_TOKEN,
apiEndpoint: headersSet.get(MiddlewareHeaders.APIEndpoint) ?? GITBOOK_API_URL,
apiToken: siteURLData.apiToken ?? GITBOOK_API_TOKEN,
});
}

@@ -28,17 +26,6 @@ export async function getServerActionBaseContext() {
* The server action is always dynamic and the request is passed through the middleware.
*/
export async function fetchServerActionSiteContext(baseContext: GitBookBaseContext) {
const headersSet = await headers();
const visitorAuthToken = headersSet.get(MiddlewareHeaders.VisitorToken);
const siteURL = headersSet.get(MiddlewareHeaders.SiteURL);

if (!siteURL) {
throw new Error('Site URL is not set by the middleware');
}

return fetchSiteContextByURL(baseContext, {
url: siteURL,
visitorAuthToken,
redirectOnError: true,
});
const siteURLData = await getSiteURLDataFromMiddleware();
return fetchSiteContextByURLLookup(baseContext, siteURLData);
}
3 changes: 2 additions & 1 deletion packages/gitbook-v2/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -70,6 +70,7 @@ async function serveSiteByURL(request: NextRequest, urlWithMode: URLWithMode) {
requestHeaders.set(MiddlewareHeaders.RouteType, routeType);
requestHeaders.set(MiddlewareHeaders.URLMode, mode);
requestHeaders.set(MiddlewareHeaders.SiteURL, `${url.origin}${data.basePath}`);
requestHeaders.set(MiddlewareHeaders.SiteURLData, JSON.stringify(data));
if (dynamicHeaders) {
for (const [key, value] of Object.entries(dynamicHeaders)) {
requestHeaders.set(key, value);
@@ -84,7 +85,7 @@ async function serveSiteByURL(request: NextRequest, urlWithMode: URLWithMode) {
encodePathInSiteContent(data.pathname),
].join('/');

console.log('route', route);
console.log(`rewriting to ${route}`);

const response = NextResponse.rewrite(new URL(`/${route}`, request.url), {
request: {
Loading
Oops, something went wrong.