diff --git a/dev/test-proxy-server.ts b/dev/test-proxy-server.ts new file mode 100644 index 000000000..43bc9cd8b --- /dev/null +++ b/dev/test-proxy-server.ts @@ -0,0 +1,46 @@ +/* + * Demo on how to proxy requests to the renderer with a given space ID and a base path. + */ + +const spaceId = Bun.argv[2]; +const basePath = Bun.argv[3] ?? ''; +const port = 5000; + +if (!spaceId) { + throw new Error('Please provide a space id as an argument'); +} + +console.log(`Proxying space ${spaceId} on http://localhost:${port}/${basePath}`); + +Bun.serve({ + port, + fetch: async (req) => { + const url = new URL(req.url); + const upUrl = isNextUrl(url) + ? `http://localhost:3000${url.pathname}` + : `http://localhost:3000/${spaceId}${url.pathname}`; + + const headers = new Headers(req.headers); + + headers.set('x-gitbook-host', url.host); + headers.set('x-gitbook-basepath', basePath); + + const response = await fetch(upUrl, { + method: req.method, + headers: headers, + verbose: true, + }); + const body = await response.text(); + + return new Response(body, { + status: response.status, + headers: { + 'content-type': response.headers.get('content-type') || 'text/html', + }, + }); + }, +}); + +function isNextUrl(url: URL) { + return url.pathname.startsWith('/_next/'); +} diff --git a/src/app/[spaceId]/[[...pathname]]/page.tsx b/src/app/[spaceId]/[[...pathname]]/page.tsx index 8d5dd1992..48bb44b0a 100644 --- a/src/app/[spaceId]/[[...pathname]]/page.tsx +++ b/src/app/[spaceId]/[[...pathname]]/page.tsx @@ -3,7 +3,7 @@ import { notFound, redirect } from 'next/navigation'; import { SpaceContent } from '@/components/SpaceContent'; import { getPageDocument } from '@/lib/api'; -import { PageHrefContext, absoluteHref, pageHref } from '@/lib/links'; +import { PageHrefContext, absoluteHref, baseUrl, pageHref } from '@/lib/links'; import { PagePathParams, fetchPageData, getPagePath } from '../fetch'; @@ -51,6 +51,7 @@ export async function generateMetadata({ params }: { params: PagePathParams }): title: { default: page.title, template: `%s | ${space.title}` }, description: page.description, generator: 'GitBook', + metadataBase: new URL(baseUrl()), icons: { icon: [ { diff --git a/src/lib/links.ts b/src/lib/links.ts index 0d835ce53..05ddeafdd 100644 --- a/src/lib/links.ts +++ b/src/lib/links.ts @@ -13,17 +13,44 @@ export interface PageHrefContext { /** * Return the base path for the current request. + * The value will start and finish with / */ export function basePath(): string { const headersList = headers(); - return headersList.get('x-gitbook-basepath') ?? ''; + let path = headersList.get('x-gitbook-basepath') ?? '/'; + + if (!path.startsWith('/')) { + path = '/' + path; + } + + if (!path.endsWith('/')) { + path = path + '/'; + } + + return path; +} + +/** + * Return the current host for the current request. + */ +export function host(): string { + const headersList = headers(); + return headersList.get('x-gitbook-host') ?? headersList.get('host') ?? ''; +} + +/** + * Return the base URL for the current request. + */ +export function baseUrl(): string { + return `https://${host()}${basePath()}`; } /** * Create an absolute href in the current content. */ export function absoluteHref(href: string): string { - return `${basePath()}/${href.startsWith('/') ? href.slice(1) : href}`; + const base = basePath(); + return `${base === '/' ? '' : base}/${href.startsWith('/') ? href.slice(1) : href}`; } /**