Compare commits

...

1 Commits

Author SHA1 Message Date
Nicolas Dorseuil 6edf3b78f0 use dataFetcher itself as the key for the weakmap 2025-06-12 14:24:11 +02:00
2 changed files with 654 additions and 612 deletions
+86 -41
View File
@@ -51,7 +51,7 @@ export function createDataFetcher(
//
getPublishedContentSite(params) {
return trace('getPublishedContentSite', () =>
getPublishedContentSite(input, {
getPublishedContentSite(this)(input, {
organizationId: params.organizationId,
siteId: params.siteId,
siteShareKey: params.siteShareKey,
@@ -60,7 +60,7 @@ export function createDataFetcher(
},
getSiteRedirectBySource(params) {
return trace('getSiteRedirectBySource', () =>
getSiteRedirectBySource(input, {
getSiteRedirectBySource(this)(input, {
organizationId: params.organizationId,
siteId: params.siteId,
siteShareKey: params.siteShareKey,
@@ -70,7 +70,7 @@ export function createDataFetcher(
},
getRevision(params) {
return trace('getRevision', () =>
getRevision(input, {
getRevision(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
metadata: params.metadata,
@@ -79,7 +79,7 @@ export function createDataFetcher(
},
getRevisionPages(params) {
return trace('getRevisionPages', () =>
getRevisionPages(input, {
getRevisionPages(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
metadata: params.metadata,
@@ -88,7 +88,7 @@ export function createDataFetcher(
},
getRevisionFile(params) {
return trace('getRevisionFile', () =>
getRevisionFile(input, {
getRevisionFile(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
fileId: params.fileId,
@@ -97,7 +97,7 @@ export function createDataFetcher(
},
getRevisionPageByPath(params) {
return trace('getRevisionPageByPath', () =>
getRevisionPageByPath(input, {
getRevisionPageByPath(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
path: params.path,
@@ -106,7 +106,7 @@ export function createDataFetcher(
},
getRevisionPageMarkdown(params) {
return trace('getRevisionPageMarkdown', () =>
getRevisionPageMarkdown(input, {
getRevisionPageMarkdown(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
pageId: params.pageId,
@@ -115,7 +115,7 @@ export function createDataFetcher(
},
getRevisionPageDocument(params) {
return trace('getRevisionPageDocument', () =>
getRevisionPageDocument(input, {
getRevisionPageDocument(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
pageId: params.pageId,
@@ -124,7 +124,7 @@ export function createDataFetcher(
},
getReusableContent(params) {
return trace('getReusableContent', () =>
getReusableContent(input, {
getReusableContent(this)(input, {
spaceId: params.spaceId,
revisionId: params.revisionId,
reusableContentId: params.reusableContentId,
@@ -133,7 +133,7 @@ export function createDataFetcher(
},
getLatestOpenAPISpecVersionContent(params) {
return trace('getLatestOpenAPISpecVersionContent', () =>
getLatestOpenAPISpecVersionContent(input, {
getLatestOpenAPISpecVersionContent(this)(input, {
organizationId: params.organizationId,
slug: params.slug,
})
@@ -141,7 +141,7 @@ export function createDataFetcher(
},
getSpace(params) {
return trace('getSpace', () =>
getSpace(input, {
getSpace(this)(input, {
spaceId: params.spaceId,
shareKey: params.shareKey,
})
@@ -149,7 +149,7 @@ export function createDataFetcher(
},
getChangeRequest(params) {
return trace('getChangeRequest', () =>
getChangeRequest(input, {
getChangeRequest(this)(input, {
spaceId: params.spaceId,
changeRequestId: params.changeRequestId,
})
@@ -157,7 +157,7 @@ export function createDataFetcher(
},
getDocument(params) {
return trace('getDocument', () =>
getDocument(input, {
getDocument(this)(input, {
spaceId: params.spaceId,
documentId: params.documentId,
})
@@ -165,7 +165,7 @@ export function createDataFetcher(
},
getComputedDocument(params) {
return trace('getComputedDocument', () =>
getComputedDocument(input, {
getComputedDocument(this)(input, {
organizationId: params.organizationId,
spaceId: params.spaceId,
source: params.source,
@@ -175,19 +175,19 @@ export function createDataFetcher(
},
getEmbedByUrl(params) {
return trace('getEmbedByUrl', () =>
getEmbedByUrl(input, {
getEmbedByUrl(this)(input, {
url: params.url,
spaceId: params.spaceId,
})
);
},
searchSiteContent(params) {
return trace('searchSiteContent', () => searchSiteContent(input, params));
return trace('searchSiteContent', () => searchSiteContent(this)(input, params));
},
renderIntegrationUi(params) {
return trace('renderIntegrationUi', () =>
renderIntegrationUi(input, {
renderIntegrationUi(this)(input, {
integrationName: params.integrationName,
request: params.request,
})
@@ -195,7 +195,7 @@ export function createDataFetcher(
},
getUserById(userId) {
return trace('getUserById', () => getUserById(input, { userId }));
return trace('getUserById', () => getUserById(this)(input, { userId }));
},
streamAIResponse(params) {
@@ -204,8 +204,11 @@ export function createDataFetcher(
};
}
const getUserById = withCacheKey(
withoutConcurrentExecution(async (_, input: DataFetcherInput, params: { userId: string }) => {
const getUserById = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (_, input: DataFetcherInput, params: { userId: string }) => {
'use cache';
return trace(`getUserById(${params.userId})`, async () => {
return wrapDataFetcherError(async () => {
@@ -218,11 +221,14 @@ const getUserById = withCacheKey(
return res.data;
});
});
})
}
)
);
const getSpace = withCacheKey(
const getSpace = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -257,8 +263,10 @@ const getSpace = withCacheKey(
)
);
const getChangeRequest = withCacheKey(
const getChangeRequest = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -295,8 +303,10 @@ const getChangeRequest = withCacheKey(
)
);
const getRevision = withCacheKey(
const getRevision = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -325,15 +335,19 @@ const getRevision = withCacheKey(
)
);
const getRevisionPages = withCacheKey(
const getRevisionPages = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
params: { spaceId: string; revisionId: string; metadata: boolean }
) => {
'use cache';
return trace(`getRevisionPages(${params.spaceId}, ${params.revisionId})`, async () => {
return trace(
`getRevisionPages(${params.spaceId}, ${params.revisionId})`,
async () => {
return wrapDataFetcherError(async () => {
const api = apiClient(input);
const res = await api.spaces.listPagesInRevisionById(
@@ -350,13 +364,16 @@ const getRevisionPages = withCacheKey(
cacheLife('max');
return res.data.pages;
});
});
}
);
}
)
);
const getRevisionFile = withCacheKey(
const getRevisionFile = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -387,8 +404,10 @@ const getRevisionFile = withCacheKey(
)
);
const getRevisionPageMarkdown = withCacheKey(
const getRevisionPageMarkdown = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -426,8 +445,10 @@ const getRevisionPageMarkdown = withCacheKey(
)
);
const getRevisionPageDocument = withCacheKey(
const getRevisionPageDocument = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -462,8 +483,10 @@ const getRevisionPageDocument = withCacheKey(
)
);
const getRevisionPageByPath = withCacheKey(
const getRevisionPageByPath = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -495,8 +518,10 @@ const getRevisionPageByPath = withCacheKey(
)
);
const getDocument = withCacheKey(
const getDocument = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (_, input: DataFetcherInput, params: { spaceId: string; documentId: string }) => {
'use cache';
return trace(`getDocument(${params.spaceId}, ${params.documentId})`, async () => {
@@ -519,8 +544,10 @@ const getDocument = withCacheKey(
)
);
const getComputedDocument = withCacheKey(
const getComputedDocument = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -568,8 +595,10 @@ const getComputedDocument = withCacheKey(
)
);
const getReusableContent = withCacheKey(
const getReusableContent = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -600,9 +629,15 @@ const getReusableContent = withCacheKey(
)
);
const getLatestOpenAPISpecVersionContent = withCacheKey(
const getLatestOpenAPISpecVersionContent = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
async (_, input: DataFetcherInput, params: { organizationId: string; slug: string }) => {
dataFetcher,
async (
_,
input: DataFetcherInput,
params: { organizationId: string; slug: string }
) => {
'use cache';
cacheTag(
getCacheTag({
@@ -634,8 +669,10 @@ const getLatestOpenAPISpecVersionContent = withCacheKey(
)
);
const getPublishedContentSite = withCacheKey(
const getPublishedContentSite = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -674,8 +711,10 @@ const getPublishedContentSite = withCacheKey(
)
);
const getSiteRedirectBySource = withCacheKey(
const getSiteRedirectBySource = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -720,8 +759,10 @@ const getSiteRedirectBySource = withCacheKey(
)
);
const getEmbedByUrl = withCacheKey(
const getEmbedByUrl = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (_, input: DataFetcherInput, params: { spaceId: string; url: string }) => {
'use cache';
cacheTag(
@@ -752,8 +793,10 @@ const getEmbedByUrl = withCacheKey(
)
);
const searchSiteContent = withCacheKey(
const searchSiteContent = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
@@ -795,8 +838,10 @@ const searchSiteContent = withCacheKey(
)
);
const renderIntegrationUi = withCacheKey(
const renderIntegrationUi = (dataFetcher: GitBookDataFetcher) =>
withCacheKey(
withoutConcurrentExecution(
dataFetcher,
async (
_,
input: DataFetcherInput,
+3 -6
View File
@@ -1,20 +1,17 @@
import { cache } from 'react';
// This is used to create a context specific to the current request.
// This version works both in cloudflare and in vercel.
const getRequestContext = cache(() => ({}));
import type { GitBookDataFetcher } from './types';
/**
* Wrap a function by preventing concurrent executions of the same function.
* With a logic to work per-request in Cloudflare Workers.
*/
export function withoutConcurrentExecution<ArgsType extends any[], ReturnType>(
dataFetcherObject: GitBookDataFetcher,
wrapped: (key: string, ...args: ArgsType) => Promise<ReturnType>
): (cacheKey: string, ...args: ArgsType) => Promise<ReturnType> {
const globalPromiseCache = new WeakMap<object, Map<string, Promise<ReturnType>>>();
return (key: string, ...args: ArgsType) => {
const globalContext = getRequestContext();
const globalContext = dataFetcherObject;
/**
* Cache storage that is scoped to the current request when executed in Cloudflare Workers,