# 📦 TinyMapCache Documentation

`TinyMapCache` is a lightweight, event-driven, in-memory cache manager designed for JavaScript environments. It is optimized for preventing duplicate requests and managing temporary data with automatic expiration.

## 🌟 Key Features

*   🚀 **High Performance:** Uses an in-memory `Map` for near-instantaneous data retrieval.
*   ⏱️ **TTL (Time-To-Live):** Automatically handles data expiration based on a configurable millisecond timer.
*   🔔 **Event-Driven Architecture:** Extends `EventEmitter` to provide hooks for lifecycle changes (`set`, `delete`, `expire`, `purge`, `clear`).
*   🛡️ **Data Integrity:** Uses `structuredClone` to return deep copies of data, preventing accidental mutations of the cached items.
*   🧹 **Cascaded Purging:** Features a unique "Global Purge" capability that can trigger expiration checks across all active cache instances simultaneously.
*   🔁 **Familiar Iteration API:** Implements `keys()`, `values()`, `entries()`, `forEach()` and `Symbol.iterator`, so it can be used in `for...of` loops and spread syntax just like a native `Map`.

---

## 🛠️ Getting Started

### Installation
Since this is an ES6 module, ensure your environment supports `import` syntax.

```javascript
import TinyMapCache from 'tiny-essentials/libs/storage/TinyMapCache';
```

### Basic Initialization
```javascript
const cache = new TinyMapCache();

// Set a custom TTL (e.g., 10 seconds)
cache.ttl = 10000; 
```

---

## 📖 API Reference

### ⚙️ Configuration & Properties

| Property | Type | Description |
| :--- | :--- | :--- |
| `ttl` | `number` | The Time-To-Live in milliseconds. Default is `300000` (5 minutes). |
| `size` | `number` | Returns the current number of items stored in the cache. |
| `[Symbol.toStringTag]` | `string` | Read-only. Always returns `'TinyMapCache'`. Used by `Object.prototype.toString`. |

### 🚀 Methods

#### `.set(key, data)`
Stores a value in the cache associated with a specific key.
*   **Key:** `string` (Required)
*   **Data:** `any` (Required)
*   **Note:** Triggers `purgeExpired(true)` before saving.

#### `.get(key)`
Retrieves the data associated with the key.
*   **Key:** `string` (Required)
*   **Returns:** The stored data if valid; `null` if expired or not found.
*   **Note:** Triggers `purgeExpired(true)` before retrieving.

#### `.has(key)`
Checks if a key exists and is valid (not expired).
*   **Key:** `string` (Required)
*   **Returns:** `boolean`
*   **Note:** Triggers `purgeExpired(true)` before checking.

#### `.delete(key)`
Removes a specific item from the cache.
*   **Key:** `string` (Required)
*   **Returns:** `boolean` (True if an element existed and was removed).

#### `.clear()`
Wipes all items from the current cache instance.

#### `.purgeExpired(clearAll = false)`
Manually triggers the expiration logic.
*   **`clearAll = true`**: Triggers a purge across **all** active `TinyMapCache` instances in the application.
*   **`clearAll = false`**: Only purges expired items in the current instance.

#### `.keys()`
Returns an iterator over the keys of all valid (non-expired) entries.
*   **Returns:** `IterableIterator<string>`
*   **Note:** Triggers `purgeExpired(true)` before building the result.

#### `.values()`
Returns an iterator over the values of all valid (non-expired) entries.
*   **Returns:** `IterableIterator<T>`
*   **Note:** Triggers `purgeExpired(true)` before building the result.

#### `.entries()`
Returns an iterator over the `[key, value]` pairs of all valid (non-expired) entries.
*   **Returns:** `IterableIterator<[string, T]>`
*   **Note:** Triggers `purgeExpired(true)` before building the result.

#### `[Symbol.iterator]()`
Alias for `.entries()`. Enables `for...of`, spread (`[...cache]`) and destructuring directly on the instance.
*   **Returns:** `IterableIterator<[string, T]>`

#### `.forEach(callbackFn, thisArg)`
Executes a provided function once for each valid (non-expired) entry.
*   **`callbackFn`:** `(data: T, key: string, cache: TinyMapCache<T>) => void` (Required)
*   **`thisArg`:** `any` (Optional) — Value to use as `this` inside `callbackFn`.
*   **Returns:** `void`
*   **Throws:** `TypeError` if `callbackFn` is not a function.
*   **Note:** Triggers `purgeExpired(true)` before iterating.

