From 5590437fc75af9fc4ed7cee78fd0c419c58455aa Mon Sep 17 00:00:00 2001 From: taranvohra Date: Wed, 20 Nov 2024 21:09:47 +0530 Subject: [PATCH 1/4] bump api client --- bun.lockb | Bin 572016 -> 572016 bytes packages/gitbook/package.json | 2 +- packages/react-contentkit/package.json | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bun.lockb b/bun.lockb index 5b99ab574f1e7ac6787004fcac6f6d06cd303989..3224336879d0a5291a3fe3b8e029cddd56111dbd 100755 GIT binary patch delta 172 zcmV;d08{_)^dj)|B9Ja1eZ}e$H3wrieXU!6E4YK3l=Ctd Date: Thu, 21 Nov 2024 11:25:39 +0530 Subject: [PATCH 2/4] redirect by source --- packages/gitbook/src/app/(site)/fetch.ts | 54 +++++++++++++++++------- packages/gitbook/src/lib/api.ts | 43 +++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/packages/gitbook/src/app/(site)/fetch.ts b/packages/gitbook/src/app/(site)/fetch.ts index 3c6b118875..b98f94f624 100644 --- a/packages/gitbook/src/app/(site)/fetch.ts +++ b/packages/gitbook/src/app/(site)/fetch.ts @@ -1,11 +1,12 @@ import { RevisionPage } from '@gitbook/api'; +import { redirect } from 'next/navigation'; import { getRevisionPageByPath, getDocument, - ContentTarget, getSpaceContentData, getSiteData, + getSiteRedirectBySource, } from '@/lib/api'; import { resolvePagePath, resolvePageId } from '@/lib/pages'; import { getSiteContentPointer } from '@/lib/pointer'; @@ -41,6 +42,7 @@ export async function fetchContentData() { site, sections, spaces, + shareKey: content.siteShareKey, customization, scripts, ancestors: [], @@ -54,7 +56,15 @@ export async function fetchContentData() { export async function fetchPageData(params: PagePathParams | PageIdParams) { const contentData = await fetchContentData(); - const page = await resolvePage(contentData.contentTarget, contentData.pages, params); + const page = await resolvePage({ + organizationId: contentData.space.organization, + siteId: contentData.site.id, + spaceId: contentData.contentTarget.spaceId, + revisionId: contentData.contentTarget.revisionId, + pages: contentData.pages, + shareKey: contentData.shareKey, + params, + }); const document = page?.page.documentId ? await getDocument(contentData.space.id, page.page.documentId) : null; @@ -70,11 +80,17 @@ export async function fetchPageData(params: PagePathParams | PageIdParams) { * Resolve a page from the params. * If the path can't be found, we try to resolve it from the API to handle redirects. */ -async function resolvePage( - contentTarget: ContentTarget, - pages: RevisionPage[], - params: PagePathParams | PageIdParams, -) { +async function resolvePage(input: { + organizationId: string; + siteId: string; + spaceId: string; + revisionId: string; + shareKey: string | undefined; + pages: RevisionPage[]; + params: PagePathParams | PageIdParams; +}) { + const { organizationId, siteId, spaceId, revisionId, pages, shareKey, params } = input; + if ('pageId' in params) { return resolvePageId(pages, params.pageId); } @@ -88,20 +104,26 @@ async function resolvePage( return page; } - // If page can't be found, we try with the API, in case we have a redirect - // We use the raw pathname to handle special/malformed redirects setup by users in the GitSync. - // The page rendering will take care of redirecting to a normalized pathname. - // // We don't test path that are too long as GitBook doesn't support them and will return a 404 anyway. if (rawPathname.length <= 512) { - const resolved = await getRevisionPageByPath( - contentTarget.spaceId, - contentTarget.revisionId, - rawPathname, - ); + // If page can't be found, we try with the API, in case we have a redirect at space level. + // We use the raw pathname to handle special/malformed redirects setup by users in the GitSync. + // The page rendering will take care of redirecting to a normalized pathname. + const resolved = await getRevisionPageByPath(spaceId, revisionId, rawPathname); if (resolved) { return resolvePageId(pages, resolved.id); } + + // If a page still can't be found, we try with the API, in case we have a redirect at site level. + const resolvedSiteRedirect = await getSiteRedirectBySource({ + organizationId, + siteId, + source: rawPathname.startsWith('/') ? rawPathname : `/${rawPathname}`, + siteShareKey: input.shareKey, + }); + if (resolvedSiteRedirect) { + return redirect(resolvedSiteRedirect.target); + } } return undefined; diff --git a/packages/gitbook/src/lib/api.ts b/packages/gitbook/src/lib/api.ts index b9a7992bde..ba016de9f7 100644 --- a/packages/gitbook/src/lib/api.ts +++ b/packages/gitbook/src/lib/api.ts @@ -620,6 +620,49 @@ export const getDocument = cache({ timeout: 20 * 1000, }); +/** + * Resolve a site redirect by its source path. + */ +export const getSiteRedirectBySource = cache({ + name: 'api.getSiteRedirectBySource', + tag: ({ siteId }) => getAPICacheTag({ tag: 'site', site: siteId }), + get: async ( + args: { + organizationId: string; + siteId: string; + /** Site share key that can be used as context to resolve site space published urls */ + siteShareKey: string | undefined; + source: string; + }, + options: CacheFunctionOptions, + ) => { + try { + const response = await api().orgs.getSiteRedirectBySource( + args.organizationId, + args.siteId, + { + shareKey: args.siteShareKey, + source: args.source, + }, + { + ...noCacheFetchOptions, + signal: options.signal, + }, + ); + return cacheResponse(response, cacheTtl_1day); + } catch (error) { + if ((error as GitBookAPIError).code === 404) { + return { + data: null, + ...cacheTtl_1day, + }; + } + + throw error; + } + }, +}); + /** * Get the infos about a site by its ID. */ From 3f64a6ebc3c130573c0ebce2c31909bee180b748 Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 21 Nov 2024 19:24:27 +0530 Subject: [PATCH 3/4] e2e test --- packages/gitbook/e2e/pages.spec.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/gitbook/e2e/pages.spec.ts b/packages/gitbook/e2e/pages.spec.ts index 92d4b6fdb8..9ae87a77de 100644 --- a/packages/gitbook/e2e/pages.spec.ts +++ b/packages/gitbook/e2e/pages.spec.ts @@ -491,6 +491,19 @@ const testCases: TestsCase[] = [ }, ], }, + { + name: 'Site Redirects', + baseUrl: 'https://gitbook-open-e2e-sites.gitbook.io/gitbook-doc/', + tests: [ + { + name: 'Redirect to SSO page', + url: 'a/redirect/to/sso', + run: async (page) => { + await expect(page.getByText('SSO')).toBeVisible(); + }, + }, + ], + }, { name: 'Share links', baseUrl: 'https://gitbook.gitbook.io/gbo-tests-share-links/', From ee7c0eefbe6bfd3825260c32255638c1d1e86cf5 Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 21 Nov 2024 20:06:49 +0530 Subject: [PATCH 4/4] fix e2e test --- packages/gitbook/e2e/pages.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitbook/e2e/pages.spec.ts b/packages/gitbook/e2e/pages.spec.ts index 9ae87a77de..e0d456dcc3 100644 --- a/packages/gitbook/e2e/pages.spec.ts +++ b/packages/gitbook/e2e/pages.spec.ts @@ -499,7 +499,7 @@ const testCases: TestsCase[] = [ name: 'Redirect to SSO page', url: 'a/redirect/to/sso', run: async (page) => { - await expect(page.getByText('SSO')).toBeVisible(); + await expect(page.locator('h1')).toHaveText('SSO'); }, }, ],