@vizamodo/edge-cache-core 0.3.26 → 0.3.28
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/runtime/cache.d.ts +29 -4
- package/dist/runtime/cache.js +50 -11
- package/package.json +1 -1
package/dist/runtime/cache.d.ts
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
type
|
|
2
|
-
ttlSec
|
|
1
|
+
export type CacheOptions = {
|
|
2
|
+
ttlSec: number;
|
|
3
3
|
forceRefresh?: boolean;
|
|
4
4
|
};
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Wrap a fetcher result to override the TTL via an absolute expiry timestamp.
|
|
7
|
+
* Use this when the upstream API tells you exactly when the data expires
|
|
8
|
+
* (e.g. OAuth token expiresAt, CDN Cache-Control, etc.).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* fetcher: async () => {
|
|
12
|
+
* const token = await getToken();
|
|
13
|
+
* return wrapResult(token.accessToken, token.expiresAt); // ISO string
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
export type WrappedResult<T> = {
|
|
17
|
+
readonly __wrapped: true;
|
|
18
|
+
readonly value: T;
|
|
19
|
+
readonly expiresAt?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function wrapResult<T>(value: T, expiresAt?: string): WrappedResult<T>;
|
|
22
|
+
/**
|
|
23
|
+
* Two-level cache: L1 in-memory → L2 edge → L3 fetcher.
|
|
24
|
+
*
|
|
25
|
+
* - ttlSec: edge cache TTL in seconds (REQUIRED). Pass 0 to skip edge write.
|
|
26
|
+
* - forceRefresh: skips L1 + L2, always calls the fetcher and writes back.
|
|
27
|
+
* - WrappedResult: return wrapResult(value, expiresAt) from fetcher to override TTL
|
|
28
|
+
* with an absolute expiry from the upstream source.
|
|
29
|
+
* - Edge and memory write failures are non-fatal and will not throw.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getCachedOrFetch<T>(key: string, fetcher: () => Promise<T | WrappedResult<T>>, options: CacheOptions): Promise<T>;
|
package/dist/runtime/cache.js
CHANGED
|
@@ -1,22 +1,61 @@
|
|
|
1
1
|
import { getEdgeCache, setEdgeCache } from "./edge-cache";
|
|
2
2
|
const memory = new Map();
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export function wrapResult(value, expiresAt) {
|
|
4
|
+
return { __wrapped: true, value, expiresAt };
|
|
5
|
+
}
|
|
6
|
+
// ─── Internals ─────────────────────────────────────────────────────────────
|
|
7
|
+
const TTL_BUFFER_SEC = 300; // 5-minute safety buffer
|
|
8
|
+
const TTL_MIN_SEC = 60; // never cache for less than 1 minute
|
|
9
|
+
function isWrapped(result) {
|
|
10
|
+
return (typeof result === "object" &&
|
|
11
|
+
result !== null &&
|
|
12
|
+
result.__wrapped === true);
|
|
13
|
+
}
|
|
14
|
+
function ttlFromExpiresAt(expiresAt) {
|
|
15
|
+
const ms = new Date(expiresAt).getTime();
|
|
16
|
+
if (Number.isNaN(ms)) {
|
|
17
|
+
return TTL_MIN_SEC; // fallback safe
|
|
7
18
|
}
|
|
8
|
-
|
|
9
|
-
|
|
19
|
+
const ttl = Math.floor((ms - Date.now()) / 1000) - TTL_BUFFER_SEC;
|
|
20
|
+
return Math.max(ttl, TTL_MIN_SEC);
|
|
21
|
+
}
|
|
22
|
+
// ─── Main ──────────────────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Two-level cache: L1 in-memory → L2 edge → L3 fetcher.
|
|
25
|
+
*
|
|
26
|
+
* - ttlSec: edge cache TTL in seconds (REQUIRED). Pass 0 to skip edge write.
|
|
27
|
+
* - forceRefresh: skips L1 + L2, always calls the fetcher and writes back.
|
|
28
|
+
* - WrappedResult: return wrapResult(value, expiresAt) from fetcher to override TTL
|
|
29
|
+
* with an absolute expiry from the upstream source.
|
|
30
|
+
* - Edge and memory write failures are non-fatal and will not throw.
|
|
31
|
+
*/
|
|
32
|
+
export async function getCachedOrFetch(key, fetcher, options) {
|
|
33
|
+
const { forceRefresh = false, ttlSec } = options;
|
|
34
|
+
if (!forceRefresh) {
|
|
35
|
+
// L1: memory
|
|
36
|
+
if (memory.has(key)) {
|
|
37
|
+
return memory.get(key);
|
|
38
|
+
}
|
|
39
|
+
// L2: edge cache
|
|
10
40
|
const edge = await getEdgeCache(key);
|
|
11
|
-
if (edge) {
|
|
41
|
+
if (edge !== null) {
|
|
12
42
|
memory.set(key, edge);
|
|
13
43
|
return edge;
|
|
14
44
|
}
|
|
15
45
|
}
|
|
16
|
-
// L3: fetch
|
|
17
|
-
const
|
|
18
|
-
|
|
46
|
+
// L3: fetch from source
|
|
47
|
+
const result = await fetcher();
|
|
48
|
+
const value = isWrapped(result) ? result.value : result;
|
|
49
|
+
const finalTtl = isWrapped(result) && result.expiresAt
|
|
50
|
+
? ttlFromExpiresAt(result.expiresAt)
|
|
51
|
+
: ttlSec;
|
|
52
|
+
// Write back to both layers — edge write is best-effort
|
|
19
53
|
memory.set(key, value);
|
|
20
|
-
|
|
54
|
+
try {
|
|
55
|
+
await setEdgeCache(key, value, finalTtl);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// non-fatal
|
|
59
|
+
}
|
|
21
60
|
return value;
|
|
22
61
|
}
|