/** * Storage contract binding the sequence model to a product's database. The * product constructs one store per (workspace, sequence, actor) request scope — * RBAC and workspace isolation happen BEFORE construction (the product's * `requireWorkspaceAccess` equivalent); the store never re-checks identity. * * Every method throws on failure — no silent nulls, no `{ ok: false }` wrappers * at this layer. The MCP dispatcher (./mcp) is the boundary that converts * thrown errors into structured tool errors the model can read and react to. * * Mutations append to the decision log themselves only when the operation * dispatcher asks (`recordDecision`); plain CRUD stays log-free so human edits * driven by the UI can batch their own decision entries. */ import type { SequenceClip, SequenceDecision, SequenceExportFormat, SequenceExportRecord, SequenceMeta, SequenceTimeline, SequenceTrack, SequenceTrackKind } from './model'; /** Define properties for a new sequence track including kind, name, and optional sort order */ export interface NewSequenceTrack { kind: SequenceTrackKind; name: string; sortOrder?: number; } /** Define properties for a new sequence clip including timing, labels, and optional metadata */ export interface NewSequenceClip { trackId: string; label: string; startFrame: number; durationFrames: number; sourceInFrame?: number; sourceOutFrame?: number | null; text?: string; language?: string; generationId?: string; assetId?: string; metadata?: Record; } /** Define optional properties to update or patch a sequence clip's attributes in a timeline */ export interface SequenceClipPatch { trackId?: string; label?: string; startFrame?: number; durationFrames?: number; sourceInFrame?: number; sourceOutFrame?: number | null; disabled?: boolean; text?: string; language?: string; metadata?: Record; } /** Define the structure for a new sequence decision with optional metadata and acceptance status */ export interface NewSequenceDecision { clipId?: string | null; kind: SequenceDecision['kind']; instruction: string; reasoningSummary?: string | null; accepted?: boolean | null; metadata?: Record; } /** Manage sequences by providing methods to get timelines, clips, and modify tracks and clips */ export interface SequenceStore { /** Full aggregate: sequence meta + tracks + clips with resolved media. */ getTimeline(): Promise; getClip(clipId: string): Promise; createTrack(input: NewSequenceTrack): Promise; createClip(input: NewSequenceClip): Promise; updateClip(clipId: string, patch: SequenceClipPatch): Promise; deleteClip(clipId: string): Promise; /** Grow (or shrink, never below the last clip end) the sequence duration. */ updateSequenceDuration(durationFrames: number): Promise; recordDecision(input: NewSequenceDecision): Promise; createExport(format: SequenceExportFormat, metadata?: Record): Promise; listDecisions(limit?: number): Promise; listExports(limit?: number): Promise; } /** Per-request scope a product binds when constructing its store. Carried so * decision rows and export rows attribute to the acting user; never trusted * from tool arguments. */ export interface SequenceStoreScope { workspaceId: string; sequenceId: string; userId: string; }