@brutalist/mcp 0.6.0 → 0.6.1
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/README.md +3 -1
- package/dist/brutalist-server.d.ts +5 -0
- package/dist/brutalist-server.d.ts.map +1 -1
- package/dist/brutalist-server.js +244 -80
- package/dist/brutalist-server.js.map +1 -1
- package/dist/cli-agents.d.ts +7 -3
- package/dist/cli-agents.d.ts.map +1 -1
- package/dist/cli-agents.js +307 -48
- package/dist/cli-agents.js.map +1 -1
- package/dist/streaming/circuit-breaker.d.ts +186 -0
- package/dist/streaming/circuit-breaker.d.ts.map +1 -0
- package/dist/streaming/circuit-breaker.js +463 -0
- package/dist/streaming/circuit-breaker.js.map +1 -0
- package/dist/streaming/intelligent-buffer.d.ts +141 -0
- package/dist/streaming/intelligent-buffer.d.ts.map +1 -0
- package/dist/streaming/intelligent-buffer.js +555 -0
- package/dist/streaming/intelligent-buffer.js.map +1 -0
- package/dist/streaming/output-parser.d.ts +89 -0
- package/dist/streaming/output-parser.d.ts.map +1 -0
- package/dist/streaming/output-parser.js +349 -0
- package/dist/streaming/output-parser.js.map +1 -0
- package/dist/streaming/progress-tracker.d.ts +149 -0
- package/dist/streaming/progress-tracker.d.ts.map +1 -0
- package/dist/streaming/progress-tracker.js +519 -0
- package/dist/streaming/progress-tracker.js.map +1 -0
- package/dist/streaming/session-manager.d.ts +238 -0
- package/dist/streaming/session-manager.d.ts.map +1 -0
- package/dist/streaming/session-manager.js +546 -0
- package/dist/streaming/session-manager.js.map +1 -0
- package/dist/streaming/sse-transport.d.ts +95 -0
- package/dist/streaming/sse-transport.d.ts.map +1 -0
- package/dist/streaming/sse-transport.js +319 -0
- package/dist/streaming/sse-transport.js.map +1 -0
- package/dist/streaming/streaming-orchestrator.d.ts +153 -0
- package/dist/streaming/streaming-orchestrator.d.ts.map +1 -0
- package/dist/streaming/streaming-orchestrator.js +436 -0
- package/dist/streaming/streaming-orchestrator.js.map +1 -0
- package/dist/test-utils/process-manager.d.ts +61 -0
- package/dist/test-utils/process-manager.d.ts.map +1 -0
- package/dist/test-utils/process-manager.js +262 -0
- package/dist/test-utils/process-manager.js.map +1 -0
- package/dist/test-utils/server-harness.d.ts +73 -0
- package/dist/test-utils/server-harness.d.ts.map +1 -0
- package/dist/test-utils/server-harness.js +296 -0
- package/dist/test-utils/server-harness.js.map +1 -0
- package/dist/test-utils/streaming-fuzz.d.ts +57 -0
- package/dist/test-utils/streaming-fuzz.d.ts.map +1 -0
- package/dist/test-utils/streaming-fuzz.js +287 -0
- package/dist/test-utils/streaming-fuzz.js.map +1 -0
- package/dist/test-utils/test-isolation.d.ts +70 -0
- package/dist/test-utils/test-isolation.d.ts.map +1 -0
- package/dist/test-utils/test-isolation.js +193 -0
- package/dist/test-utils/test-isolation.js.map +1 -0
- package/dist/tool-definitions.d.ts.map +1 -1
- package/dist/tool-definitions.js +12 -6
- package/dist/tool-definitions.js.map +1 -1
- package/dist/types/brutalist.d.ts +3 -3
- package/dist/types/brutalist.d.ts.map +1 -1
- package/dist/types/tool-config.d.ts +0 -1
- package/dist/types/tool-config.d.ts.map +1 -1
- package/dist/types/tool-config.js +0 -1
- package/dist/types/tool-config.js.map +1 -1
- package/dist/utils/response-cache.d.ts +14 -7
- package/dist/utils/response-cache.d.ts.map +1 -1
- package/dist/utils/response-cache.js +173 -62
- package/dist/utils/response-cache.js.map +1 -1
- package/package.json +13 -3
package/dist/tool-definitions.js
CHANGED
|
@@ -73,10 +73,11 @@ export const TOOL_CONFIGS = [
|
|
|
73
73
|
systemPrompt: "You are a brutal reality-checker who has watched a thousand startups die and brilliant ideas fail. Find every flaw in feasibility, every market delusion, every technical impossibility, every human factor that will kill this idea. After destroying it, grudgingly admit what tiny kernel might actually work.",
|
|
74
74
|
schemaExtensions: {
|
|
75
75
|
idea: z.string().describe("ANY idea to analyze and demolish - business, technical, creative, or otherwise"),
|
|
76
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
76
77
|
resources: z.string().optional().describe("Available resources (budget, team, time, skills)"),
|
|
77
78
|
timeline: z.string().optional().describe("Expected timeline or deadline")
|
|
78
79
|
},
|
|
79
|
-
cacheKeyFields: ['idea', 'resources', 'timeline', 'context'],
|
|
80
|
+
cacheKeyFields: ['idea', 'targetPath', 'resources', 'timeline', 'context'],
|
|
80
81
|
primaryArgField: 'idea',
|
|
81
82
|
contextBuilder: (args) => {
|
|
82
83
|
let ctx = args.context || '';
|
|
@@ -94,11 +95,12 @@ export const TOOL_CONFIGS = [
|
|
|
94
95
|
systemPrompt: "You are an architect who has watched beautiful systems die under load. Find every single point of failure, every scaling bottleneck, every cost explosion, every complexity trap. Explain why this architecture will crumble when it meets reality.",
|
|
95
96
|
schemaExtensions: {
|
|
96
97
|
architecture: z.string().describe("Architecture description, diagram, or design document"),
|
|
98
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
97
99
|
scale: z.string().optional().describe("Expected scale/load (users, requests, data)"),
|
|
98
100
|
constraints: z.string().optional().describe("Budget, timeline, or technical constraints"),
|
|
99
101
|
deployment: z.string().optional().describe("Deployment environment and strategy")
|
|
100
102
|
},
|
|
101
|
-
cacheKeyFields: ['architecture', 'scale', 'constraints', 'deployment', 'context'],
|
|
103
|
+
cacheKeyFields: ['architecture', 'targetPath', 'scale', 'constraints', 'deployment', 'context'],
|
|
102
104
|
primaryArgField: 'architecture',
|
|
103
105
|
contextBuilder: (args) => {
|
|
104
106
|
let ctx = args.context || '';
|
|
@@ -118,11 +120,12 @@ export const TOOL_CONFIGS = [
|
|
|
118
120
|
systemPrompt: "You are the harshest peer reviewer in academia. Find every methodological flaw, every statistical error, every sampling bias, every p-hacking attempt, every reproducibility crisis waiting to happen. Demolish this research with the fury of someone who has seen too much bad science.",
|
|
119
121
|
schemaExtensions: {
|
|
120
122
|
research: z.string().describe("Research description, methodology, or paper draft"),
|
|
123
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
121
124
|
field: z.string().optional().describe("Research field (ML, systems, theory, etc.)"),
|
|
122
125
|
claims: z.string().optional().describe("Main claims or contributions"),
|
|
123
126
|
data: z.string().optional().describe("Data sources, datasets, or experimental setup")
|
|
124
127
|
},
|
|
125
|
-
cacheKeyFields: ['research', 'field', 'claims', 'data', 'context'],
|
|
128
|
+
cacheKeyFields: ['research', 'targetPath', 'field', 'claims', 'data', 'context'],
|
|
126
129
|
primaryArgField: 'research',
|
|
127
130
|
contextBuilder: (args) => {
|
|
128
131
|
let ctx = args.context || '';
|
|
@@ -142,11 +145,12 @@ export const TOOL_CONFIGS = [
|
|
|
142
145
|
systemPrompt: "You are a penetration tester who has broken into everything. Find every authentication weakness, every injection point, every privilege escalation, every side channel, every social engineering vector. Explain how attackers will destroy this system.",
|
|
143
146
|
schemaExtensions: {
|
|
144
147
|
system: z.string().describe("System, application, or security design to analyze"),
|
|
148
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
145
149
|
assets: z.string().optional().describe("Critical assets or data to protect"),
|
|
146
150
|
threatModel: z.string().optional().describe("Known threats or attack vectors to consider"),
|
|
147
151
|
compliance: z.string().optional().describe("Compliance requirements (GDPR, HIPAA, etc.)")
|
|
148
152
|
},
|
|
149
|
-
cacheKeyFields: ['system', 'assets', 'threatModel', 'compliance', 'context'],
|
|
153
|
+
cacheKeyFields: ['system', 'targetPath', 'assets', 'threatModel', 'compliance', 'context'],
|
|
150
154
|
primaryArgField: 'system',
|
|
151
155
|
contextBuilder: (args) => {
|
|
152
156
|
let ctx = args.context || '';
|
|
@@ -166,11 +170,12 @@ export const TOOL_CONFIGS = [
|
|
|
166
170
|
systemPrompt: "You are a product critic who has watched thousands of products die. Find every UX disaster, every adoption barrier, every workflow failure, every assumption about user behavior that is wrong. Explain why users will abandon this in seconds.",
|
|
167
171
|
schemaExtensions: {
|
|
168
172
|
product: z.string().describe("Product description, features, or user experience to analyze"),
|
|
173
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
169
174
|
users: z.string().optional().describe("Target users or user personas"),
|
|
170
175
|
competition: z.string().optional().describe("Competitive landscape or alternatives"),
|
|
171
176
|
metrics: z.string().optional().describe("Success metrics or KPIs")
|
|
172
177
|
},
|
|
173
|
-
cacheKeyFields: ['product', 'users', 'competition', 'metrics', 'context'],
|
|
178
|
+
cacheKeyFields: ['product', 'targetPath', 'users', 'competition', 'metrics', 'context'],
|
|
174
179
|
primaryArgField: 'product',
|
|
175
180
|
contextBuilder: (args) => {
|
|
176
181
|
let ctx = args.context || '';
|
|
@@ -190,11 +195,12 @@ export const TOOL_CONFIGS = [
|
|
|
190
195
|
systemPrompt: "You are an SRE who has been paged at 3 AM too many times. Find every single point of failure, every missing redundancy, every scaling cliff, every operational nightmare. Explain why this infrastructure will fail catastrophically.",
|
|
191
196
|
schemaExtensions: {
|
|
192
197
|
infrastructure: z.string().describe("Infrastructure setup, deployment strategy, or operations plan"),
|
|
198
|
+
targetPath: z.string().describe("Directory context for CLI execution (can be '.' for current directory)"),
|
|
193
199
|
scale: z.string().optional().describe("Expected scale and load patterns"),
|
|
194
200
|
sla: z.string().optional().describe("SLA requirements or uptime targets"),
|
|
195
201
|
budget: z.string().optional().describe("Infrastructure budget or cost constraints")
|
|
196
202
|
},
|
|
197
|
-
cacheKeyFields: ['infrastructure', 'scale', 'sla', 'budget', 'context'],
|
|
203
|
+
cacheKeyFields: ['infrastructure', 'targetPath', 'scale', 'sla', 'budget', 'context'],
|
|
198
204
|
primaryArgField: 'infrastructure',
|
|
199
205
|
contextBuilder: (args) => {
|
|
200
206
|
let ctx = args.context || '';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-definitions.js","sourceRoot":"","sources":["../src/tool-definitions.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tool-definitions.js","sourceRoot":"","sources":["../src/tool-definitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
export interface BrutalistServerConfig {
|
|
2
2
|
workingDirectory?: string;
|
|
3
3
|
defaultTimeout?: number;
|
|
4
|
-
enableSandbox?: boolean;
|
|
5
4
|
transport?: 'stdio' | 'http';
|
|
6
5
|
httpPort?: number;
|
|
6
|
+
corsOrigins?: string[];
|
|
7
|
+
allowCORSWildcard?: boolean;
|
|
7
8
|
}
|
|
8
9
|
export interface CLIAgentResponse {
|
|
9
10
|
agent: 'claude' | 'codex' | 'gemini';
|
|
10
11
|
success: boolean;
|
|
11
|
-
output
|
|
12
|
+
output?: string;
|
|
12
13
|
error?: string;
|
|
13
14
|
executionTime: number;
|
|
14
15
|
command?: string;
|
|
@@ -21,7 +22,6 @@ export interface RoastOptions {
|
|
|
21
22
|
analysisType: string;
|
|
22
23
|
context?: string;
|
|
23
24
|
workingDirectory?: string;
|
|
24
|
-
enableSandbox?: boolean;
|
|
25
25
|
agents?: ('claude' | 'codex' | 'gemini')[];
|
|
26
26
|
}
|
|
27
27
|
export interface ChildProcessError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brutalist.d.ts","sourceRoot":"","sources":["../../src/types/brutalist.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,
|
|
1
|
+
{"version":3,"file":"brutalist.d.ts","sourceRoot":"","sources":["../../src/types/brutalist.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,7 +27,6 @@ export interface ToolConfig {
|
|
|
27
27
|
export declare const BASE_ROAST_SCHEMA: {
|
|
28
28
|
context: z.ZodOptional<z.ZodString>;
|
|
29
29
|
workingDirectory: z.ZodOptional<z.ZodString>;
|
|
30
|
-
enableSandbox: z.ZodOptional<z.ZodBoolean>;
|
|
31
30
|
preferredCLI: z.ZodOptional<z.ZodEnum<["claude", "codex", "gemini"]>>;
|
|
32
31
|
verbose: z.ZodOptional<z.ZodBoolean>;
|
|
33
32
|
models: z.ZodOptional<z.ZodObject<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-config.d.ts","sourceRoot":"","sources":["../../src/types/tool-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IAEb,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IAEpB,yCAAyC;IACzC,YAAY,EAAE,mBAAmB,CAAC;IAElC,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IAErB,6DAA6D;IAC7D,gBAAgB,EAAE,WAAW,CAAC;IAE9B,gDAAgD;IAChD,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;IAEvC,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"tool-config.d.ts","sourceRoot":"","sources":["../../src/types/tool-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IAEb,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IAEpB,yCAAyC;IACzC,YAAY,EAAE,mBAAmB,CAAC;IAElC,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IAErB,6DAA6D;IAC7D,gBAAgB,EAAE,WAAW,CAAC;IAE9B,gDAAgD;IAChD,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,MAAM,CAAC;IAEvC,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;CAoB7B,CAAC"}
|
|
@@ -6,7 +6,6 @@ export const BASE_ROAST_SCHEMA = {
|
|
|
6
6
|
// Context and execution parameters
|
|
7
7
|
context: z.string().optional().describe("Additional context about the analysis"),
|
|
8
8
|
workingDirectory: z.string().optional().describe("Working directory to execute from"),
|
|
9
|
-
enableSandbox: z.boolean().optional().describe("Enable sandbox mode for safe analysis (default: true)"),
|
|
10
9
|
preferredCLI: z.enum(["claude", "codex", "gemini"]).optional().describe("Preferred CLI agent to use (default: use all available CLIs)"),
|
|
11
10
|
verbose: z.boolean().optional().describe("Include detailed execution information in output (default: false)"),
|
|
12
11
|
// Model selection
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-config.js","sourceRoot":"","sources":["../../src/types/tool-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAe,MAAM,KAAK,CAAC;AAgCrC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,mCAAmC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAChF,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IACrF,
|
|
1
|
+
{"version":3,"file":"tool-config.js","sourceRoot":"","sources":["../../src/types/tool-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAe,MAAM,KAAK,CAAC;AAgCrC;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,mCAAmC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;IAChF,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;IACrF,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;IACvI,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;IAE7G,kBAAkB;IAClB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;QAChH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;QACtG,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,uBAAuB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KACpH,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IAEnE,4CAA4C;IAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;IACtG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC;IAClI,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;IAChH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;IAC3G,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;CAClH,CAAC"}
|
|
@@ -6,6 +6,8 @@ export interface CachedResponse {
|
|
|
6
6
|
requestParams: Record<string, unknown>;
|
|
7
7
|
compressed: boolean;
|
|
8
8
|
size: number;
|
|
9
|
+
sessionId?: string;
|
|
10
|
+
requestId?: string;
|
|
9
11
|
}
|
|
10
12
|
export interface CacheStats {
|
|
11
13
|
entries: number;
|
|
@@ -18,7 +20,8 @@ export interface CacheStats {
|
|
|
18
20
|
* LRU Response Cache with TTL and memory management
|
|
19
21
|
*/
|
|
20
22
|
export declare class ResponseCache {
|
|
21
|
-
private
|
|
23
|
+
private entries;
|
|
24
|
+
private analysisIdMap;
|
|
22
25
|
private accessOrder;
|
|
23
26
|
private stats;
|
|
24
27
|
private readonly maxEntries;
|
|
@@ -39,20 +42,20 @@ export declare class ResponseCache {
|
|
|
39
42
|
*/
|
|
40
43
|
generateCacheKey(params: Record<string, unknown>): string;
|
|
41
44
|
/**
|
|
42
|
-
* Generate
|
|
45
|
+
* Generate secure analysis ID (UUID instead of 8-char hash)
|
|
43
46
|
*/
|
|
44
47
|
generateAnalysisId(cacheKey: string): string;
|
|
45
48
|
/**
|
|
46
|
-
* Store response
|
|
49
|
+
* Store response with session binding
|
|
47
50
|
*/
|
|
48
|
-
set(
|
|
49
|
-
cacheKey: string;
|
|
51
|
+
set(data: Record<string, any>, content: string, cacheKey?: string, sessionId?: string, requestId?: string): Promise<{
|
|
50
52
|
analysisId: string;
|
|
53
|
+
cacheKey: string;
|
|
51
54
|
}>;
|
|
52
55
|
/**
|
|
53
|
-
* Retrieve response
|
|
56
|
+
* Retrieve response with session validation
|
|
54
57
|
*/
|
|
55
|
-
get(
|
|
58
|
+
get(analysisIdOrCacheKey: string, sessionId?: string): Promise<string | null>;
|
|
56
59
|
/**
|
|
57
60
|
* Check if key exists in cache
|
|
58
61
|
*/
|
|
@@ -77,6 +80,10 @@ export declare class ResponseCache {
|
|
|
77
80
|
* Get cache statistics
|
|
78
81
|
*/
|
|
79
82
|
getStats(): CacheStats;
|
|
83
|
+
/**
|
|
84
|
+
* Retrieve response by analysis ID, returning full cached response object
|
|
85
|
+
*/
|
|
86
|
+
getByAnalysisId(analysisId: string, sessionId?: string): Promise<CachedResponse | null>;
|
|
80
87
|
/**
|
|
81
88
|
* Clear entire cache
|
|
82
89
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/utils/response-cache.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/utils/response-cache.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAqBD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,aAAa,CAAwC;IAC7D,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,KAAK,CAMX;IAGF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,YAAY,CAAC,CAAiB;gBAE1B,OAAO,GAAE;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,sBAAsB,CAAC,EAAE,MAAM,CAAC;KAC5B;IAsBN;;OAEG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAgBzD;;OAEG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5C;;OAEG;IACG,GAAG,CACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAkEpD;;OAEG;IACG,GAAG,CAAC,oBAAoB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAuEnF;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAkB7B;;OAEG;IACH,OAAO,CAAC,MAAM;IAoBd;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;OAEG;YACW,cAAc;IAoB5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;OAEG;IACH,QAAQ,IAAI,UAAU;IAItB;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IA+D7F;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
1
|
+
import { createHash, randomUUID } from 'crypto';
|
|
2
2
|
import { gzip, gunzip } from 'zlib';
|
|
3
3
|
import { promisify } from 'util';
|
|
4
4
|
import { logger } from '../logger.js';
|
|
@@ -8,7 +8,8 @@ const gunzipAsync = promisify(gunzip);
|
|
|
8
8
|
* LRU Response Cache with TTL and memory management
|
|
9
9
|
*/
|
|
10
10
|
export class ResponseCache {
|
|
11
|
-
|
|
11
|
+
entries = new Map();
|
|
12
|
+
analysisIdMap = new Map(); // NEW: ID to cache mapping
|
|
12
13
|
accessOrder = [];
|
|
13
14
|
stats = {
|
|
14
15
|
entries: 0,
|
|
@@ -61,101 +62,145 @@ export class ResponseCache {
|
|
|
61
62
|
return hash;
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
64
|
-
* Generate
|
|
65
|
+
* Generate secure analysis ID (UUID instead of 8-char hash)
|
|
65
66
|
*/
|
|
66
67
|
generateAnalysisId(cacheKey) {
|
|
67
|
-
return
|
|
68
|
+
return randomUUID(); // Full UUID for security
|
|
68
69
|
}
|
|
69
70
|
/**
|
|
70
|
-
* Store response
|
|
71
|
+
* Store response with session binding
|
|
71
72
|
*/
|
|
72
|
-
async set(
|
|
73
|
-
const
|
|
74
|
-
const analysisId = this.generateAnalysisId(
|
|
75
|
-
// Check
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
logger.warn(`⚠️ Response too large for cache: ${sizeMB.toFixed(2)}MB > ${this.maxEntrySizeMB}MB`);
|
|
80
|
-
return { cacheKey, analysisId };
|
|
73
|
+
async set(data, content, cacheKey, sessionId, requestId) {
|
|
74
|
+
const finalCacheKey = cacheKey || this.generateCacheKey(data);
|
|
75
|
+
const analysisId = this.generateAnalysisId(finalCacheKey);
|
|
76
|
+
// Check size limits before compression
|
|
77
|
+
const sizeInMB = Buffer.byteLength(content, 'utf8') / (1024 * 1024);
|
|
78
|
+
if (sizeInMB > this.maxEntrySizeMB) {
|
|
79
|
+
throw new Error(`Response too large: ${sizeInMB.toFixed(2)}MB > ${this.maxEntrySizeMB}MB limit`);
|
|
81
80
|
}
|
|
82
81
|
// Compress if needed
|
|
83
82
|
let finalContent = content;
|
|
84
83
|
let compressed = false;
|
|
85
|
-
if (
|
|
84
|
+
if (sizeInMB > this.compressionThresholdMB) {
|
|
86
85
|
try {
|
|
87
|
-
const compressedBuffer = await gzipAsync(Buffer.from(content, '
|
|
88
|
-
const compressedSize = compressedBuffer.length / (1024 * 1024);
|
|
89
|
-
logger.info(`🗜️ Compressed response: ${sizeMB.toFixed(2)}MB → ${compressedSize.toFixed(2)}MB`);
|
|
86
|
+
const compressedBuffer = await gzipAsync(Buffer.from(content, 'utf8'));
|
|
90
87
|
finalContent = compressedBuffer.toString('base64');
|
|
91
88
|
compressed = true;
|
|
89
|
+
logger.debug(`📦 Compressed cache entry: ${sizeInMB.toFixed(2)}MB -> ${(compressedBuffer.length / (1024 * 1024)).toFixed(2)}MB`);
|
|
92
90
|
}
|
|
93
91
|
catch (error) {
|
|
94
|
-
logger.
|
|
92
|
+
logger.warn("Failed to compress cache entry, storing uncompressed", error);
|
|
95
93
|
}
|
|
96
94
|
}
|
|
97
|
-
//
|
|
98
|
-
await this.ensureCapacity(contentSize);
|
|
99
|
-
// Store in cache
|
|
95
|
+
// Create cache entry with session binding
|
|
100
96
|
const entry = {
|
|
101
97
|
content: finalContent,
|
|
98
|
+
metadata: {
|
|
99
|
+
...data,
|
|
100
|
+
sessionId,
|
|
101
|
+
requestId,
|
|
102
|
+
originalSize: sizeInMB
|
|
103
|
+
},
|
|
102
104
|
timestamp: Date.now(),
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
requestParams: params,
|
|
105
|
+
accessCount: 1,
|
|
106
|
+
size: Buffer.byteLength(finalContent, 'utf8'),
|
|
106
107
|
compressed,
|
|
107
|
-
|
|
108
|
+
sessionId,
|
|
109
|
+
requestId
|
|
108
110
|
};
|
|
109
|
-
|
|
110
|
-
this.
|
|
111
|
-
|
|
112
|
-
this.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
// Store in cache
|
|
112
|
+
this.entries.set(finalCacheKey, entry);
|
|
113
|
+
// Map analysis ID to cache key with session binding
|
|
114
|
+
this.analysisIdMap.set(analysisId, {
|
|
115
|
+
cacheKey: finalCacheKey,
|
|
116
|
+
sessionId: sessionId || 'anonymous',
|
|
117
|
+
created: Date.now()
|
|
118
|
+
});
|
|
119
|
+
// Update access order for LRU
|
|
120
|
+
this.updateAccessOrder(finalCacheKey);
|
|
121
|
+
// Update stats
|
|
122
|
+
this.stats.entries = this.entries.size;
|
|
123
|
+
this.stats.totalSize = Array.from(this.entries.values()).reduce((sum, e) => sum + e.size, 0);
|
|
124
|
+
// Ensure capacity limits
|
|
125
|
+
await this.ensureCapacity();
|
|
126
|
+
logger.debug(`✅ Cached response with analysis_id: ${analysisId} for session: ${sessionId?.substring(0, 8)}...`);
|
|
127
|
+
return { analysisId, cacheKey: finalCacheKey };
|
|
116
128
|
}
|
|
117
129
|
/**
|
|
118
|
-
* Retrieve response
|
|
130
|
+
* Retrieve response with session validation
|
|
119
131
|
*/
|
|
120
|
-
async get(
|
|
121
|
-
|
|
132
|
+
async get(analysisIdOrCacheKey, sessionId) {
|
|
133
|
+
let cacheKey;
|
|
134
|
+
let requiredSessionId;
|
|
135
|
+
// Check if it's an analysis ID first
|
|
136
|
+
const mapping = this.analysisIdMap.get(analysisIdOrCacheKey);
|
|
137
|
+
if (mapping) {
|
|
138
|
+
cacheKey = mapping.cacheKey;
|
|
139
|
+
requiredSessionId = mapping.sessionId;
|
|
140
|
+
// Validate session access
|
|
141
|
+
if (requiredSessionId !== 'anonymous') {
|
|
142
|
+
if (!sessionId || sessionId !== requiredSessionId) {
|
|
143
|
+
logger.warn(`🚫 Session mismatch for analysis ${analysisIdOrCacheKey}: ${sessionId?.substring(0, 8) || 'none'} != ${requiredSessionId?.substring(0, 8)}`);
|
|
144
|
+
this.stats.misses++;
|
|
145
|
+
return null; // Block cross-session access
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// Direct cache key access (legacy support)
|
|
151
|
+
cacheKey = analysisIdOrCacheKey;
|
|
152
|
+
}
|
|
153
|
+
const entry = this.entries.get(cacheKey);
|
|
122
154
|
if (!entry) {
|
|
123
155
|
this.stats.misses++;
|
|
124
|
-
logger.debug(`❌ Cache miss: ${keyOrId}`);
|
|
125
156
|
return null;
|
|
126
157
|
}
|
|
127
158
|
// Check TTL
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
159
|
+
if (Date.now() - entry.timestamp > this.ttlMs) {
|
|
160
|
+
logger.debug(`⏰ Cache entry expired: ${cacheKey.substring(0, 8)}...`);
|
|
161
|
+
this.entries.delete(cacheKey);
|
|
162
|
+
// Also clean up analysis ID mapping
|
|
163
|
+
if (mapping) {
|
|
164
|
+
this.analysisIdMap.delete(analysisIdOrCacheKey);
|
|
165
|
+
}
|
|
166
|
+
this.stats.misses++;
|
|
167
|
+
this.stats.evictions++;
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
// Additional session validation on the entry itself
|
|
171
|
+
if (sessionId && entry.sessionId && entry.sessionId !== sessionId && entry.sessionId !== 'anonymous') {
|
|
172
|
+
logger.warn(`🚫 Entry session mismatch for ${cacheKey.substring(0, 8)}: ${sessionId?.substring(0, 8)} != ${entry.sessionId?.substring(0, 8)}`);
|
|
132
173
|
this.stats.misses++;
|
|
133
174
|
return null;
|
|
134
175
|
}
|
|
135
|
-
// Update access
|
|
136
|
-
|
|
176
|
+
// Update access tracking
|
|
177
|
+
entry.accessCount++;
|
|
178
|
+
this.updateAccessOrder(cacheKey);
|
|
137
179
|
this.stats.hits++;
|
|
138
|
-
logger.info(`✅ Cache hit: ${keyOrId} (age: ${(age / 1000 / 60).toFixed(0)} minutes)`);
|
|
139
180
|
// Decompress if needed
|
|
181
|
+
let content = entry.content;
|
|
140
182
|
if (entry.compressed) {
|
|
141
183
|
try {
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
|
|
184
|
+
const compressedBuffer = Buffer.from(content, 'base64');
|
|
185
|
+
const decompressedBuffer = await gunzipAsync(compressedBuffer);
|
|
186
|
+
content = decompressedBuffer.toString('utf8');
|
|
145
187
|
}
|
|
146
188
|
catch (error) {
|
|
147
|
-
logger.error(
|
|
148
|
-
this.delete(keyOrId);
|
|
189
|
+
logger.error("Failed to decompress cache entry", error);
|
|
149
190
|
return null;
|
|
150
191
|
}
|
|
151
192
|
}
|
|
152
|
-
|
|
193
|
+
logger.debug(`🎯 Cache hit for session ${sessionId?.substring(0, 8)}...: ${cacheKey.substring(0, 8)}...`);
|
|
194
|
+
return content;
|
|
153
195
|
}
|
|
154
196
|
/**
|
|
155
197
|
* Check if key exists in cache
|
|
156
198
|
*/
|
|
157
199
|
has(keyOrId) {
|
|
158
|
-
|
|
200
|
+
// Check analysis ID mapping first
|
|
201
|
+
const mapping = this.analysisIdMap.get(keyOrId);
|
|
202
|
+
const cacheKey = mapping ? mapping.cacheKey : keyOrId;
|
|
203
|
+
const entry = this.entries.get(cacheKey);
|
|
159
204
|
if (!entry)
|
|
160
205
|
return false;
|
|
161
206
|
// Check if expired
|
|
@@ -170,15 +215,21 @@ export class ResponseCache {
|
|
|
170
215
|
* Delete entry from cache
|
|
171
216
|
*/
|
|
172
217
|
delete(keyOrId) {
|
|
173
|
-
|
|
218
|
+
// Check analysis ID mapping first
|
|
219
|
+
const mapping = this.analysisIdMap.get(keyOrId);
|
|
220
|
+
const cacheKey = mapping ? mapping.cacheKey : keyOrId;
|
|
221
|
+
const entry = this.entries.get(cacheKey);
|
|
174
222
|
if (entry) {
|
|
175
223
|
this.stats.totalSize -= entry.size;
|
|
176
|
-
// Delete
|
|
177
|
-
this.
|
|
178
|
-
|
|
224
|
+
// Delete from entries
|
|
225
|
+
this.entries.delete(cacheKey);
|
|
226
|
+
// Remove from analysis ID mapping if it exists
|
|
227
|
+
if (mapping) {
|
|
228
|
+
this.analysisIdMap.delete(keyOrId);
|
|
229
|
+
}
|
|
179
230
|
// Remove cache key from access order
|
|
180
|
-
this.accessOrder = this.accessOrder.filter(k => k !==
|
|
181
|
-
this.stats.entries = this.
|
|
231
|
+
this.accessOrder = this.accessOrder.filter(k => k !== cacheKey);
|
|
232
|
+
this.stats.entries = this.entries.size;
|
|
182
233
|
}
|
|
183
234
|
}
|
|
184
235
|
/**
|
|
@@ -191,17 +242,17 @@ export class ResponseCache {
|
|
|
191
242
|
/**
|
|
192
243
|
* Ensure cache has capacity for new entry
|
|
193
244
|
*/
|
|
194
|
-
async ensureCapacity(
|
|
245
|
+
async ensureCapacity() {
|
|
195
246
|
const maxTotalSize = this.maxTotalSizeMB * 1024 * 1024;
|
|
196
247
|
// Check total size limit
|
|
197
|
-
while (this.stats.totalSize
|
|
248
|
+
while (this.stats.totalSize > maxTotalSize && this.accessOrder.length > 0) {
|
|
198
249
|
const oldestKey = this.accessOrder[0];
|
|
199
250
|
logger.info(`🗑️ Evicting for size limit: ${oldestKey}`);
|
|
200
251
|
this.delete(oldestKey);
|
|
201
252
|
this.stats.evictions++;
|
|
202
253
|
}
|
|
203
254
|
// Check entry count limit
|
|
204
|
-
while (this.
|
|
255
|
+
while (this.entries.size >= this.maxEntries && this.accessOrder.length > 0) {
|
|
205
256
|
const oldestKey = this.accessOrder[0];
|
|
206
257
|
logger.info(`🗑️ Evicting for entry limit: ${oldestKey}`);
|
|
207
258
|
this.delete(oldestKey);
|
|
@@ -214,7 +265,7 @@ export class ResponseCache {
|
|
|
214
265
|
cleanupExpired() {
|
|
215
266
|
const now = Date.now();
|
|
216
267
|
let cleaned = 0;
|
|
217
|
-
for (const [key, entry] of this.
|
|
268
|
+
for (const [key, entry] of this.entries.entries()) {
|
|
218
269
|
if (now - entry.timestamp > this.ttlMs) {
|
|
219
270
|
this.delete(key);
|
|
220
271
|
cleaned++;
|
|
@@ -230,11 +281,71 @@ export class ResponseCache {
|
|
|
230
281
|
getStats() {
|
|
231
282
|
return { ...this.stats };
|
|
232
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Retrieve response by analysis ID, returning full cached response object
|
|
286
|
+
*/
|
|
287
|
+
async getByAnalysisId(analysisId, sessionId) {
|
|
288
|
+
const mapping = this.analysisIdMap.get(analysisId);
|
|
289
|
+
if (!mapping) {
|
|
290
|
+
this.stats.misses++;
|
|
291
|
+
logger.debug(`❌ Cache miss by analysis ID: ${analysisId}`);
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
// Validate session access
|
|
295
|
+
if (sessionId && mapping.sessionId !== sessionId && mapping.sessionId !== 'anonymous') {
|
|
296
|
+
logger.warn(`🚫 Session mismatch for analysis ${analysisId}: ${sessionId?.substring(0, 8)} != ${mapping.sessionId?.substring(0, 8)}`);
|
|
297
|
+
this.stats.misses++;
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
const entry = this.entries.get(mapping.cacheKey);
|
|
301
|
+
if (!entry) {
|
|
302
|
+
this.stats.misses++;
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
// Check TTL
|
|
306
|
+
const age = Date.now() - entry.timestamp;
|
|
307
|
+
if (age > this.ttlMs) {
|
|
308
|
+
logger.info(`⏰ Cache expired: ${analysisId} (age: ${(age / 1000 / 60).toFixed(0)} minutes)`);
|
|
309
|
+
this.delete(analysisId);
|
|
310
|
+
this.stats.misses++;
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
// Update access order
|
|
314
|
+
this.updateAccessOrder(mapping.cacheKey);
|
|
315
|
+
this.stats.hits++;
|
|
316
|
+
logger.info(`✅ Cache hit by analysis ID: ${analysisId} (age: ${(age / 1000 / 60).toFixed(0)} minutes)`);
|
|
317
|
+
// Decompress if needed
|
|
318
|
+
let content = entry.content;
|
|
319
|
+
if (entry.compressed) {
|
|
320
|
+
try {
|
|
321
|
+
const buffer = Buffer.from(entry.content, 'base64');
|
|
322
|
+
const decompressed = await gunzipAsync(buffer);
|
|
323
|
+
content = decompressed.toString('utf-8');
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
logger.error('Decompression failed:', error);
|
|
327
|
+
this.delete(analysisId);
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
content,
|
|
333
|
+
timestamp: entry.timestamp,
|
|
334
|
+
analysisId,
|
|
335
|
+
cacheKey: mapping.cacheKey,
|
|
336
|
+
requestParams: entry.metadata,
|
|
337
|
+
compressed: entry.compressed || false,
|
|
338
|
+
size: entry.size,
|
|
339
|
+
sessionId: entry.sessionId,
|
|
340
|
+
requestId: entry.requestId
|
|
341
|
+
};
|
|
342
|
+
}
|
|
233
343
|
/**
|
|
234
344
|
* Clear entire cache
|
|
235
345
|
*/
|
|
236
346
|
clear() {
|
|
237
|
-
this.
|
|
347
|
+
this.entries.clear();
|
|
348
|
+
this.analysisIdMap.clear();
|
|
238
349
|
this.accessOrder = [];
|
|
239
350
|
this.stats = {
|
|
240
351
|
entries: 0,
|