@gravito/stasis 3.1.1 → 3.2.0

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 CHANGED
@@ -6,18 +6,41 @@
6
6
 
7
7
  ---
8
8
 
9
- ## 📖 Quick Index
10
- * [**Architecture Deep Dive**](./docs/architecture.md) — Understand the mechanics of hybrid caching and predictive engines.
11
- * [**Observability & Protection**](./docs/observability.md) How to prevent OOM and monitor cache performance.
9
+ ## 📚 Documentation
10
+
11
+ Detailed guides and references for the Galaxy Architecture:
12
+
13
+ - [🏗️ **Architecture Deep Dive**](./docs/architecture.md) — Under the hood of tiered caching.
14
+ - [🧊 **Hybrid Caching**](./doc/HYBRID_CACHING.md) — **NEW**: L1/L2 strategy and predictive warming.
15
+ - [📊 **Observability**](./docs/observability.md) — Monitoring cache health and hit rates.
12
16
 
13
17
  ---
14
18
 
15
19
  ## 🌟 Core Capabilities
16
20
  * 🚀 **Unified API**: Seamlessly switch between Memory, Redis, File, and other storage drivers.
17
21
  * 🏗️ **Tiered Cache (Hybrid)**: Combine local Memory with distributed Redis for extreme read speeds.
18
- * 🔒 **Distributed Locks**: Atomic cross-instance concurrency control.
22
+ * 🧠 **Predictive State Warming**: Access path prediction and automated pre-fetching powered by Markov Chains.
23
+ * 🔒 **Distributed Locks**: Atomic cross-instance concurrency control across the Galaxy.
19
24
  * 🚦 **Rate Limiting**: Built-in traffic throttling on top of your cache infrastructure.
20
- * 🧠 **Smart Pre-warming**: Access path prediction and automated pre-fetching powered by Markov Chains.
25
+ * 🪐 **Galaxy-Ready**: Native integration with PlanetCore for universal caching.
26
+
27
+ ## 🌌 Role in Galaxy Architecture
28
+
29
+ In the **Gravito Galaxy Architecture**, Stasis acts as the **Thermal Buffer (Insulation Layer)**.
30
+
31
+ - **Load Insulation**: Protects the `Atlas` Data Gravity core from being overwhelmed by repetitive queries, ensuring low-latency responses for the `Photon` Sensing Layer.
32
+ - **Distributed Consistency**: Works with `Plasma` to provide a consistent view of frequently accessed state across multiple Satellite instances.
33
+ - **Predictive Efficiency**: Uses advanced algorithms to warm up the cache before a Satellite even receives a request, minimizing cold-start latency in serverless or edge environments.
34
+
35
+ ```mermaid
36
+ graph TD
37
+ P[Photon: Sensing] --> S[Satellite]
38
+ S --> Stasis{Stasis Buffer}
39
+ Stasis -- "Hit" --> S
40
+ Stasis -- "Miss" --> Atlas[(Atlas: DB)]
41
+ Atlas --> Stasis
42
+ Stasis -.-> Plasma[(Plasma: Shared State)]
43
+ ```
21
44
 
22
45
  ## 📦 Installation
