···66export * from "./history";
77export * from "./math";
88export * from "./model";
99+export * from "./persist/DocRepo";
910export * from "./persistence/db";
1011export * from "./persistence/desktop";
1112export * from "./persistence/web";
1213export * from "./reactivity";
1314export * from "./tools";
1515+export * from "./ui/filebrowser";
1416export * from "./ui/statusbar";
+34
packages/core/src/persist/DocRepo.ts
···11+export type Timestamp = number;
22+33+export type BoardMeta = { id: string; name: string; createdAt: Timestamp; updatedAt: Timestamp };
44+55+/**
66+ * Shared document repository contract used by both web and desktop persistence layers.
77+ * Provides the minimal operations required for listing and managing boards.
88+ */
99+export interface DocRepo {
1010+ /**
1111+ * Fetch all boards ordered by most recently updated first.
1212+ */
1313+ listBoards(): Promise<BoardMeta[]>;
1414+1515+ /**
1616+ * Create a new board and return its identifier.
1717+ */
1818+ createBoard(name: string): Promise<string>;
1919+2020+ /**
2121+ * Load the requested board into the active editing context.
2222+ */
2323+ openBoard(boardId: string): Promise<void>;
2424+2525+ /**
2626+ * Rename the board.
2727+ */
2828+ renameBoard(boardId: string, name: string): Promise<void>;
2929+3030+ /**
3131+ * Delete the board and all associated records.
3232+ */
3333+ deleteBoard(boardId: string): Promise<void>;
3434+}
+2-1
packages/core/src/persistence/db.ts
···11import Dexie, { type Transaction } from "dexie";
22import { PageRecord as PageOps } from "../model";
33-import type { BindingRow, BoardMeta, MetaRow, MigrationRow, PageRow, ShapeRow, Timestamp } from "./web";
33+import type { BoardMeta, Timestamp } from "../persist/DocRepo";
44+import type { BindingRow, MetaRow, MigrationRow, PageRow, ShapeRow } from "./web";
4556export const DB_NAME = "inkfinite";
67
+2-1
packages/core/src/persistence/desktop.ts
···11import type { BindingRecord, Document, PageRecord, ShapeRecord } from "../model";
22-import type { BoardMeta, DocOrder, LoadedDoc } from "./web";
22+import type { BoardMeta } from "../persist/DocRepo";
33+import type { DocOrder, LoadedDoc } from "./web";
3445/**
56 * Desktop file representation - combines board metadata with document content
+23-14
packages/core/src/persistence/web.ts
···11-/* eslint-disable unicorn/no-await-expression-member */
21import Dexie from "dexie";
32import {
43 type BindingRecord,
···109 type ShapeRecord,
1110 ShapeRecord as ShapeOps,
1211} from "../model";
1313-1414-export type Timestamp = number;
1515-1616-export type BoardMeta = { id: string; name: string; createdAt: Timestamp; updatedAt: Timestamp };
1212+import type { BoardMeta, DocRepo, Timestamp } from "../persist/DocRepo";
17131814export type PageRow = PageRecord & { boardId: string; updatedAt: Timestamp };
1915···50465147export type PersistenceSinkOptions = { debounceMs?: number };
52485353-export interface DocRepo {
5454- listBoards(): Promise<BoardMeta[]>;
5555- createBoard(name: string): Promise<string>;
5656- renameBoard(boardId: string, name: string): Promise<void>;
5757- deleteBoard(boardId: string): Promise<void>;
4949+export interface PersistentDocRepo extends DocRepo {
5850 loadDoc(boardId: string): Promise<LoadedDoc>;
5951 applyDocPatch(boardId: string, patch: DocPatch): Promise<void>;
6052 exportBoard(boardId: string): Promise<BoardExport>;
···7466const shapeOrderKey = (boardId: string) => `${SHAPE_ORDER_META_PREFIX}${boardId}`;
75677668/**
7777- * Create a Dexie-backed DocRepo used by the web app.
6969+ * Create a Dexie-backed persistent DocRepo used by the web app.
7870 */
7979-export function createWebDocRepo(database: DexieLike, options?: WebRepoOptions): DocRepo {
7171+export function createWebDocRepo(database: DexieLike, options?: WebRepoOptions): PersistentDocRepo {
8072 const now = () => options?.now?.() ?? Date.now();
81738274 const boards = () => database.table<BoardMeta>("boards");
···256248 return boardId;
257249 }
258250259259- return { listBoards, createBoard, renameBoard, deleteBoard, loadDoc, applyDocPatch, exportBoard, importBoard };
251251+ async function openBoard(boardId: string): Promise<void> {
252252+ const exists = await boards().get(boardId);
253253+ if (!exists) {
254254+ throw new Error(`Board ${boardId} not found`);
255255+ }
256256+ }
257257+258258+ return {
259259+ listBoards,
260260+ createBoard,
261261+ openBoard,
262262+ renameBoard,
263263+ deleteBoard,
264264+ loadDoc,
265265+ applyDocPatch,
266266+ exportBoard,
267267+ importBoard,
268268+ };
260269}
261270262271/**
···295304/**
296305 * Batch doc patches and flush them with a debounce to cut down on Dexie writes.
297306 */
298298-export function createPersistenceSink(repo: DocRepo, options?: PersistenceSinkOptions): PersistenceSink {
307307+export function createPersistenceSink(repo: PersistentDocRepo, options?: PersistenceSinkOptions): PersistenceSink {
299308 const debounceMs = options?.debounceMs ?? 200;
300309 let pendingBoardId: string | null = null;
301310 let pendingPatch: DocPatch | null = null;