From 44c35c043d448e920ff21dacfd0594ef62698614 Mon Sep 17 00:00:00 2001 From: Steeve Pastorelli Date: Wed, 30 Apr 2025 19:09:26 +0200 Subject: [PATCH 01/11] Add methods in visitor util to return visitor unsigned claims and token --- packages/gitbook-v2/src/middleware.ts | 7 +- ...visitor-token.test.ts => visitors.test.ts} | 139 ++++++++++++++++- .../src/lib/{visitor-token.ts => visitors.ts} | 143 ++++++++++++++++++ packages/gitbook/src/middleware.ts | 24 +-- 4 files changed, 296 insertions(+), 17 deletions(-) rename packages/gitbook/src/lib/{visitor-token.test.ts => visitors.test.ts} (56%) rename packages/gitbook/src/lib/{visitor-token.ts => visitors.ts} (69%) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index dd983b536a..36666b7706 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -10,9 +10,9 @@ import { type ResponseCookies, getPathScopedCookieName, getResponseCookiesForVisitorAuth, - getVisitorToken, + getVisitorPayload, normalizeVisitorAuthURL, -} from '@/lib/visitor-token'; +} from '@/lib/visitors'; import { serveResizedImage } from '@/routes/image'; import { DataFetcherError, @@ -85,8 +85,7 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) { // // Detect and extract the visitor authentication token from the request // - // @ts-ignore - request typing - const visitorToken = getVisitorToken({ + const { visitorToken } = getVisitorPayload({ cookies: request.cookies.getAll(), url: siteRequestURL, }); diff --git a/packages/gitbook/src/lib/visitor-token.test.ts b/packages/gitbook/src/lib/visitors.test.ts similarity index 56% rename from packages/gitbook/src/lib/visitor-token.test.ts rename to packages/gitbook/src/lib/visitors.test.ts index a1f07d2504..c5ff586458 100644 --- a/packages/gitbook/src/lib/visitor-token.test.ts +++ b/packages/gitbook/src/lib/visitors.test.ts @@ -6,7 +6,8 @@ import { getVisitorAuthCookieName, getVisitorAuthCookieValue, getVisitorToken, -} from './visitor-token'; + getVisitorUnsignedClaims, +} from './visitors'; describe('getVisitorAuthToken', () => { it('should return the token from the query parameters', () => { @@ -158,3 +159,139 @@ function assertVisitorAuthCookieValue( throw new Error('Expected a VisitorAuthCookieValue'); } + +describe('getVisitorPublicClaims', () => { + it('should merge claims from multiple public cookies', () => { + const cookies = [ + { + name: 'gitbook-visitor-public-bucket', + value: JSON.stringify({ bucket: { flags: { SITE_AI: true, SITE_PREVIEW: true } } }), + }, + { + name: 'gitbook-visitor-public-launchdarkly', + value: JSON.stringify({ + launchdarkly: { flags: { ALPHA: true, API: true } }, + }), + }, + ]; + + const url = new URL('https://example.com/'); + const claims = getVisitorUnsignedClaims({ cookies, url }); + + expect(claims).toStrictEqual({ + bucket: { flags: { SITE_AI: true, SITE_PREVIEW: true } }, + launchdarkly: { flags: { ALPHA: true, API: true } }, + }); + }); + + it('should parse visitor.* query params with simple types', () => { + const url = new URL( + 'https://example.com/?visitor.isEnterprise=true&visitor.language=fr&visitor.country=fr' + ); + + const claims = getVisitorUnsignedClaims({ cookies: [], url }); + + expect(claims).toStrictEqual({ + isEnterprise: true, + language: 'fr', + country: 'fr', + }); + }); + + it('should ignore params that do not match visitor.* convention', () => { + const url = new URL('https://example.com/?visitor.isEnterprise=true&otherParam=true'); + + const claims = getVisitorUnsignedClaims({ cookies: [], url }); + + expect(claims).toStrictEqual({ + isEnterprise: true, + // otherParam is not present + }); + }); + + it('should ignore public cookies not present in the allowed list', () => { + const url = new URL('https://example.com/'); + + const claims = getVisitorUnsignedClaims({ + cookies: [ + { + name: 'gitbook-visitor-public', + value: JSON.stringify({ role: 'admin', language: 'fr' }), + }, + // The claims in this cookie should be ignored + { + name: 'gitbook-visitor-public-disallowed', + value: JSON.stringify({ + disallowed: { flags: { SITE_AI: true, SITE_PREVIEW: true } }, + }), + }, + ], + url, + }); + + expect(claims).toStrictEqual({ + role: 'admin', + language: 'fr', + }); + }); + + it('should support nested query param keys via dot notation', () => { + const url = new URL( + 'https://example.com/?visitor.isEnterprise=true&visitor.flags.ALPHA=true&visitor.flags.API=false' + ); + + const claims = getVisitorUnsignedClaims({ cookies: [], url }); + + expect(claims).toStrictEqual({ + isEnterprise: true, + flags: { + ALPHA: true, + API: false, + }, + }); + }); + + it('should ignore invalid JSON in cookie values', () => { + const cookies = [ + { + name: 'gitbook-visitor-public', + value: '{not: "json"}', + }, + ]; + const url = new URL('https://example.com/'); + const claims = getVisitorUnsignedClaims({ cookies, url }); + + expect(claims).toStrictEqual({}); + }); + + it('should merge claims from cookies and visitor.* query params', () => { + const cookies = [ + { + name: 'gitbook-visitor-public', + value: JSON.stringify({ role: 'admin', language: 'fr' }), + }, + { + name: 'gitbook-visitor-public-bucket', + value: JSON.stringify({ bucket: { flags: { SITE_AI: true, SITE_PREVIEW: true } } }), + }, + ]; + const url = new URL( + 'https://example.com/?visitor.isEnterprise=true&visitor.flags.ALPHA=true&visitor.flags.API=false' + ); + + const claims = getVisitorUnsignedClaims({ cookies, url }); + + expect(claims).toStrictEqual({ + role: 'admin', + language: 'fr', + bucket: { + flags: { SITE_AI: true, SITE_PREVIEW: true }, + }, + isEnterprise: true, + flags: { + ALPHA: true, + API: false, + }, + }); + }); +}); diff --git a/packages/gitbook/src/lib/visitor-token.ts b/packages/gitbook/src/lib/visitors.ts similarity index 69% rename from packages/gitbook/src/lib/visitor-token.ts rename to packages/gitbook/src/lib/visitors.ts index 64f0c97931..7369581cbd 100644 --- a/packages/gitbook/src/lib/visitor-token.ts +++ b/packages/gitbook/src/lib/visitors.ts @@ -4,6 +4,11 @@ import hash from 'object-hash'; const VISITOR_AUTH_PARAM = 'jwt_token'; export const VISITOR_TOKEN_COOKIE = 'gitbook-visitor-token'; +const VISITOR_UNSIGNED_CLAIM_COOKIES = [ + 'gitbook-visitor-public', + 'gitbook-visitor-public-bucket', + 'gitbook-visitor-public-launchdarkly', +]; /** * Typing for a cookie, matching the internal type of Next.js. @@ -30,6 +35,25 @@ type VisitorAuthCookieValue = { token: string; }; +type ClaimPrimitive = + | string + | number + | boolean + | null + | undefined + | { [key: string]: ClaimPrimitive } + | ClaimPrimitive[]; + +/** + * The result of a visitor info lookup that can include: + * - a visitor token (JWT) + * - a record of visitor public/unsigned claims (JSON object) + */ +export type VisitorPayload = { + visitorToken: VisitorTokenLookup; + unsignedClaims: Record; +}; + /** * The result of a visitor token lookup. */ @@ -53,6 +77,25 @@ export type VisitorTokenLookup = /** Not visitor token was found */ | undefined; +/** + * Get the visitor info for the request including its token and/or unsigned claims when present. + */ +export function getVisitorPayload({ + cookies, + url, +}: { + cookies: RequestCookies; + url: URL | NextRequest['nextUrl']; +}): VisitorPayload { + const visitorToken = getVisitorToken({ cookies, url }); + const unsignedClaims = getVisitorUnsignedClaims({ cookies, url }); + + return { + visitorToken, + unsignedClaims, + }; +} + /** * Get the visitor token for the request. This token can either be in the * query parameters or stored as a cookie. @@ -82,6 +125,106 @@ export function getVisitorToken({ } } +/** + * Get the visitor unsigned/public claims for the request. They can either be in `visitor.` query + * parameters or stored in special `gitbook-visitor-public-*` cookies. + */ +export function getVisitorUnsignedClaims(args: { + cookies: RequestCookies; + url: URL | NextRequest['nextUrl']; +}): Record { + const { cookies, url } = args; + const claims: Record = {}; + + for (const cookie of cookies) { + if (VISITOR_UNSIGNED_CLAIM_COOKIES.includes(cookie.name)) { + try { + const parsed = JSON.parse(cookie.value); + if (typeof parsed === 'object' && parsed !== null) { + Object.assign(claims, parsed); + } + } catch (_err) { + console.warn(`Invalid JSON in unsigned claim cookie "${cookie.name}"`); + } + } + } + + for (const [key, value] of url.searchParams.entries()) { + if (key.startsWith('visitor.')) { + const claimPath = key.substring('visitor.'.length); + const claimValue = parseVisitorQueryParamValue(value); + setVisitorClaimByPath(claims, claimPath, claimValue); + } + } + + return claims; +} + +/** + * Set the value of claims in a claims object at a specific path. + */ +function setVisitorClaimByPath( + claims: Record, + keyPath: string, + value: ClaimPrimitive +): void { + const keys = keyPath.split('.'); + let current = claims; + + for (let index = 0; index < keys.length; index++) { + const key = keys[index]; + + if (index === keys.length - 1) { + current[key] = value; + } else { + if (!(key in current) || !isClaimPrimitiveObject(current[key])) { + current[key] = {}; + } + + current = current[key]; + } + } +} + +function isClaimPrimitiveObject(value: unknown): value is Record { + return typeof value === 'object' && value !== null; +} + +/** + * Parse the value expected in a `visitor.` URL query parameter. + */ +function parseVisitorQueryParamValue(value: string): ClaimPrimitive { + if (value === 'true') { + return true; + } + + if (value === 'false') { + return false; + } + + if (value === 'null') { + return null; + } + + if (value === 'undefined') { + return undefined; + } + + const num = Number(value); + if (!Number.isNaN(num) && value.trim() !== '') { + return num; + } + + try { + const parsed = JSON.parse(value); + if (typeof parsed === 'object' && parsed !== null) { + return parsed; + } + } catch {} + + return value; +} + /** * Return the lookup result for content served with visitor auth. */ diff --git a/packages/gitbook/src/middleware.ts b/packages/gitbook/src/middleware.ts index 30f7b44e6a..04b1b40dd9 100644 --- a/packages/gitbook/src/middleware.ts +++ b/packages/gitbook/src/middleware.ts @@ -24,9 +24,9 @@ import { type ResponseCookies, type VisitorTokenLookup, getResponseCookiesForVisitorAuth, - getVisitorToken, + getVisitorPayload, normalizeVisitorAuthURL, -} from '@/lib/visitor-token'; +} from '@/lib/visitors'; import { joinPath, withLeadingSlash } from '@/lib/paths'; import { getProxyModeBasePath } from '@/lib/proxy'; @@ -392,17 +392,17 @@ async function lookupSiteInProxy(request: NextRequest, url: URL): Promise { - const visitorAuthToken = getVisitorToken({ + const { visitorToken } = getVisitorPayload({ cookies: request.cookies.getAll(), url, }); - const lookup = await lookupSiteByAPI(url, visitorAuthToken); + const lookup = await lookupSiteByAPI(url, visitorToken); return { ...lookup, - ...('basePath' in lookup && visitorAuthToken - ? getLookupResultForVisitorAuth(lookup.basePath, visitorAuthToken) + ...('basePath' in lookup && visitorToken + ? getLookupResultForVisitorAuth(lookup.basePath, visitorToken) : {}), - visitorToken: visitorAuthToken?.token, + visitorToken: visitorToken?.token, }; } @@ -609,12 +609,12 @@ async function lookupSiteInMultiPathMode(request: NextRequest, url: URL): Promis const target = new URL(targetStr); target.search = url.search; - const visitorAuthToken = getVisitorToken({ + const { visitorToken } = getVisitorPayload({ cookies: request.cookies.getAll(), url: target, }); - const lookup = await lookupSiteByAPI(target, visitorAuthToken); + const lookup = await lookupSiteByAPI(target, visitorToken); if ('error' in lookup) { return lookup; } @@ -641,10 +641,10 @@ async function lookupSiteInMultiPathMode(request: NextRequest, url: URL): Promis ...lookup, siteBasePath: joinPath(target.host, lookup.siteBasePath), basePath: joinPath(target.host, lookup.basePath), - ...('basePath' in lookup && visitorAuthToken - ? getLookupResultForVisitorAuth(lookup.basePath, visitorAuthToken) + ...('basePath' in lookup && visitorToken + ? getLookupResultForVisitorAuth(lookup.basePath, visitorToken) : {}), - visitorToken: visitorAuthToken?.token, + visitorToken: visitorToken?.token, }; } From f8817bbae8438b9bc29621a92aa34bea0a087a67 Mon Sep 17 00:00:00 2001 From: Steeve Pastorelli Date: Wed, 30 Apr 2025 19:16:43 +0200 Subject: [PATCH 02/11] Fix missed reference --- packages/gitbook/e2e/internal.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitbook/e2e/internal.spec.ts b/packages/gitbook/e2e/internal.spec.ts index d5e49b705f..83181c3c9a 100644 --- a/packages/gitbook/e2e/internal.spec.ts +++ b/packages/gitbook/e2e/internal.spec.ts @@ -12,7 +12,7 @@ import { VISITOR_TOKEN_COOKIE, getVisitorAuthCookieName, getVisitorAuthCookieValue, -} from '@/lib/visitor-token'; +} from '@/lib/visitors'; import { getSiteAPIToken } from '../tests/utils'; import { From c327f3e2b6a366a90c8ff03049c147cee7a9c7b0 Mon Sep 17 00:00:00 2001 From: Steeve Pastorelli Date: Wed, 7 May 2025 18:13:27 +0200 Subject: [PATCH 03/11] Add resolvePublishedContentByUrl method in lookup to use new endpoint --- bun.lock | 34 +++-- package.json | 2 +- packages/cache-tags/package.json | 2 +- packages/gitbook-v2/package.json | 14 +- packages/gitbook-v2/src/lib/data/lookup.ts | 143 ++++++++++++++++----- packages/gitbook/package.json | 2 +- packages/gitbook/src/lib/visitors.ts | 4 +- packages/react-contentkit/package.json | 2 +- 8 files changed, 137 insertions(+), 66 deletions(-) diff --git a/bun.lock b/bun.lock index d720c44b84..5848d1c611 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ "name": "@gitbook/cache-tags", "version": "0.3.1", "dependencies": { - "@gitbook/api": "^0.111.0", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "assert-never": "^1.2.1", }, "devDependencies": { @@ -51,7 +51,7 @@ "name": "gitbook", "version": "0.11.1", "dependencies": { - "@gitbook/api": "*", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "@gitbook/cache-do": "workspace:*", "@gitbook/cache-tags": "workspace:*", "@gitbook/colors": "workspace:*", @@ -143,7 +143,7 @@ "name": "gitbook-v2", "version": "0.2.5", "dependencies": { - "@gitbook/api": "*", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "@gitbook/cache-tags": "workspace:*", "@sindresorhus/fnv1a": "^3.1.0", "assert-never": "^1.2.1", @@ -202,7 +202,7 @@ "name": "@gitbook/react-contentkit", "version": "0.7.0", "dependencies": { - "@gitbook/api": "*", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "@gitbook/icons": "workspace:*", "classnames": "^2.5.1", }, @@ -260,7 +260,7 @@ }, "overrides": { "@codemirror/state": "6.4.1", - "@gitbook/api": "0.113.0", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "react": "^19.0.0", "react-dom": "^19.0.0", }, @@ -625,7 +625,7 @@ "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="], - "@gitbook/api": ["@gitbook/api@0.113.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-PWMeAkdm4bHSl3b5OmtcmskZ6qRkkDhauCPybo8sGnjS03O14YAUtubAQiNCKX/uwbs+yiQ8KRPyeIwn+g42yw=="], + "@gitbook/api": ["@gitbook/api@https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }], "@gitbook/cache-do": ["@gitbook/cache-do@workspace:packages/cache-do"], @@ -635,8 +635,6 @@ "@gitbook/emoji-codepoints": ["@gitbook/emoji-codepoints@workspace:packages/emoji-codepoints"], - "@gitbook/fontawesome-pro": ["@gitbook/fontawesome-pro@1.0.8", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "^6.6.0" } }, "sha512-i4PgiuGyUb52Muhc52kK3aMJIMfMkA2RbPW30tre8a6M8T6mWTfYo6gafSgjNvF1vH29zcuB8oBYnF0gO4XcHA=="], - "@gitbook/icons": ["@gitbook/icons@workspace:packages/icons"], "@gitbook/openapi-parser": ["@gitbook/openapi-parser@workspace:packages/openapi-parser"], @@ -4077,7 +4075,7 @@ "gaxios/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "gitbook-v2/next": ["next@15.4.0-canary.7", "", { "dependencies": { "@next/env": "15.4.0-canary.7", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.0-canary.7", "@next/swc-darwin-x64": "15.4.0-canary.7", "@next/swc-linux-arm64-gnu": "15.4.0-canary.7", "@next/swc-linux-arm64-musl": "15.4.0-canary.7", "@next/swc-linux-x64-gnu": "15.4.0-canary.7", "@next/swc-linux-x64-musl": "15.4.0-canary.7", "@next/swc-win32-arm64-msvc": "15.4.0-canary.7", "@next/swc-win32-x64-msvc": "15.4.0-canary.7", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-ZYjT0iu+4osz8XIlr31MuoXaNQKRU75UcwEgNBt93gftoh6tzV2Mebz6sOGeVReYuYUvYlLJJksMBTNcFcPbSA=="], + "gitbook-v2/next": ["next@15.4.0-canary.24", "", { "dependencies": { "@next/env": "15.4.0-canary.24", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.0-canary.24", "@next/swc-darwin-x64": "15.4.0-canary.24", "@next/swc-linux-arm64-gnu": "15.4.0-canary.24", "@next/swc-linux-arm64-musl": "15.4.0-canary.24", "@next/swc-linux-x64-gnu": "15.4.0-canary.24", "@next/swc-linux-x64-musl": "15.4.0-canary.24", "@next/swc-win32-arm64-msvc": "15.4.0-canary.24", "@next/swc-win32-x64-msvc": "15.4.0-canary.24", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-YzjyAhuNu/DSejEyjk8palmoHRyB6w0El5pUmNemeDLs/qaK8GgWjd6CcFcxEYvBiEjhID6B6t+pDfbTms7Xsw=="], "global-dirs/ini": ["ini@1.3.7", "", {}, "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="], @@ -4969,23 +4967,23 @@ "gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - "gitbook-v2/next/@next/env": ["@next/env@15.4.0-canary.7", "", {}, "sha512-q8S7f2lQti3Y3gcAPzE8Pj8y0EwiWHVyyilMzoLbDPXGVfxlQhXLRiFdy2cDkKN4DyjGZWDeehEtw4huvJAa3Q=="], + "gitbook-v2/next/@next/env": ["@next/env@15.4.0-canary.24", "", {}, "sha512-a9XW8stKoDILs5ySIhv/WvnXqfdBJ3CSMFZk6DGWogaHj0JcZmjJqZYWc5PVO6rdswXuYzpnEHXKZ54l05PUrg=="], - "gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.4.0-canary.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+TMxUu5CAWNe+UFRc47BZAXQxCRqZfVbGyCldddiog4MorvL7kBxSd1qlmrwI73fRRKtXkHIH1TaeItyxzC9rQ=="], + "gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.4.0-canary.24", "", { "os": "darwin", "cpu": "arm64" }, "sha512-KZTWf+lKcn/xU3QmTSGzxeWpsKe2HVhkH9A8Q0ZSbu2GKulekqlgA3Er0IdOAIs76ici7GOtOQAt4k8xjpX85g=="], - "gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.4.0-canary.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-veXp8lg/X/7O+pG9BDQ3OizFz3B40v29jsvEWj+ULY/W8Z6+dCSd5XPP2M8fG/gKKKA0D6L0CnnM2Mj0RRSUJw=="], + "gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.4.0-canary.24", "", { "os": "darwin", "cpu": "x64" }, "sha512-QrSRUkggMA0kfYOxM5Xn5h3SBgI3Qbq+G1SmH71/VXz2NmG7HjrcyQPG4wYp6w7v3jhubSqPREzDjPNqtOxP1Q=="], - "gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.4.0-canary.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-KxNGfW7BO0Z5B9rJyl9p7YVjNrxAhu06mH6h1PSdouZG7YMYpdRCconVXeuBI0PEu6g3ywNrOVxZUk1V6G5u0Q=="], + "gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.4.0-canary.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nsn3SmZzAjYS/n+ZDGvCxsrE7ngMTZu0h4vp+L7nBb6kPNzipnDpwqPTy2heCqlIVA7xPnMCYJ5UKaFHyYjecg=="], - "gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.4.0-canary.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-THgXgmP/cC4DsNwvC6uqB90CebB7Ep1KyZajQL3fYKT5V4SWr46yngKLyoyJVeAYWJH908MrWddf7Ya/Zq7cyg=="], + "gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.4.0-canary.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-SvQ7/Jx5ZqvVFMf3xpSKJg9azj0YOJpPdhR383NdOI9Eem5QLjnbWLEWqfc6p8hNkNzEpAuhEdf5bOWnMLFBxg=="], - "gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.4.0-canary.7", "", { "os": "linux", "cpu": "x64" }, "sha512-kpLB3Jj7fProynQYj2ahFyZlJs0xwm71VzCVrNRu6u7qJGXn6dK5h7+hro8y/y1iqjXWgCLSdxWSHahhWK8XdQ=="], + "gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.4.0-canary.24", "", { "os": "linux", "cpu": "x64" }, "sha512-nfngpiPavN+phfCnjeS0tqAo8DBtjHGHFnQB30mLZwvVQ6buiAn4BlSgh7hjApaDGNOlPDondC8t6yNDMuakUQ=="], - "gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.4.0-canary.7", "", { "os": "linux", "cpu": "x64" }, "sha512-rnGAKvl4cWPVV9D+SybWOGijm0VmKXyqQ+IN0A6WDgdlYZAZP0ZnJv/rq7DSvuOh19AXS8UpQc88SelXV/3j3Q=="], + "gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.4.0-canary.24", "", { "os": "linux", "cpu": "x64" }, "sha512-7HLdl3cZq3uaBPK0es6GhSNIX9rI0b8YJ+AoETPM4LzTG5P/Wfbx+KY3dLlTfU3Ycf4DpwFxlmQeogsT/NYKzg=="], - "gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.4.0-canary.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-/PRbn//EuR3UGiquk050gqvjxLliEgGBy1Cx9KkpAT7szaHOBj1mDDQmxMTEhRex4i3YfKGJXWn5mLMCveya6Q=="], + "gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.4.0-canary.24", "", { "os": "win32", "cpu": "arm64" }, "sha512-dqHsTLd0kkh3BjpA+GBgqmkqCHq4HPtUXZPc25ti0fistb2pOy9oFG3r1sO8DoYY//gUI4hgacFt1snv2MsyYA=="], - "gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.0-canary.7", "", { "os": "win32", "cpu": "x64" }, "sha512-7a92XL+DlrbWyycCpQjjQMHOrsA0p+VvS7iA2dyi89Xsq0qtOPzFH0Gb56fsjh6M6BQGFhboOSzjmpjlkMTilQ=="], + "gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.0-canary.24", "", { "os": "win32", "cpu": "x64" }, "sha512-HxldCCDWW1ytENYu+gNnXg6bRCsMYZs/cMW5uFgc3jXRl4DJ8vpPIjVmjATtatlMJvw4JwGaFdnEjwD8R2H6dA=="], "gitbook-v2/next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], diff --git a/package.json b/package.json index 00f323e2f4..878054dcb2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "packageManager": "bun@1.2.8", "overrides": { "@codemirror/state": "6.4.1", - "@gitbook/api": "0.113.0", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/packages/cache-tags/package.json b/packages/cache-tags/package.json index 3d25aa8f48..cd71ced292 100644 --- a/packages/cache-tags/package.json +++ b/packages/cache-tags/package.json @@ -10,7 +10,7 @@ }, "version": "0.3.1", "dependencies": { - "@gitbook/api": "^0.111.0", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "assert-never": "^1.2.1" }, "devDependencies": { diff --git a/packages/gitbook-v2/package.json b/packages/gitbook-v2/package.json index 50cf96a0d7..64f4823ffb 100644 --- a/packages/gitbook-v2/package.json +++ b/packages/gitbook-v2/package.json @@ -3,17 +3,17 @@ "version": "0.2.5", "private": true, "dependencies": { + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/cache-tags": "workspace:*", + "@sindresorhus/fnv1a": "^3.1.0", + "assert-never": "^1.2.1", + "jwt-decode": "^4.0.0", "next": "canary", "react": "^19.0.0", "react-dom": "^19.0.0", - "@gitbook/api": "*", - "@gitbook/cache-tags": "workspace:*", - "@sindresorhus/fnv1a": "^3.1.0", - "server-only": "^0.0.1", - "warn-once": "^0.1.1", "rison": "^0.1.1", - "jwt-decode": "^4.0.0", - "assert-never": "^1.2.1" + "server-only": "^0.0.1", + "warn-once": "^0.1.1" }, "devDependencies": { "gitbook": "*", diff --git a/packages/gitbook-v2/src/lib/data/lookup.ts b/packages/gitbook-v2/src/lib/data/lookup.ts index 498f6e8859..feb3ef1725 100644 --- a/packages/gitbook-v2/src/lib/data/lookup.ts +++ b/packages/gitbook-v2/src/lib/data/lookup.ts @@ -1,55 +1,128 @@ import { race, tryCatch } from '@/lib/async'; import { joinPath, joinPathWithBaseURL } from '@/lib/paths'; import { trace } from '@/lib/tracing'; -import type { PublishedSiteContentLookup } from '@gitbook/api'; +import type { HttpResponse, PublishedSiteContentLookup, SiteVisitorPayload } from '@gitbook/api'; import { apiClient } from './api'; import { getExposableError } from './errors'; import type { DataFetcherResponse } from './types'; import { getURLLookupAlternatives, stripURLSearch } from './urls'; -/** - * Lookup a content by its URL using the GitBook API. - * To optimize caching, we try multiple lookup alternatives and return the first one that matches. - */ -export async function getPublishedContentByURL(input: { +interface LookupPublishedContentByUrlSharedInput { url: string; - visitorAuthToken: string | null; redirectOnError: boolean; apiToken: string | null; +} + +interface FetchLookupAPIResultFnArgs { + url: string; + signal: AbortSignal; +} +type FetchLookupAPIResponse = + | { + data?: undefined; + error: Error; + } + | { + data: HttpResponse< + PublishedSiteContentLookup, + { + error: { + code: 404; + message: string; + }; + } + >; + error?: undefined; + }; + +/** + * Lookup a content by its URL using the GitBook resolvePublishedContentByUrl API endpoint. + * To optimize caching, we try multiple lookup alternatives and return the first one that matches. + */ +export async function resolvePublishedContentByUrl( + input: LookupPublishedContentByUrlSharedInput & { visitorPayload: SiteVisitorPayload } +) { + return lookupPublishedContentByUrl({ + url: input.url, + fetchLookupAPIResult: async ({ url, signal }: FetchLookupAPIResultFnArgs) => { + const api = await apiClient({ apiToken: input.apiToken }); + + return trace( + { + operation: 'resolvePublishedContentByUrl', + name: url, + }, + () => + tryCatch( + api.urls.resolvePublishedContentByUrl( + { + url, + ...(input.visitorPayload ? { visitor: input.visitorPayload } : {}), + redirectOnError: input.redirectOnError, + // @ts-expect-error - cacheVersion is not a real query param + cacheVersion: 'v2', + }, + { signal } + ) + ) + ); + }, + }); +} + +/** + * Lookup a content by its URL using the GitBook getPublishedContentByUrl API endpoint. + * To optimize caching, we try multiple lookup alternatives and return the first one that matches. + * + * @deprecated use resolvePublishedContentByUrl. + * + */ +export async function getPublishedContentByURL( + input: LookupPublishedContentByUrlSharedInput & { + visitorAuthToken: string | null; + } +) { + return lookupPublishedContentByUrl({ + url: input.url, + fetchLookupAPIResult: async ({ url, signal }: FetchLookupAPIResultFnArgs) => { + const api = await apiClient({ apiToken: input.apiToken }); + + return trace( + { + operation: 'getPublishedContentByURL', + name: url, + }, + () => + tryCatch( + api.urls.getPublishedContentByUrl( + { + url, + visitorAuthToken: input.visitorAuthToken ?? undefined, + redirectOnError: input.redirectOnError, + // @ts-expect-error - cacheVersion is not a real query param + cacheVersion: 'v2', + }, + { signal } + ) + ) + ); + }, + }); +} + +async function lookupPublishedContentByUrl(input: { + url: LookupPublishedContentByUrlSharedInput['url']; + fetchLookupAPIResult: (args: FetchLookupAPIResultFnArgs) => Promise; }): Promise> { const lookupURL = new URL(input.url); const url = stripURLSearch(lookupURL); const lookup = getURLLookupAlternatives(url); const result = await race(lookup.urls, async (alternative, { signal }) => { - const api = await apiClient({ apiToken: input.apiToken }); - - const callResult = await trace( - { - operation: 'getPublishedContentByURL', - name: alternative.url, - }, - () => - tryCatch( - api.urls.getPublishedContentByUrl( - { - url: alternative.url, - visitorAuthToken: input.visitorAuthToken ?? undefined, - redirectOnError: input.redirectOnError, - - // As this endpoint is cached by our API, we version the request - // to void getting stale data with missing properties. - // this could be improved by ensuring our API cache layer is versioned - // or invalidated when needed - // @ts-expect-error - cacheVersion is not a real query param - cacheVersion: 'v2', - }, - { - signal, - } - ) - ) - ); + const callResult = await input.fetchLookupAPIResult({ + url: alternative.url, + signal, + }); if (callResult.error) { if (alternative.primary) { diff --git a/packages/gitbook/package.json b/packages/gitbook/package.json index 5d0939b249..800cb10d04 100644 --- a/packages/gitbook/package.json +++ b/packages/gitbook/package.json @@ -16,7 +16,7 @@ "clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math" }, "dependencies": { - "@gitbook/api": "*", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "@gitbook/cache-do": "workspace:*", "@gitbook/cache-tags": "workspace:*", "@gitbook/colors": "workspace:*", diff --git a/packages/gitbook/src/lib/visitors.ts b/packages/gitbook/src/lib/visitors.ts index 7369581cbd..f9164d178a 100644 --- a/packages/gitbook/src/lib/visitors.ts +++ b/packages/gitbook/src/lib/visitors.ts @@ -49,7 +49,7 @@ type ClaimPrimitive = * - a visitor token (JWT) * - a record of visitor public/unsigned claims (JSON object) */ -export type VisitorPayload = { +export type VisitorPayloadLookup = { visitorToken: VisitorTokenLookup; unsignedClaims: Record; }; @@ -86,7 +86,7 @@ export function getVisitorPayload({ }: { cookies: RequestCookies; url: URL | NextRequest['nextUrl']; -}): VisitorPayload { +}): VisitorPayloadLookup { const visitorToken = getVisitorToken({ cookies, url }); const unsignedClaims = getVisitorUnsignedClaims({ cookies, url }); diff --git a/packages/react-contentkit/package.json b/packages/react-contentkit/package.json index d2c8bd8ee7..522b4b0044 100644 --- a/packages/react-contentkit/package.json +++ b/packages/react-contentkit/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "classnames": "^2.5.1", - "@gitbook/api": "*", + "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", "@gitbook/icons": "workspace:*" }, "peerDependencies": { From 265d52b21a8be943fa5c4ad64df6534428eb35ed Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 16:50:50 +0530 Subject: [PATCH 04/11] bump api package --- bun.lock | 34 ++++++++++++++------------ package.json | 2 +- packages/cache-tags/package.json | 2 +- packages/gitbook-v2/package.json | 2 +- packages/gitbook/package.json | 2 +- packages/react-contentkit/package.json | 2 +- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/bun.lock b/bun.lock index 5848d1c611..6e27a46b06 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ "name": "@gitbook/cache-tags", "version": "0.3.1", "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "assert-never": "^1.2.1", }, "devDependencies": { @@ -51,7 +51,7 @@ "name": "gitbook", "version": "0.11.1", "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/cache-do": "workspace:*", "@gitbook/cache-tags": "workspace:*", "@gitbook/colors": "workspace:*", @@ -143,7 +143,7 @@ "name": "gitbook-v2", "version": "0.2.5", "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/cache-tags": "workspace:*", "@sindresorhus/fnv1a": "^3.1.0", "assert-never": "^1.2.1", @@ -202,7 +202,7 @@ "name": "@gitbook/react-contentkit", "version": "0.7.0", "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/icons": "workspace:*", "classnames": "^2.5.1", }, @@ -260,7 +260,7 @@ }, "overrides": { "@codemirror/state": "6.4.1", - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "react": "^19.0.0", "react-dom": "^19.0.0", }, @@ -625,7 +625,7 @@ "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="], - "@gitbook/api": ["@gitbook/api@https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }], + "@gitbook/api": ["@gitbook/api@0.115.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-Lyj+1WVNnE/Zuuqa/1ZdnUQfUiNE6es89RFK6CJ+Tb36TFwls6mbHKXCZsBwSYyoMYTVK39WQ3Nob6Nw6+TWCA=="], "@gitbook/cache-do": ["@gitbook/cache-do@workspace:packages/cache-do"], @@ -635,6 +635,8 @@ "@gitbook/emoji-codepoints": ["@gitbook/emoji-codepoints@workspace:packages/emoji-codepoints"], + "@gitbook/fontawesome-pro": ["@gitbook/fontawesome-pro@1.0.8", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "^6.6.0" } }, "sha512-i4PgiuGyUb52Muhc52kK3aMJIMfMkA2RbPW30tre8a6M8T6mWTfYo6gafSgjNvF1vH29zcuB8oBYnF0gO4XcHA=="], + "@gitbook/icons": ["@gitbook/icons@workspace:packages/icons"], "@gitbook/openapi-parser": ["@gitbook/openapi-parser@workspace:packages/openapi-parser"], @@ -4075,7 +4077,7 @@ "gaxios/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "gitbook-v2/next": ["next@15.4.0-canary.24", "", { "dependencies": { "@next/env": "15.4.0-canary.24", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.0-canary.24", "@next/swc-darwin-x64": "15.4.0-canary.24", "@next/swc-linux-arm64-gnu": "15.4.0-canary.24", "@next/swc-linux-arm64-musl": "15.4.0-canary.24", "@next/swc-linux-x64-gnu": "15.4.0-canary.24", "@next/swc-linux-x64-musl": "15.4.0-canary.24", "@next/swc-win32-arm64-msvc": "15.4.0-canary.24", "@next/swc-win32-x64-msvc": "15.4.0-canary.24", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-YzjyAhuNu/DSejEyjk8palmoHRyB6w0El5pUmNemeDLs/qaK8GgWjd6CcFcxEYvBiEjhID6B6t+pDfbTms7Xsw=="], + "gitbook-v2/next": ["next@15.4.0-canary.26", "", { "dependencies": { "@next/env": "15.4.0-canary.26", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.4.0-canary.26", "@next/swc-darwin-x64": "15.4.0-canary.26", "@next/swc-linux-arm64-gnu": "15.4.0-canary.26", "@next/swc-linux-arm64-musl": "15.4.0-canary.26", "@next/swc-linux-x64-gnu": "15.4.0-canary.26", "@next/swc-linux-x64-musl": "15.4.0-canary.26", "@next/swc-win32-arm64-msvc": "15.4.0-canary.26", "@next/swc-win32-x64-msvc": "15.4.0-canary.26", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-0lq0x+H4ewc6vXth3S9shrcK3eYl+4wLXQqdboVwBbJe0ykB3+QbGdXFIEICCZsmbAOaii0ag0tzqD3y/vr3bw=="], "global-dirs/ini": ["ini@1.3.7", "", {}, "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ=="], @@ -4967,23 +4969,23 @@ "gaxios/https-proxy-agent/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], - "gitbook-v2/next/@next/env": ["@next/env@15.4.0-canary.24", "", {}, "sha512-a9XW8stKoDILs5ySIhv/WvnXqfdBJ3CSMFZk6DGWogaHj0JcZmjJqZYWc5PVO6rdswXuYzpnEHXKZ54l05PUrg=="], + "gitbook-v2/next/@next/env": ["@next/env@15.4.0-canary.26", "", {}, "sha512-+WeMYRfTZWaosbIAjuNESPVjynDz/NKukoR7mF/u3Wuwr40KgScpxD0IuU0T7XbPfprnaInSKAylufFvrXRh+A=="], - "gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.4.0-canary.24", "", { "os": "darwin", "cpu": "arm64" }, "sha512-KZTWf+lKcn/xU3QmTSGzxeWpsKe2HVhkH9A8Q0ZSbu2GKulekqlgA3Er0IdOAIs76ici7GOtOQAt4k8xjpX85g=="], + "gitbook-v2/next/@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.4.0-canary.26", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HxtmV8Uoai8Z4wAU1tFWzASogAS+xVVP5Z5frbFu0yQ+1ocb9xQTjNqhiD5xPSAU8pNGWasCod8tlTCBzJzHQg=="], - "gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.4.0-canary.24", "", { "os": "darwin", "cpu": "x64" }, "sha512-QrSRUkggMA0kfYOxM5Xn5h3SBgI3Qbq+G1SmH71/VXz2NmG7HjrcyQPG4wYp6w7v3jhubSqPREzDjPNqtOxP1Q=="], + "gitbook-v2/next/@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.4.0-canary.26", "", { "os": "darwin", "cpu": "x64" }, "sha512-1MLiD1Bj6xSi5MkkQ8IK7A13KZJG9bzoWqdXT/tveVCinmYrl/zY7z/9dgvG+84gAE6uN4BGjp6f3IxRsvYDBA=="], - "gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.4.0-canary.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nsn3SmZzAjYS/n+ZDGvCxsrE7ngMTZu0h4vp+L7nBb6kPNzipnDpwqPTy2heCqlIVA7xPnMCYJ5UKaFHyYjecg=="], + "gitbook-v2/next/@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.4.0-canary.26", "", { "os": "linux", "cpu": "arm64" }, "sha512-cIVgFgOdMDbnPixR/u3ICW60/HlnDbACCb2O+p9+DJj7s1dsN63Cs9qxc9pDJb7tgL0BFPhYcmGeJfd/bZ4h7w=="], - "gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.4.0-canary.24", "", { "os": "linux", "cpu": "arm64" }, "sha512-SvQ7/Jx5ZqvVFMf3xpSKJg9azj0YOJpPdhR383NdOI9Eem5QLjnbWLEWqfc6p8hNkNzEpAuhEdf5bOWnMLFBxg=="], + "gitbook-v2/next/@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.4.0-canary.26", "", { "os": "linux", "cpu": "arm64" }, "sha512-o4YS6E3FD2DpZBDvUai9bPMLcpcNZ3THc2BzysSbZeARPiAQuKoudwPJoCpi2t7vajrvczpxBwTPG2uL05ypEA=="], - "gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.4.0-canary.24", "", { "os": "linux", "cpu": "x64" }, "sha512-nfngpiPavN+phfCnjeS0tqAo8DBtjHGHFnQB30mLZwvVQ6buiAn4BlSgh7hjApaDGNOlPDondC8t6yNDMuakUQ=="], + "gitbook-v2/next/@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.4.0-canary.26", "", { "os": "linux", "cpu": "x64" }, "sha512-M2/MFrQcPI7Ul5Fq5AOeoARrT0B9SrGiy7BLnPuE7Iai1+xkhfSsxIMF5JeDm/GfJnzcwA2oSvrOg0e7KKdaCA=="], - "gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.4.0-canary.24", "", { "os": "linux", "cpu": "x64" }, "sha512-7HLdl3cZq3uaBPK0es6GhSNIX9rI0b8YJ+AoETPM4LzTG5P/Wfbx+KY3dLlTfU3Ycf4DpwFxlmQeogsT/NYKzg=="], + "gitbook-v2/next/@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.4.0-canary.26", "", { "os": "linux", "cpu": "x64" }, "sha512-p5JpQ7k/1LyBzNZglqA8JJm7GRmadPkTyHoWaqMxhiVdcQHGbjwsiNjjAtMNjetNOXxj8ebxjiBsAt+34Ak1IQ=="], - "gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.4.0-canary.24", "", { "os": "win32", "cpu": "arm64" }, "sha512-dqHsTLd0kkh3BjpA+GBgqmkqCHq4HPtUXZPc25ti0fistb2pOy9oFG3r1sO8DoYY//gUI4hgacFt1snv2MsyYA=="], + "gitbook-v2/next/@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.4.0-canary.26", "", { "os": "win32", "cpu": "arm64" }, "sha512-FlXIBNOSwnGxxN+HekUfz4Y0n4gPGzqcY3wa3p+5JhzFT7r0oCxMxOdRbs7w8jF5b6uSkWVIQXWFL43F6+8J4g=="], - "gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.0-canary.24", "", { "os": "win32", "cpu": "x64" }, "sha512-HxldCCDWW1ytENYu+gNnXg6bRCsMYZs/cMW5uFgc3jXRl4DJ8vpPIjVmjATtatlMJvw4JwGaFdnEjwD8R2H6dA=="], + "gitbook-v2/next/@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.4.0-canary.26", "", { "os": "win32", "cpu": "x64" }, "sha512-h9CKrDiEeBof+8IgHStYATYrKVuUt8ggy6429kViWlDbuY6gkuIplf3IRlfpdWAB32I1e4qqUVl/s2xRMgQdqg=="], "gitbook-v2/next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], diff --git a/package.json b/package.json index 878054dcb2..447997ab82 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "packageManager": "bun@1.2.8", "overrides": { "@codemirror/state": "6.4.1", - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, diff --git a/packages/cache-tags/package.json b/packages/cache-tags/package.json index cd71ced292..8850dafbd6 100644 --- a/packages/cache-tags/package.json +++ b/packages/cache-tags/package.json @@ -10,7 +10,7 @@ }, "version": "0.3.1", "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "assert-never": "^1.2.1" }, "devDependencies": { diff --git a/packages/gitbook-v2/package.json b/packages/gitbook-v2/package.json index 64f4823ffb..f19b6951d8 100644 --- a/packages/gitbook-v2/package.json +++ b/packages/gitbook-v2/package.json @@ -3,7 +3,7 @@ "version": "0.2.5", "private": true, "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/cache-tags": "workspace:*", "@sindresorhus/fnv1a": "^3.1.0", "assert-never": "^1.2.1", diff --git a/packages/gitbook/package.json b/packages/gitbook/package.json index 800cb10d04..4294327546 100644 --- a/packages/gitbook/package.json +++ b/packages/gitbook/package.json @@ -16,7 +16,7 @@ "clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math" }, "dependencies": { - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/cache-do": "workspace:*", "@gitbook/cache-tags": "workspace:*", "@gitbook/colors": "workspace:*", diff --git a/packages/react-contentkit/package.json b/packages/react-contentkit/package.json index 522b4b0044..09e6cc8e7c 100644 --- a/packages/react-contentkit/package.json +++ b/packages/react-contentkit/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "classnames": "^2.5.1", - "@gitbook/api": "https://pkg.pr.new/GitbookIO/integrations/@gitbook/api@811", + "@gitbook/api": "^0.115.0", "@gitbook/icons": "workspace:*" }, "peerDependencies": { From b80ecaa0d1b18128c8bf6851977b06c057e93af1 Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 17:19:40 +0530 Subject: [PATCH 05/11] refactor --- packages/gitbook-v2/src/lib/data/lookup.ts | 41 ++++++++-------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/packages/gitbook-v2/src/lib/data/lookup.ts b/packages/gitbook-v2/src/lib/data/lookup.ts index feb3ef1725..ec8c52fff1 100644 --- a/packages/gitbook-v2/src/lib/data/lookup.ts +++ b/packages/gitbook-v2/src/lib/data/lookup.ts @@ -1,37 +1,25 @@ import { race, tryCatch } from '@/lib/async'; import { joinPath, joinPathWithBaseURL } from '@/lib/paths'; import { trace } from '@/lib/tracing'; -import type { HttpResponse, PublishedSiteContentLookup, SiteVisitorPayload } from '@gitbook/api'; +import type { GitBookAPI, PublishedSiteContentLookup, SiteVisitorPayload } from '@gitbook/api'; import { apiClient } from './api'; import { getExposableError } from './errors'; import type { DataFetcherResponse } from './types'; import { getURLLookupAlternatives, stripURLSearch } from './urls'; -interface LookupPublishedContentByUrlSharedInput { +interface LookupPublishedContentByUrlInput { url: string; redirectOnError: boolean; apiToken: string | null; } -interface FetchLookupAPIResultFnArgs { - url: string; - signal: AbortSignal; -} type FetchLookupAPIResponse = | { data?: undefined; error: Error; } | { - data: HttpResponse< - PublishedSiteContentLookup, - { - error: { - code: 404; - message: string; - }; - } - >; + data: Awaited>; error?: undefined; }; @@ -40,13 +28,12 @@ type FetchLookupAPIResponse = * To optimize caching, we try multiple lookup alternatives and return the first one that matches. */ export async function resolvePublishedContentByUrl( - input: LookupPublishedContentByUrlSharedInput & { visitorPayload: SiteVisitorPayload } + input: LookupPublishedContentByUrlInput & { visitorPayload: SiteVisitorPayload } ) { return lookupPublishedContentByUrl({ url: input.url, - fetchLookupAPIResult: async ({ url, signal }: FetchLookupAPIResultFnArgs) => { - const api = await apiClient({ apiToken: input.apiToken }); - + fetchLookupAPIResult: ({ url, signal }) => { + const api = apiClient({ apiToken: input.apiToken }); return trace( { operation: 'resolvePublishedContentByUrl', @@ -59,8 +46,6 @@ export async function resolvePublishedContentByUrl( url, ...(input.visitorPayload ? { visitor: input.visitorPayload } : {}), redirectOnError: input.redirectOnError, - // @ts-expect-error - cacheVersion is not a real query param - cacheVersion: 'v2', }, { signal } ) @@ -78,15 +63,14 @@ export async function resolvePublishedContentByUrl( * */ export async function getPublishedContentByURL( - input: LookupPublishedContentByUrlSharedInput & { + input: LookupPublishedContentByUrlInput & { visitorAuthToken: string | null; } ) { return lookupPublishedContentByUrl({ url: input.url, - fetchLookupAPIResult: async ({ url, signal }: FetchLookupAPIResultFnArgs) => { - const api = await apiClient({ apiToken: input.apiToken }); - + fetchLookupAPIResult: ({ url, signal }) => { + const api = apiClient({ apiToken: input.apiToken }); return trace( { operation: 'getPublishedContentByURL', @@ -111,8 +95,11 @@ export async function getPublishedContentByURL( } async function lookupPublishedContentByUrl(input: { - url: LookupPublishedContentByUrlSharedInput['url']; - fetchLookupAPIResult: (args: FetchLookupAPIResultFnArgs) => Promise; + url: string; + fetchLookupAPIResult: (args: { + url: string; + signal: AbortSignal; + }) => Promise; }): Promise> { const lookupURL = new URL(input.url); const url = stripURLSearch(lookupURL); From 9373490f6fb248922d842dbbd536cd38a0daa8ba Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 17:22:44 +0530 Subject: [PATCH 06/11] rename test --- packages/gitbook/src/lib/visitors.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gitbook/src/lib/visitors.test.ts b/packages/gitbook/src/lib/visitors.test.ts index c5ff586458..e48bec7292 100644 --- a/packages/gitbook/src/lib/visitors.test.ts +++ b/packages/gitbook/src/lib/visitors.test.ts @@ -160,7 +160,7 @@ function assertVisitorAuthCookieValue( throw new Error('Expected a VisitorAuthCookieValue'); } -describe('getVisitorPublicClaims', () => { +describe('getVisitorUnsignedClaims', () => { it('should merge claims from multiple public cookies', () => { const cookies = [ { From 8e002db88a00c4165c96f2c52fe449ae8f21d4e7 Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 17:28:44 +0530 Subject: [PATCH 07/11] use prefix --- packages/gitbook/src/lib/visitors.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/gitbook/src/lib/visitors.ts b/packages/gitbook/src/lib/visitors.ts index f9164d178a..c6a7aae986 100644 --- a/packages/gitbook/src/lib/visitors.ts +++ b/packages/gitbook/src/lib/visitors.ts @@ -4,11 +4,7 @@ import hash from 'object-hash'; const VISITOR_AUTH_PARAM = 'jwt_token'; export const VISITOR_TOKEN_COOKIE = 'gitbook-visitor-token'; -const VISITOR_UNSIGNED_CLAIM_COOKIES = [ - 'gitbook-visitor-public', - 'gitbook-visitor-public-bucket', - 'gitbook-visitor-public-launchdarkly', -]; +const VISITOR_UNSIGNED_CLAIMS_PREFIX = 'gitbook-visitor-public'; /** * Typing for a cookie, matching the internal type of Next.js. @@ -137,7 +133,7 @@ export function getVisitorUnsignedClaims(args: { const claims: Record = {}; for (const cookie of cookies) { - if (VISITOR_UNSIGNED_CLAIM_COOKIES.includes(cookie.name)) { + if (cookie.name.startsWith(VISITOR_UNSIGNED_CLAIMS_PREFIX)) { try { const parsed = JSON.parse(cookie.value); if (typeof parsed === 'object' && parsed !== null) { From 7df6ce222aa591141a4305a5b8f3d7236680322b Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 17:54:23 +0530 Subject: [PATCH 08/11] Use resolvePublishedContentByUrl --- packages/gitbook-v2/src/middleware.ts | 49 ++++++++++++++++++++------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index 36666b7706..f272b391b2 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -19,6 +19,7 @@ import { getPublishedContentByURL, getVisitorAuthBasePath, normalizeURL, + resolvePublishedContentByUrl, throwIfDataError, } from '@v2/lib/data'; import { isGitBookAssetsHostURL, isGitBookHostURL } from '@v2/lib/env'; @@ -33,6 +34,11 @@ export const config = { type URLWithMode = { url: URL; mode: 'url' | 'url-host' }; +/** + * Temporary list of hosts to test adaptive content using the new resolution API. + */ +const ADAPTIVE_CONTENT_HOSTS = ['docs.gitbook.com', 'adaptive-docs.gitbook-staging.com']; + export async function middleware(request: NextRequest) { try { const requestURL = new URL(request.url); @@ -85,25 +91,42 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) { // // Detect and extract the visitor authentication token from the request // - const { visitorToken } = getVisitorPayload({ + const { visitorToken, unsignedClaims } = getVisitorPayload({ cookies: request.cookies.getAll(), url: siteRequestURL, }); const withAPIToken = async (apiToken: string | null) => { + const isAdaptiveContentHost = ADAPTIVE_CONTENT_HOSTS.includes(siteRequestURL.hostname); const siteURLData = await throwIfDataError( - getPublishedContentByURL({ - url: siteRequestURL.toString(), - visitorAuthToken: visitorToken?.token ?? null, - // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow - // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. - // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. - redirectOnError: visitorToken?.source === 'visitor-auth-cookie', - - // Use the API token passed in the request, if any - // as it could be used for .preview hostnames - apiToken, - }) + isAdaptiveContentHost + ? resolvePublishedContentByUrl({ + url: siteRequestURL.toString(), + visitorPayload: { + jwtToken: visitorToken?.token ?? undefined, + unsignedClaims, + }, + // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow + // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. + // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. + redirectOnError: visitorToken?.source === 'visitor-auth-cookie', + + // Use the API token passed in the request, if any + // as it could be used for .preview hostnames + apiToken, + }) + : getPublishedContentByURL({ + url: siteRequestURL.toString(), + visitorAuthToken: visitorToken?.token ?? null, + // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow + // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. + // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. + redirectOnError: visitorToken?.source === 'visitor-auth-cookie', + + // Use the API token passed in the request, if any + // as it could be used for .preview hostnames + apiToken, + }) ); const cookies: ResponseCookies = []; From dc1d65f4c1d3e5949ecafa274b098a4f908940ae Mon Sep 17 00:00:00 2001 From: taranvohra Date: Thu, 8 May 2025 17:55:40 +0530 Subject: [PATCH 09/11] remove disallowed test --- packages/gitbook/src/lib/visitors.test.ts | 26 ----------------------- 1 file changed, 26 deletions(-) diff --git a/packages/gitbook/src/lib/visitors.test.ts b/packages/gitbook/src/lib/visitors.test.ts index e48bec7292..82060fcdfa 100644 --- a/packages/gitbook/src/lib/visitors.test.ts +++ b/packages/gitbook/src/lib/visitors.test.ts @@ -209,32 +209,6 @@ describe('getVisitorUnsignedClaims', () => { }); }); - it('should ignore public cookies not present in the allowed list', () => { - const url = new URL('https://example.com/'); - - const claims = getVisitorUnsignedClaims({ - cookies: [ - { - name: 'gitbook-visitor-public', - value: JSON.stringify({ role: 'admin', language: 'fr' }), - }, - // The claims in this cookie should be ignored - { - name: 'gitbook-visitor-public-disallowed', - value: JSON.stringify({ - disallowed: { flags: { SITE_AI: true, SITE_PREVIEW: true } }, - }), - }, - ], - url, - }); - - expect(claims).toStrictEqual({ - role: 'admin', - language: 'fr', - }); - }); - it('should support nested query param keys via dot notation', () => { const url = new URL( 'https://example.com/?visitor.isEnterprise=true&visitor.flags.ALPHA=true&visitor.flags.API=false' From 3a0b8fb36cb0e65f46748ea38ffaf7b9f804821e Mon Sep 17 00:00:00 2001 From: taranvohra Date: Fri, 9 May 2025 11:41:32 +0530 Subject: [PATCH 10/11] review --- packages/gitbook-v2/src/lib/data/lookup.ts | 27 ++++--------- packages/gitbook-v2/src/middleware.ts | 47 +++++++++------------- 2 files changed, 25 insertions(+), 49 deletions(-) diff --git a/packages/gitbook-v2/src/lib/data/lookup.ts b/packages/gitbook-v2/src/lib/data/lookup.ts index ec8c52fff1..4c999bd7a4 100644 --- a/packages/gitbook-v2/src/lib/data/lookup.ts +++ b/packages/gitbook-v2/src/lib/data/lookup.ts @@ -11,25 +11,14 @@ interface LookupPublishedContentByUrlInput { url: string; redirectOnError: boolean; apiToken: string | null; + visitorPayload: SiteVisitorPayload; } -type FetchLookupAPIResponse = - | { - data?: undefined; - error: Error; - } - | { - data: Awaited>; - error?: undefined; - }; - /** * Lookup a content by its URL using the GitBook resolvePublishedContentByUrl API endpoint. * To optimize caching, we try multiple lookup alternatives and return the first one that matches. */ -export async function resolvePublishedContentByUrl( - input: LookupPublishedContentByUrlInput & { visitorPayload: SiteVisitorPayload } -) { +export async function resolvePublishedContentByUrl(input: LookupPublishedContentByUrlInput) { return lookupPublishedContentByUrl({ url: input.url, fetchLookupAPIResult: ({ url, signal }) => { @@ -62,11 +51,7 @@ export async function resolvePublishedContentByUrl( * @deprecated use resolvePublishedContentByUrl. * */ -export async function getPublishedContentByURL( - input: LookupPublishedContentByUrlInput & { - visitorAuthToken: string | null; - } -) { +export async function getPublishedContentByURL(input: LookupPublishedContentByUrlInput) { return lookupPublishedContentByUrl({ url: input.url, fetchLookupAPIResult: ({ url, signal }) => { @@ -81,7 +66,7 @@ export async function getPublishedContentByURL( api.urls.getPublishedContentByUrl( { url, - visitorAuthToken: input.visitorAuthToken ?? undefined, + visitorAuthToken: input.visitorPayload.jwtToken ?? undefined, redirectOnError: input.redirectOnError, // @ts-expect-error - cacheVersion is not a real query param cacheVersion: 'v2', @@ -94,12 +79,14 @@ export async function getPublishedContentByURL( }); } +type TryCatch = ReturnType>; + async function lookupPublishedContentByUrl(input: { url: string; fetchLookupAPIResult: (args: { url: string; signal: AbortSignal; - }) => Promise; + }) => TryCatch>>; }): Promise> { const lookupURL = new URL(input.url); const url = stripURLSearch(lookupURL); diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index f272b391b2..14bfa45f29 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -97,36 +97,25 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) { }); const withAPIToken = async (apiToken: string | null) => { - const isAdaptiveContentHost = ADAPTIVE_CONTENT_HOSTS.includes(siteRequestURL.hostname); + const resolve = ADAPTIVE_CONTENT_HOSTS.includes(siteRequestURL.hostname) + ? resolvePublishedContentByUrl + : getPublishedContentByURL; const siteURLData = await throwIfDataError( - isAdaptiveContentHost - ? resolvePublishedContentByUrl({ - url: siteRequestURL.toString(), - visitorPayload: { - jwtToken: visitorToken?.token ?? undefined, - unsignedClaims, - }, - // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow - // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. - // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. - redirectOnError: visitorToken?.source === 'visitor-auth-cookie', - - // Use the API token passed in the request, if any - // as it could be used for .preview hostnames - apiToken, - }) - : getPublishedContentByURL({ - url: siteRequestURL.toString(), - visitorAuthToken: visitorToken?.token ?? null, - // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow - // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. - // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. - redirectOnError: visitorToken?.source === 'visitor-auth-cookie', - - // Use the API token passed in the request, if any - // as it could be used for .preview hostnames - apiToken, - }) + resolve({ + url: siteRequestURL.toString(), + visitorPayload: { + jwtToken: visitorToken?.token ?? undefined, + unsignedClaims, + }, + // When the visitor auth token is pulled from the cookie, set redirectOnError when calling getPublishedContentByUrl to allow + // redirecting when the token is invalid as we could be dealing with stale token stored in the cookie. + // For example when the VA backend signature has changed but the token stored in the cookie is not yet expired. + redirectOnError: visitorToken?.source === 'visitor-auth-cookie', + + // Use the API token passed in the request, if any + // as it could be used for .preview hostnames + apiToken, + }) ); const cookies: ResponseCookies = []; From 7ddb0b7ad25463ff90835898d6bdb5245d8a3c8b Mon Sep 17 00:00:00 2001 From: taranvohra Date: Fri, 9 May 2025 13:54:28 +0530 Subject: [PATCH 11/11] add another host --- packages/gitbook-v2/src/middleware.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/gitbook-v2/src/middleware.ts b/packages/gitbook-v2/src/middleware.ts index 14bfa45f29..5cb34052f8 100644 --- a/packages/gitbook-v2/src/middleware.ts +++ b/packages/gitbook-v2/src/middleware.ts @@ -37,7 +37,11 @@ type URLWithMode = { url: URL; mode: 'url' | 'url-host' }; /** * Temporary list of hosts to test adaptive content using the new resolution API. */ -const ADAPTIVE_CONTENT_HOSTS = ['docs.gitbook.com', 'adaptive-docs.gitbook-staging.com']; +const ADAPTIVE_CONTENT_HOSTS = [ + 'docs.gitbook.com', + 'adaptive-docs.gitbook-staging.com', + 'enriched-content-playground.gitbook-staging.io', +]; export async function middleware(request: NextRequest) { try {