learn and share notes on atproto (wip) 馃
malfestio.stormlightlabs.org/
readability
solid
axum
atproto
srs
1import Dexie, { type EntityTable } from "dexie";
2import type { CardType, Visibility } from "./model";
3
4export type SyncStatus = "local_only" | "synced" | "pending_push" | "conflict";
5
6type EntityKind = "deck" | "card" | "note";
7
8type OperationKind = "push" | "delete";
9
10type SyncTracking = { syncStatus: SyncStatus; localVersion: number; pdsCid?: string };
11
12export type LocalDeck = SyncTracking & {
13 id: string;
14 ownerDid: string;
15 title: string;
16 description: string;
17 tags: string[];
18 visibility: Visibility;
19 publishedAt?: string;
20 forkOf?: string;
21 pdsUri?: string;
22 updatedAt: string;
23};
24
25export type LocalCard = SyncTracking & {
26 id: string;
27 deckId: string;
28 front: string;
29 back: string;
30 mediaUrl?: string;
31 cardType: CardType;
32 hints: string[];
33};
34
35export type LocalNote = SyncTracking & {
36 id: string;
37 ownerDid: string;
38 title: string;
39 body: string;
40 tags: string[];
41 visibility: Visibility;
42 publishedAt?: string;
43 links: string[];
44 pdsUri?: string;
45 updatedAt: string;
46};
47
48export type SyncQueueItem = {
49 id?: number;
50 entityType: EntityKind;
51 entityId: string;
52 operation: OperationKind;
53 createdAt: string;
54 retryCount: number;
55 lastError?: string;
56};
57
58class MalfestioDatabase extends Dexie {
59 decks!: EntityTable<LocalDeck, "id">;
60 cards!: EntityTable<LocalCard, "id">;
61 notes!: EntityTable<LocalNote, "id">;
62 syncQueue!: EntityTable<SyncQueueItem, "id">;
63
64 constructor() {
65 super("malfestio");
66
67 this.version(1).stores({
68 decks: "id, ownerDid, syncStatus, updatedAt",
69 cards: "id, deckId, syncStatus",
70 notes: "id, ownerDid, syncStatus, updatedAt",
71 syncQueue: "++id, entityType, entityId, createdAt",
72 });
73 }
74}
75
76export const db = new MalfestioDatabase();
77
78export function generateLocalId(): string {
79 return `local_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
80}
81
82export function isLocalId(id: string): boolean {
83 return id.startsWith("local_");
84}