safe-memory-layer 1.0.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.
@@ -0,0 +1,650 @@
1
+ /**
2
+ * Core type definitions for safe-memory-layer.
3
+ *
4
+ * @module types
5
+ */
6
+ /** Strategy to use when the store reaches its maximum entry limit. */
7
+ type MaxEntriesStrategy = "reject" | "FIFO" | "LRU";
8
+ /** Options for setting an individual entry. */
9
+ interface SetOptions {
10
+ /** Time-to-live in milliseconds. After this duration, the entry expires. */
11
+ ttl?: number;
12
+ }
13
+ /** Configuration options for creating a MemoryStore. */
14
+ interface MemoryStoreOptions<K, V> {
15
+ /** Default TTL in milliseconds for all entries (default: no expiration). */
16
+ defaultTTL?: number;
17
+ /** Interval in milliseconds between automatic cleanup runs (default: 10000). */
18
+ cleanupInterval?: number;
19
+ /** Whether to automatically run cleanup on an interval (default: true). */
20
+ autoCleanup?: boolean;
21
+ /** Whether to automatically dispose the store after being empty for a configurable time (default: false). */
22
+ autoDispose?: boolean;
23
+ /** Time in milliseconds to wait after empty before auto-disposing (default: 60000). */
24
+ autoDisposeDelay?: number;
25
+ /** Maximum number of entries allowed in the store (default: no limit). */
26
+ maxEntries?: number;
27
+ /** Strategy when max entries is reached (default: "reject"). */
28
+ maxEntriesStrategy?: MaxEntriesStrategy;
29
+ /** Callback invoked when an entry expires. */
30
+ onExpire?: (key: K, value: V) => void;
31
+ /** Callback invoked when an entry is deleted. */
32
+ onDelete?: (key: K, value: V) => void;
33
+ /** Callback invoked after a cleanup cycle completes. */
34
+ onCleanup?: (stats: CleanupStats) => void;
35
+ }
36
+ /** Statistics about a cleanup cycle. */
37
+ interface CleanupStats {
38
+ /** Number of entries removed during cleanup. */
39
+ removed: number;
40
+ /** Total number of entries before cleanup. */
41
+ totalBefore: number;
42
+ /** Total number of entries after cleanup. */
43
+ totalAfter: number;
44
+ /** Duration of the cleanup cycle in milliseconds. */
45
+ duration: number;
46
+ }
47
+ /** Statistics about the store. */
48
+ interface StoreStats {
49
+ /** Current number of entries in the store. */
50
+ entries: number;
51
+ /** Total number of entries that have expired. */
52
+ expired: number;
53
+ /** Total number of entries that have been deleted. */
54
+ deleted: number;
55
+ /** Total number of cleanup cycles completed. */
56
+ cleaned: number;
57
+ /** Uptime of the store in milliseconds. */
58
+ uptime: number;
59
+ /** Estimated memory usage in bytes (approximate). */
60
+ memoryEstimate: number;
61
+ }
62
+ /** Internal entry stored in the map. */
63
+ interface InternalEntry<K, V> {
64
+ /** The stored value. */
65
+ value: V;
66
+ /** The key (stored for cleanup callbacks). */
67
+ key: K;
68
+ /** Expiration timestamp (ms since epoch), or undefined if no expiration. */
69
+ expiresAt: number | undefined;
70
+ /** Timestamp of last access (for LRU). */
71
+ lastAccessed: number;
72
+ /** Timestamp of creation. */
73
+ createdAt: number;
74
+ }
75
+ /** Internal options for the MemoryStore constructor. */
76
+ interface InternalStoreOptions<K, V> {
77
+ defaultTTL: number | undefined;
78
+ cleanupInterval: number;
79
+ autoCleanup: boolean;
80
+ autoDispose: boolean;
81
+ autoDisposeDelay: number;
82
+ maxEntries: number | undefined;
83
+ maxEntriesStrategy: MaxEntriesStrategy;
84
+ onExpire: ((key: K, value: V) => void) | undefined;
85
+ onDelete: ((key: K, value: V) => void) | undefined;
86
+ onCleanup: ((stats: CleanupStats) => void) | undefined;
87
+ }
88
+ /** Options for WeakMemoryStore. */
89
+ interface WeakMemoryStoreOptions<V> {
90
+ /** Callback invoked when an entry is deleted. */
91
+ onDelete?: (value: V) => void;
92
+ }
93
+ /** Feature detection result for FinalizationRegistry. */
94
+ interface FeatureSupport {
95
+ /** Whether FinalizationRegistry is available. */
96
+ finalizationRegistry: boolean;
97
+ }
98
+
99
+ /**
100
+ * Main MemoryStore implementation for safe-memory-layer.
101
+ *
102
+ * Provides a secure, lightweight, dependency-free abstraction for storing
103
+ * temporary in-memory data with TTL support, automatic cleanup, and
104
+ * memory leak prevention.
105
+ *
106
+ * @module MemoryStore
107
+ */
108
+
109
+ /**
110
+ * A secure, high-performance in-memory store with TTL support,
111
+ * automatic cleanup, and memory leak prevention.
112
+ *
113
+ * @typeParam K - The type of keys stored in the map.
114
+ * @typeParam V - The type of values stored in the map.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const store = new MemoryStore<string, User>();
119
+ *
120
+ * // Set with TTL
121
+ * store.set("user:123", user, { ttl: 60000 });
122
+ *
123
+ * // Get
124
+ * const user = store.get("user:123");
125
+ * ```
126
+ */
127
+ declare class MemoryStore<K, V> implements Iterable<[K, V]> {
128
+ #private;
129
+ /**
130
+ * Creates a new MemoryStore instance.
131
+ *
132
+ * @param options - Configuration options for the store.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const store = new MemoryStore({
137
+ * defaultTTL: 60000,
138
+ * cleanupInterval: 5000,
139
+ * autoCleanup: true,
140
+ * maxEntries: 1000,
141
+ * maxEntriesStrategy: "LRU"
142
+ * });
143
+ * ```
144
+ */
145
+ constructor(options?: MemoryStoreOptions<K, V>);
146
+ /**
147
+ * Stores a value with the given key.
148
+ *
149
+ * @param key - The key to store the value under.
150
+ * @param value - The value to store.
151
+ * @param options - Optional settings (e.g., TTL).
152
+ * @returns True if the value was stored, false if rejected (e.g., max entries reached).
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * store.set("token", token, { ttl: 60000 });
157
+ * ```
158
+ */
159
+ set(key: K, value: V, options?: SetOptions): boolean;
160
+ /**
161
+ * Retrieves a value by key.
162
+ *
163
+ * @param key - The key to look up.
164
+ * @returns The value if found and not expired, undefined otherwise.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * const user = store.get("user:123");
169
+ * ```
170
+ */
171
+ get(key: K): V | undefined;
172
+ /**
173
+ * Checks if a key exists in the store and is not expired.
174
+ *
175
+ * @param key - The key to check.
176
+ * @returns True if the key exists and is not expired.
177
+ */
178
+ has(key: K): boolean;
179
+ /**
180
+ * Deletes a value by key.
181
+ *
182
+ * @param key - The key to delete.
183
+ * @returns True if the key was present, false otherwise.
184
+ */
185
+ delete(key: K): boolean;
186
+ /**
187
+ * Removes all entries from the store.
188
+ */
189
+ clear(): void;
190
+ /**
191
+ * Returns the number of entries in the store.
192
+ * Excludes expired entries.
193
+ */
194
+ get size(): number;
195
+ /**
196
+ * Returns an iterator of all keys.
197
+ */
198
+ keys(): IterableIterator<K>;
199
+ /**
200
+ * Returns an iterator of all values.
201
+ */
202
+ values(): IterableIterator<V>;
203
+ /**
204
+ * Returns an iterator of all [key, value] pairs.
205
+ */
206
+ entries(): IterableIterator<[K, V]>;
207
+ /**
208
+ * Returns an iterator for the store (for...of support).
209
+ */
210
+ [Symbol.iterator](): IterableIterator<[K, V]>;
211
+ /**
212
+ * Runs a cleanup cycle, removing all expired entries.
213
+ *
214
+ * @returns The number of entries removed.
215
+ */
216
+ cleanup(): number;
217
+ /**
218
+ * Compacts the store by removing expired entries.
219
+ * Alias for cleanup().
220
+ */
221
+ compact(): number;
222
+ /**
223
+ * Returns statistics about the store.
224
+ *
225
+ * @returns A snapshot of the current statistics.
226
+ */
227
+ stats(): StoreStats;
228
+ /**
229
+ * Disposes the store, stopping all timers and releasing references.
230
+ * After disposal, the store cannot be used.
231
+ */
232
+ dispose(): void;
233
+ /**
234
+ * Checks if the store has been disposed.
235
+ */
236
+ get disposed(): boolean;
237
+ }
238
+
239
+ /**
240
+ * WeakMemoryStore implementation for safe-memory-layer.
241
+ *
242
+ * Provides an object-only storage layer using WeakMap internally.
243
+ * Objects disappear automatically after garbage collection.
244
+ * No iteration, no manual cleanup required.
245
+ *
246
+ * @module WeakMemoryStore
247
+ */
248
+
249
+ /**
250
+ * A memory store that uses WeakMap for object-only storage.
251
+ *
252
+ * Keys must be objects. Values are held weakly and will be
253
+ * automatically garbage collected when no longer referenced elsewhere.
254
+ *
255
+ * **Limitations:**
256
+ * - Keys must be objects (not primitives)
257
+ * - No iteration support (WeakMap is not iterable)
258
+ * - No size property
259
+ * - No TTL support
260
+ * - No automatic cleanup needed
261
+ *
262
+ * @typeParam V - The type of values stored in the map.
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * const weakStore = new WeakMemoryStore<User>();
267
+ *
268
+ * const user = { id: 1, name: "Alice" };
269
+ * weakStore.set(user, userData);
270
+ *
271
+ * // When 'user' is no longer referenced, the entry is automatically removed
272
+ * ```
273
+ */
274
+ declare class WeakMemoryStore<V> {
275
+ #private;
276
+ /**
277
+ * Creates a new WeakMemoryStore instance.
278
+ *
279
+ * @param options - Configuration options for the store.
280
+ *
281
+ * @example
282
+ * ```ts
283
+ * const store = new WeakMemoryStore({
284
+ * onDelete: (value) => console.log("Deleted:", value)
285
+ * });
286
+ * ```
287
+ */
288
+ constructor(options?: WeakMemoryStoreOptions<V>);
289
+ /**
290
+ * Stores a value with the given object key.
291
+ *
292
+ * @param key - The object key to store the value under. Must be an object.
293
+ * @param value - The value to store.
294
+ * @returns True if the value was stored.
295
+ *
296
+ * @example
297
+ * ```ts
298
+ * const obj = { id: 1 };
299
+ * weakStore.set(obj, { name: "Alice" });
300
+ * ```
301
+ */
302
+ set(key: object, value: V): boolean;
303
+ /**
304
+ * Retrieves a value by object key.
305
+ *
306
+ * @param key - The object key to look up.
307
+ * @returns The value if found, undefined otherwise.
308
+ *
309
+ * @example
310
+ * ```ts
311
+ * const user = weakStore.get(obj);
312
+ * ```
313
+ */
314
+ get(key: object): V | undefined;
315
+ /**
316
+ * Checks if a key exists in the store.
317
+ *
318
+ * @param key - The object key to check.
319
+ * @returns True if the key exists.
320
+ */
321
+ has(key: object): boolean;
322
+ /**
323
+ * Deletes a value by object key.
324
+ *
325
+ * @param key - The object key to delete.
326
+ * @returns True if the key was present, false otherwise.
327
+ */
328
+ delete(key: object): boolean;
329
+ /**
330
+ * Removes all entries from the store.
331
+ * Note: This does not prevent garbage collection of the keys.
332
+ */
333
+ clear(): void;
334
+ /**
335
+ * Returns the number of deleted entries.
336
+ * Note: Cannot return current size (WeakMap limitation).
337
+ */
338
+ get deleted(): number;
339
+ /**
340
+ * Returns statistics about the store.
341
+ * Note: entries count is not available for WeakMap.
342
+ *
343
+ * @returns A snapshot of the current statistics.
344
+ */
345
+ stats(): {
346
+ deleted: number;
347
+ uptime: number;
348
+ };
349
+ /**
350
+ * Disposes the store, releasing the WeakMap reference.
351
+ * After disposal, the store cannot be used.
352
+ */
353
+ dispose(): void;
354
+ /**
355
+ * Checks if the store has been disposed.
356
+ */
357
+ get disposed(): boolean;
358
+ }
359
+
360
+ /**
361
+ * Scheduler for automatic cleanup of expired entries.
362
+ *
363
+ * Design:
364
+ * - Single interval timer for all cleanup operations
365
+ * - Automatically stops when the store is empty to save CPU
366
+ * - Restarts when new entries are added
367
+ * - Very low CPU usage with configurable interval
368
+ *
369
+ * @module Scheduler
370
+ */
371
+ /**
372
+ * Function type for cleanup callbacks.
373
+ * Returns the number of entries that were cleaned up.
374
+ */
375
+ type CleanupFn = () => number;
376
+ /**
377
+ * Manages a periodic cleanup scheduler.
378
+ * Stops automatically when empty, restarts when needed.
379
+ */
380
+ declare class Scheduler {
381
+ #private;
382
+ /**
383
+ * Creates a new Scheduler.
384
+ *
385
+ * @param cleanupFn - Function to call for cleanup. Should return count of removed entries.
386
+ * @param interval - Interval in milliseconds between cleanup runs.
387
+ * @param onEmpty - Optional callback when cleanup finds the store empty.
388
+ */
389
+ constructor(cleanupFn: CleanupFn, interval: number, onEmpty?: () => void);
390
+ /**
391
+ * Starts the scheduler if it's not already running.
392
+ * Does nothing if already started.
393
+ */
394
+ start(): void;
395
+ /**
396
+ * Stops the scheduler if running.
397
+ * Safe to call multiple times.
398
+ */
399
+ stop(): void;
400
+ /**
401
+ * Restarts the scheduler (stops then starts).
402
+ */
403
+ restart(): void;
404
+ /**
405
+ * Whether the scheduler is currently running.
406
+ */
407
+ get running(): boolean;
408
+ /**
409
+ * Disposes the scheduler, stopping it and releasing all references.
410
+ */
411
+ dispose(): void;
412
+ }
413
+
414
+ /**
415
+ * Statistics tracking for safe-memory-layer.
416
+ *
417
+ * Tracks store metrics including entry counts, expiration counts,
418
+ * deletion counts, cleanup cycles, uptime, and memory estimates.
419
+ *
420
+ * @module Stats
421
+ */
422
+
423
+ /**
424
+ * Tracks statistics for a MemoryStore instance.
425
+ *
426
+ * All counters are monotonically increasing (except entries).
427
+ */
428
+ declare class Stats {
429
+ #private;
430
+ /**
431
+ * Creates a new Stats instance.
432
+ *
433
+ * @param createdAt - Timestamp when the store was created.
434
+ */
435
+ constructor(createdAt: number);
436
+ /**
437
+ * Increments the expired counter.
438
+ */
439
+ incrementExpired(): void;
440
+ /**
441
+ * Increments the deleted counter.
442
+ */
443
+ incrementDeleted(): void;
444
+ /**
445
+ * Increments the cleaned counter.
446
+ */
447
+ incrementCleaned(): void;
448
+ /**
449
+ * Sets the current number of entries.
450
+ *
451
+ * @param count - The current entry count.
452
+ */
453
+ setEntries(count: number): void;
454
+ /**
455
+ * Returns the current statistics snapshot.
456
+ *
457
+ * @param currentEntries - Current number of entries (overrides internal count).
458
+ * @returns A snapshot of the current statistics.
459
+ */
460
+ snapshot(currentEntries?: number): StoreStats;
461
+ /**
462
+ * Creates a cleanup stats object.
463
+ *
464
+ * @param removed - Number of entries removed.
465
+ * @param totalBefore - Total entries before cleanup.
466
+ * @param totalAfter - Total entries after cleanup.
467
+ * @param duration - Duration of cleanup in ms.
468
+ * @returns A CleanupStats object.
469
+ */
470
+ createCleanupStats(removed: number, totalBefore: number, totalAfter: number, duration: number): CleanupStats;
471
+ /**
472
+ * Estimates memory usage based on entry count.
473
+ * This is a rough approximation for monitoring purposes.
474
+ *
475
+ * @param entryCount - Number of entries.
476
+ * @returns Estimated memory usage in bytes.
477
+ */
478
+ estimateMemory(entryCount: number): number;
479
+ /**
480
+ * Resets all statistics.
481
+ */
482
+ reset(): void;
483
+ }
484
+
485
+ /**
486
+ * Event handling utilities for safe-memory-layer.
487
+ *
488
+ * Provides type-safe event emission with error isolation.
489
+ * All callbacks are wrapped to prevent crashes from propagating.
490
+ *
491
+ * @module Events
492
+ */
493
+
494
+ /**
495
+ * Type-safe event emitter for store events.
496
+ * All callbacks are error-isolated.
497
+ */
498
+ declare class EventEmitter<K, V> {
499
+ #private;
500
+ /**
501
+ * Registers a listener for the expire event.
502
+ *
503
+ * @param callback - Function to call when an entry expires.
504
+ */
505
+ onExpire(callback: (key: K, value: V) => void): void;
506
+ /**
507
+ * Registers a listener for the delete event.
508
+ *
509
+ * @param callback - Function to call when an entry is deleted.
510
+ */
511
+ onDelete(callback: (key: K, value: V) => void): void;
512
+ /**
513
+ * Registers a listener for the cleanup event.
514
+ *
515
+ * @param callback - Function to call after cleanup completes.
516
+ */
517
+ onCleanup(callback: (stats: CleanupStats) => void): void;
518
+ /**
519
+ * Emits an expire event to all registered listeners.
520
+ * Errors in callbacks are isolated and logged.
521
+ *
522
+ * @param key - The key of the expired entry.
523
+ * @param value - The value of the expired entry.
524
+ */
525
+ emitExpire(key: K, value: V): void;
526
+ /**
527
+ * Emits a delete event to all registered listeners.
528
+ * Errors in callbacks are isolated and logged.
529
+ *
530
+ * @param key - The key of the deleted entry.
531
+ * @param value - The value of the deleted entry.
532
+ */
533
+ emitDelete(key: K, value: V): void;
534
+ /**
535
+ * Emits a cleanup event to all registered listeners.
536
+ * Errors in callbacks are isolated and logged.
537
+ *
538
+ * @param stats - The cleanup statistics.
539
+ */
540
+ emitCleanup(stats: CleanupStats): void;
541
+ /**
542
+ * Removes all event listeners.
543
+ */
544
+ removeAllListeners(): void;
545
+ /**
546
+ * Disposes the event emitter, removing all listeners.
547
+ */
548
+ dispose(): void;
549
+ }
550
+
551
+ /**
552
+ * Entry type and factory for safe-memory-layer.
553
+ *
554
+ * Represents a single entry in the memory store with expiration tracking.
555
+ *
556
+ * @module Entry
557
+ */
558
+
559
+ /**
560
+ * Creates a new internal entry with the given value and options.
561
+ *
562
+ * @param key - The key for this entry.
563
+ * @param value - The value to store.
564
+ * @param options - Optional settings including TTL.
565
+ * @param now - Current timestamp (for testability).
566
+ * @returns A new InternalEntry instance.
567
+ */
568
+ declare function createEntry<K, V>(key: K, value: V, options?: SetOptions, now?: number): InternalEntry<K, V>;
569
+ /**
570
+ * Checks whether an entry has expired.
571
+ *
572
+ * @param entry - The entry to check.
573
+ * @param now - Current timestamp (for testability).
574
+ * @returns True if the entry has expired.
575
+ */
576
+ declare function isExpired<K, V>(entry: InternalEntry<K, V>, now?: number): boolean;
577
+ /**
578
+ * Updates the last accessed timestamp on an entry.
579
+ * Uses a monotonic counter to ensure unique LRU ordering.
580
+ *
581
+ * @param entry - The entry to update.
582
+ * @param now - Current timestamp (for testability).
583
+ */
584
+ declare function touchEntry<K, V>(entry: InternalEntry<K, V>, now?: number): void;
585
+ /**
586
+ * Calculates the remaining TTL in milliseconds.
587
+ *
588
+ * @param entry - The entry to check.
589
+ * @param now - Current timestamp (for testability).
590
+ * @returns Remaining milliseconds, or undefined if no expiration.
591
+ */
592
+ declare function getRemainingTTL<K, V>(entry: InternalEntry<K, V>, now?: number): number | undefined;
593
+
594
+ /**
595
+ * Safe timer utilities for safe-memory-layer.
596
+ *
597
+ * Provides platform-agnostic timer creation and cleanup.
598
+ * Uses only Web-compatible APIs (setTimeout/clearTimeout).
599
+ *
600
+ * @module utils/timer
601
+ */
602
+ /** Represents a timer handle that can be cancelled. */
603
+ interface TimerHandle {
604
+ /** Cancels the timer. Safe to call multiple times. */
605
+ cancel: () => void;
606
+ /** Whether the timer has been cancelled. */
607
+ readonly cancelled: boolean;
608
+ }
609
+ /**
610
+ * Creates a safe timer that can be cancelled.
611
+ * Uses setTimeout internally for maximum compatibility.
612
+ *
613
+ * @param fn - The function to execute after the delay.
614
+ * @param delay - The delay in milliseconds.
615
+ * @returns A TimerHandle that can be used to cancel the timer.
616
+ */
617
+ declare function createTimer(fn: () => void, delay: number): TimerHandle;
618
+ /**
619
+ * Creates an interval timer that runs a function repeatedly.
620
+ *
621
+ * @param fn - The function to execute on each interval.
622
+ * @param interval - The interval in milliseconds.
623
+ * @returns A TimerHandle that can be used to cancel the interval.
624
+ */
625
+ declare function createInterval(fn: () => void, interval: number): TimerHandle;
626
+
627
+ /**
628
+ * Feature detection utilities for safe-memory-layer.
629
+ *
630
+ * Detects available platform features and provides graceful fallbacks.
631
+ *
632
+ * @module utils/featureDetection
633
+ */
634
+
635
+ /**
636
+ * Detects which platform features are available.
637
+ * This is called once at module load time and cached.
638
+ */
639
+ declare function detectFeatures(): FeatureSupport;
640
+ /**
641
+ * Returns the cached feature support flags, detecting them on first call.
642
+ */
643
+ declare function getFeatures(): FeatureSupport;
644
+ /**
645
+ * Creates a FinalizationRegistry if available, otherwise returns null.
646
+ * Never throws if FinalizationRegistry is unavailable.
647
+ */
648
+ declare function createSafeFinalizationRegistry<T>(cleanup: (heldValue: T) => void): FinalizationRegistry<T> | null;
649
+
650
+ export { type CleanupFn, type CleanupStats, EventEmitter, type FeatureSupport, type InternalEntry, type InternalStoreOptions, type MaxEntriesStrategy, MemoryStore, type MemoryStoreOptions, Scheduler, type SetOptions, Stats, type StoreStats, type TimerHandle, WeakMemoryStore, type WeakMemoryStoreOptions, createEntry, createInterval, createSafeFinalizationRegistry, createTimer, detectFeatures, getFeatures, getRemainingTTL, isExpired, touchEntry };