Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
# cache
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`PreparedStatementCache` is an LRU-bounded cache for `bun:sqlite` prepared statement objects, keyed by SQL text. Reusing prepared statements avoids the overhead of repeated SQL parsing and optimisation — a significant win for hot query paths. The cache is bounded to prevent unbounded memory growth in applications that generate many distinct SQL strings.
The cache integrates with OpenTelemetry to surface hit/miss/eviction counters at `sqlite.cache.hits`, `sqlite.cache.misses`, and `sqlite.cache.evictions`. These are no-ops when no OTel provider is registered, keeping the module safe for use in zero-dependency environments.
## Features
- LRU eviction when `size >= maxSize` (default `128`)
- `get(sql)` — returns cached statement or `undefined`; updates LRU order
- `set(sql, stmt)` — inserts or updates; evicts LRU entry when at capacity, calling `stmt.finalize()` on the evicted statement
- `invalidate()` — clears all entries and calls `finalize()` on each held statement; called by `SqliteAdapter.migrate()` to prevent stale plan reuse after schema changes
- `size` / `maxSize` read-only getters
- OTel counters: `sqlite.cache.hits`, `sqlite.cache.misses`, `sqlite.cache.evictions`
- `static resetInstruments()` — clears the OTel lazy singleton for test isolation
## Usage: Basic Example
```ts
import { PreparedStatementCache } from "@suaveplan/db-sqlite/cache/cache";
const cache = new PreparedStatementCache();
const stmt = sqlite.prepare("SELECT * FROM users WHERE id = ?");
cache.set("SELECT * FROM users WHERE id = ?", stmt);
const hit = cache.get("SELECT * FROM users WHERE id = ?");
// hit === stmt
```
## Usage: Advanced Example
```ts
import { PreparedStatementCache } from "@suaveplan/db-sqlite/cache/cache";
// Small cache for testing eviction
const cache = new PreparedStatementCache(3);
for (let i = 0; i < 4; i++) {
const sql = `SELECT ${i} FROM t`;
cache.set(sql, { finalize: () => undefined }); // mock statement
}
console.log(cache.size); // 3 — first entry evicted
cache.invalidate();
console.log(cache.size); // 0 — all entries cleared
```
## API Reference
### `new PreparedStatementCache(maxSize?: number)`
Constructs a new cache. `maxSize` defaults to `128`.
### `get(sql: string): Statement | undefined`
Returns the cached statement for `sql`, or `undefined` on miss. Increments `sqlite.cache.hits` or `sqlite.cache.misses`. Updates LRU order on hit.
### `set(sql: string, stmt: Statement): void`
Inserts or updates the cache entry for `sql`. On capacity overflow, evicts the least-recently-used entry, calling `stmt.finalize()` on it, and increments `sqlite.cache.evictions`.
### `invalidate(): void`
Clears all entries. Calls `stmt.finalize()` on each held statement before clearing. Called automatically by `SqliteAdapter.migrate()`.
### `size: number`
Current number of cached entries.
### `maxSize: number`
Maximum capacity as set at construction.
### `static resetInstruments(): void`
Clears the lazy OTel instruments singleton. Use in tests to ensure each test suite starts with a fresh counter baseline.
## Implementation Notes
LRU ordering is maintained with a parallel `string[]` array (`#lruOrder`) rather than a doubly-linked list. This is simpler and sufficient for cache sizes up to a few hundred entries — `Array.indexOf` and `splice` on an array of at most 128 strings add negligible overhead compared to a SQLite query round-trip. For much larger caches a linked-list implementation would be preferable.
`finalize()` is called defensively with a try/catch because `bun:sqlite` statements may already be finalised if the underlying database was closed before the cache was cleared.