---

## 🔔 Event Listeners

The `TinyMapCache` emits several events that you can listen to for advanced logic (like logging or synchronizing databases).

| Event | Payload Type | Description |
| :--- | :--- | :--- |
| `'set'` | `{ key: string, data: T }` | Emitted when a new item is successfully stored. |
| `'delete'` | `{ key: string }` | Emitted when an item is manually removed. |
| `'expire'` | `{ key: string, data: T }` | Emitted when an item is removed due to TTL expiration. |
| `'purge'` | `{ count: number }` | Emitted when multiple items are removed during a purge. |
| `'clear'` | `void` | Emitted when the entire cache is wiped. |

---

## 💡 Practical Implementation Examples

### 1. Basic Usage with TTL
This is the most common way to use the cache to avoid redundant API calls.

```javascript
const userCache = new TinyMapCache();
userCache.ttl = 60000; // 1 minute

async function getUserData(userId) {
  const cachedUser = userCache.get(userId);
  
  if (cachedUser) {
    console.log("📦 Serving from cache");
    return cachedUser;
  }

  console.log("🌐 Fetching from API...");
  const data = await fetchFromDatabase(userId); // Simulated API call
  userCache.set(userId, data);
  return data;
}
```

### 2. Using Events for Monitoring
You can use events to track how much data is expiring in your system.

```javascript
const monitorCache = new TinyMapCache();

monitorCache.on('expire', (payload) => {
  console.warn(`⚠️ Item expired: ${payload.key}`);
});

monitorCache.on('purge', (payload) => {
  console.log(`🧹 Cleanup complete. Removed ${payload.count} items.`);
});
```

### 3. Advanced: Cascaded Purging
If your application creates many cache instances (e.g., one per user session), you can clear them all at once to free up memory.

```javascript
const sessionCache1 = new TinyMapCache();
const sessionCache2 = new TinyMapCache();

sessionCache1.set('session_id', 123);
sessionCache2.set('session_id', 456);

// This will trigger purgeExpired(false) on sessionCache2
sessionCache1.purgeExpired(true); 
```

### 4. Iterating Over the Cache
All iteration helpers return a **snapshot** of the valid entries at the moment of the call. Expired items are never yielded.

```javascript
const cache = new TinyMapCache();
cache.set('user:1', { name: 'Yasmin' });
cache.set('user:2', { name: 'Isabela' });

// for...of (uses Symbol.iterator)
for (const [key, user] of cache) {
  console.log(key, user.name);
}

// Spread into an array
const allKeys = [...cache.keys()];
const allUsers = [...cache.values()];

// forEach with a bound context
cache.forEach(function (user, key) {
  console.log(`${key} -> ${user.name}`, this.label);
}, { label: '(cached)' });
```

### 5. Map Compatibility Cheat Sheet
| Native `Map` | `TinyMapCache` | Notes |
| :--- | :--- | :--- |
| `map.get(k)` | `cache.get(k)` | Returns `null` instead of `undefined` when missing. |
| `map.set(k, v)` | `cache.set(k, v)` | Requires a `string` key. |
| `map.has(k)` | `cache.has(k)` | Expired keys return `false`. |
| `map.delete(k)` | `cache.delete(k)` | Emits `'delete'`. |
| `map.clear()` | `cache.clear()` | Emits `'clear'`. |
| `map.size` | `cache.size` | — |
| `map.keys()` | `cache.keys()` | Skips expired entries. |
| `map.values()` | `cache.values()` | Skips expired entries. |
| `map.entries()` | `cache.entries()` | Skips expired entries. |
| `map.forEach(fn)` | `cache.forEach(fn)` | Same argument order. |
| `[...map]` | `[...cache]` | Same `[key, value]` shape. |
| `new Map(iterable)` | ❌ Not supported | See "Important Technical Notes". |

---

## ⚠️ Important Technical Notes

1.  **Automatic Cleanup:** Most methods (`get`, `set`, `has`, `delete`) automatically call `purgeExpired(true)`. This ensures you are always working with fresh data, but be aware that in very large caches, this adds a small overhead to every call.
2.  **Memory Management:** When a `TinyMapCache` instance becomes empty (size 0), it automatically removes itself from the internal `#instances` set to prevent memory leaks.
4.  **Snapshot Semantics:** The iteration methods (`keys`, `values`, `entries`, `forEach`) build a snapshot array before returning. Mutating the cache while iterating is therefore safe, but the loop will **not** see changes made after it started.
