veryfront 0.0.81 → 0.0.82
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/esm/deno.js +1 -1
- package/esm/src/cache/backend.d.ts +20 -0
- package/esm/src/cache/backend.d.ts.map +1 -1
- package/esm/src/cache/backend.js +57 -0
- package/esm/src/cache/hash.d.ts +107 -0
- package/esm/src/cache/hash.d.ts.map +1 -0
- package/esm/src/cache/hash.js +166 -0
- package/esm/src/cache/index.d.ts +3 -0
- package/esm/src/cache/index.d.ts.map +1 -1
- package/esm/src/cache/index.js +3 -0
- package/esm/src/cache/module-cache.d.ts +82 -0
- package/esm/src/cache/module-cache.d.ts.map +1 -0
- package/esm/src/cache/module-cache.js +214 -0
- package/esm/src/cache/multi-tier.d.ts +177 -0
- package/esm/src/cache/multi-tier.d.ts.map +1 -0
- package/esm/src/cache/multi-tier.js +352 -0
- package/esm/src/cli/templates/integration-loader.d.ts.map +1 -1
- package/esm/src/cli/templates/integration-loader.js +2 -4
- package/esm/src/modules/react-loader/ssr-module-loader/loader.d.ts.map +1 -1
- package/esm/src/modules/react-loader/ssr-module-loader/loader.js +121 -14
- package/esm/src/observability/tracing/span-names.d.ts +2 -0
- package/esm/src/observability/tracing/span-names.d.ts.map +1 -1
- package/esm/src/observability/tracing/span-names.js +2 -0
- package/esm/src/rendering/orchestrator/module-loader/cache.d.ts +10 -2
- package/esm/src/rendering/orchestrator/module-loader/cache.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/cache.js +11 -6
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +72 -77
- package/esm/src/transforms/esm/http-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/http-cache.js +6 -29
- package/esm/src/transforms/esm/transform-cache.d.ts +25 -0
- package/esm/src/transforms/esm/transform-cache.d.ts.map +1 -1
- package/esm/src/transforms/esm/transform-cache.js +45 -0
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/index.js +2 -36
- package/esm/src/utils/constants/cache.d.ts +4 -0
- package/esm/src/utils/constants/cache.d.ts.map +1 -1
- package/esm/src/utils/constants/cache.js +14 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/cache/backend.ts +62 -0
- package/src/src/cache/hash.ts +205 -0
- package/src/src/cache/index.ts +3 -0
- package/src/src/cache/module-cache.ts +252 -0
- package/src/src/cache/multi-tier.ts +503 -0
- package/src/src/cli/templates/integration-loader.ts +2 -8
- package/src/src/modules/react-loader/ssr-module-loader/loader.ts +137 -18
- package/src/src/observability/tracing/span-names.ts +2 -0
- package/src/src/rendering/orchestrator/module-loader/cache.ts +14 -8
- package/src/src/rendering/orchestrator/module-loader/index.ts +94 -89
- package/src/src/transforms/esm/http-cache.ts +12 -32
- package/src/src/transforms/esm/transform-cache.ts +53 -0
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/index.ts +2 -40
- package/src/src/utils/constants/cache.ts +21 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standardized Cache Hashing Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent hashing for cache keys across the codebase.
|
|
5
|
+
* All cache keys should use these utilities to ensure:
|
|
6
|
+
* - Consistent format with type prefixes
|
|
7
|
+
* - Collision resistance between different cache types
|
|
8
|
+
* - Easy debugging and key parsing
|
|
9
|
+
*
|
|
10
|
+
* Key format: `{type}:{hash}` or `{type}:{version}:{hash}`
|
|
11
|
+
*
|
|
12
|
+
* @module cache/hash
|
|
13
|
+
*/
|
|
14
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
import { simpleHash } from "../utils/hash-utils.js";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Cache key types for different cache domains.
|
|
21
|
+
* Using type prefixes prevents collisions between different caches.
|
|
22
|
+
*/
|
|
23
|
+
export type CacheKeyType =
|
|
24
|
+
| "http" // HTTP module cache (esm.sh bundles)
|
|
25
|
+
| "mod" // Module transform cache
|
|
26
|
+
| "esm" // ESM resolution cache
|
|
27
|
+
| "render" // Render result cache
|
|
28
|
+
| "mdx" // MDX bundle cache
|
|
29
|
+
| "css" // CSS/Tailwind cache
|
|
30
|
+
| "file" // File content cache
|
|
31
|
+
| "config"; // Configuration cache
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Fast, synchronous hash function for cache keys.
|
|
35
|
+
*
|
|
36
|
+
* Uses DJB2 algorithm - good distribution, very fast.
|
|
37
|
+
* Returns a positive number suitable for string conversion.
|
|
38
|
+
*
|
|
39
|
+
* @param input - String to hash
|
|
40
|
+
* @returns Positive integer hash
|
|
41
|
+
*/
|
|
42
|
+
export function fastHash(input: string): number {
|
|
43
|
+
let hash = 5381;
|
|
44
|
+
|
|
45
|
+
for (let i = 0; i < input.length; i++) {
|
|
46
|
+
hash = ((hash << 5) + hash) ^ input.charCodeAt(i);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return hash >>> 0; // Convert to unsigned 32-bit
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Convert a hash number to a compact string representation.
|
|
54
|
+
*
|
|
55
|
+
* Uses base36 for compact output (0-9, a-z).
|
|
56
|
+
*/
|
|
57
|
+
export function hashToString(hash: number): string {
|
|
58
|
+
return hash.toString(36);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fast synchronous hash that returns a string.
|
|
63
|
+
*
|
|
64
|
+
* Combines fastHash + hashToString for convenience.
|
|
65
|
+
*/
|
|
66
|
+
export function hashString(input: string): string {
|
|
67
|
+
return hashToString(fastHash(input));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generate a cache key with type prefix.
|
|
72
|
+
*
|
|
73
|
+
* Format: `{type}:{hash}`
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* getCacheKey("http", "https://esm.sh/react@18.3.1")
|
|
78
|
+
* // Returns: "http:1abc2def"
|
|
79
|
+
*
|
|
80
|
+
* getCacheKey("mod", "pages/index.tsx")
|
|
81
|
+
* // Returns: "mod:xyz789"
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export function getCacheKey(type: CacheKeyType, input: string): string {
|
|
85
|
+
const hash = hashString(input);
|
|
86
|
+
return `${type}:${hash}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Generate a versioned cache key with type prefix.
|
|
91
|
+
*
|
|
92
|
+
* Format: `{type}:v{version}:{hash}`
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* getVersionedCacheKey("mod", 12, "pages/index.tsx:abc123")
|
|
97
|
+
* // Returns: "mod:v12:xyz789"
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function getVersionedCacheKey(
|
|
101
|
+
type: CacheKeyType,
|
|
102
|
+
version: number | string,
|
|
103
|
+
input: string,
|
|
104
|
+
): string {
|
|
105
|
+
const hash = hashString(input);
|
|
106
|
+
return `${type}:v${version}:${hash}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Generate a cache key with multiple components.
|
|
111
|
+
*
|
|
112
|
+
* Useful for keys that depend on multiple inputs.
|
|
113
|
+
* Components are joined with colons before hashing.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* getCompoundCacheKey("mod", ["projectId", "filePath", "contentHash"])
|
|
118
|
+
* // Returns: "mod:abc123"
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function getCompoundCacheKey(type: CacheKeyType, components: string[]): string {
|
|
122
|
+
const combined = components.join(":");
|
|
123
|
+
return getCacheKey(type, combined);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Parse a cache key into its components.
|
|
128
|
+
*
|
|
129
|
+
* @returns The type prefix and hash, or null if invalid format
|
|
130
|
+
*/
|
|
131
|
+
export function parseCacheKey(
|
|
132
|
+
key: string,
|
|
133
|
+
): { type: string; hash: string; version?: string } | null {
|
|
134
|
+
const parts = key.split(":");
|
|
135
|
+
|
|
136
|
+
if (parts.length < 2) return null;
|
|
137
|
+
|
|
138
|
+
const type = parts[0]!;
|
|
139
|
+
const rest = parts.slice(1);
|
|
140
|
+
|
|
141
|
+
// Check for version: type:vN:hash
|
|
142
|
+
if (rest[0]?.startsWith("v") && /^v\d+$/.test(rest[0])) {
|
|
143
|
+
return {
|
|
144
|
+
type,
|
|
145
|
+
version: rest[0].slice(1),
|
|
146
|
+
hash: rest.slice(1).join(":"),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
type,
|
|
152
|
+
hash: rest.join(":"),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* SHA-256 async hash for content-addressed keys.
|
|
158
|
+
*
|
|
159
|
+
* Use this when you need cryptographic strength (e.g., content hashes).
|
|
160
|
+
* For cache keys where speed matters more, use hashString().
|
|
161
|
+
*/
|
|
162
|
+
export async function sha256Hash(input: string): Promise<string> {
|
|
163
|
+
const data = new TextEncoder().encode(input);
|
|
164
|
+
const hashBuffer = await dntShim.crypto.subtle.digest("SHA-256", data);
|
|
165
|
+
return Array.from(new Uint8Array(hashBuffer))
|
|
166
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
167
|
+
.join("");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Short SHA-256 hash (8 characters).
|
|
172
|
+
*
|
|
173
|
+
* Good balance between collision resistance and key length.
|
|
174
|
+
*/
|
|
175
|
+
export async function sha256Short(input: string): Promise<string> {
|
|
176
|
+
const full = await sha256Hash(input);
|
|
177
|
+
return full.slice(0, 8);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Generate HTTP bundle filename from URL.
|
|
182
|
+
*
|
|
183
|
+
* Consistent with existing http-cache.ts format: `http-{hash}.mjs`
|
|
184
|
+
*/
|
|
185
|
+
export function getHttpBundleFilename(normalizedUrl: string): string {
|
|
186
|
+
const hash = simpleHash(normalizedUrl);
|
|
187
|
+
return `http-${hash}.mjs`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Extract hash from HTTP bundle filename.
|
|
192
|
+
*
|
|
193
|
+
* @returns The hash string, or null if not a valid bundle filename
|
|
194
|
+
*/
|
|
195
|
+
export function parseHttpBundleFilename(filename: string): string | null {
|
|
196
|
+
const match = filename.match(/^http-(\d+)\.mjs$/);
|
|
197
|
+
return match?.[1] ?? null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check if a value looks like a cache key.
|
|
202
|
+
*/
|
|
203
|
+
export function isCacheKey(value: string): boolean {
|
|
204
|
+
return /^[a-z]+:[a-z0-9]+/.test(value);
|
|
205
|
+
}
|
package/src/src/cache/index.ts
CHANGED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pod-Level Module Cache Singleton
|
|
3
|
+
*
|
|
4
|
+
* Provides shared module caches that persist across all RenderPipeline instances
|
|
5
|
+
* within a pod. This dramatically improves cache hit rates for unchanged modules
|
|
6
|
+
* compared to per-request caches.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - LRU eviction to bound memory usage
|
|
10
|
+
* - TTL-based expiration to pick up source changes
|
|
11
|
+
* - Automatic registration with cache registry for debugging
|
|
12
|
+
* - Project-scoped invalidation support
|
|
13
|
+
*
|
|
14
|
+
* @module cache/module-cache
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { LRUCache } from "../utils/lru-wrapper.js";
|
|
18
|
+
import { rendererLogger as logger } from "../utils/index.js";
|
|
19
|
+
import { registerLRUCache } from "./registry.js";
|
|
20
|
+
import {
|
|
21
|
+
ESM_CACHE_MAX_ENTRIES,
|
|
22
|
+
ESM_CACHE_TTL_MS,
|
|
23
|
+
MODULE_CACHE_MAX_ENTRIES,
|
|
24
|
+
MODULE_CACHE_TTL_MS,
|
|
25
|
+
} from "../utils/constants/cache.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Pod-level module cache singleton.
|
|
29
|
+
*
|
|
30
|
+
* Maps module cache keys to transformed temp file paths.
|
|
31
|
+
* Key format: `{projectId}:{filePath}`
|
|
32
|
+
*/
|
|
33
|
+
let moduleCache: LRUCache<string, string> | null = null;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Pod-level ESM cache singleton.
|
|
37
|
+
*
|
|
38
|
+
* Maps ESM specifiers to resolved URLs or file paths.
|
|
39
|
+
* Key format varies by usage.
|
|
40
|
+
*/
|
|
41
|
+
let esmCache: LRUCache<string, string> | null = null;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Cache statistics for monitoring.
|
|
45
|
+
*/
|
|
46
|
+
interface ModuleCacheStats {
|
|
47
|
+
moduleCache: {
|
|
48
|
+
size: number;
|
|
49
|
+
maxEntries: number;
|
|
50
|
+
ttlMs: number;
|
|
51
|
+
};
|
|
52
|
+
esmCache: {
|
|
53
|
+
size: number;
|
|
54
|
+
maxEntries: number;
|
|
55
|
+
ttlMs: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get or create the pod-level module cache.
|
|
61
|
+
*
|
|
62
|
+
* The cache is created lazily on first access and persists for the pod's lifetime.
|
|
63
|
+
* Uses LRU eviction and TTL-based expiration.
|
|
64
|
+
*/
|
|
65
|
+
export function getModuleCache(): LRUCache<string, string> {
|
|
66
|
+
if (!moduleCache) {
|
|
67
|
+
moduleCache = new LRUCache<string, string>({
|
|
68
|
+
maxEntries: MODULE_CACHE_MAX_ENTRIES,
|
|
69
|
+
ttlMs: MODULE_CACHE_TTL_MS,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Register with cache registry for debugging and invalidation
|
|
73
|
+
registerLRUCache("pod-module-cache", moduleCache);
|
|
74
|
+
|
|
75
|
+
logger.info("[ModuleCache] Pod-level module cache initialized", {
|
|
76
|
+
maxEntries: MODULE_CACHE_MAX_ENTRIES,
|
|
77
|
+
ttlMs: MODULE_CACHE_TTL_MS,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return moduleCache;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get or create the pod-level ESM cache.
|
|
85
|
+
*
|
|
86
|
+
* Used for caching ESM resolution results (specifier → URL mappings).
|
|
87
|
+
*/
|
|
88
|
+
export function getEsmCache(): LRUCache<string, string> {
|
|
89
|
+
if (!esmCache) {
|
|
90
|
+
esmCache = new LRUCache<string, string>({
|
|
91
|
+
maxEntries: ESM_CACHE_MAX_ENTRIES,
|
|
92
|
+
ttlMs: ESM_CACHE_TTL_MS,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Register with cache registry for debugging and invalidation
|
|
96
|
+
registerLRUCache("pod-esm-cache", esmCache);
|
|
97
|
+
|
|
98
|
+
logger.info("[ModuleCache] Pod-level ESM cache initialized", {
|
|
99
|
+
maxEntries: ESM_CACHE_MAX_ENTRIES,
|
|
100
|
+
ttlMs: ESM_CACHE_TTL_MS,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return esmCache;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Create a Map-compatible interface for the module cache.
|
|
108
|
+
*
|
|
109
|
+
* This provides backward compatibility with code expecting Map<string, string>.
|
|
110
|
+
* The underlying storage is the pod-level LRU cache singleton.
|
|
111
|
+
*/
|
|
112
|
+
export function createModuleCache(): Map<string, string> {
|
|
113
|
+
const cache = getModuleCache();
|
|
114
|
+
return createMapInterface(cache);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create a Map-compatible interface for the ESM cache.
|
|
119
|
+
*
|
|
120
|
+
* This provides backward compatibility with code expecting Map<string, string>.
|
|
121
|
+
*/
|
|
122
|
+
export function createEsmCache(): Map<string, string> {
|
|
123
|
+
const cache = getEsmCache();
|
|
124
|
+
return createMapInterface(cache);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a Map-compatible interface backed by an LRU cache.
|
|
129
|
+
*/
|
|
130
|
+
function createMapInterface(cache: LRUCache<string, string>): Map<string, string> {
|
|
131
|
+
// Create a proxy that delegates to the LRU cache
|
|
132
|
+
// This allows existing code expecting Map to work unchanged
|
|
133
|
+
return {
|
|
134
|
+
get(key: string): string | undefined {
|
|
135
|
+
return cache.get(key);
|
|
136
|
+
},
|
|
137
|
+
set(key: string, value: string): Map<string, string> {
|
|
138
|
+
cache.set(key, value);
|
|
139
|
+
return this;
|
|
140
|
+
},
|
|
141
|
+
has(key: string): boolean {
|
|
142
|
+
return cache.has(key);
|
|
143
|
+
},
|
|
144
|
+
delete(key: string): boolean {
|
|
145
|
+
return cache.delete(key);
|
|
146
|
+
},
|
|
147
|
+
clear(): void {
|
|
148
|
+
cache.clear();
|
|
149
|
+
},
|
|
150
|
+
get size(): number {
|
|
151
|
+
return cache.size;
|
|
152
|
+
},
|
|
153
|
+
// Required Map methods that iterate - these work but may be expensive
|
|
154
|
+
*keys(): IterableIterator<string> {
|
|
155
|
+
yield* cache.keys();
|
|
156
|
+
},
|
|
157
|
+
*values(): IterableIterator<string> {
|
|
158
|
+
for (const key of cache.keys()) {
|
|
159
|
+
const value = cache.get(key);
|
|
160
|
+
if (value !== undefined) yield value;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
*entries(): IterableIterator<[string, string]> {
|
|
164
|
+
for (const key of cache.keys()) {
|
|
165
|
+
const value = cache.get(key);
|
|
166
|
+
if (value !== undefined) yield [key, value];
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
forEach(callback: (value: string, key: string, map: Map<string, string>) => void): void {
|
|
170
|
+
for (const key of cache.keys()) {
|
|
171
|
+
const value = cache.get(key);
|
|
172
|
+
if (value !== undefined) callback(value, key, this);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
[Symbol.iterator](): IterableIterator<[string, string]> {
|
|
176
|
+
return this.entries();
|
|
177
|
+
},
|
|
178
|
+
[Symbol.toStringTag]: "Map",
|
|
179
|
+
} as Map<string, string>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get statistics about the module caches.
|
|
184
|
+
*/
|
|
185
|
+
export function getModuleCacheStats(): ModuleCacheStats {
|
|
186
|
+
return {
|
|
187
|
+
moduleCache: {
|
|
188
|
+
size: moduleCache?.size ?? 0,
|
|
189
|
+
maxEntries: MODULE_CACHE_MAX_ENTRIES,
|
|
190
|
+
ttlMs: MODULE_CACHE_TTL_MS,
|
|
191
|
+
},
|
|
192
|
+
esmCache: {
|
|
193
|
+
size: esmCache?.size ?? 0,
|
|
194
|
+
maxEntries: ESM_CACHE_MAX_ENTRIES,
|
|
195
|
+
ttlMs: ESM_CACHE_TTL_MS,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Clear all module caches.
|
|
202
|
+
*
|
|
203
|
+
* Used for invalidation when project content changes.
|
|
204
|
+
*/
|
|
205
|
+
export function clearModuleCaches(): void {
|
|
206
|
+
moduleCache?.clear();
|
|
207
|
+
esmCache?.clear();
|
|
208
|
+
logger.info("[ModuleCache] All module caches cleared");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Clear module cache entries for a specific project.
|
|
213
|
+
*
|
|
214
|
+
* @param projectId - The project ID to clear entries for
|
|
215
|
+
* @returns Number of entries cleared
|
|
216
|
+
*/
|
|
217
|
+
export function clearModuleCacheForProject(projectId: string): number {
|
|
218
|
+
if (!moduleCache) return 0;
|
|
219
|
+
|
|
220
|
+
let cleared = 0;
|
|
221
|
+
const keysToDelete: string[] = [];
|
|
222
|
+
|
|
223
|
+
for (const key of moduleCache.keys()) {
|
|
224
|
+
if (key.startsWith(`${projectId}:`)) {
|
|
225
|
+
keysToDelete.push(key);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const key of keysToDelete) {
|
|
230
|
+
moduleCache.delete(key);
|
|
231
|
+
cleared++;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (cleared > 0) {
|
|
235
|
+
logger.info("[ModuleCache] Cleared module cache for project", { projectId, cleared });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return cleared;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Destroy the module caches and cleanup resources.
|
|
243
|
+
*
|
|
244
|
+
* Should be called on server shutdown.
|
|
245
|
+
*/
|
|
246
|
+
export function destroyModuleCaches(): void {
|
|
247
|
+
moduleCache?.destroy();
|
|
248
|
+
esmCache?.destroy();
|
|
249
|
+
moduleCache = null;
|
|
250
|
+
esmCache = null;
|
|
251
|
+
logger.info("[ModuleCache] Module caches destroyed");
|
|
252
|
+
}
|