first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
# `cache/lru.ts`
## Purpose
`LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to
`LRU_DEFAULT_CAPACITY` entries (10 000) with `LRU_DEFAULT_TTL_MS` (24 h)
expiry, keyed by the uppercase 5-hex SHA-1 prefix. The TTL clock is the
injectable `Clock` from `@suaveplan/types` so tests can advance virtual
time without timers. Eviction policy is least-recently-used at capacity
plus eager TTL eviction on read.
## Features
- O(1) `get`/`set`/`delete` over a `Map<string, CacheEntry<V>>` with
recency tracked by insertion order — re-inserting on read bumps the
key to the tail.
- TTL eviction at access time: stale entries are dropped and reported as
cache misses; no background timer is required.
- Constructor-time overrides for `capacity`, `ttlMs`, and `clock` so the
same class powers production caches, deterministic tests, and
experimental tunings.
- Key normalisation to uppercase hex on every operation — case-insensitive
reads and writes share the same slot.
## Usage: Basic Example
```ts
import { LruHibpCache } from "@suaveplan/hibp";
const cache = new LruHibpCache<{ pwned: boolean; count: number }>();
cache.set("F3BBB", { pwned: true, count: 1 });
cache.get("f3bbb"); // case-insensitive hit
```
## Usage: Advanced Example
```ts
import { LruHibpCache } from "@suaveplan/hibp";
let now = 0;
const cache = new LruHibpCache<number>({
capacity: 50,
ttlMs: 5_000,
clock: () => now,
});
cache.set("A", 1);
now = 4_999;
cache.get("A"); // 1
now = 5_001;
cache.get("A"); // undefined (TTL-evicted)
```
## API Reference
- `new LruHibpCache<V>(options?)` — `capacity`, `ttlMs`, `clock`.
- `LRU_DEFAULT_CAPACITY = 10_000`.
- `LRU_DEFAULT_TTL_MS = 24 * 60 * 60 * 1000`.
## Implementation Notes
Insertion-order tracking via JavaScript `Map` is the canonical O(1) LRU
implementation in pure JS. The class avoids `setInterval`-based eviction
because that would require timer cleanup on disposal and add jitter to
TTL behaviour; on-read TTL is cheap and deterministic. The capacity loop
guards against `capacity: 0` by evicting immediately after the insert.