72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
/**
|
|
* The StorageAdapter contract — the seam that makes web / desktop / local modes
|
|
* possible. Defined once here; every feature codes against this, never a backend.
|
|
* See PLAN.md §3.4.
|
|
*/
|
|
|
|
import type {
|
|
Board,
|
|
Book,
|
|
Chapter,
|
|
DocumentRef,
|
|
Entity,
|
|
NewProject,
|
|
Project,
|
|
ProjectMeta,
|
|
PlotBeat,
|
|
AISession,
|
|
} from "./types.js";
|
|
|
|
/** Live-update events fanned out to subscribed clients. */
|
|
export type StoreEvent =
|
|
| { type: "doc-changed"; projectId: string; docId: string; rev: number }
|
|
| { type: "entity-changed"; projectId: string; entityId: string; kind: string }
|
|
| { type: "board-changed"; projectId: string; boardId: string }
|
|
| { type: "ai-session-changed"; projectId: string; sessionId: string }
|
|
| { type: "presence"; projectId: string; users: unknown[] }
|
|
| { type: "conflict"; docId: string; remoteRev: number };
|
|
|
|
export interface StorageAdapter {
|
|
// projects
|
|
listProjects(): Promise<ProjectMeta[]>;
|
|
createProject(p: NewProject): Promise<Project>;
|
|
getProject(id: string): Promise<Project>;
|
|
deleteProject?(id: string): Promise<void>;
|
|
|
|
// books & chapters
|
|
createBook(b: { projectId: string; title: string }): Promise<Book>;
|
|
listBooks(projectId: string): Promise<Book[]>;
|
|
listChapters(bookId: string): Promise<Chapter[]>;
|
|
deleteChapter?(id: string): Promise<void>;
|
|
|
|
// content (debounced autosave)
|
|
saveDocument(doc: DocumentRef): Promise<void>;
|
|
getChapter(id: string): Promise<Chapter | null>;
|
|
saveEntity(e: Entity): Promise<void>;
|
|
/**
|
|
* List entities for a project, optionally filtered by kind ("character" |
|
|
* "world" | "note"). Returns every entity when `kind` is omitted.
|
|
*/
|
|
listEntities(projectId: string, kind?: string): Promise<Entity[]>;
|
|
getEntity(projectId: string, kind: string, id: string): Promise<Entity | null>;
|
|
deleteEntity(projectId: string, kind: string, id: string): Promise<void>;
|
|
/**
|
|
* Fuzzy search across an entity's name and field values. Returns matches
|
|
* ordered best-first; empty `q` returns all entities for the project.
|
|
*/
|
|
searchEntities(projectId: string, q: string): Promise<Entity[]>;
|
|
saveBoard(b: Board): Promise<void>;
|
|
/** Load the story board for a project (by id `b.id`, scoped to `projectId`). */
|
|
getBoard(projectId: string): Promise<Board | null>;
|
|
|
|
/** Plot beats — the atomic units of story structure (CHUNK #5). */
|
|
listPlotBeats(projectId: string): Promise<PlotBeat[]>;
|
|
savePlotBeat(b: PlotBeat): Promise<void>;
|
|
deletePlotBeat(projectId: string, id: string): Promise<void>;
|
|
|
|
saveAISession(s: AISession): Promise<void>;
|
|
|
|
// live updates
|
|
onEvent(cb: (e: StoreEvent) => void): () => void;
|
|
}
|