125 lines
2.5 KiB
TypeScript
125 lines
2.5 KiB
TypeScript
/**
|
|
* rNotes Automerge document schemas.
|
|
*
|
|
* Granularity: one Automerge document per notebook.
|
|
* DocId format: {space}:notes:notebooks:{notebookId}
|
|
*
|
|
* The shape matches the PG→Automerge migration adapter
|
|
* (server/local-first/migration/pg-to-automerge.ts:notesMigration)
|
|
* and the client-side NotebookDoc type in folk-notes-app.ts.
|
|
*/
|
|
|
|
import type { DocSchema } from '../../shared/local-first/document';
|
|
|
|
// ── Document types ──
|
|
|
|
export interface NoteItem {
|
|
id: string;
|
|
notebookId: string;
|
|
authorId: string | null;
|
|
title: string;
|
|
content: string;
|
|
contentPlain: string;
|
|
type: 'NOTE' | 'CLIP' | 'BOOKMARK' | 'CODE' | 'IMAGE' | 'FILE' | 'AUDIO';
|
|
url: string | null;
|
|
language: string | null;
|
|
fileUrl: string | null;
|
|
mimeType: string | null;
|
|
fileSize: number | null;
|
|
duration: number | null;
|
|
isPinned: boolean;
|
|
sortOrder: number;
|
|
tags: string[];
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface NotebookMeta {
|
|
id: string;
|
|
title: string;
|
|
slug: string;
|
|
description: string;
|
|
coverColor: string;
|
|
isPublic: boolean;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
export interface NotebookDoc {
|
|
meta: {
|
|
module: string;
|
|
collection: string;
|
|
version: number;
|
|
spaceSlug: string;
|
|
createdAt: number;
|
|
};
|
|
notebook: NotebookMeta;
|
|
items: Record<string, NoteItem>;
|
|
}
|
|
|
|
// ── Schema registration ──
|
|
|
|
export const notebookSchema: DocSchema<NotebookDoc> = {
|
|
module: 'notes',
|
|
collection: 'notebooks',
|
|
version: 1,
|
|
init: (): NotebookDoc => ({
|
|
meta: {
|
|
module: 'notes',
|
|
collection: 'notebooks',
|
|
version: 1,
|
|
spaceSlug: '',
|
|
createdAt: Date.now(),
|
|
},
|
|
notebook: {
|
|
id: '',
|
|
title: 'Untitled Notebook',
|
|
slug: '',
|
|
description: '',
|
|
coverColor: '#3b82f6',
|
|
isPublic: false,
|
|
createdAt: Date.now(),
|
|
updatedAt: Date.now(),
|
|
},
|
|
items: {},
|
|
}),
|
|
};
|
|
|
|
// ── Helpers ──
|
|
|
|
/** Generate a docId for a notebook. */
|
|
export function notebookDocId(space: string, notebookId: string) {
|
|
return `${space}:notes:notebooks:${notebookId}` as const;
|
|
}
|
|
|
|
/** Create a fresh NoteItem with defaults. */
|
|
export function createNoteItem(
|
|
id: string,
|
|
notebookId: string,
|
|
title: string,
|
|
opts: Partial<NoteItem> = {},
|
|
): NoteItem {
|
|
const now = Date.now();
|
|
return {
|
|
id,
|
|
notebookId,
|
|
authorId: null,
|
|
title,
|
|
content: '',
|
|
contentPlain: '',
|
|
type: 'NOTE',
|
|
url: null,
|
|
language: null,
|
|
fileUrl: null,
|
|
mimeType: null,
|
|
fileSize: null,
|
|
duration: null,
|
|
isPinned: false,
|
|
sortOrder: 0,
|
|
tags: [],
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
...opts,
|
|
};
|
|
}
|