first commit
This commit is contained in:
94
docs/security-stack/security/hibp/src/cache/cache.md
vendored
Normal file
94
docs/security-stack/security/hibp/src/cache/cache.md
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# `cache/cache.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs --> - lru — `LruHibpCache<V>` is the default cache for `H…
|
||||
- [lru](./lru.md) — `LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to `LRU_DEFAULT_CAPACITY` entries (10 000) with `L…
|
||||
- [null](./null.md) — `NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when the caller explicitly opts out of caching (`cac…
|
||||
- lru — `LruHibpCache<V>` is the default cache for `H…
|
||||
|
||||
- [lru](./lru.md) — `LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to `LRU_DEFAULT_CAPACITY` entries (10 000) with `L…
|
||||
- [null](./null.md) — `NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when the caller explicitly opts out of caching (`cac…
|
||||
|
||||
- lru — `LruHibpCache<V>` is the default cache for `H…
|
||||
|
||||
- [lru](./lru.md) — `LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to `LRU_DEFAULT_CAPACITY` entries (10 000) with `L…
|
||||
- [null](./null.md) — `NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when the caller explicitly opts out of caching (`cac…
|
||||
|
||||
- lru — `LruHibpCache<V>` is the default cache for `H…
|
||||
|
||||
- [lru](./lru.md) — `LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to `LRU_DEFAULT_CAPACITY` entries (10 000) with `L…
|
||||
- [null](./null.md) — `NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when the caller explicitly opts out of caching (`cac…
|
||||
- [lru](./lru.md) — `LruHibpCache<V>` is the default cache for `HibpClient`. It holds up to `LRU_DEFAULT_CAPACITY` entries (10 000) with `L…
|
||||
- [null](./null.md) — `NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when the caller explicitly opts out of caching (`cac…
|
||||
|
||||
## Purpose
|
||||
|
||||
Declares the `HibpCacheLike<V>` interface — the universal contract every
|
||||
cache backend implements. The `HibpClient` orchestrator is parametric in
|
||||
this type, so swapping `LruHibpCache` for a Redis-backed adapter is a
|
||||
constructor option, not a refactor. Living at this layer means downstream
|
||||
storage choices stay isolated from the range-API logic.
|
||||
|
||||
## Features
|
||||
|
||||
- Four-method surface: `get`, `set`, `delete`, `size`.
|
||||
- Generic over value type `V` so a cache of `PwnedResult`, a cache of raw
|
||||
range bodies, and a cache of typed `Breach[]` all use the same shape.
|
||||
- Synchronous semantics — async backends adapt by buffering or by
|
||||
resolving the cache outside the request critical path.
|
||||
- Zero runtime — purely a TypeScript interface.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import type { HibpCacheLike } from "@suaveplan/hibp";
|
||||
|
||||
class MapCache implements HibpCacheLike<{ pwned: boolean; count: number }> {
|
||||
private store = new Map<string, { pwned: boolean; count: number }>();
|
||||
get(k: string) { return this.store.get(k); }
|
||||
set(k: string, v: { pwned: boolean; count: number }) { this.store.set(k, v); }
|
||||
delete(k: string) { return this.store.delete(k); }
|
||||
get size() { return this.store.size; }
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import type { HibpCacheLike } from "@suaveplan/hibp";
|
||||
|
||||
export class CountingCache<V> implements HibpCacheLike<V> {
|
||||
public hits = 0;
|
||||
public misses = 0;
|
||||
public constructor(private inner: HibpCacheLike<V>) {}
|
||||
get(k: string) {
|
||||
const v = this.inner.get(k);
|
||||
if (v === undefined) this.misses++;
|
||||
else this.hits++;
|
||||
return v;
|
||||
}
|
||||
set(k: string, v: V) { this.inner.set(k, v); }
|
||||
delete(k: string) { return this.inner.delete(k); }
|
||||
get size() { return this.inner.size; }
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `HibpCacheLike<V>` — interface with `get`, `set`, `delete`, `size`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The interface is synchronous on purpose: every documented HIBP cache
|
||||
backend is in-memory or microsecond-bound, so the simpler shape is worth
|
||||
it. If a future use case requires an async cache, the `HibpClient` will
|
||||
need a parallel `HibpAsyncCacheLike` rather than mutating this contract
|
||||
and breaking every existing implementation. The `size` field is
|
||||
deliberately a getter rather than a method so adapters wrapping an
|
||||
underlying `Map` can return the map's `size` directly; method-style
|
||||
would force an extra function call per probe. Consumers wiring exotic
|
||||
backends — Redis, IndexedDB, OPFS — typically wrap their async client
|
||||
in a write-through cache that buffers writes and lazily refreshes
|
||||
reads, exposing this synchronous shape to `HibpClient` while preserving
|
||||
durability behind the scenes.
|
||||
65
docs/security-stack/security/hibp/src/cache/lru.md
vendored
Normal file
65
docs/security-stack/security/hibp/src/cache/lru.md
vendored
Normal 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.
|
||||
54
docs/security-stack/security/hibp/src/cache/null.md
vendored
Normal file
54
docs/security-stack/security/hibp/src/cache/null.md
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
# `cache/null.ts`
|
||||
|
||||
## Purpose
|
||||
|
||||
`NullHibpCache<V>` is the always-miss adapter used by `HibpClient` when
|
||||
the caller explicitly opts out of caching (`cache: null`). It satisfies
|
||||
the `HibpCacheLike<V>` shape so the orchestrator code stays branch-free —
|
||||
every cache call goes through the same interface, but the null adapter
|
||||
makes every lookup a miss and every store a no-op.
|
||||
|
||||
## Features
|
||||
|
||||
- `get` always returns `undefined`.
|
||||
- `set` is a no-op.
|
||||
- `delete` always returns `false`.
|
||||
- `size` is always `0`.
|
||||
- Zero allocation per call — instances are stateless beyond the JS class
|
||||
identity.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { HibpClient, NullHibpCache } from "@suaveplan/hibp";
|
||||
|
||||
const client = new HibpClient({ cache: new NullHibpCache() });
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { HibpClient } from "@suaveplan/hibp";
|
||||
|
||||
// Shorthand: passing `null` resolves to NullHibpCache internally.
|
||||
const client = new HibpClient({ cache: null });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new NullHibpCache<V>()` — generic, no options.
|
||||
- All `HibpCacheLike<V>` methods present and conformant.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Using a dedicated class instead of an inline conditional avoids a
|
||||
property branch on every `HibpClient.checkPassword` call. It also keeps
|
||||
the public type system honest: a `HibpCacheLike` is always a real cache,
|
||||
never `undefined`. Callers who want caching disabled make that intention
|
||||
explicit by constructing or asking for `NullHibpCache`. The class is
|
||||
generic so consumers of typed cache values (e.g. `Breach[]` caches
|
||||
layered on top of the package) still get the right type for their
|
||||
`get()` returns when they inject a `NullHibpCache<Breach[]>` instead.
|
||||
Tests benefit too — running `checkPassword` against a `NullHibpCache`
|
||||
guarantees every call exercises the full fetch+parse path, with no
|
||||
hidden cache hits hiding behaviour bugs.
|
||||
Reference in New Issue
Block a user