@@ -87,14 +87,30 @@ const cacheTtl_1day = {
8787 ttl : 24 * 60 * 60 ,
8888} ;
8989
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 > ( ) ;
91107
92108export const DEFAULT_API_ENDPOINT = process . env . GITBOOK_API_URL ?? 'https://api.gitbook.com' ;
93109
94110/**
95111 * Create a new API client with a token.
96112 */
97- export function apiWithToken ( apiToken : string ) : GitBookAPI {
113+ export function apiWithToken ( apiToken : string , contextId : string | undefined ) : GitBookAPIContext {
98114 const headersList = headers ( ) ;
99115 const apiEndpoint = headersList . get ( 'x-gitbook-api' ) ?? DEFAULT_API_ENDPOINT ;
100116
@@ -104,34 +120,35 @@ export function apiWithToken(apiToken: string): GitBookAPI {
104120 userAgent : userAgent ( ) ,
105121 } ) ;
106122
107- return gitbook ;
123+ return { client : gitbook , contextId } ;
108124}
109125
110126/**
111127 * Create an API client for the current request.
112128 */
113- export function api ( ) : GitBookAPI {
129+ export function api ( ) : GitBookAPIContext {
114130 const existing = apiSyncStorage . getStore ( ) ;
115131 if ( existing ) {
116132 return existing ;
117133 }
118134
119135 const headersList = headers ( ) ;
120136 const apiToken = headersList . get ( 'x-gitbook-token' ) ;
137+ const contextId = headersList . get ( 'x-gitbook-token-context' ) ?? undefined ;
121138
122139 if ( ! apiToken ) {
123140 throw new Error (
124141 'Missing GitBook API token, please check that the request is correctly processed by the middleware' ,
125142 ) ;
126143 }
127144
128- return apiWithToken ( apiToken ) ;
145+ return apiWithToken ( apiToken , contextId ) ;
129146}
130147
131148/**
132149 * Use an API client for an async function.
133150 */
134- export function withAPI < T > ( client : GitBookAPI , fn : ( ) => Promise < T > ) : Promise < T > {
151+ export function withAPI < T > ( client : GitBookAPIContext , fn : ( ) => Promise < T > ) : Promise < T > {
135152 return apiSyncStorage . run ( client , fn ) ;
136153}
137154
@@ -164,7 +181,7 @@ export const getUserById = cache({
164181 } ) ,
165182 get : async ( userId : string , options : CacheFunctionOptions ) => {
166183 try {
167- const response = await api ( ) . users . getUserById ( userId , {
184+ const response = await api ( ) . client . users . getUserById ( userId , {
168185 signal : options . signal ,
169186 ...noCacheFetchOptions ,
170187 } ) ;
@@ -200,7 +217,7 @@ export const getPublishedContentByUrl = cache({
200217 options : CacheFunctionOptions ,
201218 ) => {
202219 try {
203- const response = await api ( ) . urls . getPublishedContentByUrl (
220+ const response = await api ( ) . client . urls . getPublishedContentByUrl (
204221 {
205222 url,
206223 visitorAuthToken,
@@ -249,7 +266,7 @@ export const getSpace = cache({
249266 name : 'api.getSpace' ,
250267 tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
251268 get : async ( spaceId : string , shareKey : string | undefined , options : CacheFunctionOptions ) => {
252- const response = await api ( ) . spaces . getSpaceById (
269+ const response = await api ( ) . client . spaces . getSpaceById (
253270 spaceId ,
254271 {
255272 shareKey,
@@ -273,7 +290,7 @@ export const getChangeRequest = cache({
273290 tag : ( spaceId , changeRequestId ) =>
274291 getAPICacheTag ( { tag : 'change-request' , space : spaceId , changeRequest : changeRequestId } ) ,
275292 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 , {
277294 ...noCacheFetchOptions ,
278295 signal : options . signal ,
279296 } ) ;
@@ -301,13 +318,14 @@ export const getRevision = cache({
301318 name : 'api.getRevision.v2' ,
302319 tag : ( spaceId , revisionId ) =>
303320 getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
321+ getKeySuffix : ( ) => api ( ) . contextId ,
304322 get : async (
305323 spaceId : string ,
306324 revisionId : string ,
307325 fetchOptions : GetRevisionOptions ,
308326 options : CacheFunctionOptions ,
309327 ) => {
310- const response = await api ( ) . spaces . getRevisionById (
328+ const response = await api ( ) . client . spaces . getRevisionById (
311329 spaceId ,
312330 revisionId ,
313331 {
@@ -331,13 +349,14 @@ export const getRevisionPages = cache({
331349 name : 'api.getRevisionPages.v4' ,
332350 tag : ( spaceId , revisionId ) =>
333351 getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
352+ getKeySuffix : ( ) => api ( ) . contextId ,
334353 get : async (
335354 spaceId : string ,
336355 revisionId : string ,
337356 fetchOptions : GetRevisionOptions ,
338357 options : CacheFunctionOptions ,
339358 ) => {
340- const response = await api ( ) . spaces . listPagesInRevisionById (
359+ const response = await api ( ) . client . spaces . listPagesInRevisionById (
341360 spaceId ,
342361 revisionId ,
343362 {
@@ -364,6 +383,7 @@ export const getRevisionPageByPath = cache({
364383 name : 'api.getRevisionPageByPath.v3' ,
365384 tag : ( spaceId , revisionId ) =>
366385 getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
386+ getKeySuffix : ( ) => api ( ) . contextId ,
367387 get : async (
368388 spaceId : string ,
369389 revisionId : string ,
@@ -373,7 +393,7 @@ export const getRevisionPageByPath = cache({
373393 const encodedPath = encodeURIComponent ( pagePath ) ;
374394
375395 try {
376- const response = await api ( ) . spaces . getPageInRevisionByPath (
396+ const response = await api ( ) . client . spaces . getPageInRevisionByPath (
377397 spaceId ,
378398 revisionId ,
379399 encodedPath ,
@@ -416,7 +436,7 @@ const getRevisionFileById = cache({
416436 ) => {
417437 try {
418438 const response = await ( async ( ) => {
419- return api ( ) . spaces . getFileInRevisionById (
439+ return api ( ) . client . spaces . getFileInRevisionById (
420440 spaceId ,
421441 revisionId ,
422442 fileId ,
@@ -445,6 +465,7 @@ const getRevisionReusableContentById = cache({
445465 name : 'api.getRevisionReusableContentById.v1' ,
446466 tag : ( spaceId , revisionId ) =>
447467 getAPICacheTag ( { tag : 'revision' , space : spaceId , revision : revisionId } ) ,
468+ getKeySuffix : ( ) => api ( ) . contextId ,
448469 get : async (
449470 spaceId : string ,
450471 revisionId : string ,
@@ -453,7 +474,7 @@ const getRevisionReusableContentById = cache({
453474 ) => {
454475 try {
455476 const response = await ( async ( ) => {
456- return api ( ) . spaces . getReusableContentInRevisionById (
477+ return api ( ) . client . spaces . getReusableContentInRevisionById (
457478 spaceId ,
458479 revisionId ,
459480 reusableContentId ,
@@ -489,7 +510,7 @@ const getRevisionAllFiles = cache({
489510 get : async ( spaceId : string , revisionId : string , options : CacheFunctionOptions ) => {
490511 const response = await getAll (
491512 ( params ) =>
492- api ( ) . spaces . listFilesInRevisionById (
513+ api ( ) . client . spaces . listFilesInRevisionById (
493514 spaceId ,
494515 revisionId ,
495516 {
@@ -600,8 +621,9 @@ export const getDocument = cache({
600621 name : 'api.getDocument.v2' ,
601622 tag : ( spaceId , documentId ) =>
602623 getAPICacheTag ( { tag : 'document' , space : spaceId , document : documentId } ) ,
624+ getKeySuffix : ( ) => api ( ) . contextId ,
603625 get : async ( spaceId : string , documentId : string , options : CacheFunctionOptions ) => {
604- const response = await api ( ) . spaces . getDocumentById (
626+ const response = await api ( ) . client . spaces . getDocumentById (
605627 spaceId ,
606628 documentId ,
607629 {
@@ -626,6 +648,7 @@ export const getDocument = cache({
626648export const getSiteRedirectBySource = cache ( {
627649 name : 'api.getSiteRedirectBySource' ,
628650 tag : ( { siteId } ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
651+ getKeySuffix : ( ) => api ( ) . contextId ,
629652 get : async (
630653 args : {
631654 organizationId : string ;
@@ -637,7 +660,7 @@ export const getSiteRedirectBySource = cache({
637660 options : CacheFunctionOptions ,
638661 ) => {
639662 try {
640- const response = await api ( ) . orgs . getSiteRedirectBySource (
663+ const response = await api ( ) . client . orgs . getSiteRedirectBySource (
641664 args . organizationId ,
642665 args . siteId ,
643666 {
@@ -669,8 +692,9 @@ export const getSiteRedirectBySource = cache({
669692export const getSite = cache ( {
670693 name : 'api.getSite' ,
671694 tag : ( organizationId , siteId ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
695+ getKeySuffix : ( ) => api ( ) . contextId ,
672696 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 , {
674698 ...noCacheFetchOptions ,
675699 signal : options . signal ,
676700 } ) ;
@@ -686,6 +710,7 @@ export const getSite = cache({
686710export const getPublishedContentSite = cache ( {
687711 name : 'api.getPublishedContentSite' ,
688712 tag : ( { siteId } ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
713+ getKeySuffix : ( ) => api ( ) . contextId ,
689714 get : async (
690715 args : {
691716 organizationId : string ;
@@ -694,7 +719,7 @@ export const getPublishedContentSite = cache({
694719 } ,
695720 options : CacheFunctionOptions ,
696721 ) => {
697- const response = await api ( ) . orgs . getPublishedContentSite (
722+ const response = await api ( ) . client . orgs . getPublishedContentSite (
698723 args . organizationId ,
699724 args . siteId ,
700725 {
@@ -826,7 +851,7 @@ export const getCollection = cache({
826851 name : 'api.getCollection' ,
827852 tag : ( collectionId ) => getAPICacheTag ( { tag : 'collection' , collection : collectionId } ) ,
828853 get : async ( collectionId : string , options : CacheFunctionOptions ) => {
829- const response = await api ( ) . collections . getCollectionById ( collectionId , {
854+ const response = await api ( ) . client . collections . getCollectionById ( collectionId , {
830855 ...noCacheFetchOptions ,
831856 signal : options . signal ,
832857 } ) ;
@@ -844,7 +869,7 @@ export const getCollectionSpaces = cache({
844869 tag : ( collectionId ) => getAPICacheTag ( { tag : 'collection' , collection : collectionId } ) ,
845870 get : async ( collectionId : string , options : CacheFunctionOptions ) => {
846871 const response = await getAll ( ( params ) =>
847- api ( ) . collections . listSpacesInCollectionById ( collectionId , params , {
872+ api ( ) . client . collections . listSpacesInCollectionById ( collectionId , params , {
848873 ...noCacheFetchOptions ,
849874 signal : options . signal ,
850875 } ) ,
@@ -896,14 +921,15 @@ export async function getSpaceContentData(
896921export const searchSpaceContent = cache ( {
897922 name : 'api.searchSpaceContent' ,
898923 tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
924+ getKeySuffix : ( ) => api ( ) . contextId ,
899925 get : async (
900926 spaceId : string ,
901927 /** The revision ID is used as a cache bust key, to avoid revalidating lot of cache entries by tags */
902928 revisionId : string ,
903929 query : string ,
904930 options : CacheFunctionOptions ,
905931 ) => {
906- const response = await api ( ) . spaces . searchSpaceContent (
932+ const response = await api ( ) . client . spaces . searchSpaceContent (
907933 spaceId ,
908934 { query } ,
909935 {
@@ -921,8 +947,9 @@ export const searchSpaceContent = cache({
921947export const searchParentContent = cache ( {
922948 name : 'api.searchParentContent' ,
923949 tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
950+ getKeySuffix : ( ) => api ( ) . contextId ,
924951 get : async ( parentId : string , query : string , options : CacheFunctionOptions ) => {
925- const response = await api ( ) . search . searchContent (
952+ const response = await api ( ) . client . search . searchContent (
926953 { query } ,
927954 {
928955 ...noCacheFetchOptions ,
@@ -941,6 +968,7 @@ export const searchParentContent = cache({
941968export const searchSiteContent = cache ( {
942969 name : 'api.searchSiteContent' ,
943970 tag : ( organizationId , siteId ) => getAPICacheTag ( { tag : 'site' , site : siteId } ) ,
971+ getKeySuffix : ( ) => api ( ) . contextId ,
944972 get : async (
945973 organizationId : string ,
946974 siteId : string ,
@@ -953,7 +981,7 @@ export const searchSiteContent = cache({
953981 cacheBust ?: string ,
954982 options ?: CacheFunctionOptions ,
955983 ) => {
956- const response = await api ( ) . orgs . searchSiteContent (
984+ const response = await api ( ) . client . orgs . searchSiteContent (
957985 organizationId ,
958986 siteId ,
959987 {
@@ -980,7 +1008,7 @@ export const getRecommendedQuestionsInSpace = cache({
9801008 name : 'api.getRecommendedQuestionsInSpace' ,
9811009 tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
9821010 get : async ( spaceId : string , options : CacheFunctionOptions ) => {
983- const response = await api ( ) . spaces . getRecommendedQuestionsInSpace ( spaceId , {
1011+ const response = await api ( ) . client . spaces . getRecommendedQuestionsInSpace ( spaceId , {
9841012 ...noCacheFetchOptions ,
9851013 signal : options . signal ,
9861014 } ) ;
@@ -999,7 +1027,7 @@ export const renderIntegrationUi = cache({
9991027 request : RequestRenderIntegrationUI ,
10001028 options : CacheFunctionOptions ,
10011029 ) => {
1002- const response = await api ( ) . integrations . renderIntegrationUiWithPost (
1030+ const response = await api ( ) . client . integrations . renderIntegrationUiWithPost (
10031031 integrationName ,
10041032 request ,
10051033 {
@@ -1018,7 +1046,7 @@ export const renderIntegrationUi = cache({
10181046export const getEmbedByUrl = cache ( {
10191047 name : 'api.getEmbedByUrl' ,
10201048 get : async ( url : string , options : CacheFunctionOptions ) => {
1021- const response = await api ( ) . urls . getEmbedByUrl (
1049+ const response = await api ( ) . client . urls . getEmbedByUrl (
10221050 { url } ,
10231051 {
10241052 ...noCacheFetchOptions ,
@@ -1036,7 +1064,7 @@ export const getEmbedByUrlInSpace = cache({
10361064 name : 'api.getEmbedByUrlInSpace' ,
10371065 tag : ( spaceId ) => getAPICacheTag ( { tag : 'space' , space : spaceId } ) ,
10381066 get : async ( spaceId : string , url : string , options : CacheFunctionOptions ) => {
1039- const response = await api ( ) . spaces . getEmbedByUrlInSpace (
1067+ const response = await api ( ) . client . spaces . getEmbedByUrlInSpace (
10401068 spaceId ,
10411069 { url } ,
10421070 {
0 commit comments