Files
initiative/specs/029-on-demand-bestiary/contracts/bestiary-port.md

2.6 KiB

Contract: BestiarySourceCache Port

Feature: 029-on-demand-bestiary Layer: Application (port interface, implemented by web adapter)

Purpose

Defines the interface for caching and retrieving full bestiary source data. The application layer uses this port to look up full creature stat blocks. The web adapter implements it using IndexedDB.

Interface: BestiarySourceCache

getCreature(creatureId: CreatureId): Creature | undefined

Look up a full creature by its ID from the cache.

  • Input: creatureId — branded string in format {source}:{slug}
  • Output: Full Creature object if the creature's source is cached, undefined otherwise
  • Side effects: None (read-only)

isSourceCached(sourceCode: string): boolean

Check whether a source's data has been cached.

  • Input: sourceCode — source identifier (e.g., "XMM")
  • Output: true if the source has been fetched and cached, false otherwise

cacheSource(sourceCode: string, displayName: string, creatures: Creature[]): Promise<void>

Store a full source's worth of normalized creature data.

  • Input: source code, display name, array of normalized creatures
  • Output: Resolves when data is persisted
  • Behavior: Overwrites any existing cache for this source

getCachedSources(): CachedSourceInfo[]

List all cached sources for the management UI.

  • Output: Array of { sourceCode: string, displayName: string, creatureCount: number, cachedAt: number }

clearSource(sourceCode: string): Promise<void>

Remove a single source's cached data.

  • Input: source code to clear
  • Output: Resolves when data is removed

clearAll(): Promise<void>

Remove all cached source data.

  • Output: Resolves when all data is removed

Index Adapter (no port)

The index adapter (bestiary-index-adapter.ts) exposes plain exported functions consumed directly by the web adapter hooks. No application-layer port is needed because the index is a static build-time asset with no I/O variability. See apps/web/src/adapters/bestiary-index-adapter.ts for the implementation.

Exported functions: loadBestiaryIndex(), getSourceDisplayName(sourceCode), getDefaultFetchUrl(sourceCode).

Invariants

  1. getCreature MUST return undefined for any creature whose source is not cached — never throw.
  2. cacheSource MUST be idempotent — calling it twice with the same data produces the same result.
  3. clearSource MUST NOT affect other cached sources.
  4. search MUST return an empty array for queries shorter than 2 characters.
  5. The index adapter MUST be available synchronously after app initialization — no async loading state for search.