xypriss-security 1.0.8 → 1.0.10
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/components/cache/SCC.js +623 -0
- package/dist/cjs/components/cache/SCC.js.map +1 -0
- package/dist/cjs/components/cache/index.js +3 -616
- package/dist/cjs/components/cache/index.js.map +1 -1
- package/dist/cjs/components/cache/useCache.js +0 -11
- package/dist/cjs/components/cache/useCache.js.map +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/shared/logger/Logger.js +7 -0
- package/dist/cjs/shared/logger/Logger.js.map +1 -1
- package/dist/cjs/src/cache/SecureCacheAdapter.js +1226 -0
- package/dist/cjs/src/cache/SecureCacheAdapter.js.map +1 -0
- package/dist/cjs/src/cache/index.js +37 -0
- package/dist/cjs/src/cache/index.js.map +1 -0
- package/dist/cjs/src/encryption/EncryptionService.js +400 -0
- package/dist/cjs/src/encryption/EncryptionService.js.map +1 -0
- package/dist/esm/components/cache/SCC.js +621 -0
- package/dist/esm/components/cache/SCC.js.map +1 -0
- package/dist/esm/components/cache/index.js +4 -615
- package/dist/esm/components/cache/index.js.map +1 -1
- package/dist/esm/components/cache/useCache.js +0 -11
- package/dist/esm/components/cache/useCache.js.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/shared/logger/Logger.js +7 -1
- package/dist/esm/shared/logger/Logger.js.map +1 -1
- package/dist/esm/src/cache/SecureCacheAdapter.js +1224 -0
- package/dist/esm/src/cache/SecureCacheAdapter.js.map +1 -0
- package/dist/esm/src/cache/index.js +3 -0
- package/dist/esm/src/cache/index.js.map +1 -0
- package/dist/esm/src/encryption/EncryptionService.js +379 -0
- package/dist/esm/src/encryption/EncryptionService.js.map +1 -0
- package/dist/index.d.ts +705 -715
- package/package.json +1 -1
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var SecureCacheAdapter = require('../../src/cache/SecureCacheAdapter.js');
|
|
4
|
+
require('xypriss-security');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* SecureCacheClient - Secure caching solution
|
|
8
|
+
*
|
|
9
|
+
* A high-performance, secure cache client that supports multiple backend strategies
|
|
10
|
+
* including memory-only, Redis-only, and hybrid (memory + Redis) configurations.
|
|
11
|
+
* Features military-grade AES-256-GCM encryption, intelligent compression, and
|
|
12
|
+
* comprehensive monitoring capabilities.
|
|
13
|
+
*
|
|
14
|
+
* ## Features
|
|
15
|
+
* - **Multi-Strategy Support**: Memory, Redis, or Hybrid caching
|
|
16
|
+
* - **Military-Grade Security**: AES-256-GCM encryption with key rotation
|
|
17
|
+
* - **High Availability**: Redis Cluster and Sentinel support
|
|
18
|
+
* - **Performance Optimized**: Intelligent compression and hot data promotion
|
|
19
|
+
* - **Production Ready**: Comprehensive monitoring and health checks
|
|
20
|
+
* - **Type Safe**: Full TypeScript support with detailed interfaces
|
|
21
|
+
*
|
|
22
|
+
* ## Supported Cache Strategies
|
|
23
|
+
* - `memory`: Ultra-fast in-memory caching with LRU eviction
|
|
24
|
+
* - `redis`: Distributed Redis caching with clustering support
|
|
25
|
+
* - `hybrid`: Memory-first with Redis backup for optimal performance
|
|
26
|
+
*
|
|
27
|
+
* ## Security Features
|
|
28
|
+
* - AES-256-GCM encryption for all cached data
|
|
29
|
+
* - Automatic key rotation and tamper detection
|
|
30
|
+
* - Secure serialization with integrity verification
|
|
31
|
+
* - Access pattern monitoring and anomaly detection
|
|
32
|
+
*
|
|
33
|
+
* @example Basic Redis Configuration
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { SecureCacheClient } from "xypriss-security";
|
|
36
|
+
*
|
|
37
|
+
* const cache = new SecureCacheClient({
|
|
38
|
+
* strategy: "redis",
|
|
39
|
+
* redis: {
|
|
40
|
+
* host: "localhost",
|
|
41
|
+
* port: 6379,
|
|
42
|
+
* password: "your-secure-password"
|
|
43
|
+
* }
|
|
44
|
+
* });
|
|
45
|
+
*
|
|
46
|
+
* await cache.connect();
|
|
47
|
+
* await cache.set("user:123", { name: "John", role: "admin" }, { ttl: 3600 });
|
|
48
|
+
* const user = await cache.get("user:123");
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Hybrid Strategy with Encryption
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const cache = new SecureCacheClient({
|
|
54
|
+
* strategy: "hybrid",
|
|
55
|
+
* memory: {
|
|
56
|
+
* maxSize: 100, // 100MB
|
|
57
|
+
* maxEntries: 10000
|
|
58
|
+
* },
|
|
59
|
+
* redis: {
|
|
60
|
+
* host: "redis-cluster.example.com",
|
|
61
|
+
* port: 6379,
|
|
62
|
+
* cluster: {
|
|
63
|
+
* enabled: true,
|
|
64
|
+
* nodes: [
|
|
65
|
+
* { host: "redis-1", port: 6379 },
|
|
66
|
+
* { host: "redis-2", port: 6379 }
|
|
67
|
+
* ]
|
|
68
|
+
* }
|
|
69
|
+
* },
|
|
70
|
+
* security: {
|
|
71
|
+
* encryption: true,
|
|
72
|
+
* keyRotation: true
|
|
73
|
+
* }
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* @example Advanced Usage with Tags and Monitoring
|
|
78
|
+
* ```typescript
|
|
79
|
+
* // Store data with tags for bulk invalidation
|
|
80
|
+
* await cache.set("product:123", productData, {
|
|
81
|
+
* ttl: 1800,
|
|
82
|
+
* tags: ["products", "category:electronics"]
|
|
83
|
+
* });
|
|
84
|
+
*
|
|
85
|
+
* // Batch operations for better performance
|
|
86
|
+
* await cache.mset({
|
|
87
|
+
* "user:1": userData1,
|
|
88
|
+
* "user:2": userData2
|
|
89
|
+
* }, { ttl: 3600 });
|
|
90
|
+
*
|
|
91
|
+
* // Invalidate by tags
|
|
92
|
+
* await cache.invalidateByTags(["products"]);
|
|
93
|
+
*
|
|
94
|
+
* // Monitor cache health
|
|
95
|
+
* const health = cache.getHealth();
|
|
96
|
+
* if (health.status !== "healthy") {
|
|
97
|
+
* console.warn("Cache issues:", health.details);
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
* // Get performance statistics
|
|
101
|
+
* const stats = await cache.getStats();
|
|
102
|
+
* console.log(`Hit rate: ${stats.memory.hitRate * 100}%`);
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @since 4.2.3
|
|
106
|
+
* @version 4.2.3
|
|
107
|
+
* @author NEHONIX
|
|
108
|
+
* @see {@link ICacheAdapter} for the complete interface definition
|
|
109
|
+
* @see {@link https://lab.nehonix.space/nehonix_viewer/_doc/Nehonix%20XyPrissSecurity} for detailed documentation
|
|
110
|
+
*/
|
|
111
|
+
class SecureCacheClient {
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new SecureCacheClient instance
|
|
114
|
+
*
|
|
115
|
+
* @param config - Cache configuration object
|
|
116
|
+
* @param config.strategy - Cache strategy: "memory", "redis", or "hybrid"
|
|
117
|
+
* @param config.redis - Redis configuration (required for "redis" and "hybrid" strategies)
|
|
118
|
+
* @param config.redis.host - Redis server hostname
|
|
119
|
+
* @param config.redis.port - Redis server port
|
|
120
|
+
* @param config.redis.password - Redis authentication password
|
|
121
|
+
* @param config.redis.cluster - Redis cluster configuration
|
|
122
|
+
* @param config.memory - Memory cache configuration (for "memory" and "hybrid" strategies)
|
|
123
|
+
* @param config.memory.maxSize - Maximum memory cache size in MB
|
|
124
|
+
* @param config.memory.maxEntries - Maximum number of cache entries
|
|
125
|
+
* @param config.security - Security configuration
|
|
126
|
+
* @param config.security.encryption - Enable AES-256-GCM encryption
|
|
127
|
+
* @param config.security.keyRotation - Enable automatic key rotation
|
|
128
|
+
* @param config.monitoring - Monitoring and health check configuration
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const cache = new SecureCacheClient({
|
|
133
|
+
* strategy: "hybrid",
|
|
134
|
+
* redis: { host: "localhost", port: 6379 },
|
|
135
|
+
* memory: { maxSize: 100, maxEntries: 10000 },
|
|
136
|
+
* security: { encryption: true }
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
constructor(config) {
|
|
141
|
+
this.adapter = null;
|
|
142
|
+
this.config = config;
|
|
143
|
+
// Adapter will be created lazily on first use
|
|
144
|
+
this.adapter = new SecureCacheAdapter.SecureCacheAdapter(this.config);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Ensures the cache adapter is initialized
|
|
148
|
+
* @private
|
|
149
|
+
* @returns Promise resolving to the initialized adapter
|
|
150
|
+
*/
|
|
151
|
+
async ensureAdapter() {
|
|
152
|
+
if (!this.adapter) {
|
|
153
|
+
// Use dynamic import for production compatibility
|
|
154
|
+
const { SecureCacheAdapter } = await Promise.resolve().then(function () { return require('../../src/cache/index.js'); });
|
|
155
|
+
this.adapter = new SecureCacheAdapter(this.config);
|
|
156
|
+
throw new Error("SecureCacheAdapter integration not available in this context");
|
|
157
|
+
}
|
|
158
|
+
return this.adapter; // Non-null assertion since we just created it
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Retrieves a value from the cache
|
|
162
|
+
*
|
|
163
|
+
* @param key - The cache key to retrieve
|
|
164
|
+
* @returns Promise resolving to the cached value, or null if not found
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* const user = await cache.read<User>("user:123");
|
|
169
|
+
* if (user) {
|
|
170
|
+
* console.log("Found user:", user.name);
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
async read(key) {
|
|
175
|
+
const adapter = await this.ensureAdapter();
|
|
176
|
+
return adapter.get(key);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Retrieves a value from the cache (alias for get method)
|
|
180
|
+
*
|
|
181
|
+
* @param key - The cache key to retrieve
|
|
182
|
+
* @returns Promise resolving to the cached value, or null if not found
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const user = await cache.read<User>("user:123");
|
|
187
|
+
* if (user) {
|
|
188
|
+
* console.log("Found user:", user.name);
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
/**
|
|
193
|
+
* Stores a value in the cache with optional TTL and tags
|
|
194
|
+
*
|
|
195
|
+
* @param key - The cache key to store the value under
|
|
196
|
+
* @param value - The value to cache (will be automatically serialized)
|
|
197
|
+
* @param options - Optional caching options
|
|
198
|
+
* @param options.ttl - Time to live in seconds (default: configured TTL)
|
|
199
|
+
* @param options.tags - Array of tags for bulk invalidation
|
|
200
|
+
* @returns Promise resolving to true if successful, false otherwise
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* // Basic usage
|
|
205
|
+
* await cache.write("user:123", { name: "John", role: "admin" });
|
|
206
|
+
*
|
|
207
|
+
* // With TTL (1 hour)
|
|
208
|
+
* await cache.write("session:abc", sessionData, { ttl: 3600 });
|
|
209
|
+
*
|
|
210
|
+
* // With tags for bulk invalidation
|
|
211
|
+
* await cache.write("product:456", productData, {
|
|
212
|
+
* ttl: 1800,
|
|
213
|
+
* tags: ["products", "category:electronics"]
|
|
214
|
+
* });
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
async write(key, value, options) {
|
|
218
|
+
const adapter = await this.ensureAdapter();
|
|
219
|
+
return adapter.set(key, value, options);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Stores a value in the cache (alias for set method)
|
|
223
|
+
*
|
|
224
|
+
* @param key - The cache key to store the value under
|
|
225
|
+
* @param value - The value to cache (will be automatically serialized)
|
|
226
|
+
* @param options - Optional caching options
|
|
227
|
+
* @param options.ttl - Time to live in seconds (default: configured TTL)
|
|
228
|
+
* @param options.tags - Array of tags for bulk invalidation
|
|
229
|
+
* @returns Promise resolving to true if successful, false otherwise
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* ```typescript
|
|
233
|
+
* // Basic usage
|
|
234
|
+
* await cache.write("user:123", { name: "John", role: "admin" });
|
|
235
|
+
*
|
|
236
|
+
* // With TTL (1 hour)
|
|
237
|
+
* await cache.write("session:abc", sessionData, { ttl: 3600 });
|
|
238
|
+
*
|
|
239
|
+
* // With tags for bulk invalidation
|
|
240
|
+
* await cache.write("product:456", productData, {
|
|
241
|
+
* ttl: 1800,
|
|
242
|
+
* tags: ["products", "category:electronics"]
|
|
243
|
+
* });
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
/**
|
|
247
|
+
* Deletes a value from the cache
|
|
248
|
+
*
|
|
249
|
+
* @param key - The cache key to delete
|
|
250
|
+
* @returns Promise resolving to true if the key was deleted, false if not found
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* const deleted = await cache.delete("user:123");
|
|
255
|
+
* if (deleted) {
|
|
256
|
+
* console.log("User cache cleared");
|
|
257
|
+
* }
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
async delete(key) {
|
|
261
|
+
const adapter = await this.ensureAdapter();
|
|
262
|
+
return adapter.delete(key);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Checks if a key exists in the cache
|
|
266
|
+
*
|
|
267
|
+
* @param key - The cache key to check
|
|
268
|
+
* @returns Promise resolving to true if the key exists, false otherwise
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* ```typescript
|
|
272
|
+
* if (await cache.exists("user:123")) {
|
|
273
|
+
* console.log("User is cached");
|
|
274
|
+
* }
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
async exists(key) {
|
|
278
|
+
const adapter = await this.ensureAdapter();
|
|
279
|
+
return adapter.exists(key);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Clears all cached data
|
|
283
|
+
*
|
|
284
|
+
* ⚠️ **Warning**: This operation is irreversible and will remove all cached data
|
|
285
|
+
*
|
|
286
|
+
* @returns Promise that resolves when the cache is cleared
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```typescript
|
|
290
|
+
* await cache.clear();
|
|
291
|
+
* console.log("All cache data cleared");
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
async clear() {
|
|
295
|
+
const adapter = await this.ensureAdapter();
|
|
296
|
+
return adapter.clear();
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Establishes connection to the cache backend
|
|
300
|
+
*
|
|
301
|
+
* Must be called before using the cache. For Redis strategies, this establishes
|
|
302
|
+
* the connection to the Redis server(s). For memory-only strategy, this initializes
|
|
303
|
+
* the in-memory cache.
|
|
304
|
+
*
|
|
305
|
+
* @returns Promise that resolves when the connection is established
|
|
306
|
+
* @throws {Error} If connection fails
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* try {
|
|
311
|
+
* await cache.connect();
|
|
312
|
+
* console.log("Cache connected successfully");
|
|
313
|
+
* } catch (error) {
|
|
314
|
+
* console.error("Failed to connect to cache:", error);
|
|
315
|
+
* }
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
async connect() {
|
|
319
|
+
const adapter = await this.ensureAdapter();
|
|
320
|
+
return adapter.connect();
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Closes the connection to the cache backend
|
|
324
|
+
*
|
|
325
|
+
* Gracefully closes all connections and cleans up resources. Should be called
|
|
326
|
+
* when shutting down the application.
|
|
327
|
+
*
|
|
328
|
+
* @returns Promise that resolves when the connection is closed
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* process.on('SIGTERM', async () => {
|
|
333
|
+
* await cache.disconnect();
|
|
334
|
+
* console.log("Cache disconnected");
|
|
335
|
+
* });
|
|
336
|
+
* ```
|
|
337
|
+
*/
|
|
338
|
+
async disconnect() {
|
|
339
|
+
const adapter = await this.ensureAdapter();
|
|
340
|
+
return adapter.disconnect();
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Retrieves comprehensive cache performance statistics
|
|
344
|
+
*
|
|
345
|
+
* @returns Promise resolving to detailed statistics including hit rates, memory usage, and performance metrics
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```typescript
|
|
349
|
+
* const stats = await cache.getStats();
|
|
350
|
+
* console.log(`Memory hit rate: ${stats.memory.hitRate * 100}%`);
|
|
351
|
+
* console.log(`Redis hit rate: ${stats.redis?.hitRate * 100}%`);
|
|
352
|
+
* console.log(`Total operations: ${stats.operations.total}`);
|
|
353
|
+
* console.log(`Average response time: ${stats.performance.avgResponseTime}ms`);
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
async getStats() {
|
|
357
|
+
const adapter = await this.ensureAdapter();
|
|
358
|
+
const stats = await adapter.getStats();
|
|
359
|
+
// Transform the adapter stats to match our interface
|
|
360
|
+
return {
|
|
361
|
+
memory: {
|
|
362
|
+
hitRate: stats.memory?.hitRate || 0,
|
|
363
|
+
missRate: stats.memory?.missRate || 0,
|
|
364
|
+
size: stats.memory?.size || 0,
|
|
365
|
+
entries: stats.memory?.entries || 0,
|
|
366
|
+
maxSize: stats.memory?.maxSize || 0,
|
|
367
|
+
maxEntries: stats.memory?.maxEntries || 0,
|
|
368
|
+
},
|
|
369
|
+
redis: stats.redis
|
|
370
|
+
? {
|
|
371
|
+
hitRate: stats.redis.hitRate || 0,
|
|
372
|
+
missRate: stats.redis.missRate || 0,
|
|
373
|
+
connected: stats.redis.connected || false,
|
|
374
|
+
memoryUsage: stats.redis.memoryUsage || 0,
|
|
375
|
+
keyCount: stats.redis.keyCount || 0,
|
|
376
|
+
}
|
|
377
|
+
: undefined,
|
|
378
|
+
operations: {
|
|
379
|
+
total: stats.operations?.total || stats.total || 0,
|
|
380
|
+
gets: stats.operations?.gets || stats.gets || 0,
|
|
381
|
+
sets: stats.operations?.sets || stats.sets || 0,
|
|
382
|
+
deletes: stats.operations?.deletes || stats.deletes || 0,
|
|
383
|
+
errors: stats.operations?.errors || stats.errors || 0,
|
|
384
|
+
},
|
|
385
|
+
performance: {
|
|
386
|
+
avgResponseTime: stats.performance?.avgResponseTime ||
|
|
387
|
+
stats.avgResponseTime ||
|
|
388
|
+
0,
|
|
389
|
+
p95ResponseTime: stats.performance?.p95ResponseTime ||
|
|
390
|
+
stats.p95ResponseTime ||
|
|
391
|
+
0,
|
|
392
|
+
p99ResponseTime: stats.performance?.p99ResponseTime ||
|
|
393
|
+
stats.p99ResponseTime ||
|
|
394
|
+
0,
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Retrieves multiple values from the cache in a single operation
|
|
400
|
+
*
|
|
401
|
+
* @param keys - Array of cache keys to retrieve
|
|
402
|
+
* @returns Promise resolving to an object with key-value pairs (missing keys are omitted)
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* const users = await cache.mread<User>(["user:1", "user:2", "user:3"]);
|
|
407
|
+
* console.log(users); // { "user:1": {...}, "user:2": {...} }
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
async mread(keys) {
|
|
411
|
+
const adapter = await this.ensureAdapter();
|
|
412
|
+
return adapter.mget(keys);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Stores multiple key-value pairs in a single operation
|
|
416
|
+
*
|
|
417
|
+
* @param entries - Object with key-value pairs or array of [key, value] tuples
|
|
418
|
+
* @param options - Optional caching options applied to all entries
|
|
419
|
+
* @param options.ttl - Time to live in seconds for all entries
|
|
420
|
+
* @param options.tags - Array of tags applied to all entries
|
|
421
|
+
* @returns Promise resolving to true if successful, false otherwise
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* ```typescript
|
|
425
|
+
* // Using object notation
|
|
426
|
+
* await cache.mwrite({
|
|
427
|
+
* "user:1": { name: "Alice" },
|
|
428
|
+
* "user:2": { name: "Bob" }
|
|
429
|
+
* }, { ttl: 3600 });
|
|
430
|
+
*
|
|
431
|
+
* // Using array notation
|
|
432
|
+
* await cache.mwrite([
|
|
433
|
+
* ["session:abc", sessionData1],
|
|
434
|
+
* ["session:def", sessionData2]
|
|
435
|
+
* ], { ttl: 1800, tags: ["sessions"] });
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
async mwrite(entries, options) {
|
|
439
|
+
const adapter = await this.ensureAdapter();
|
|
440
|
+
return adapter.mset(entries, options);
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Invalidates all cache entries that have any of the specified tags
|
|
444
|
+
*
|
|
445
|
+
* @param tags - Array of tags to invalidate
|
|
446
|
+
* @returns Promise resolving to the number of entries invalidated
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* ```typescript
|
|
450
|
+
* // Invalidate all product-related cache entries
|
|
451
|
+
* const count = await cache.invalidateByTags(["products", "inventory"]);
|
|
452
|
+
* console.log(`Invalidated ${count} cache entries`);
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
async invalidateByTags(tags) {
|
|
456
|
+
const adapter = await this.ensureAdapter();
|
|
457
|
+
return adapter.invalidateByTags(tags);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Gets the remaining time-to-live for a cache key
|
|
461
|
+
*
|
|
462
|
+
* @param key - The cache key to check
|
|
463
|
+
* @returns Promise resolving to TTL in seconds, or -1 if key doesn't exist, -2 if no TTL set
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```typescript
|
|
467
|
+
* const ttl = await cache.getTTL("user:123");
|
|
468
|
+
* if (ttl > 0) {
|
|
469
|
+
* console.log(`Key expires in ${ttl} seconds`);
|
|
470
|
+
* }
|
|
471
|
+
* ```
|
|
472
|
+
*/
|
|
473
|
+
async getTTL(key) {
|
|
474
|
+
const adapter = await this.ensureAdapter();
|
|
475
|
+
return adapter.getTTL(key);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Sets or updates the expiration time for a cache key
|
|
479
|
+
*
|
|
480
|
+
* @param key - The cache key to set expiration for
|
|
481
|
+
* @param ttl - Time to live in seconds
|
|
482
|
+
* @returns Promise resolving to true if successful, false if key doesn't exist
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* // Extend expiration to 1 hour
|
|
487
|
+
* await cache.expire("user:123", 3600);
|
|
488
|
+
*
|
|
489
|
+
* // Set short expiration for temporary data
|
|
490
|
+
* await cache.expire("temp:data", 60);
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
493
|
+
async expire(key, ttl) {
|
|
494
|
+
const adapter = await this.ensureAdapter();
|
|
495
|
+
return adapter.expire(key, ttl);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Retrieves all cache keys matching an optional pattern
|
|
499
|
+
*
|
|
500
|
+
* ⚠️ **Warning**: Use with caution in production as this can be expensive for large caches
|
|
501
|
+
*
|
|
502
|
+
* @param pattern - Optional glob-style pattern to filter keys (Redis syntax)
|
|
503
|
+
* @returns Promise resolving to array of matching keys
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```typescript
|
|
507
|
+
* // Get all keys
|
|
508
|
+
* const allKeys = await cache.keys();
|
|
509
|
+
*
|
|
510
|
+
* // Get user-related keys
|
|
511
|
+
* const userKeys = await cache.keys("user:*");
|
|
512
|
+
*
|
|
513
|
+
* // Get session keys with pattern
|
|
514
|
+
* const sessionKeys = await cache.keys("session:*:active");
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
async keys(pattern) {
|
|
518
|
+
const adapter = await this.ensureAdapter();
|
|
519
|
+
return adapter.keys(pattern);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Gets the current health status of the cache system
|
|
523
|
+
*
|
|
524
|
+
* @returns Health status object with overall status and detailed information
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* const health = cache.getHealth();
|
|
529
|
+
*
|
|
530
|
+
* switch (health.status) {
|
|
531
|
+
* case "healthy":
|
|
532
|
+
* console.log("Cache is operating normally");
|
|
533
|
+
* break;
|
|
534
|
+
* case "degraded":
|
|
535
|
+
* console.warn("Cache has issues but is functional:", health.details);
|
|
536
|
+
* break;
|
|
537
|
+
* case "unhealthy":
|
|
538
|
+
* console.error("Cache is not functional:", health.details);
|
|
539
|
+
* break;
|
|
540
|
+
* }
|
|
541
|
+
*
|
|
542
|
+
* // Check specific metrics
|
|
543
|
+
* if (health.details.redis?.connected === false) {
|
|
544
|
+
* console.error("Redis connection lost");
|
|
545
|
+
* }
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
getHealth() {
|
|
549
|
+
if (!this.adapter) {
|
|
550
|
+
return {
|
|
551
|
+
status: "unhealthy",
|
|
552
|
+
details: {
|
|
553
|
+
errors: ["Cache adapter not initialized"],
|
|
554
|
+
lastCheck: new Date(),
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
return this.adapter.getHealth();
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Memoizes a function with intelligent caching
|
|
562
|
+
*
|
|
563
|
+
* This method implements memoization - caching function results based on their inputs.
|
|
564
|
+
* It simplifies the common pattern of:
|
|
565
|
+
* 1. Generate a cache key from function parameters
|
|
566
|
+
* 2. Check if result exists in cache
|
|
567
|
+
* 3. If not, execute the function and cache the result
|
|
568
|
+
* 4. Return the cached or computed result
|
|
569
|
+
*
|
|
570
|
+
* @param keyGenerator - Function that generates a cache key from the parameters
|
|
571
|
+
* @param computeFunction - Function to execute if cache miss occurs
|
|
572
|
+
* @param options - Optional caching options
|
|
573
|
+
* @returns A memoized version of the function
|
|
574
|
+
*
|
|
575
|
+
* @example
|
|
576
|
+
* ```typescript
|
|
577
|
+
* import { Hash } from "xypriss-security";
|
|
578
|
+
*
|
|
579
|
+
* // Simple memoization with automatic key generation
|
|
580
|
+
* const memoizedSum = cache.memoize(
|
|
581
|
+
* (a: number, b: number) => Hash.create(String(a + b)).toString("hex"),
|
|
582
|
+
* (a: number, b: number) => a + b,
|
|
583
|
+
* { ttl: 3600 }
|
|
584
|
+
* );
|
|
585
|
+
*
|
|
586
|
+
* const result = await memoizedSum(1, 2); // Computes and caches
|
|
587
|
+
* const cached = await memoizedSum(1, 2); // Returns from cache
|
|
588
|
+
*
|
|
589
|
+
* // Advanced usage with async function
|
|
590
|
+
* const fetchUser = cache.memoize(
|
|
591
|
+
* (userId: string) => `user:${userId}`,
|
|
592
|
+
* async (userId: string) => {
|
|
593
|
+
* const response = await fetch(`/api/users/${userId}`);
|
|
594
|
+
* return response.json();
|
|
595
|
+
* },
|
|
596
|
+
* { ttl: 1800, tags: ["users"] }
|
|
597
|
+
* );
|
|
598
|
+
*
|
|
599
|
+
* const user = await fetchUser("123");
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
memoize(keyGenerator, computeFunction, options) {
|
|
603
|
+
return async (...args) => {
|
|
604
|
+
// Ensure cache is connected
|
|
605
|
+
await this.ensureAdapter();
|
|
606
|
+
// Generate cache key
|
|
607
|
+
const cacheKey = keyGenerator(...args);
|
|
608
|
+
// Try to get from cache first
|
|
609
|
+
const cachedResult = await this.read(cacheKey);
|
|
610
|
+
if (cachedResult !== null && cachedResult !== undefined) {
|
|
611
|
+
return cachedResult;
|
|
612
|
+
}
|
|
613
|
+
// Cache miss - compute the result
|
|
614
|
+
const result = await computeFunction(...args);
|
|
615
|
+
// Store in cache
|
|
616
|
+
await this.write(cacheKey, result, options);
|
|
617
|
+
return result;
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
exports.SecureCacheClient = SecureCacheClient;
|
|
623
|
+
//# sourceMappingURL=SCC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SCC.js","sources":["../../../../src/components/cache/SCC.ts"],"sourcesContent":[null],"names":["SecureCacheAdapter"],"mappings":"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"}
|