Skip to content

Commit fecdbe8

Browse files
authored
Support dynamic expressions (#3295)
1 parent 9316ccd commit fecdbe8

File tree

12 files changed

+168
-11
lines changed

12 files changed

+168
-11
lines changed

packages/gitbook-v2/src/lib/data/api.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ export function createDataFetcher(
113113
})
114114
);
115115
},
116+
getRevisionPageDocument(params) {
117+
return trace('getRevisionPageDocument', () =>
118+
getRevisionPageDocument(input, {
119+
spaceId: params.spaceId,
120+
revisionId: params.revisionId,
121+
pageId: params.pageId,
122+
})
123+
);
124+
},
116125
getReusableContent(params) {
117126
return trace('getReusableContent', () =>
118127
getReusableContent(input, {
@@ -417,6 +426,42 @@ const getRevisionPageMarkdown = withCacheKey(
417426
)
418427
);
419428

429+
const getRevisionPageDocument = withCacheKey(
430+
withoutConcurrentExecution(
431+
async (
432+
_,
433+
input: DataFetcherInput,
434+
params: { spaceId: string; revisionId: string; pageId: string }
435+
) => {
436+
'use cache';
437+
return trace(
438+
`getRevisionPageDocument(${params.spaceId}, ${params.revisionId}, ${params.pageId})`,
439+
async () => {
440+
return wrapDataFetcherError(async () => {
441+
const api = apiClient(input);
442+
const res = await api.spaces.getPageDocumentInRevisionById(
443+
params.spaceId,
444+
params.revisionId,
445+
params.pageId,
446+
{
447+
evaluated: true,
448+
},
449+
{
450+
...noCacheFetchOptions,
451+
}
452+
);
453+
454+
cacheTag(...getCacheTagsFromResponse(res));
455+
cacheLife('max');
456+
457+
return res.data;
458+
});
459+
}
460+
);
461+
}
462+
)
463+
);
464+
420465
const getRevisionPageByPath = withCacheKey(
421466
withoutConcurrentExecution(
422467
async (
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export * from './api';
22
export * from './types';
3-
export * from './pages';
43
export * from './urls';
54
export * from './errors';
65
export * from './lookup';
76
export * from './visitor';
7+
export * from './pages';

packages/gitbook-v2/src/lib/data/pages.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
import type { JSONDocument, RevisionPageDocument, Space } from '@gitbook/api';
1+
import { waitUntil } from '@/lib/waitUntil';
2+
import type { JSONDocument, RevisionPageDocument } from '@gitbook/api';
3+
import type { GitBookSiteContext, GitBookSpaceContext } from '../context';
24
import { getDataOrNull } from './errors';
3-
import type { GitBookDataFetcher } from './types';
45

56
/**
67
* Get the document for a page.
78
*/
89
export async function getPageDocument(
9-
dataFetcher: GitBookDataFetcher,
10-
space: Space,
10+
context: GitBookSpaceContext | GitBookSiteContext,
1111
page: RevisionPageDocument
1212
): Promise<JSONDocument | null> {
13+
const { dataFetcher, space } = context;
14+
15+
if (
16+
'site' in context &&
17+
(context.site.id === 'site_JOVzv' || context.site.id === 'site_IxAYj')
18+
) {
19+
return getDataOrNull(
20+
dataFetcher.getRevisionPageDocument({
21+
spaceId: space.id,
22+
revisionId: space.revision,
23+
pageId: page.id,
24+
})
25+
);
26+
}
27+
1328
if (page.documentId) {
1429
return getDataOrNull(
1530
dataFetcher.getDocument({ spaceId: space.id, documentId: page.documentId })
@@ -26,5 +41,30 @@ export async function getPageDocument(
2641
);
2742
}
2843

44+
// Pre-fetch the document to start filling the cache before we migrate to this API.
45+
if (isInPercentRollout(space.id, 10)) {
46+
await waitUntil(
47+
getDataOrNull(
48+
dataFetcher.getRevisionPageDocument({
49+
spaceId: space.id,
50+
revisionId: space.revision,
51+
pageId: page.id,
52+
})
53+
)
54+
);
55+
}
56+
2957
return null;
3058
}
59+
60+
function isInPercentRollout(value: string, rollout: number) {
61+
return getRandomPercent(value) < rollout;
62+
}
63+
64+
function getRandomPercent(value: string) {
65+
const hash = value.split('').reduce((acc, char) => {
66+
return acc + char.charCodeAt(0);
67+
}, 0);
68+
69+
return hash % 100;
70+
}

packages/gitbook-v2/src/lib/data/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ export interface GitBookDataFetcher {
106106
pageId: string;
107107
}): Promise<DataFetcherResponse<string>>;
108108

109+
/**
110+
* Get the document of a page by its path.
111+
*/
112+
getRevisionPageDocument(params: {
113+
spaceId: string;
114+
revisionId: string;
115+
pageId: string;
116+
}): Promise<DataFetcherResponse<api.JSONDocument>>;
117+
109118
/**
110119
* Get a document by its space ID and document ID.
111120
*/

packages/gitbook/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"typecheck": "tsc --noEmit",
1111
"e2e": "playwright test e2e/internal.spec.ts",
1212
"e2e-customers": "playwright test e2e/customers.spec.ts",
13-
"unit": "bun test {src,packages}",
13+
"unit": "bun test {src,packages} --preload ./tests/preload-bun.ts",
1414
"generate": "gitbook-icons ./public/~gitbook/static/icons custom-icons && gitbook-math ./public/~gitbook/static/math",
1515
"copy:icons": "gitbook-icons ./public/~gitbook/static/icons",
1616
"clean": "rm -rf ./.next && rm -rf ./public/~gitbook/static/icons && rm -rf ./public/~gitbook/static/math"

packages/gitbook/src/components/PDF/PDFPage.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
} from '@gitbook/api';
1010
import { Icon } from '@gitbook/icons';
1111
import type { GitBookSiteContext, GitBookSpaceContext } from '@v2/lib/context';
12-
import { getPageDocument } from '@v2/lib/data';
1312
import type { GitBookLinker } from '@v2/lib/links';
1413
import type { Metadata } from 'next';
1514
import { notFound } from 'next/navigation';
@@ -29,6 +28,7 @@ import { PageControlButtons } from './PageControlButtons';
2928
import { PrintButton } from './PrintButton';
3029
import './pdf.css';
3130
import { sanitizeGitBookAppURL } from '@/lib/app';
31+
import { getPageDocument } from '@v2/lib/data';
3232

3333
const DEFAULT_LIMIT = 100;
3434

@@ -224,8 +224,7 @@ async function PDFPageDocument(props: {
224224
context: GitBookSpaceContext;
225225
}) {
226226
const { page, context } = props;
227-
const { space } = context;
228-
const document = await getPageDocument(context.dataFetcher, space, page);
227+
const document = await getPageDocument(context, page);
229228

230229
return (
231230
<PrintPage id={getPagePDFContainerId(page)}>

packages/gitbook/src/components/SitePage/SitePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export async function SitePage(props: SitePageProps) {
6262
const withSections = Boolean(sections && sections.list.length > 0);
6363
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
6464

65-
const document = await getPageDocument(context.dataFetcher, context.space, page);
65+
const document = await getPageDocument(context, page);
6666

6767
return (
6868
<PageContextProvider pageId={page.id} spaceId={context.space.id} title={page.title}>

packages/gitbook/src/lib/api.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,39 @@ export const getRevisionPageByPath = cache({
493493
},
494494
});
495495

496+
/**
497+
* Get a document from a page by its ID
498+
*/
499+
export const getRevisionPageDocument = cache({
500+
name: 'api.getRevisionPageDocument.v1',
501+
tag: (spaceId, revisionId) =>
502+
getCacheTag({ tag: 'revision', space: spaceId, revision: revisionId }),
503+
tagImmutable: true,
504+
getKeySuffix: getAPIContextId,
505+
get: async (
506+
spaceId: string,
507+
revisionId: string,
508+
pageId: string,
509+
options: CacheFunctionOptions
510+
) => {
511+
const apiCtx = await api();
512+
const response = await apiCtx.client.spaces.getPageDocumentInRevisionById(
513+
spaceId,
514+
revisionId,
515+
pageId,
516+
{
517+
evaluated: true,
518+
},
519+
{
520+
...noCacheFetchOptions,
521+
signal: options.signal,
522+
}
523+
);
524+
525+
return cacheResponse(response, cacheTtl_7days);
526+
},
527+
});
528+
496529
/**
497530
* Resolve a file by its ID.
498531
* It should not be used directly, use `getRevisionFile` instead.

packages/gitbook/src/lib/references.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export async function resolveContentRef(
155155
});
156156

157157
if (resolveAnchorText) {
158-
const document = await getPageDocument(dataFetcher, space, page);
158+
const document = await getPageDocument(context, page);
159159
if (document) {
160160
const block = getBlockById(document, anchor);
161161
if (block) {

packages/gitbook/src/lib/v1.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
getRevision,
2626
getRevisionFile,
2727
getRevisionPageByPath,
28+
getRevisionPageDocument,
2829
getRevisionPages,
2930
getSiteRedirectBySource,
3031
getSpace,
@@ -241,6 +242,18 @@ function getDataFetcherV1(apiTokenOverride?: string): GitBookDataFetcher {
241242
);
242243
},
243244

245+
getRevisionPageDocument(params) {
246+
return withAPI(() =>
247+
wrapDataFetcherError(async () => {
248+
return getRevisionPageDocument(
249+
params.spaceId,
250+
params.revisionId,
251+
params.pageId
252+
);
253+
})
254+
);
255+
},
256+
244257
getRevisionPageByPath(params) {
245258
return withAPI(() =>
246259
wrapDataFetcherError(async () => {

packages/gitbook/src/lib/waitUntil.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import type { ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';
2+
import { getCloudflareContext as getCloudflareContextV2 } from '@v2/lib/data/cloudflare';
3+
import { isV2 } from './v2';
24

35
let pendings: Array<Promise<unknown>> = [];
46

@@ -47,6 +49,14 @@ export async function waitUntil(promise: Promise<unknown>) {
4749
return;
4850
}
4951

52+
if (isV2()) {
53+
const context = getCloudflareContextV2();
54+
if (context) {
55+
context.ctx.waitUntil(promise);
56+
return;
57+
}
58+
}
59+
5060
const cloudflareContext = await getGlobalContext();
5161
if ('waitUntil' in cloudflareContext) {
5262
cloudflareContext.waitUntil(promise);

packages/gitbook/tests/preload-bun.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { mock } from 'bun:test';
2+
3+
/**
4+
* Mock the `server-only` module to avoid errors when running tests as it doesn't work well in Bun
5+
*/
6+
mock.module('server-only', () => {
7+
return {};
8+
});

0 commit comments

Comments
 (0)