Files
PubScript/packages/core/src/storage.ts
T

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;
}