Files
2026-05-27 23:29:53 +01:00

6.6 KiB

OpenSpec Change: enterprise-browser-cache-browser

  • Change ID: enterprise-browser-cache-browser
  • Package: @suaveplan/cache-browser
  • Category: browser
  • Target path: browser/storage/cache-browser
  • Status: IN PROGRESS
  • Date: 2026-04-24
  • Reference spec: /mnt/s/web/suaveplan/enterprise/cache-browser.md

Summary

Deliver @suaveplan/cache-browser on the genesis branch at enterprise quality. The package provides browser-side cache implementations (LocalStorageCache, SessionStorageCache, IndexedDBCache) plugging into @suaveplan/cache, plus quota utilities, pluggable serializers, cross-tab invalidation via @suaveplan/broadcast-channel, pluggable eviction strategies, and OTel metrics. Auto-registration contract and sideEffects declaration are aligned.


Current-state audit (genesis)

Fresh build — does not exist on genesis yet.


Available workspace deps on genesis

Package Role
@suaveplan/cache (workspace:^) Cache interface, CacheFactory
@suaveplan/events (workspace:^) Storage-event multiplexer
@suaveplan/error (workspace:^) Typed cache errors
@suaveplan/types (workspace:^) LoggerLike
@suaveplan/broadcast-channel (workspace:^) Cross-tab invalidation
@suaveplan/crypto (workspace:^) Optional AES-GCM encryption transform
@suaveplan/schema-registry (workspace:^) Register cache config schemas
zod (catalog:forms) Config schemas
@opentelemetry/api (catalog:observability) Cache hit/miss/eviction metrics
tslib (catalog:build) Runtime helpers

Dev: vitest, @vitest/coverage-istanbul, fake-indexeddb (catalog:testing), @playwright/test, @suaveplan/testing.


Preserved public API surface

// Three cache implementations
class LocalStorageCache implements Cache { constructor(config: LocalStorageCacheConfig) }
class SessionStorageCache implements Cache { constructor(config: SessionStorageCacheConfig) }
class IndexedDBCache implements Cache { constructor(config: IndexedDBCacheConfig) }

// Subpath exports
// @suaveplan/cache-browser/localstorage
// @suaveplan/cache-browser/sessionstorage
// @suaveplan/cache-browser/indexeddb
// @suaveplan/cache-browser/register  (explicit auto-registration)

// Quota utilities
function getStorageQuota(): Promise<StorageQuota>
function isStorageNearQuota(threshold?: number): Promise<boolean>
function estimateStorageSize(): Promise<number>
function handleQuotaExceeded(cache: Cache, strategy: EvictionStrategy): Promise<void>
function isStorageAvailable(type: 'localStorage' | 'sessionStorage'): boolean

// Serialization
function defaultSerializer<T>(value: T): string
function defaultDeserializer<T>(raw: string): T
function isSerializable(value: unknown): boolean
function safeDeserialize<T>(raw: string): T | undefined

// Storage events
class StorageEventHandler { ... }
const globalStorageEventHandler: StorageEventHandler

// Config types
interface LocalStorageCacheConfig { namespace: string; ttl?: number; serializer?: Serializer<unknown> }
interface SessionStorageCacheConfig { namespace: string; ttl?: number; serializer?: Serializer<unknown> }
interface IndexedDBCacheConfig { dbName: string; storeName: string; ttl?: number; schemaVersion?: number; serializer?: Serializer<unknown> }

New additions for genesis

1. sideEffects contract

Auto-registration moves to explicit @suaveplan/cache-browser/register subpath; "sideEffects": false is then accurate for all other entry points. The register subpath is a sideEffects: ["./dist/register.js"] entry.

2. Pluggable Serializer<T> interface

interface Serializer<T> { serialize(value: T): string; deserialize(raw: string): T }

Default: JSON. Alternatives: CborSerializer (via @msgpack/msgpack), StructuredCloneSerializer.

3. EvictionStrategy interface

interface EvictionStrategy { selectForEviction(entries: CacheEntry[]): CacheEntry[] }
class LRUEviction implements EvictionStrategy { ... }
class LFUEviction implements EvictionStrategy { ... }
class TTLFirstEviction implements EvictionStrategy { ... }

4. Cross-tab invalidation

LocalStorageCache and IndexedDBCache accept an optional broadcastChannel?: TypedBroadcastChannel — on write/delete/clear, publishes invalidation events so other tabs update their in-memory views.

5. Split oversized files

Each implementation splits into: store.ts (core CRUD), ttl.ts (expiry logic), quota.ts (quota guard), events.ts (storage-event wiring). All ≤300 lines.

6. Public introspection surface

cache.getMetrics(): CacheMetrics replaces private-property reach-through in tests.

7. Error codes

CACHE_QUOTA_EXCEEDED, CACHE_SERIALIZATION_FAILED, INDEXEDDB_NOT_AVAILABLE.

8. OTel metrics

Counter cache.hits_total{backend}, counter cache.misses_total{backend}, counter cache.evictions_total{strategy}, histograms cache.read_ms, cache.write_ms.


File layout

browser/storage/cache-browser/
  package.json
  tsconfig.json
  vitest.config.ts
  src/
    index.ts
    register.ts              (explicit CacheFactory.register calls; sideEffects entry)
    error-codes.ts
    indexeddb/
      store/        (store.ts, store.test.ts, store.md)
      ttl/          (ttl.ts, ttl.test.ts, ttl.md)
      quota/        (quota.ts, quota.test.ts, quota.md)
      events/       (events.ts, events.test.ts, events.md)
      indexeddb/    (indexeddb.ts — orchestrator, indexeddb.test.ts, indexeddb.md, indexeddb.types.ts)
    localstorage/
      store/
      ttl/
      quota/
      events/
      localstorage/ (localstorage.ts, localstorage.test.ts, localstorage.md, localstorage.types.ts)
    sessionstorage/
      store/
      ttl/
      sessionstorage/ (sessionstorage.ts, sessionstorage.test.ts, sessionstorage.md, sessionstorage.types.ts)
    utils/
      quota/         (getStorageQuota, isStorageNearQuota, estimateStorageSize, handleQuotaExceeded, isStorageAvailable)
      serialization/ (defaultSerializer/Deserializer, isSerializable, safeDeserialize, Serializer interface)
      storage-events/(StorageEventHandler, globalStorageEventHandler)
    eviction/
      lru-eviction/
      lfu-eviction/
      ttl-first-eviction/
    types/
      types/         (all shared types)
  tests/
    integration.test.ts
  e2e/
    cache-browser.spec.ts   (Playwright: Chromium/WebKit/Firefox real storage)

Impact

Downstream: @suaveplan/analytics-browser, @suaveplan/pwa, @suaveplan/network-discovery-*, any package using browser caching.

Prerequisites: @suaveplan/cache, @suaveplan/events, @suaveplan/error, @suaveplan/broadcast-channel on Verdaccio.