/** * The shapes that travel between the server, IndexedDB and the UI. * * Most bugs in this app have been shape bugs: a field that is sometimes absent, * a body cached in the wrong format, a stale object adopted over a fresh one. * These types exist to make that class of mistake fail at build time. */ /* ── Drawing ── */ export type StrokeTool = "pen" | "highlighter" | "eraser"; export interface Stroke { /** Tool the stroke was drawn with. */ t: StrokeTool; /** Colour, `#rrggbb`. */ c: string; /** Width in canonical page units, not pixels. */ s: number; /** Flat `[x0, y0, x1, y1, …]` in canonical page space. */ p: number[]; } export interface StrokeDoc { v: number; /** Canonical page width the points are expressed in. */ w: number; /** Canonical page height. */ h: number; strokes: Stroke[]; /** Save token — lets the editor recognise its own write coming back. */ t?: string; } /* ── Notes ── */ export type NoteKind = "text" | "pdf"; /** Note metadata, as held in the notes list. */ export interface NoteMeta { id: string; title: string; /** "pdf" notes render a document instead of the text editor. */ type?: NoteKind; /** Attachment holding the PDF, for notes of type "pdf". */ pdfAttachmentId?: string | null; folderId: string | null; starred: boolean; trashed: boolean; createdAt: string; updatedAt: string; /** Position in the notebook's own order, used when sorting is set to manual. */ sortOrder?: number; /** Set while a note created offline has not reached the server yet. */ _pendingCreate?: boolean; } /** The lazily loaded body of a note. */ export interface NoteContent { /** Serialised document: `{"v":2,"doc":…}`, or a v1 `{html,tasks}` string. */ content: string; /** Legacy raster drawing as a data URL, for notes predating vector strokes. */ drawingData: string | null; drawingStrokes: StrokeDoc | null; /** Server revision this copy came from, used to spot a stale cache. */ updatedAt?: string | null; } /** * How a notebook's notes are ordered. * * "manual" is the user's own arrangement, kept in each note's `sortOrder`; the * rest are derived from the notes themselves and need nothing stored. */ export type SortMode = "manual" | "updated" | "oldest" | "created" | "title"; /** * A line drawn between notes in a notebook's own order. * * `order` is "how many notes come before me", so it stays meaningful as the * notes around it are renamed, edited or opened. */ export interface Separator { id: string; label: string; order: number; } export interface Notebook { id: string; name: string; cover: number; /** Pattern laid over the colour, chosen separately from it. */ coverPattern?: number; sortOrder: number; /** Versions kept per note here; null means the server's default. */ maxVersions?: number | null; /** Null means the app default, newest first. */ sortMode?: SortMode | null; /** Lines drawn between notes in the manual order. */ separators?: Separator[]; _pendingCreate?: boolean; } /** How the note body is set. Presentation only — the export is unaffected. */ export type NoteFont = "serif" | "sans" | "mono"; export interface UserPreferences { noteFont: NoteFont; } export interface User { id: string; username: string; displayName: string; /** Admins may create, delete and reset the password of other accounts. */ isAdmin?: boolean; /** Interface settings, kept on the account so they follow you to the phone. */ preferences?: UserPreferences; /** * How many versions a notebook keeps when it names no number of its own. * * Sent by the server rather than written into the interface: it is set with * `MAX_VERSIONS_PER_NOTE`, and a dialog that said "50" would start lying the * day that is changed. */ defaultMaxVersions?: number; } /** A user row as the admin panel sees it. */ export interface ManagedUser extends User { createdAt: string; noteCount: number; /** True for the admin doing the looking — they may not delete themselves. */ isSelf: boolean; } /* ── Version history ── */ export type VersionReason = "edit" | "large-deletion" | "drawing" | "drawing-cleared" | "before-restore"; export interface NoteVersionSummary { id: number; title: string | null; device_id: string | null; reason: VersionReason | string; created_at: string; content_size: number | null; has_drawing: boolean; } export interface NoteVersion { id: number; title: string | null; created_at: string; device_id: string | null; reason: string; content: string; drawingStrokes: StrokeDoc | null; } /* ── Links ── */ export interface Backlink { id: string; title: string; notebook_id: string | null; notebook_name: string | null; updated_at: string; } export type LinkKind = "note" | "notebook"; export interface LinkTarget { id: string; label: string; kind: LinkKind; } /* ── Sync ── */ export type SyncStatus = "synced" | "syncing" | "pending" | "offline" | "error"; /** A change waiting to be pushed to the server. */ export interface QueueEntry { queueId: number; action: string; data: Record; timestamp: number; attempts?: number; lastError?: string; } /* ── Attachments ── */ export interface AttachmentInfo { id: string; mime: string; size: number; deduplicated: boolean; } /* ── Search ── */ export interface SearchHit { id: string; score: number; /** Excerpt around the first matching term. */ snippet: string; }