From ff3ec5b4fa2e7095767e543d336dbaf498a2c541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 27 Feb 2025 09:06:48 +0100 Subject: [PATCH 1/3] Cache OpenAPI using next "use cache" for v2 --- packages/gitbook/src/lib/openapi/fetch.ts | 76 +++++++++++++------ packages/gitbook/src/lib/v2.ts | 9 ++- .../react-openapi/src/OpenAPICodeSample.tsx | 7 +- 3 files changed, 63 insertions(+), 29 deletions(-) diff --git a/packages/gitbook/src/lib/openapi/fetch.ts b/packages/gitbook/src/lib/openapi/fetch.ts index b26ce56136..4040bde4a5 100644 --- a/packages/gitbook/src/lib/openapi/fetch.ts +++ b/packages/gitbook/src/lib/openapi/fetch.ts @@ -6,6 +6,7 @@ import type { GitBookAnyContext } from '@v2/lib/context'; import { type CacheFunctionOptions, cache, noCacheFetchOptions } from '@/lib/cache'; import { resolveContentRef } from '../references'; +import { isV2 } from '../v2'; import { enrichFilesystem } from './enrich'; const weakmap = new WeakMap(); @@ -65,32 +66,18 @@ async function baseResolveOpenAPIBlock(args: ResolveOpenAPIBlockArgs): ResolveOp } } -const fetchFilesystem = cache({ - name: 'openapi.fetch.v6', - get: async (url: string, options: CacheFunctionOptions) => { - // Wrap the raw string to prevent invalid URLs from being passed to fetch. - // This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch: - // https://github.com/cloudflare/workerd/issues/1957 - const response = await fetch(new URL(url), { - ...noCacheFetchOptions, - signal: options.signal, - }); +async function fetchFilesystem(url: string) { + if (isV2()) { + return await fetchFilesystemV2(url); + } - if (!response.ok) { - throw new Error( - `Failed to fetch OpenAPI file: ${response.status} ${response.statusText}` - ); - } + return await fetchFilesystemV1(url); +} - const text = await response.text(); - const filesystem = await parseOpenAPI({ - value: text, - rootURL: url, - // If we fetch the OpenAPI specification - // it's the legacy system, it means the spec can be trusted here. - trust: true, - }); - const richFilesystem = await enrichFilesystem(filesystem); +const fetchFilesystemV1 = cache({ + name: 'openapi.fetch.v6', + get: async (url: string, options: CacheFunctionOptions) => { + const richFilesystem = await fetchFilesystemUncached(url, options); return { // Cache for 4 hours ttl: 24 * 60 * 60, @@ -100,3 +87,44 @@ const fetchFilesystem = cache({ }; }, }); + +async function fetchFilesystemV2(url: string) { + 'use cache'; + + // TODO: add cache lifetime once we can use next.js 15 code here + + const response = await fetchFilesystemUncached(url); + + return response; +} + +async function fetchFilesystemUncached( + url: string, + options?: { + signal?: AbortSignal; + } +) { + // Wrap the raw string to prevent invalid URLs from being passed to fetch. + // This can happen if the URL has whitespace, which is currently handled differently by Cloudflare's implementation of fetch: + // https://github.com/cloudflare/workerd/issues/1957 + const response = await fetch(new URL(url), { + ...noCacheFetchOptions, + signal: options?.signal, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch OpenAPI file: ${response.status} ${response.statusText}`); + } + + const text = await response.text(); + const filesystem = await parseOpenAPI({ + value: text, + rootURL: url, + // If we fetch the OpenAPI specification + // it's the legacy system, it means the spec can be trusted here. + trust: true, + }); + const richFilesystem = await enrichFilesystem(filesystem); + + return richFilesystem; +} diff --git a/packages/gitbook/src/lib/v2.ts b/packages/gitbook/src/lib/v2.ts index 158c5d1c59..0d4c9db6d0 100644 --- a/packages/gitbook/src/lib/v2.ts +++ b/packages/gitbook/src/lib/v2.ts @@ -1,8 +1,15 @@ +/** + * Check if the code is running in v2. + */ +export function isV2() { + return process.env.GITBOOK_V2 === 'true'; +} + /** * Assert that the code is not running in v2. */ export function assertIsNotV2() { - if (process.env.GITBOOK_V2 === 'true') { + if (isV2()) { throw new Error('This code is not available in V2'); } } diff --git a/packages/react-openapi/src/OpenAPICodeSample.tsx b/packages/react-openapi/src/OpenAPICodeSample.tsx index fd37fb3a70..8cfba1716c 100644 --- a/packages/react-openapi/src/OpenAPICodeSample.tsx +++ b/packages/react-openapi/src/OpenAPICodeSample.tsx @@ -5,8 +5,7 @@ import { generateMediaTypeExample, generateSchemaExample } from './generateSchem import { stringifyOpenAPI } from './stringifyOpenAPI'; import type { OpenAPIContextProps, OpenAPIOperationData } from './types'; import { getDefaultServerURL } from './util/server'; -import { createStateKey } from './utils'; -import { checkIsReference } from './utils'; +import { checkIsReference, createStateKey } from './utils'; /** * Display code samples to execute the operation. @@ -95,8 +94,8 @@ export function OpenAPICodeSample(props: { typeof sample.lang === 'string' ); }) - .map((sample) => ({ - key: `redocly-${sample.lang}`, + .map((sample, index) => ({ + key: `redocly-${sample.lang}-${index}`, label: sample.label, body: context.renderCodeBlock({ code: sample.source, From 1e62d599eb665777d6d20377e4f4c0a8670db75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 27 Feb 2025 09:24:04 +0100 Subject: [PATCH 2/3] Disable the vercel toolbar for e2e tests --- packages/gitbook/e2e/util.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/gitbook/e2e/util.ts b/packages/gitbook/e2e/util.ts index 39483d2523..832b43e33a 100644 --- a/packages/gitbook/e2e/util.ts +++ b/packages/gitbook/e2e/util.ts @@ -154,6 +154,12 @@ export function runTestCases(testCases: TestsCase[]) { })) ); } + + // Disable the Vercel toolbar + await page.setExtraHTTPHeaders({ + 'x-vercel-skip-toolbar': '1', + }); + await page.goto(url); if (testEntry.run) { await testEntry.run(page); From b3faa3f8c28e6999c90efeca9c2313afe345f5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 27 Feb 2025 09:27:19 +0100 Subject: [PATCH 3/3] Review --- packages/gitbook/src/lib/openapi/fetch.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gitbook/src/lib/openapi/fetch.ts b/packages/gitbook/src/lib/openapi/fetch.ts index 4040bde4a5..ab78653af9 100644 --- a/packages/gitbook/src/lib/openapi/fetch.ts +++ b/packages/gitbook/src/lib/openapi/fetch.ts @@ -66,12 +66,12 @@ async function baseResolveOpenAPIBlock(args: ResolveOpenAPIBlockArgs): ResolveOp } } -async function fetchFilesystem(url: string) { +function fetchFilesystem(url: string) { if (isV2()) { - return await fetchFilesystemV2(url); + return fetchFilesystemV2(url); } - return await fetchFilesystemV1(url); + return fetchFilesystemV1(url); } const fetchFilesystemV1 = cache({