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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 safe-memory-layer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,501 @@
1
+ # Safe Memory Layer
2
+
3
+ Secure, lightweight, dependency-free in-memory storage with TTL support, automatic cleanup, and memory leak prevention for Node.js and modern browsers.
4
+
5
+ ## Features
6
+
7
+ - **Memory Safety**: Automatic cleanup of expired entries, leak prevention, and safe resource management
8
+ - **TTL Support**: Time-based expiration with lazy and active cleanup
9
+ - **Automatic Cleanup**: Background scheduler that stops when empty to save CPU
10
+ - **WeakMap Support**: Object-only storage with automatic garbage collection
11
+ - **LRU/FIFO Eviction**: Configurable strategies when reaching max entries
12
+ - **Event Callbacks**: Monitor expiration, deletion, and cleanup events
13
+ - **Statistics**: Track entries, expired count, deleted count, and uptime
14
+ - **Auto-Dispose**: Automatically dispose store after being empty for a configurable time
15
+ - **Zero Dependencies**: No external runtime dependencies
16
+ - **TypeScript**: Full generic typing with strict mode compatibility
17
+ - **Tree-Shakeable ESM**: Optimized bundle size
18
+ - **Browser & Node.js**: Works in both environments
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install safe-memory-layer
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```typescript
29
+ import { MemoryStore } from "safe-memory-layer";
30
+
31
+ // Create a store
32
+ const store = new MemoryStore<string, User>();
33
+
34
+ // Set values with optional TTL
35
+ store.set("user:123", user, { ttl: 60000 }); // Expires in 60 seconds
36
+
37
+ // Get values
38
+ const user = store.get("user:123");
39
+
40
+ // Check existence
41
+ if (store.has("user:123")) {
42
+ console.log("User exists");
43
+ }
44
+
45
+ // Clean up when done
46
+ store.dispose();
47
+ ```
48
+
49
+ ## API Reference
50
+
51
+ ### MemoryStore
52
+
53
+ The main in-memory store with TTL support and automatic cleanup.
54
+
55
+ #### Constructor
56
+
57
+ ```typescript
58
+ const store = new MemoryStore<K, V>(options?: MemoryStoreOptions<K, V>);
59
+ ```
60
+
61
+ **Options:**
62
+
63
+ | Option | Type | Default | Description |
64
+ |--------|------|---------|-------------|
65
+ | `defaultTTL` | `number \| undefined` | `undefined` | Default TTL in milliseconds for all entries |
66
+ | `cleanupInterval` | `number` | `10000` | Interval between automatic cleanup runs (ms) |
67
+ | `autoCleanup` | `boolean` | `true` | Enable automatic cleanup |
68
+ | `autoDispose` | `boolean` | `false` | Auto-dispose after being empty for `autoDisposeDelay` |
69
+ | `autoDisposeDelay` | `number` | `60000` | Delay before auto-dispose (ms) |
70
+ | `maxEntries` | `number \| undefined` | `undefined` | Maximum number of entries |
71
+ | `maxEntriesStrategy` | `"reject" \| "FIFO" \| "LRU"` | `"reject"` | Strategy when max entries is reached |
72
+ | `onExpire` | `(key: K, value: V) => void` | `undefined` | Callback when entry expires |
73
+ | `onDelete` | `(key: K, value: V) => void` | `undefined` | Callback when entry is deleted |
74
+ | `onCleanup` | `(stats: CleanupStats) => void` | `undefined` | Callback after cleanup cycle |
75
+
76
+ #### Methods
77
+
78
+ ##### set(key, value, options?)
79
+
80
+ Stores a value with the given key.
81
+
82
+ ```typescript
83
+ store.set("key", value, { ttl: 60000 });
84
+ ```
85
+
86
+ **Returns:** `boolean` - `true` if stored, `false` if rejected (max entries reached)
87
+
88
+ ##### get(key)
89
+
90
+ Retrieves a value by key.
91
+
92
+ ```typescript
93
+ const value = store.get("key");
94
+ ```
95
+
96
+ **Returns:** `V | undefined` - The value or `undefined` if not found/expired
97
+
98
+ ##### has(key)
99
+
100
+ Checks if a key exists and is not expired.
101
+
102
+ ```typescript
103
+ if (store.has("key")) {
104
+ // Key exists
105
+ }
106
+ ```
107
+
108
+ **Returns:** `boolean`
109
+
110
+ ##### delete(key)
111
+
112
+ Deletes a value by key.
113
+
114
+ ```typescript
115
+ const deleted = store.delete("key");
116
+ ```
117
+
118
+ **Returns:** `boolean` - `true` if key was present
119
+
120
+ ##### clear()
121
+
122
+ Removes all entries.
123
+
124
+ ```typescript
125
+ store.clear();
126
+ ```
127
+
128
+ ##### size
129
+
130
+ Returns the number of non-expired entries.
131
+
132
+ ```typescript
133
+ const count = store.size;
134
+ ```
135
+
136
+ **Returns:** `number`
137
+
138
+ ##### keys()
139
+
140
+ Returns an iterator of all keys.
141
+
142
+ ```typescript
143
+ for (const key of store.keys()) {
144
+ console.log(key);
145
+ }
146
+ ```
147
+
148
+ **Returns:** `IterableIterator<K>`
149
+
150
+ ##### values()
151
+
152
+ Returns an iterator of all non-expired values.
153
+
154
+ ```typescript
155
+ for (const value of store.values()) {
156
+ console.log(value);
157
+ }
158
+ ```
159
+
160
+ **Returns:** `IterableIterator<V>`
161
+
162
+ ##### entries()
163
+
164
+ Returns an iterator of all [key, value] pairs.
165
+
166
+ ```typescript
167
+ for (const [key, value] of store.entries()) {
168
+ console.log(key, value);
169
+ }
170
+ ```
171
+
172
+ **Returns:** `IterableIterator<[K, V]>`
173
+
174
+ ##### cleanup()
175
+
176
+ Removes all expired entries.
177
+
178
+ ```typescript
179
+ const removed = store.cleanup();
180
+ ```
181
+
182
+ **Returns:** `number` - Number of entries removed
183
+
184
+ ##### compact()
185
+
186
+ Alias for `cleanup()`.
187
+
188
+ ```typescript
189
+ const removed = store.compact();
190
+ ```
191
+
192
+ ##### stats()
193
+
194
+ Returns statistics about the store.
195
+
196
+ ```typescript
197
+ const stats = store.stats();
198
+ console.log(stats);
199
+ ```
200
+
201
+ **Returns:** `StoreStats`
202
+
203
+ ```typescript
204
+ interface StoreStats {
205
+ entries: number; // Current number of entries
206
+ expired: number; // Total expired entries
207
+ deleted: number; // Total deleted entries
208
+ cleaned: number; // Total cleanup cycles
209
+ uptime: number; // Uptime in milliseconds
210
+ memoryEstimate: number; // Estimated memory usage in bytes
211
+ }
212
+ ```
213
+
214
+ ##### dispose()
215
+
216
+ Disposes the store, stopping all timers and releasing references.
217
+
218
+ ```typescript
219
+ store.dispose();
220
+ ```
221
+
222
+ After disposal, the store cannot be used.
223
+
224
+ ##### disposed
225
+
226
+ Checks if the store has been disposed.
227
+
228
+ ```typescript
229
+ if (store.disposed) {
230
+ console.log("Store is disposed");
231
+ }
232
+ ```
233
+
234
+ **Returns:** `boolean`
235
+
236
+ ### WeakMemoryStore
237
+
238
+ Object-only storage using WeakMap for automatic garbage collection.
239
+
240
+ #### Constructor
241
+
242
+ ```typescript
243
+ const weakStore = new WeakMemoryStore<V>(options?: WeakMemoryStoreOptions<V>);
244
+ ```
245
+
246
+ **Options:**
247
+
248
+ | Option | Type | Default | Description |
249
+ |--------|------|---------|-------------|
250
+ | `onDelete` | `(value: V) => void` | `undefined` | Callback when entry is deleted |
251
+
252
+ #### Methods
253
+
254
+ ##### set(key, value)
255
+
256
+ Stores a value with an object key.
257
+
258
+ ```typescript
259
+ const obj = { id: 1 };
260
+ weakStore.set(obj, { name: "Alice" });
261
+ ```
262
+
263
+ **Returns:** `boolean`
264
+
265
+ ##### get(key)
266
+
267
+ Retrieves a value by object key.
268
+
269
+ ```typescript
270
+ const value = weakStore.get(obj);
271
+ ```
272
+
273
+ **Returns:** `V | undefined`
274
+
275
+ ##### has(key)
276
+
277
+ Checks if a key exists.
278
+
279
+ ```typescript
280
+ if (weakStore.has(obj)) {
281
+ // Key exists
282
+ }
283
+ ```
284
+
285
+ **Returns:** `boolean`
286
+
287
+ ##### delete(key)
288
+
289
+ Deletes a value by object key.
290
+
291
+ ```typescript
292
+ const deleted = weakStore.delete(obj);
293
+ ```
294
+
295
+ **Returns:** `boolean`
296
+
297
+ ##### clear()
298
+
299
+ Removes all entries.
300
+
301
+ ```typescript
302
+ weakStore.clear();
303
+ ```
304
+
305
+ ##### deleted
306
+
307
+ Returns the number of deleted entries.
308
+
309
+ ```typescript
310
+ const count = weakStore.deleted;
311
+ ```
312
+
313
+ **Returns:** `number`
314
+
315
+ ##### stats()
316
+
317
+ Returns statistics.
318
+
319
+ ```typescript
320
+ const stats = weakStore.stats();
321
+ ```
322
+
323
+ **Returns:** `{ deleted: number; uptime: number }`
324
+
325
+ ##### dispose()
326
+
327
+ Disposes the store.
328
+
329
+ ```typescript
330
+ weakStore.dispose();
331
+ ```
332
+
333
+ ##### disposed
334
+
335
+ Checks if the store has been disposed.
336
+
337
+ ```typescript
338
+ if (weakStore.disposed) {
339
+ console.log("Store is disposed");
340
+ }
341
+ ```
342
+
343
+ **Returns:** `boolean`
344
+
345
+ ## Examples
346
+
347
+ ### Basic Cache
348
+
349
+ ```typescript
350
+ const cache = new MemoryStore<string, string>();
351
+ cache.set("key", "value");
352
+ console.log(cache.get("key")); // "value"
353
+ cache.dispose();
354
+ ```
355
+
356
+ ### TTL Cache
357
+
358
+ ```typescript
359
+ const ttlCache = new MemoryStore<string, User>({
360
+ defaultTTL: 60000, // 1 minute
361
+ cleanupInterval: 10000,
362
+ });
363
+
364
+ ttlCache.set("user:1", user, { ttl: 30000 }); // 30 seconds
365
+ ```
366
+
367
+ ### Session Storage
368
+
369
+ ```typescript
370
+ const sessionStore = new MemoryStore<string, Session>({
371
+ defaultTTL: 30 * 60 * 1000, // 30 minutes
372
+ maxEntries: 1000,
373
+ maxEntriesStrategy: "LRU",
374
+ });
375
+
376
+ sessionStore.set(sessionId, sessionData);
377
+ ```
378
+
379
+ ### Token Storage
380
+
381
+ ```typescript
382
+ const authStore = new MemoryStore<string, TokenData>({
383
+ defaultTTL: 3600000, // 1 hour
384
+ maxEntries: 5000,
385
+ maxEntriesStrategy: "FIFO",
386
+ });
387
+
388
+ authStore.set(`token:${token}`, tokenData);
389
+ ```
390
+
391
+ ### Weak Object Cache
392
+
393
+ ```typescript
394
+ const weakStore = new WeakMemoryStore<UserData>();
395
+
396
+ const user = { id: 1 };
397
+ weakStore.set(user, { name: "Alice" });
398
+
399
+ // When 'user' is garbage collected, entry is automatically removed
400
+ ```
401
+
402
+ ### Event Monitoring
403
+
404
+ ```typescript
405
+ const store = new MemoryStore<string, Data>({
406
+ onExpire: (key, value) => {
407
+ console.log(`Expired: ${key}`);
408
+ },
409
+ onDelete: (key, value) => {
410
+ console.log(`Deleted: ${key}`);
411
+ },
412
+ onCleanup: (stats) => {
413
+ console.log(`Cleaned ${stats.removed} entries`);
414
+ },
415
+ });
416
+ ```
417
+
418
+ ### Auto-Dispose
419
+
420
+ ```typescript
421
+ const store = new MemoryStore<string, Data>({
422
+ autoDispose: true,
423
+ autoDisposeDelay: 60000, // 1 minute
424
+ });
425
+
426
+ store.set("key", value);
427
+ store.delete("key");
428
+ // Store will auto-dispose after 1 minute of being empty
429
+ ```
430
+
431
+ ## Best Practices
432
+
433
+ 1. **Always dispose stores**: Call `dispose()` when done to release timers and references
434
+ 2. **Use appropriate TTLs**: Set TTLs based on data freshness requirements
435
+ 3. **Configure cleanup interval**: Balance between cleanup frequency and CPU usage
436
+ 4. **Use LRU for caches**: LRU eviction works well for cache scenarios
437
+ 5. **Use FIFO for queues**: FIFO eviction works well for queue-like data
438
+ 6. **Monitor with callbacks**: Use event callbacks to track store behavior
439
+ 7. **Avoid storing large objects**: Keep values small for better performance
440
+ 8. **Use WeakMemoryStore for object metadata**: When keys are objects that may be GC'd
441
+
442
+ ## Performance
443
+
444
+ - **O(1)** get, set, delete operations
445
+ - **O(n)** cleanup (iterates all entries)
446
+ - **O(n)** size (counts non-expired entries)
447
+ - Minimal memory allocations
448
+ - Single timer for all cleanup operations
449
+ - Automatic scheduler pause when empty
450
+
451
+ ## Browser Compatibility
452
+
453
+ Works in all modern browsers that support:
454
+ - ES2022
455
+ - WeakMap
456
+ - Map
457
+ - setTimeout/setInterval
458
+
459
+ No Node.js-specific APIs are used.
460
+
461
+ ## TypeScript Support
462
+
463
+ Full TypeScript support with generics:
464
+
465
+ ```typescript
466
+ interface User {
467
+ id: string;
468
+ name: string;
469
+ email: string;
470
+ }
471
+
472
+ const store = new MemoryStore<string, User>();
473
+ store.set("user:1", { id: "1", name: "Alice", email: "alice@example.com" });
474
+ const user = store.get("user:1"); // Type: User | undefined
475
+ ```
476
+
477
+ ## License
478
+
479
+ MIT
480
+
481
+ ## Contributing
482
+
483
+ Contributions are welcome! Please ensure all tests pass before submitting a PR.
484
+
485
+ ```bash
486
+ npm test
487
+ ```
488
+
489
+ ## Changelog
490
+
491
+ ### 1.0.0
492
+
493
+ - Initial release
494
+ - MemoryStore with TTL support
495
+ - WeakMemoryStore with WeakMap
496
+ - Automatic cleanup scheduler
497
+ - LRU/FIFO eviction strategies
498
+ - Event callbacks
499
+ - Statistics tracking
500
+ - Auto-dispose feature
501
+ - Full TypeScript support