UNPKG

endfield-mcp

Version:

MCP Server for Arknights: Endfield (TypeScript / stdio + Streamable HTTP)

84 lines • 2.93 kB
/** * Story reader core — store binding and catalog loading. * * This module is the shared spine of the story domain. It owns the JsonStore * reference and the two eager-loaded catalog caches (`index.json`, * `missions.json`). The chapter, scene, and search sub-modules import the * lazy loaders exported here so the catalog is parsed exactly once across * the whole domain. * * ## Loading strategy * * The catalog (index/missions) loads eagerly into memory at first access * (~2.4MB). Individual conv files load on-demand by conv key (each tens * of KB). This mirrors PRTS-MCP's ZipStore pattern and keeps memory * bounded — we never hold all 97MB of dialogue in memory at once. * * ## Cache lifecycle * * This module only owns the catalog caches. `clearStoryCatalogCaches()` * resets just those. The full-domain orchestrators (`bindStoryStore`, * `clearStoryCaches`) live in `./story.ts` (the barrel facade) so they * can clear sibling caches atomically without this module reaching into * its siblings (which would muddy the layering). */ // --------------------------------------------------------------------------- // Store reference + catalog cache (module-level singletons) // --------------------------------------------------------------------------- let _store = null; let _entries = null; let _missionNames = null; /** * Wire the JsonStore. Called once at startup by the barrel's * `bindStoryStore` orchestrator, which also clears all sibling caches. */ export function setStoryStore(store) { _store = store; } /** Reset only the catalog caches owned by this module. */ export function clearStoryCatalogCaches() { _entries = null; _missionNames = null; } export function hasStoryData() { try { return store().exists("index.json"); } catch { return false; } } // --------------------------------------------------------------------------- // Internal accessors — exported for sibling modules (same domain, same layer) // --------------------------------------------------------------------------- export function store() { if (_store === null) { throw new Error("Story reader used before bindStoryStore() — call it once at startup."); } return _store; } export function entries() { if (_entries !== null) return _entries; const raw = store().readJson("index.json"); _entries = (raw.entries ?? []).map((e) => ({ key: e.k, domain: e.d, mission: e.m, scene: e.s, type: e.t, actorCount: e.a, lineCount: e.n, preview: e.p, tags: e.tags ?? [], })); return _entries; } export function missionNames() { if (_missionNames !== null) return _missionNames; const raw = store().readJson("missions.json"); _missionNames = raw.missionNames ?? {}; return _missionNames; } //# sourceMappingURL=storyCore.js.map