1
1
import { getCloudflareContext } from '@opennextjs/cloudflare' ;
2
2
3
- import pMemoize , { type CacheStorage } from 'p-memoize' ;
4
- // import { getCloudflareContext } from './cloudflare';
3
+ import pMemoize from 'p-memoize' ;
5
4
6
- // const requestWeakCache = new WeakMap<object, WeakMap<any, any>>();
5
+ const requestWeakCache = new WeakMap < object , WeakMap < any , any > > ( ) ;
7
6
8
7
/**
9
8
* We wrap 'use cache' calls in a p-memoize function to avoid
@@ -12,94 +11,28 @@ import pMemoize, { type CacheStorage } from 'p-memoize';
12
11
* Hopefully one day this can be done directly by 'use cache'.
13
12
*/
14
13
export function memoize < F extends ( ...args : any [ ] ) => any > ( f : F ) : F {
15
- // const globalContext = getCloudflareContext()?.cf ?? globalThis;
16
-
17
- // const requestCache = requestWeakCache.get(globalContext);
18
- // if (requestCache) {
19
- // const cache = requestCache.get(f);
20
- // if (cache) {
21
- // return cache as F;
22
- // }
23
- // }
24
-
25
- if ( process . env . NODE_ENV === 'production' ) {
26
- return f ;
14
+ const globalContext = getCloudflareContext ( ) ?. cf ?? globalThis ;
15
+
16
+ /**
17
+ * Cache storage that is scoped to the current request when executed in Cloudflare Workers,
18
+ * to avoid "Cannot perform I/O on behalf of a different request" errors.
19
+ */
20
+ const requestCache = requestWeakCache . get ( globalContext ) ?? new WeakMap < any , any > ( ) ;
21
+ const cached = requestCache . get ( f ) ;
22
+ if ( cached ) {
23
+ return cached as F ;
27
24
}
28
25
29
- const getFunctionCache = async ( ) => {
30
- const functionsCache = await getRequestCacheWeakMap ( ) ;
31
- const cache = functionsCache . get ( f ) ;
32
- if ( cache ) {
33
- return cache ;
34
- }
35
-
36
- const newCache = new Map < string , unknown > ( ) ;
37
- functionsCache . set ( f , newCache ) ;
38
- return newCache ;
39
- } ;
40
-
41
- return pMemoize ( f , {
26
+ const memoized = pMemoize ( f , {
42
27
cacheKey : ( args ) => {
43
28
return JSON . stringify ( deepSortValue ( args ) ) ;
44
29
} ,
45
- /**
46
- * Cache storage that is scoped to the current request when executed in Cloudflare Workers,
47
- * to avoid "Cannot perform I/O on behalf of a different request" errors.
48
- */
49
- cache : {
50
- has : async ( key ) => {
51
- const cache = await getFunctionCache ( ) ;
52
- return cache . has ( key ) ;
53
- } ,
54
- get : async ( key ) => {
55
- const cache = await getFunctionCache ( ) ;
56
- return cache . get ( key ) as Awaited < ReturnType < F > > | undefined ;
57
- } ,
58
- set : async ( key , value ) => {
59
- const cache = await getFunctionCache ( ) ;
60
- cache . set ( key , value ) ;
61
- } ,
62
- delete : async ( key ) => {
63
- const cache = await getFunctionCache ( ) ;
64
- cache . delete ( key ) ;
65
- } ,
66
- clear : async ( ) => {
67
- const cache = await getFunctionCache ( ) ;
68
- cache . clear ?.( ) ;
69
- } ,
70
- } ,
71
30
} ) ;
72
- }
73
31
74
- const globalCache = new WeakMap < any , CacheStorage < string , unknown > > ( ) ;
75
- const perRequestCache = new WeakMap < object , WeakMap < any , CacheStorage < string , unknown > > > ( ) ;
76
-
77
- /**
78
- * Get a global weakmap that is scoped to the current request when executed in Cloudflare Workers,
79
- * to avoid "Cannot perform I/O on behalf of a different request" errors.
80
- * And global when executed in Node.js.
81
- */
82
- async function getRequestCacheWeakMap ( ) : Promise < WeakMap < any , CacheStorage < string , unknown > > > {
83
- try {
84
- const cloudflareContext = getCloudflareContext ( ) ;
85
- if ( cloudflareContext ?. cf ) {
86
- // `cf` changes for each request, we can use it as an identifier of the request to isolate the cache per request
87
- const requestCache = perRequestCache . get ( cloudflareContext . cf ) ;
88
- if ( requestCache ) {
89
- return requestCache ;
90
- }
91
-
92
- const newRequestCache = new WeakMap < any , CacheStorage < string , unknown > > ( ) ;
93
- perRequestCache . set ( cloudflareContext . cf , newRequestCache ) ;
94
- return newRequestCache ;
95
- }
96
- } catch ( error ) {
97
- if ( process . env . NODE_ENV === 'production' && ! process . env . VERCEL ) {
98
- throw error ;
99
- }
100
- }
32
+ requestCache . set ( f , memoized ) ;
33
+ requestWeakCache . set ( globalContext , requestCache ) ;
101
34
102
- return globalCache ;
35
+ return memoized ;
103
36
}
104
37
105
38
export function getCacheKey ( args : any [ ] ) {
0 commit comments