diff --git a/src/app/(space)/fetch.ts b/src/app/(space)/fetch.ts index c73b5ac03..7e7203308 100644 --- a/src/app/(space)/fetch.ts +++ b/src/app/(space)/fetch.ts @@ -40,6 +40,7 @@ export function getContentPointer(): ContentPointer | SiteContentPointer { if (siteId) { const organizationId = headerSet.get('x-gitbook-content-organization'); const siteSpaceId = headerSet.get('x-gitbook-content-site-space'); + const siteUrl = headerSet.get('x-gitbook-content-url'); if (!organizationId) { throw new Error('Missing site content headers'); } @@ -48,6 +49,7 @@ export function getContentPointer(): ContentPointer | SiteContentPointer { siteId, spaceId, siteSpaceId: siteSpaceId ?? undefined, + siteUrl: siteUrl ?? undefined, organizationId, revisionId: headerSet.get('x-gitbook-content-revision') ?? undefined, changeRequestId: headerSet.get('x-gitbook-content-changerequest') ?? undefined, @@ -71,7 +73,10 @@ export async function fetchSpaceData() { const [{ space, contentTarget, pages, customization, scripts }, parentSite] = await Promise.all( 'siteId' in content - ? [getCurrentSiteData(content), fetchParentSite(content.organizationId, content.siteId)] + ? [ + getCurrentSiteData(content), + fetchParentSite(content.organizationId, content.siteId, content.siteUrl), + ] : [getSpaceData(content)], ); @@ -102,7 +107,7 @@ export async function fetchPageData(params: PagePathParams | PageIdParams) { const page = await resolvePage(contentTarget, pages, params); const [parent, document] = await Promise.all([ 'siteId' in content - ? fetchParentSite(content.organizationId, content.siteId) + ? fetchParentSite(content.organizationId, content.siteId, content.siteUrl) : fetchParentCollection(space), page?.page.documentId ? getDocument(space.id, page.page.documentId) : null, ]); @@ -173,10 +178,14 @@ async function fetchParentCollection(space: Space) { return { parent: collection, spaces }; } -async function fetchParentSite(organizationId: string, siteId: string) { +async function fetchParentSite( + organizationId: string, + siteId: string, + siteUrl: string | undefined, +) { const [site, siteSpaces] = await Promise.all([ getSite(organizationId, siteId), - getSiteSpaces(organizationId, siteId), + getSiteSpaces(organizationId, siteId, siteUrl ?? null), ]); const spaces: Record = {}; diff --git a/src/components/Search/server-actions.tsx b/src/components/Search/server-actions.tsx index cbd0395b5..743cb2bff 100644 --- a/src/components/Search/server-actions.tsx +++ b/src/components/Search/server-actions.tsx @@ -76,7 +76,7 @@ export async function searchParentContent( api.searchParentContent(parent.id, query), parent.object === 'collection' ? api.getCollectionSpaces(parent.id) : null, parent.object === 'site' && 'organizationId' in pointer - ? api.getSiteSpaces(pointer.organizationId, parent.id) + ? api.getSiteSpaces(pointer.organizationId, parent.id, pointer.siteUrl ?? null) : null, ]); diff --git a/src/lib/api.ts b/src/lib/api.ts index 1da689af9..f6c1b9f64 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -47,6 +47,11 @@ export interface SiteContentPointer extends ContentPointer { * ID of the siteSpace can be undefined when rendering in multi-id mode (for site previews) */ siteSpaceId: string | undefined; + /** + * URL of the site content that was used for lookup. Only set for `multi` and `multi-path` modes + * where an URL is involved in the lookup/resolution + */ + siteUrl: string | undefined; } /** @@ -126,6 +131,8 @@ export type PublishedContentWithCache = | ((PublishedContentLookup | PublishedSiteContentLookup) & { cacheMaxAge?: number; cacheTags?: string[]; + /** Published content URL that was used for lookup */ + contentUrl?: string; }) | { error: { @@ -235,6 +242,7 @@ export const getPublishedContentByUrl = cache( ...response.data, cacheMaxAge: parsed.ttl, cacheTags: parsed.tags, + contentUrl: url, }; return { tags: [ @@ -736,12 +744,28 @@ export const getSite = cache( */ export const getSiteSpaces = cache( 'api.getSiteSpaces', - async (organizationId: string, siteId: string, options: CacheFunctionOptions) => { + async ( + organizationId: string, + siteId: string, + /** + * Additional site URL that can be used as context to resolve site space published urls + */ + siteUrlContext: string | null, + options: CacheFunctionOptions, + ) => { const response = await getAll((params) => - api().orgs.listSiteSpaces(organizationId, siteId, params, { - ...noCacheFetchOptions, - signal: options.signal, - }), + api().orgs.listSiteSpaces( + organizationId, + siteId, + { + ...params, + context: siteUrlContext ?? undefined, + }, + { + ...noCacheFetchOptions, + signal: options.signal, + }, + ), ); return cacheResponse(response, { diff --git a/src/middleware.ts b/src/middleware.ts index fbd262311..bdbad2831 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -209,6 +209,9 @@ export async function middleware(request: NextRequest) { headers.set('x-gitbook-content-site-space', resolved.siteSpace); } } + if (resolved.contentUrl) { + headers.set('x-gitbook-content-url', resolved.contentUrl); + } if (resolved.revision) { headers.set('x-gitbook-content-revision', resolved.revision); } @@ -659,6 +662,7 @@ async function lookupSpaceByAPI( apiToken: data.apiToken, cacheMaxAge: data.cacheMaxAge, cacheTags: data.cacheTags, + contentUrl: data.contentUrl, ...('site' in data ? { site: data.site, siteSpace: data.siteSpace, organization: data.organization } : {}),