@@ -87,14 +87,30 @@ const cacheTtl_1day = {
87
87
ttl : 24 * 60 * 60 ,
88
88
} ;
89
89
90
- const apiSyncStorage = new AsyncLocalStorage < GitBookAPI > ( ) ;
90
+ export type GitBookAPIContext = {
91
+ /**
92
+ * Instance of the GitBook API client.
93
+ */
94
+ client : GitBookAPI ;
95
+
96
+ /**
97
+ * Context ID representing a hash of the visitor's attributes/assertions that are
98
+ * included in the claims property of the content API JWT token.
99
+ *
100
+ * It serves as a suffix for the cache key to ensure that the content cache is invalidated
101
+ * when these attributees/assertions change.
102
+ */
103
+ contextId : string | undefined ;
104
+ } ;
105
+
106
+ const apiSyncStorage = new AsyncLocalStorage < GitBookAPIContext > ( ) ;
91
107
92
108
export const DEFAULT_API_ENDPOINT = process . env . GITBOOK_API_URL ?? 'https://api.gitbook.com' ;
93
109
94
110
/**
95
111
* Create a new API client with a token.
96
112
*/
97
- export function apiWithToken ( apiToken : string ) : GitBookAPI {
113
+ export function apiWithToken ( apiToken : string , contextId : string | undefined ) : GitBookAPIContext {
98
114
const headersList = headers ( ) ;
99
115
const apiEndpoint = headersList . get ( 'x-gitbook-api' ) ?? DEFAULT_API_ENDPOINT ;
100
116
@@ -104,34 +120,35 @@ export function apiWithToken(apiToken: string): GitBookAPI {
104
120
userAgent : userAgent ( ) ,
105
121
} ) ;
106
122
107
- return gitbook ;
123
+ return { client : gitbook , contextId } ;
108
124
}
109
125
110
126
/**
111
127
* Create an API client for the current request.
112
128
*/
113
- export function api ( ) : GitBookAPI {
129
+ export function api ( ) : GitBookAPIContext {
114
130
const existing = apiSyncStorage . getStore ( ) ;
115
131
if ( existing ) {
116
132
return existing ;
117
133
}
118
134
119
135
const headersList = headers ( ) ;
120
136
const apiToken = headersList . get ( 'x-gitbook-token' ) ;
137
+ const contextId = headersList . get ( 'x-gitbook-token-context' ) ?? undefined ;
121
138
122
139
if ( ! apiToken ) {
123
140
throw new Error (
124
141
'Missing GitBook API token, please check that the request is correctly processed by the middleware' ,
125
142
) ;
126
143
}
127
144
128
- return apiWithToken ( apiToken ) ;
145
+ return apiWithToken ( apiToken , contextId ) ;
129
146
}
130
147
131
148
/**
132
149
* Use an API client for an async function.
133
150
*/
134
- export function withAPI < T > ( client : GitBookAPI , fn : ( ) => Promise < T > ) : Promise < T > {
151
+ export function withAPI < T > ( client : GitBookAPIContext , fn : ( ) => Promise < T > ) : Promise < T > {
135
152
return apiSyncStorage . run ( client , fn ) ;
136
153
}
137
154
@@ -164,7 +181,7 @@ export const getUserById = cache({
164
181
} ) ,
165
182
get : async ( userId : string , options : CacheFunctionOptions ) => {
166
183
try {
167
- const response = await api ( ) . users . getUserById ( userId , {
184
+ const response = await api ( ) . client . users . getUserById ( userId , {
168
185
signal : options . signal ,
169
186
...noCacheFetchOptions ,
170
187
} ) ;
@@ -200,7 +217,7 @@ export const getPublishedContentByUrl = cache({
200
217
options : CacheFunctionOptions ,
201
218
) => {
202
219
try {
203
- const response = await api ( ) . urls . getPublishedContentByUrl (
220
+ const response = await api ( ) . client . urls . getPublishedContentByUrl (
204
221
{
205
222
url,
206
223
visitorAuthToken,
@@ -249,7 +266,7 @@ export const getSpace = cache({
249
266
name : 'api.getSpace' ,
250
267
tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
251
268
get : async ( spaceId : string , shareKey : string | undefined , options : CacheFunctionOptions ) => {
252
- const response = await api ( ) . spaces . getSpaceById (
269
+ const response = await api ( ) . client . spaces . getSpaceById (
253
270
spaceId ,
254
271
{
255
272
shareKey,
@@ -273,7 +290,7 @@ export const getChangeRequest = cache({
273
290
tag : ( spaceId , changeRequestId ) =>
274
291
getAPICacheTag ( { tag : 'change-request' , space : spaceId , changeRequest : changeRequestId } ) ,
275
292
get : async ( spaceId : string , changeRequestId : string , options : CacheFunctionOptions ) => {
276
- const response = await api ( ) . spaces . getChangeRequestById ( spaceId , changeRequestId , {
293
+ const response = await api ( ) . client . spaces . getChangeRequestById ( spaceId , changeRequestId , {
277
294
...noCacheFetchOptions ,
278
295
signal : options . signal ,
279
296
} ) ;
@@ -301,13 +318,14 @@ export const getRevision = cache({
301
318
name : 'api.getRevision.v2' ,
302
319
tag : ( spaceId , revisionId ) =>
303
320
getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
321
+ getKeySuffix : ( ) => api ( ) . contextId ,
304
322
get : async (
305
323
spaceId : string ,
306
324
revisionId : string ,
307
325
fetchOptions : GetRevisionOptions ,
308
326
options : CacheFunctionOptions ,
309
327
) => {
310
- const response = await api ( ) . spaces . getRevisionById (
328
+ const response = await api ( ) . client . spaces . getRevisionById (
311
329
spaceId ,
312
330
revisionId ,
313
331
{
@@ -331,13 +349,14 @@ export const getRevisionPages = cache({
331
349
name : 'api.getRevisionPages.v4' ,
332
350
tag : ( spaceId , revisionId ) =>
333
351
getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
352
+ getKeySuffix : ( ) => api ( ) . contextId ,
334
353
get : async (
335
354
spaceId : string ,
336
355
revisionId : string ,
337
356
fetchOptions : GetRevisionOptions ,
338
357
options : CacheFunctionOptions ,
339
358
) => {
340
- const response = await api ( ) . spaces . listPagesInRevisionById (
359
+ const response = await api ( ) . client . spaces . listPagesInRevisionById (
341
360
spaceId ,
342
361
revisionId ,
343
362
{
@@ -364,6 +383,7 @@ export const getRevisionPageByPath = cache({
364
383
name : 'api.getRevisionPageByPath.v3' ,
365
384
tag : ( spaceId , revisionId ) =>
366
385
getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
386
+ getKeySuffix : ( ) => api ( ) . contextId ,
367
387
get : async (
368
388
spaceId : string ,
369
389
revisionId : string ,
@@ -373,7 +393,7 @@ export const getRevisionPageByPath = cache({
373
393
const encodedPath = encodeURIComponent ( pagePath ) ;
374
394
375
395
try {
376
- const response = await api ( ) . spaces . getPageInRevisionByPath (
396
+ const response = await api ( ) . client . spaces . getPageInRevisionByPath (
377
397
spaceId ,
378
398
revisionId ,
379
399
encodedPath ,
@@ -416,7 +436,7 @@ const getRevisionFileById = cache({
416
436
) => {
417
437
try {
418
438
const response = await ( async ( ) => {
419
- return api ( ) . spaces . getFileInRevisionById (
439
+ return api ( ) . client . spaces . getFileInRevisionById (
420
440
spaceId ,
421
441
revisionId ,
422
442
fileId ,
@@ -445,6 +465,7 @@ const getRevisionReusableContentById = cache({
445
465
name : 'api.getRevisionReusableContentById.v1' ,
446
466
tag : ( spaceId , revisionId ) =>
447
467
getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
468
+ getKeySuffix : ( ) => api ( ) . contextId ,
448
469
get : async (
449
470
spaceId : string ,
450
471
revisionId : string ,
@@ -453,7 +474,7 @@ const getRevisionReusableContentById = cache({
453
474
) => {
454
475
try {
455
476
const response = await ( async ( ) => {
456
- return api ( ) . spaces . getReusableContentInRevisionById (
477
+ return api ( ) . client . spaces . getReusableContentInRevisionById (
457
478
spaceId ,
458
479
revisionId ,
459
480
reusableContentId ,
@@ -489,7 +510,7 @@ const getRevisionAllFiles = cache({
489
510
get : async ( spaceId : string , revisionId : string , options : CacheFunctionOptions ) => {
490
511
const response = await getAll (
491
512
( params ) =>
492
- api ( ) . spaces . listFilesInRevisionById (
513
+ api ( ) . client . spaces . listFilesInRevisionById (
493
514
spaceId ,
494
515
revisionId ,
495
516
{
@@ -600,8 +621,9 @@ export const getDocument = cache({
600
621
name : 'api.getDocument.v2' ,
601
622
tag : ( spaceId , documentId ) =>
602
623
getAPICacheTag ( { tag : 'document' , space : spaceId , document : documentId } ) ,
624
+ getKeySuffix : ( ) => api ( ) . contextId ,
603
625
get : async ( spaceId : string , documentId : string , options : CacheFunctionOptions ) => {
604
- const response = await api ( ) . spaces . getDocumentById (
626
+ const response = await api ( ) . client . spaces . getDocumentById (
605
627
spaceId ,
606
628
documentId ,
607
629
{
@@ -626,6 +648,7 @@ export const getDocument = cache({
626
648
export const getSiteRedirectBySource = cache ( {
627
649
name : 'api.getSiteRedirectBySource' ,
628
650
tag : ( { siteId } ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
651
+ getKeySuffix : ( ) => api ( ) . contextId ,
629
652
get : async (
630
653
args : {
631
654
organizationId : string ;
@@ -637,7 +660,7 @@ export const getSiteRedirectBySource = cache({
637
660
options : CacheFunctionOptions ,
638
661
) => {
639
662
try {
640
- const response = await api ( ) . orgs . getSiteRedirectBySource (
663
+ const response = await api ( ) . client . orgs . getSiteRedirectBySource (
641
664
args . organizationId ,
642
665
args . siteId ,
643
666
{
@@ -669,8 +692,9 @@ export const getSiteRedirectBySource = cache({
669
692
export const getSite = cache ( {
670
693
name : 'api.getSite' ,
671
694
tag : ( organizationId , siteId ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
695
+ getKeySuffix : ( ) => api ( ) . contextId ,
672
696
get : async ( organizationId : string , siteId : string , options : CacheFunctionOptions ) => {
673
- const response = await api ( ) . orgs . getSiteById ( organizationId , siteId , {
697
+ const response = await api ( ) . client . orgs . getSiteById ( organizationId , siteId , {
674
698
...noCacheFetchOptions ,
675
699
signal : options . signal ,
676
700
} ) ;
@@ -686,6 +710,7 @@ export const getSite = cache({
686
710
export const getPublishedContentSite = cache ( {
687
711
name : 'api.getPublishedContentSite' ,
688
712
tag : ( { siteId } ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
713
+ getKeySuffix : ( ) => api ( ) . contextId ,
689
714
get : async (
690
715
args : {
691
716
organizationId : string ;
@@ -694,7 +719,7 @@ export const getPublishedContentSite = cache({
694
719
} ,
695
720
options : CacheFunctionOptions ,
696
721
) => {
697
- const response = await api ( ) . orgs . getPublishedContentSite (
722
+ const response = await api ( ) . client . orgs . getPublishedContentSite (
698
723
args . organizationId ,
699
724
args . siteId ,
700
725
{
@@ -826,7 +851,7 @@ export const getCollection = cache({
826
851
name : 'api.getCollection' ,
827
852
tag : ( collectionId ) => getAPICacheTag ( { tag : 'collection' , collection : collectionId } ) ,
828
853
get : async ( collectionId : string , options : CacheFunctionOptions ) => {
829
- const response = await api ( ) . collections . getCollectionById ( collectionId , {
854
+ const response = await api ( ) . client . collections . getCollectionById ( collectionId , {
830
855
...noCacheFetchOptions ,
831
856
signal : options . signal ,
832
857
} ) ;
@@ -844,7 +869,7 @@ export const getCollectionSpaces = cache({
844
869
tag : ( collectionId ) => getAPICacheTag ( { tag : 'collection' , collection : collectionId } ) ,
845
870
get : async ( collectionId : string , options : CacheFunctionOptions ) => {
846
871
const response = await getAll ( ( params ) =>
847
- api ( ) . collections . listSpacesInCollectionById ( collectionId , params , {
872
+ api ( ) . client . collections . listSpacesInCollectionById ( collectionId , params , {
848
873
...noCacheFetchOptions ,
849
874
signal : options . signal ,
850
875
} ) ,
@@ -896,14 +921,15 @@ export async function getSpaceContentData(
896
921
export const searchSpaceContent = cache ( {
897
922
name : 'api.searchSpaceContent' ,
898
923
tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
924
+ getKeySuffix : ( ) => api ( ) . contextId ,
899
925
get : async (
900
926
spaceId : string ,
901
927
/** The revision ID is used as a cache bust key, to avoid revalidating lot of cache entries by tags */
902
928
revisionId : string ,
903
929
query : string ,
904
930
options : CacheFunctionOptions ,
905
931
) => {
906
- const response = await api ( ) . spaces . searchSpaceContent (
932
+ const response = await api ( ) . client . spaces . searchSpaceContent (
907
933
spaceId ,
908
934
{ query } ,
909
935
{
@@ -921,8 +947,9 @@ export const searchSpaceContent = cache({
921
947
export const searchParentContent = cache ( {
922
948
name : 'api.searchParentContent' ,
923
949
tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
950
+ getKeySuffix : ( ) => api ( ) . contextId ,
924
951
get : async ( parentId : string , query : string , options : CacheFunctionOptions ) => {
925
- const response = await api ( ) . search . searchContent (
952
+ const response = await api ( ) . client . search . searchContent (
926
953
{ query } ,
927
954
{
928
955
...noCacheFetchOptions ,
@@ -941,6 +968,7 @@ export const searchParentContent = cache({
941
968
export const searchSiteContent = cache ( {
942
969
name : 'api.searchSiteContent' ,
943
970
tag : ( organizationId , siteId ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
971
+ getKeySuffix : ( ) => api ( ) . contextId ,
944
972
get : async (
945
973
organizationId : string ,
946
974
siteId : string ,
@@ -953,7 +981,7 @@ export const searchSiteContent = cache({
953
981
cacheBust ?: string ,
954
982
options ?: CacheFunctionOptions ,
955
983
) => {
956
- const response = await api ( ) . orgs . searchSiteContent (
984
+ const response = await api ( ) . client . orgs . searchSiteContent (
957
985
organizationId ,
958
986
siteId ,
959
987
{
@@ -980,7 +1008,7 @@ export const getRecommendedQuestionsInSpace = cache({
980
1008
name : 'api.getRecommendedQuestionsInSpace' ,
981
1009
tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
982
1010
get : async ( spaceId : string , options : CacheFunctionOptions ) => {
983
- const response = await api ( ) . spaces . getRecommendedQuestionsInSpace ( spaceId , {
1011
+ const response = await api ( ) . client . spaces . getRecommendedQuestionsInSpace ( spaceId , {
984
1012
...noCacheFetchOptions ,
985
1013
signal : options . signal ,
986
1014
} ) ;
@@ -999,7 +1027,7 @@ export const renderIntegrationUi = cache({
999
1027
request : RequestRenderIntegrationUI ,
1000
1028
options : CacheFunctionOptions ,
1001
1029
) => {
1002
- const response = await api ( ) . integrations . renderIntegrationUiWithPost (
1030
+ const response = await api ( ) . client . integrations . renderIntegrationUiWithPost (
1003
1031
integrationName ,
1004
1032
request ,
1005
1033
{
@@ -1018,7 +1046,7 @@ export const renderIntegrationUi = cache({
1018
1046
export const getEmbedByUrl = cache ( {
1019
1047
name : 'api.getEmbedByUrl' ,
1020
1048
get : async ( url : string , options : CacheFunctionOptions ) => {
1021
- const response = await api ( ) . urls . getEmbedByUrl (
1049
+ const response = await api ( ) . client . urls . getEmbedByUrl (
1022
1050
{ url } ,
1023
1051
{
1024
1052
...noCacheFetchOptions ,
@@ -1036,7 +1064,7 @@ export const getEmbedByUrlInSpace = cache({
1036
1064
name : 'api.getEmbedByUrlInSpace' ,
1037
1065
tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
1038
1066
get : async ( spaceId : string , url : string , options : CacheFunctionOptions ) => {
1039
- const response = await api ( ) . spaces . getEmbedByUrlInSpace (
1067
+ const response = await api ( ) . client . spaces . getEmbedByUrlInSpace (
1040
1068
spaceId ,
1041
1069
{ url } ,
1042
1070
{
0 commit comments