131 lines
3.4 KiB
Markdown
131 lines
3.4 KiB
Markdown
# OpenSpec Change: enterprise-server-cache-memory
|
|
|
|
- **Change ID**: enterprise-server-cache-memory
|
|
- **Package**: `@suaveplan/cache-memory`
|
|
- **Category**: server/data
|
|
- **Target path**: `server/data/cache-memory`
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-04-24
|
|
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/cache-memory.md`
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Deliver `@suaveplan/cache-memory` on the genesis branch from scratch at enterprise quality. The package provides a zero-dependency, in-process LRU + TTL cache adapter implementing the same interface contract as `@suaveplan/cache-redis`. It is the primary testing stand-in and the default cache for single-server deployments. Genesis ships with a doubly-linked-list LRU eviction algorithm, injectable `Clock` for deterministic time testing, Zod-validated options, OTel counters/histograms, structured logging, and 100% test coverage via property-based tests.
|
|
|
|
---
|
|
|
|
## Current-state audit (genesis)
|
|
|
|
Does not exist on genesis — fresh build.
|
|
|
|
---
|
|
|
|
## Available workspace deps on genesis
|
|
|
|
| Package | Role |
|
|
|---|---|
|
|
| `@suaveplan/error` (`workspace:^`) | Typed error codes for `CACHE_MEMORY.*` |
|
|
| `@suaveplan/types` (`workspace:^`) | `StorageLike`, `LoggerLike`, `Clock` |
|
|
| `@suaveplan/logger` (`workspace:^`) | Structured logs |
|
|
| `zod` (`catalog:forms`) | Options validation |
|
|
| `@opentelemetry/api` (`catalog:observability`) | Counters + histograms |
|
|
| `tslib` (`catalog:build`) | Runtime helpers |
|
|
|
|
---
|
|
|
|
## Public API surface
|
|
|
|
### Adapter
|
|
|
|
```ts
|
|
class MemoryCacheAdapter {
|
|
constructor(options?: MemoryCacheOptions)
|
|
get(key: string): Promise<Uint8Array | undefined>
|
|
set(key: string, value: Uint8Array, ttlMs?: number): Promise<void>
|
|
delete(key: string): Promise<boolean>
|
|
has(key: string): Promise<boolean>
|
|
list(prefix?: string): Promise<string[]>
|
|
clear(): Promise<void>
|
|
ttl(key: string): Promise<number | undefined>
|
|
size(): number
|
|
stats(): CacheStats
|
|
}
|
|
|
|
function createMemoryCacheAdapter(options?: MemoryCacheOptions): MemoryCacheAdapter
|
|
```
|
|
|
|
### Options + types
|
|
|
|
```ts
|
|
interface MemoryCacheOptions {
|
|
maxSize?: number // max number of entries, default: 1000
|
|
defaultTtlMs?: number // default TTL when none supplied; undefined = no expiry
|
|
clock?: Clock // injectable for testing
|
|
logger?: LoggerLike
|
|
}
|
|
|
|
interface CacheStats {
|
|
hits: number
|
|
misses: number
|
|
evictions: number
|
|
size: number
|
|
hitRate: number
|
|
}
|
|
|
|
const MemoryCacheOptionsSchema: z.ZodSchema<MemoryCacheOptions>
|
|
```
|
|
|
|
### Error codes
|
|
|
|
```ts
|
|
type MemoryCacheErrorCode =
|
|
| 'CACHE_MEMORY_INVALID_KEY'
|
|
| 'CACHE_MEMORY_CAPACITY_EXCEEDED'
|
|
|
|
function registerMemoryCacheErrorCodes(): void
|
|
```
|
|
|
|
---
|
|
|
|
## File layout
|
|
|
|
```text
|
|
server/data/cache-memory/
|
|
package.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
src/
|
|
index.ts
|
|
error-codes.ts
|
|
constants/
|
|
index.ts
|
|
types/
|
|
cache-memory.types.ts
|
|
cache-memory.types.md
|
|
adapter/
|
|
memory-cache-adapter/
|
|
memory-cache-adapter.ts
|
|
memory-cache-adapter.md
|
|
memory-cache-adapter.types.ts
|
|
memory-cache-adapter.test.ts
|
|
index.ts
|
|
lru/
|
|
lru-cache/
|
|
lru-cache.ts
|
|
lru-cache.md
|
|
lru-cache.test.ts
|
|
index.ts
|
|
tests/
|
|
property.test.ts
|
|
```
|
|
|
|
---
|
|
|
|
## Impact
|
|
|
|
Downstream consumers: testing utilities, unit-test doubles for packages that depend on `cache-redis`. Universal helper — no Node.js IO, pure in-process.
|
|
|
|
**Prerequisites on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`.
|