23
46
  ```bash
@@ -0,0 +1,484 @@
1
+ import { type CacheEventMode, type CacheEvents, CacheRepository } from './CacheRepository';
2
+ import { RateLimiter } from './RateLimiter';
3
+ import type { CacheStore } from './store';
4
+ import type { CacheTtl } from './types';
5
+ /**
6
+ * Configuration for a specific cache store driver.
7
+ *
8
+ * Defines the connection parameters and behavior for different storage backends
9
+ * like in-memory, local filesystem, or Redis.
10
+ *
11
+ * @public
12
+ * @since 3.0.0
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const config: StoreConfig = { driver: 'redis', connection: 'default' };
17
+ * ```
18
+ */
19
+ export type StoreConfig = {
20
+ driver: 'memory';
21
+ maxItems?: number;
22
+ } | {
23
+ driver: 'file';
24
+ directory: string;
25
+ } | {
26
+ driver: 'redis';
27
+ connection?: string;
28
+ prefix?: string;
29
+ } | {
30
+ driver: 'null';
31
+ } | {
32
+ driver: 'provider';
33
+ } | {
34
+ driver: 'tiered';
35
+ local: string;
36
+ remote: string;
37
+ } | {
38
+ driver: 'circuit-breaker';
39
+ primary: string;
40
+ maxFailures?: number;
41
+ resetTimeout?: number;
42
+ fallback?: string;
43
+ };
44
+ /**
45
+ * Global cache configuration for managing multiple named stores.
46
+ *
47
+ * Provides a central manifest to define default behavior, global key prefixing,
48
+ * and the registry of available storage backends.
49
+ *
50
+ * @public
51
+ * @since 3.0.0
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const config: CacheConfig = {
56
+ * default: 'redis',
57
+ * prefix: 'app:',
58
+ * stores: {
59
+ * redis: { driver: 'redis' }
60
+ * }
61
+ * };
62
+ * ```
63
+ */
64
+ export type CacheConfig = {
65
+ /**
66
+ * The name of the default store to use when no store is explicitly requested.
67
+ */
68
+ default?: string;
69
+ /**
70
+ * Global prefix prepended to all cache keys across all stores to prevent collisions.
71
+ */
72
+ prefix?: string;
73
+ /**
74
+ * Global default time-to-live for cache entries when not specified in write operations.
75
+ */
76
+ defaultTtl?: CacheTtl;
77
+ /**
78
+ * Map of named store configurations, optionally including pre-instantiated providers.
79
+ */
80
+ stores?: Record<string, StoreConfig & {
81
+ provider?: CacheStore;
82
+ }>;
83
+ };
84
+ /**
85
+ * Orchestrates multiple cache stores and provides a unified API.
86
+ *
87
+ * Acts as a central registry for cache repositories, supporting various drivers
88
+ * (Memory, File, Redis). It provides both a multi-store API for targeted operations
89
+ * and a proxy API that forwards calls to the default store.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const cache = new CacheManager(factory, {
94
+ * default: 'redis',
95
+ * stores: {
96
+ * redis: { driver: 'redis', prefix: 'myapp:' }
97
+ * }
98
+ * });
99
+ *
100
+ * await cache.set('key', 'value', 3600);
101
+ * const val = await cache.get('key');
102
+ * ```
103
+ *
104
+ * @public
105
+ * @since 3.0.0
106
+ */
107
+ export declare class CacheManager {
108
+ private readonly storeFactory;
109
+ private readonly config;
110
+ private readonly events?;
111
+ private readonly eventOptions?;
112
+ /**
113
+ * Internal registry of initialized cache repositories.
114
+ */
115
+ private stores;
116
+ /**
117
+ * Initialize a new CacheManager instance.
118
+ *
119
+ * @param storeFactory - Factory function to create low-level store instances by name.
120
+ * @param config - Configuration manifest for stores and global defaults.
121
+ * @param events - Optional event handlers for cache lifecycle hooks.
122
+ * @param eventOptions - Configuration for how events are dispatched and handled.
123
+ */
124
+ constructor(storeFactory: (name: string) => CacheStore, config?: CacheConfig, events?: CacheEvents, eventOptions?: {
125
+ mode?: CacheEventMode;
126
+ throwOnError?: boolean;
127
+ onError?: (error: unknown, event: keyof CacheEvents, payload: {
128
+ key?: string;
129
+ }) => void;
130
+ });
131
+ /**
132
+ * Get a rate limiter instance for a specific store.
133
+ *
134
+ * Provides a specialized interface for throttling actions based on cache keys,
135
+ * leveraging the underlying storage for persistence.
136
+ *
137
+ * @param name - Store name (defaults to the configured default store).
138
+ * @returns A RateLimiter instance bound to the requested store.
139
+ * @throws {Error} If the requested store cannot be initialized.
140
+ *
141
+ * @example
142
+ * ```typescript
143
+ * const limiter = cache.limiter('redis');
144
+ * if (await limiter.tooManyAttempts('login:1', 5)) {
145
+ * throw new Error('Too many attempts');
146
+ * }
147
+ * ```
148
+ */
149
+ limiter(name?: string): RateLimiter;
150
+ /**
151
+ * Resolve a named cache repository.
152
+ *
153
+ * Lazily initializes and caches the repository instance for the given store name.
154
+ * If no name is provided, it falls back to the default store.
155
+ *
156
+ * @param name - Store name to retrieve.
157
+ * @returns Initialized CacheRepository instance.
158
+ * @throws {Error} If the store factory fails to create the underlying store or the driver is unsupported.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const redis = cache.store('redis');
163
+ * await redis.put('key', 'value', 60);
164
+ * ```
165
+ */
166
+ store(name?: string): CacheRepository;
167
+ /**
168
+ * Retrieve an item from the default cache store.
169
+ *
170
+ * If the key is missing, the provided default value or the result of the
171
+ * default value closure will be returned.
172
+ *
173
+ * @param key - Unique cache key.
174
+ * @param defaultValue - Fallback value or factory to execute on cache miss.
175
+ * @returns Cached value or the resolved default.
176
+ * @throws {Error} If the underlying store driver encounters a read error or connection failure.
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const value = await cache.get('user:1', { name: 'Guest' });
181
+ * ```
182
+ */
183
+ get<T = unknown>(key: string, defaultValue?: T | (() => T | Promise<T>)): Promise<T>;
184
+ /**
185
+ * Determine if an item exists in the default cache store.
186
+ *
187
+ * @param key - The unique cache key.
188
+ * @returns True if the key exists and has not expired.
189
+ * @throws {Error} If the underlying store driver encounters a connection error.
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * if (await cache.has('session:active')) {
194
+ * // ...
195
+ * }
196
+ * ```
197
+ */
198
+ has(key: string): Promise<boolean>;
199
+ /**
200
+ * Determine if an item is missing from the default cache store.
201
+ *
202
+ * @param key - The unique cache key.
203
+ * @returns True if the key does not exist or has expired.
204
+ * @throws {Error} If the underlying store driver encounters a connection error.
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * if (await cache.missing('config:loaded')) {
209
+ * await loadConfig();
210
+ * }
211
+ * ```
212
+ */
213
+ missing(key: string): Promise<boolean>;
214
+ /**
215
+ * Store an item in the default cache store for a specific duration.
216
+ *
217
+ * @param key - The unique cache key.
218
+ * @param value - The data to be cached.
219
+ * @param ttl - Expiration time in seconds or a specific Date.
220
+ * @returns A promise that resolves when the write is complete.
221
+ * @throws {Error} If the value cannot be serialized or the store is read-only.
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * await cache.put('key', 'value', 60); // 60 seconds
226
+ * ```
227
+ */
228
+ put(key: string, value: unknown, ttl: CacheTtl): Promise<void>;
229
+ /**
230
+ * Store an item in the default cache store (alias for put).
231
+ *
232
+ * @param key - The unique cache key.
233
+ * @param value - The data to be cached.
234
+ * @param ttl - Optional expiration time.
235
+ * @returns A promise that resolves when the write is complete.
236
+ * @throws {Error} If the underlying store driver encounters a write error.
237
+ *
238
+ * @example
239
+ * ```typescript
240
+ * await cache.set('theme', 'dark');
241
+ * ```
242
+ */
243
+ set(key: string, value: unknown, ttl?: CacheTtl): Promise<void>;
244
+ /**
245
+ * Store an item in the default cache store only if it does not already exist.
246
+ *
247
+ * @param key - The unique cache key.
248
+ * @param value - The data to be cached.
249
+ * @param ttl - Optional expiration time.
250
+ * @returns True if the item was added, false if it already existed.
251
+ * @throws {Error} If the underlying store driver encounters a write error.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * const added = await cache.add('lock:process', true, 30);
256
+ * ```
257
+ */
258
+ add(key: string, value: unknown, ttl?: CacheTtl): Promise<boolean>;
259
+ /**
260
+ * Store an item in the default cache store indefinitely.
261
+ *
262
+ * @param key - The unique cache key.
263
+ * @param value - The data to be cached.
264
+ * @returns A promise that resolves when the write is complete.
265
+ * @throws {Error} If the underlying store driver encounters a write error.
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * await cache.forever('system:version', '1.0.0');
270
+ * ```
271
+ */
272
+ forever(key: string, value: unknown): Promise<void>;
273
+ /**
274
+ * Get an item from the cache, or execute the callback and store the result.
275
+ *
276
+ * Ensures the value is cached after the first miss. This provides an atomic-like
277
+ * "get or set" flow to prevent multiple concurrent fetches of the same data.
278
+ *
279
+ * @param key - Unique cache key.
280
+ * @param ttl - Duration to cache the result if a miss occurs.
281
+ * @param callback - Logic to execute to fetch fresh data.
282
+ * @returns Cached or freshly fetched value.
283
+ * @throws {Error} If the callback fails or the store write operation errors.
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * const user = await cache.remember('user:1', 60, async () => {
288
+ * return await db.findUser(1);
289
+ * });
290
+ * ```
291
+ */
292
+ remember<T = unknown>(key: string, ttl: CacheTtl, callback: () => Promise<T> | T): Promise<T>;
293
+ /**
294
+ * Get an item from the cache, or execute the callback and store the result forever.
295
+ *
296
+ * @param key - The unique cache key.
297
+ * @param callback - The closure to execute to fetch the fresh data.
298
+ * @returns The cached or freshly fetched value.
299
+ * @throws {Error} If the callback throws or the store write fails.
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * const settings = await cache.rememberForever('global:settings', () => {
304
+ * return fetchSettingsFromApi();
305
+ * });
306
+ * ```
307
+ */
308
+ rememberForever<T = unknown>(key: string, callback: () => Promise<T> | T): Promise<T>;
309
+ /**
310
+ * Retrieve multiple items from the default cache store by their keys.
311
+ *
312
+ * @param keys - An array of unique cache keys.
313
+ * @returns An object mapping keys to their cached values (or null if missing).
314
+ * @throws {Error} If the underlying store driver encounters a read error.
315
+ *
316
+ * @example
317
+ * ```typescript
318
+ * const values = await cache.many(['key1', 'key2']);
319
+ * ```
320
+ */
321
+ many<T = unknown>(keys: readonly string[]): Promise<Record<string, T>>;
322
+ /**
323
+ * Store multiple items in the default cache store for a specific duration.
324
+ *
325
+ * @param values - An object mapping keys to the values to be stored.
326
+ * @param ttl - Expiration time in seconds or a specific Date.
327
+ * @returns A promise that resolves when all writes are complete.
328
+ * @throws {Error} If the underlying store driver encounters a write error.
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * await cache.putMany({ a: 1, b: 2 }, 60);
333
+ * ```
334
+ */
335
+ putMany(values: Record<string, unknown>, ttl: CacheTtl): Promise<void>;
336
+ /**
337
+ * Get an item from the cache, allowing stale data while refreshing in background.
338
+ *
339
+ * Implements the Stale-While-Revalidate pattern to minimize latency for
340
+ * frequently accessed but expensive data.
341
+ *
342
+ * @param key - The unique cache key.
343
+ * @param ttlSeconds - How long the value is considered fresh.
344
+ * @param staleSeconds - How long to serve stale data while refreshing.
345
+ * @param callback - The closure to execute to refresh the data.
346
+ * @returns The cached (possibly stale) or freshly fetched value.
347
+ * @throws {Error} If the callback throws during an initial fetch.
348
+ *
349
+ * @example
350
+ * ```typescript
351
+ * const data = await cache.flexible('stats', 60, 30, () => fetchStats());
352
+ * ```
353
+ */
354
+ flexible<T = unknown>(key: string, ttlSeconds: number, staleSeconds: number, callback: () => Promise<T> | T): Promise<T>;
355
+ /**
356
+ * Retrieve an item from the default cache store and then delete it.
357
+ *
358
+ * Useful for one-time notifications or temporary tokens.
359
+ *
360
+ * @param key - The unique cache key.
361
+ * @param defaultValue - Fallback value if the key is missing.
362
+ * @returns The cached value before deletion, or the default.
363
+ * @throws {Error} If the underlying store driver encounters a read or delete error.
364
+ *
365
+ * @example
366
+ * ```typescript
367
+ * const token = await cache.pull('temp_token');
368
+ * ```
369
+ */
370
+ pull<T = unknown>(key: string, defaultValue?: T): Promise<T>;
371
+ /**
372
+ * Remove an item from the default cache store.
373
+ *
374
+ * @param key - The unique cache key.
375
+ * @returns True if the item was removed, false otherwise.
376
+ * @throws {Error} If the underlying store driver encounters a delete error.
377
+ *
378
+ * @example
379
+ * ```typescript
380
+ * await cache.forget('user:1');
381
+ * ```
382
+ */
383
+ forget(key: string): Promise<boolean>;
384
+ /**
385
+ * Remove an item from the default cache store (alias for forget).
386
+ *
387
+ * @param key - The unique cache key.
388
+ * @returns True if the item was removed, false otherwise.
389
+ * @throws {Error} If the underlying store driver encounters a delete error.
390
+ *
391
+ * @example
392
+ * ```typescript
393
+ * await cache.delete('old_key');
394
+ * ```
395
+ */
396
+ delete(key: string): Promise<boolean>;
397
+ /**
398
+ * Remove all items from the default cache store.
399
+ *
400
+ * @returns A promise that resolves when the flush is complete.
401
+ * @throws {Error} If the underlying store driver encounters a flush error.
402
+ *
403
+ * @example
404
+ * ```typescript
405
+ * await cache.flush();
406
+ * ```
407
+ */
408
+ flush(): Promise<void>;
409
+ /**
410
+ * Clear the entire default cache store (alias for flush).
411
+ *
412
+ * @returns A promise that resolves when the clear is complete.
413
+ * @throws {Error} If the underlying store driver encounters a clear error.
414
+ *
415
+ * @example
416
+ * ```typescript
417
+ * await cache.clear();
418
+ * ```
419
+ */
420
+ clear(): Promise<void>;
421
+ /**
422
+ * Increment the value of an integer item in the default cache store.
423
+ *
424
+ * @param key - Unique cache key.
425
+ * @param value - Amount to add.
426
+ * @returns New value after incrementing.
427
+ * @throws {Error} If existing value is not a number or the store is read-only.
428
+ *
429
+ * @example
430
+ * ```typescript
431
+ * const count = await cache.increment('page_views');
432
+ * ```
433
+ */
434
+ increment(key: string, value?: number): Promise<number>;
435
+ /**
436
+ * Decrement the value of an integer item in the default cache store.
437
+ *
438
+ * @param key - Unique cache key.
439
+ * @param value - Amount to subtract.
440
+ * @returns New value after decrementing.
441
+ * @throws {Error} If existing value is not a number or the store is read-only.
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * const remaining = await cache.decrement('stock:1');
446
+ * ```
447
+ */
448
+ decrement(key: string, value?: number): Promise<number>;
449
+ /**
450
+ * Get a distributed lock instance from the default cache store.
451
+ *
452
+ * @param name - The unique name of the lock.
453
+ * @param seconds - The duration the lock should be held for.
454
+ * @returns A CacheLock instance.
455
+ * @throws {Error} If the underlying store does not support locking.
456
+ *
457
+ * @example
458
+ * ```typescript
459
+ * const lock = cache.lock('process_data', 10);
460
+ * if (await lock.get()) {
461
+ * // ...
462
+ * await lock.release();
463
+ * }
464
+ * ```
465
+ */
466
+ lock(name: string, seconds?: number): import("./locks").CacheLock;
467
+ /**
468
+ * Access a tagged cache section for grouped operations.
469
+ *
470
+ * Tags allow you to clear groups of cache entries simultaneously.
471
+ * Note: This is only supported by specific drivers like 'memory'.
472
+ *
473
+ * @param tags - An array of tag names.
474
+ * @returns A tagged cache repository instance.
475
+ * @throws {Error} If the underlying store driver does not support tags.
476
+ *
477
+ * @example
478
+ * ```typescript
479
+ * await cache.tags(['users', 'profiles']).put('user:1', data, 60);
480
+ * await cache.tags(['users']).flush(); // Clears all 'users' tagged entries
481
+ * ```
482
+ */
483
+ tags(tags: readonly string[]): CacheRepository;
484
+ }