@modern-js/runtime-utils 2.65.0 → 2.65.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/browser/nestedRoutes.js +11 -11
- package/dist/cjs/node/index.js +3 -6
- package/dist/cjs/node/storer/container.js +8 -15
- package/dist/cjs/universal/async_storage.js +31 -0
- package/dist/cjs/{node/storage.js → universal/async_storage.server.js} +18 -12
- package/dist/cjs/universal/cache.js +247 -0
- package/dist/esm/browser/nestedRoutes.js +12 -12
- package/dist/esm/node/index.js +2 -4
- package/dist/esm/node/storer/container.js +8 -5
- package/dist/esm/universal/async_storage.js +7 -0
- package/dist/esm/{node/storage.js → universal/async_storage.server.js} +13 -8
- package/dist/esm/universal/cache.js +355 -0
- package/dist/esm-node/browser/nestedRoutes.js +11 -11
- package/dist/esm-node/node/index.js +2 -4
- package/dist/esm-node/node/storer/container.js +8 -5
- package/dist/esm-node/universal/async_storage.js +7 -0
- package/dist/esm-node/{node/storage.js → universal/async_storage.server.js} +13 -8
- package/dist/esm-node/universal/cache.js +216 -0
- package/dist/types/browser/nestedRoutes.d.ts +2 -3
- package/dist/types/node/index.d.ts +1 -4
- package/dist/types/node/loaderContext/index.d.ts +1 -13
- package/dist/types/node/storer/container.d.ts +1 -1
- package/dist/types/node/storer/index.d.ts +1 -1
- package/dist/types/server/nestedRoutes.d.ts +1 -2
- package/dist/types/universal/async_storage.d.ts +2 -0
- package/dist/types/universal/async_storage.server.d.ts +18 -0
- package/dist/types/universal/cache.d.ts +28 -0
- package/package.json +14 -8
- package/dist/types/node/storage.d.ts +0 -5
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { LRUCache } from "lru-cache";
|
|
2
|
+
import { getAsyncLocalStorage } from "./async_storage";
|
|
3
|
+
const CacheSize = {
|
|
4
|
+
KB: 1024,
|
|
5
|
+
MB: 1024 * 1024,
|
|
6
|
+
GB: 1024 * 1024 * 1024
|
|
7
|
+
};
|
|
8
|
+
const CacheTime = {
|
|
9
|
+
SECOND: 1e3,
|
|
10
|
+
MINUTE: 60 * 1e3,
|
|
11
|
+
HOUR: 60 * 60 * 1e3,
|
|
12
|
+
DAY: 24 * 60 * 60 * 1e3,
|
|
13
|
+
WEEK: 7 * 24 * 60 * 60 * 1e3,
|
|
14
|
+
MONTH: 30 * 24 * 60 * 60 * 1e3
|
|
15
|
+
};
|
|
16
|
+
const isServer = typeof window === "undefined";
|
|
17
|
+
const requestCacheMap = /* @__PURE__ */ new WeakMap();
|
|
18
|
+
let lruCache;
|
|
19
|
+
let cacheConfig = {
|
|
20
|
+
maxSize: CacheSize.GB
|
|
21
|
+
};
|
|
22
|
+
const tagFnMap = /* @__PURE__ */ new Map();
|
|
23
|
+
function addTagFnRelation(tag, fn) {
|
|
24
|
+
let fns = tagFnMap.get(tag);
|
|
25
|
+
if (!fns) {
|
|
26
|
+
fns = /* @__PURE__ */ new Set();
|
|
27
|
+
tagFnMap.set(tag, fns);
|
|
28
|
+
}
|
|
29
|
+
fns.add(fn);
|
|
30
|
+
}
|
|
31
|
+
function configureCache(config) {
|
|
32
|
+
cacheConfig = {
|
|
33
|
+
...cacheConfig,
|
|
34
|
+
...config
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function getLRUCache() {
|
|
38
|
+
if (!lruCache) {
|
|
39
|
+
lruCache = new LRUCache({
|
|
40
|
+
maxSize: cacheConfig.maxSize,
|
|
41
|
+
sizeCalculation: (value) => {
|
|
42
|
+
if (!value.size) {
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
let size = 0;
|
|
46
|
+
for (const [k, item] of value.entries()) {
|
|
47
|
+
size += k.length * 2;
|
|
48
|
+
size += estimateObjectSize(item.data);
|
|
49
|
+
size += 8;
|
|
50
|
+
}
|
|
51
|
+
return size;
|
|
52
|
+
},
|
|
53
|
+
updateAgeOnGet: true,
|
|
54
|
+
updateAgeOnHas: true
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return lruCache;
|
|
58
|
+
}
|
|
59
|
+
function estimateObjectSize(data) {
|
|
60
|
+
const type = typeof data;
|
|
61
|
+
if (type === "number")
|
|
62
|
+
return 8;
|
|
63
|
+
if (type === "boolean")
|
|
64
|
+
return 4;
|
|
65
|
+
if (type === "string")
|
|
66
|
+
return Math.max(data.length * 2, 1);
|
|
67
|
+
if (data === null || data === void 0)
|
|
68
|
+
return 1;
|
|
69
|
+
if (ArrayBuffer.isView(data)) {
|
|
70
|
+
return Math.max(data.byteLength, 1);
|
|
71
|
+
}
|
|
72
|
+
if (Array.isArray(data)) {
|
|
73
|
+
return Math.max(data.reduce((acc, item) => acc + estimateObjectSize(item), 0), 1);
|
|
74
|
+
}
|
|
75
|
+
if (data instanceof Map || data instanceof Set) {
|
|
76
|
+
return 1024;
|
|
77
|
+
}
|
|
78
|
+
if (data instanceof Date) {
|
|
79
|
+
return 8;
|
|
80
|
+
}
|
|
81
|
+
if (type === "object") {
|
|
82
|
+
return Math.max(Object.entries(data).reduce((acc, [key, value]) => acc + key.length * 2 + estimateObjectSize(value), 0), 1);
|
|
83
|
+
}
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
function generateKey(args) {
|
|
87
|
+
return JSON.stringify(args, (_, value) => {
|
|
88
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
89
|
+
return Object.keys(value).sort().reduce((result, key) => {
|
|
90
|
+
result[key] = value[key];
|
|
91
|
+
return result;
|
|
92
|
+
}, {});
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function cache(fn, options) {
|
|
98
|
+
const { tag = "default", maxAge = CacheTime.MINUTE * 5, revalidate = 0 } = options || {};
|
|
99
|
+
const store = getLRUCache();
|
|
100
|
+
const tags = Array.isArray(tag) ? tag : [
|
|
101
|
+
tag
|
|
102
|
+
];
|
|
103
|
+
tags.forEach((t) => addTagFnRelation(t, fn));
|
|
104
|
+
return async (...args) => {
|
|
105
|
+
if (isServer && typeof options === "undefined") {
|
|
106
|
+
var _storage_useContext;
|
|
107
|
+
const storage = getAsyncLocalStorage();
|
|
108
|
+
const request = storage === null || storage === void 0 ? void 0 : (_storage_useContext = storage.useContext()) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.request;
|
|
109
|
+
if (request) {
|
|
110
|
+
let requestCache = requestCacheMap.get(request);
|
|
111
|
+
if (!requestCache) {
|
|
112
|
+
requestCache = /* @__PURE__ */ new Map();
|
|
113
|
+
requestCacheMap.set(request, requestCache);
|
|
114
|
+
}
|
|
115
|
+
const key = generateKey(args);
|
|
116
|
+
if (requestCache.has(key)) {
|
|
117
|
+
return requestCache.get(key);
|
|
118
|
+
}
|
|
119
|
+
const promise = fn(...args);
|
|
120
|
+
requestCache.set(key, promise);
|
|
121
|
+
try {
|
|
122
|
+
const data = await promise;
|
|
123
|
+
return data;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
requestCache.delete(key);
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} else if (typeof options !== "undefined") {
|
|
130
|
+
let tagCache = store.get(fn);
|
|
131
|
+
if (!tagCache) {
|
|
132
|
+
tagCache = /* @__PURE__ */ new Map();
|
|
133
|
+
}
|
|
134
|
+
const key = generateKey(args);
|
|
135
|
+
const cached = tagCache.get(key);
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
if (cached) {
|
|
138
|
+
const age = now - cached.timestamp;
|
|
139
|
+
if (age < maxAge) {
|
|
140
|
+
return cached.data;
|
|
141
|
+
}
|
|
142
|
+
if (revalidate > 0 && age < maxAge + revalidate) {
|
|
143
|
+
if (!cached.isRevalidating) {
|
|
144
|
+
cached.isRevalidating = true;
|
|
145
|
+
Promise.resolve().then(async () => {
|
|
146
|
+
try {
|
|
147
|
+
const newData = await fn(...args);
|
|
148
|
+
tagCache.set(key, {
|
|
149
|
+
data: newData,
|
|
150
|
+
timestamp: Date.now(),
|
|
151
|
+
isRevalidating: false
|
|
152
|
+
});
|
|
153
|
+
store.set(fn, tagCache);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
cached.isRevalidating = false;
|
|
156
|
+
if (isServer) {
|
|
157
|
+
var _storage_useContext_monitors, _storage_useContext2;
|
|
158
|
+
const storage = getAsyncLocalStorage();
|
|
159
|
+
storage === null || storage === void 0 ? void 0 : (_storage_useContext2 = storage.useContext()) === null || _storage_useContext2 === void 0 ? void 0 : (_storage_useContext_monitors = _storage_useContext2.monitors) === null || _storage_useContext_monitors === void 0 ? void 0 : _storage_useContext_monitors.error(error.message);
|
|
160
|
+
} else {
|
|
161
|
+
console.error("Background revalidation failed:", error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return cached.data;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const data = await fn(...args);
|
|
170
|
+
tagCache.set(key, {
|
|
171
|
+
data,
|
|
172
|
+
timestamp: now,
|
|
173
|
+
isRevalidating: false
|
|
174
|
+
});
|
|
175
|
+
store.set(fn, tagCache);
|
|
176
|
+
return data;
|
|
177
|
+
} else {
|
|
178
|
+
console.warn("The cache function will not work because it runs on the browser and there are no options are provided.");
|
|
179
|
+
return fn(...args);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function withRequestCache(handler) {
|
|
184
|
+
if (!isServer) {
|
|
185
|
+
return handler;
|
|
186
|
+
}
|
|
187
|
+
return async (req, ...args) => {
|
|
188
|
+
const storage = getAsyncLocalStorage();
|
|
189
|
+
return storage.run({
|
|
190
|
+
request: req
|
|
191
|
+
}, () => handler(req, ...args));
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function revalidateTag(tag) {
|
|
195
|
+
const fns = tagFnMap.get(tag);
|
|
196
|
+
if (fns) {
|
|
197
|
+
fns.forEach((fn) => {
|
|
198
|
+
lruCache === null || lruCache === void 0 ? void 0 : lruCache.delete(fn);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function clearStore() {
|
|
203
|
+
lruCache === null || lruCache === void 0 ? void 0 : lruCache.clear();
|
|
204
|
+
lruCache = void 0;
|
|
205
|
+
tagFnMap.clear();
|
|
206
|
+
}
|
|
207
|
+
export {
|
|
208
|
+
CacheSize,
|
|
209
|
+
CacheTime,
|
|
210
|
+
cache,
|
|
211
|
+
clearStore,
|
|
212
|
+
configureCache,
|
|
213
|
+
generateKey,
|
|
214
|
+
revalidateTag,
|
|
215
|
+
withRequestCache
|
|
216
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { NestedRoute
|
|
3
|
-
export declare const transformNestedRoutes: (routes: NestedRoute[]
|
|
2
|
+
import type { NestedRoute } from '@modern-js/types';
|
|
3
|
+
export declare const transformNestedRoutes: (routes: NestedRoute[]) => import("react-router-dom").RouteObject[];
|
|
4
4
|
type DeferredDataComponentType = (props?: {
|
|
5
5
|
nonce?: string;
|
|
6
6
|
}) => JSX.Element | null;
|
|
@@ -8,6 +8,5 @@ export declare const renderNestedRoute: (nestedRoute: NestedRoute, options?: {
|
|
|
8
8
|
parent?: NestedRoute;
|
|
9
9
|
DeferredDataComponent?: DeferredDataComponentType;
|
|
10
10
|
props?: Record<string, any>;
|
|
11
|
-
reporter?: Reporter;
|
|
12
11
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
13
12
|
export {};
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
/**
|
|
3
2
|
* ssr helpers
|
|
4
3
|
*/
|
|
5
|
-
|
|
6
|
-
declare const run: <O>(context: IncomingHttpHeaders, cb: () => O | Promise<O>) => Promise<O>, useHeaders: () => IncomingHttpHeaders;
|
|
7
|
-
export { run, useHeaders };
|
|
4
|
+
export { storage } from '../universal/async_storage.server';
|
|
8
5
|
export { serializeJson } from './serialize';
|
|
9
6
|
export * from './loaderContext';
|
|
10
7
|
export * from './stream';
|
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
import type { Reporter } from '@modern-js/types';
|
|
2
|
-
export { createRequestContext, type RequestContext } from './createRequestCtx';
|
|
2
|
+
export { createRequestContext, type RequestContext, } from './createRequestCtx';
|
|
3
3
|
export type { LoaderContext } from './createLoaderCtx';
|
|
4
|
-
/**
|
|
5
|
-
* @deprecated
|
|
6
|
-
* Use `context.get('reporter')` instead of `context.get(reporterCtx)`. The `reporterCtx` will be removed in next major version.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
*
|
|
10
|
-
* const loader = ({ context }: LoaderFunctionArgs) => {
|
|
11
|
-
* const reporter = context?.get('reporter')
|
|
12
|
-
* // doSomething
|
|
13
|
-
* }
|
|
14
|
-
*
|
|
15
|
-
*/
|
|
16
4
|
export declare const reporterCtx: import("./createLoaderCtx").LoaderContext<Reporter>;
|
|
@@ -8,7 +8,7 @@ interface MemoryContainerOptions {
|
|
|
8
8
|
* MemoryContainer, it use lur-cache as cahe layer.
|
|
9
9
|
* It has a Time to Live, by default as 1 hour.
|
|
10
10
|
*/
|
|
11
|
-
export declare class MemoryContainer<K, V
|
|
11
|
+
export declare class MemoryContainer<K extends string, V extends {}> implements Container<K, V> {
|
|
12
12
|
private static BYTE;
|
|
13
13
|
private static KB;
|
|
14
14
|
private static MB;
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type ServerContext = Pick<ModernServerContext, 'logger' | 'req' | 'reporter' | 'res' | 'params' | 'headers' | 'method' | 'url' | 'host' | 'protocol' | 'origin' | 'href' | 'path' | 'query'>;
|
|
1
|
+
import type { ServerRoute } from '@modern-js/types';
|
|
3
2
|
export declare const matchEntry: (pathname: string, entries: ServerRoute[]) => ServerRoute | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { IncomingHttpHeaders } from 'http';
|
|
3
|
+
import type { Monitors } from '@modern-js/types';
|
|
4
|
+
declare const storage: {
|
|
5
|
+
run: <O>(context: {
|
|
6
|
+
monitors?: Monitors | undefined;
|
|
7
|
+
headers?: IncomingHttpHeaders | undefined;
|
|
8
|
+
request?: Request | undefined;
|
|
9
|
+
}, cb: () => O | Promise<O>) => Promise<O>;
|
|
10
|
+
useContext: () => {
|
|
11
|
+
monitors?: Monitors | undefined;
|
|
12
|
+
headers?: IncomingHttpHeaders | undefined;
|
|
13
|
+
request?: Request | undefined;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
type Storage = typeof storage;
|
|
17
|
+
export { storage, type Storage };
|
|
18
|
+
export declare const getAsyncLocalStorage: () => Storage;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const CacheSize: {
|
|
2
|
+
readonly KB: 1024;
|
|
3
|
+
readonly MB: number;
|
|
4
|
+
readonly GB: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const CacheTime: {
|
|
7
|
+
readonly SECOND: 1000;
|
|
8
|
+
readonly MINUTE: number;
|
|
9
|
+
readonly HOUR: number;
|
|
10
|
+
readonly DAY: number;
|
|
11
|
+
readonly WEEK: number;
|
|
12
|
+
readonly MONTH: number;
|
|
13
|
+
};
|
|
14
|
+
interface CacheOptions {
|
|
15
|
+
tag?: string | string[];
|
|
16
|
+
maxAge?: number;
|
|
17
|
+
revalidate?: number;
|
|
18
|
+
}
|
|
19
|
+
interface CacheConfig {
|
|
20
|
+
maxSize: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function configureCache(config: CacheConfig): void;
|
|
23
|
+
export declare function generateKey(args: unknown[]): string;
|
|
24
|
+
export declare function cache<T extends (...args: any[]) => Promise<any>>(fn: T, options?: CacheOptions): T;
|
|
25
|
+
export declare function withRequestCache<T extends (req: Request, ...args: any[]) => Promise<any>>(handler: T): T;
|
|
26
|
+
export declare function revalidateTag(tag: string): void;
|
|
27
|
+
export declare function clearStore(): void;
|
|
28
|
+
export {};
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"modern",
|
|
16
16
|
"modern.js"
|
|
17
17
|
],
|
|
18
|
-
"version": "2.65.
|
|
18
|
+
"version": "2.65.2",
|
|
19
19
|
"_comment": "Provide ESM and CJS exports, ESM is used by runtime package, for treeshaking",
|
|
20
20
|
"exports": {
|
|
21
21
|
"./router": {
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
},
|
|
31
31
|
"./browser": {
|
|
32
32
|
"types": "./dist/types/browser/index.d.ts",
|
|
33
|
-
"jsnext:source": "./src/browser/index.d.ts",
|
|
34
33
|
"require": "./dist/cjs/browser/index.js",
|
|
35
34
|
"default": "./dist/esm/browser/index.js"
|
|
36
35
|
},
|
|
@@ -83,6 +82,11 @@
|
|
|
83
82
|
"types": "./dist/types/merge.d.ts",
|
|
84
83
|
"require": "./dist/cjs/merge.js",
|
|
85
84
|
"default": "./dist/esm/merge.js"
|
|
85
|
+
},
|
|
86
|
+
"./cache": {
|
|
87
|
+
"types": "./dist/types/universal/cache.d.ts",
|
|
88
|
+
"require": "./dist/cjs/universal/cache.js",
|
|
89
|
+
"default": "./dist/esm/universal/cache.js"
|
|
86
90
|
}
|
|
87
91
|
},
|
|
88
92
|
"publishConfig": {
|
|
@@ -130,16 +134,20 @@
|
|
|
130
134
|
],
|
|
131
135
|
"merge": [
|
|
132
136
|
"./dist/types/merge.d.ts"
|
|
137
|
+
],
|
|
138
|
+
"cache": [
|
|
139
|
+
"./dist/types/universal/cache.d.ts"
|
|
133
140
|
]
|
|
134
141
|
}
|
|
135
142
|
},
|
|
136
143
|
"dependencies": {
|
|
137
144
|
"@remix-run/router": "1.20.0",
|
|
138
145
|
"@swc/helpers": "0.5.13",
|
|
139
|
-
"lru-cache": "^
|
|
146
|
+
"lru-cache": "^11.0.2",
|
|
140
147
|
"react-router-dom": "6.27.0",
|
|
141
148
|
"serialize-javascript": "^6.0.0",
|
|
142
|
-
"@modern-js/
|
|
149
|
+
"@modern-js/types": "2.65.2",
|
|
150
|
+
"@modern-js/utils": "2.65.2"
|
|
143
151
|
},
|
|
144
152
|
"peerDependencies": {
|
|
145
153
|
"react": ">=17.0.0",
|
|
@@ -155,16 +163,14 @@
|
|
|
155
163
|
},
|
|
156
164
|
"devDependencies": {
|
|
157
165
|
"@types/jest": "^29",
|
|
158
|
-
"@types/lru-cache": "^5.1.1",
|
|
159
166
|
"@types/node": "^14",
|
|
160
167
|
"@types/serialize-javascript": "^5.0.1",
|
|
161
168
|
"jest": "^29",
|
|
162
169
|
"react": "^18.3.1",
|
|
163
170
|
"react-dom": "^18.3.1",
|
|
164
171
|
"typescript": "^5",
|
|
165
|
-
"@
|
|
166
|
-
"@scripts/
|
|
167
|
-
"@scripts/jest-config": "2.65.0"
|
|
172
|
+
"@scripts/build": "2.65.2",
|
|
173
|
+
"@scripts/jest-config": "2.65.2"
|
|
168
174
|
},
|
|
169
175
|
"sideEffects": false,
|
|
170
176
|
"scripts": {
|