forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathofflineRepository.ts
More file actions
133 lines (111 loc) · 4.01 KB
/
Copy pathofflineRepository.ts
File metadata and controls
133 lines (111 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
* offlineRepository.ts — Issue #490
*
* Typed offline repository for splits and queued payments.
* Replaces the `any`-based helpers in indexedDB.ts with store-specific
* typed methods and handles schema migration from v1 → v2.
*/
import { openDB, type IDBPDatabase } from 'idb';
import {
DB_NAME,
DB_VERSION,
STORES,
type OfflineSplit,
type QueuedPayment,
} from '../types/offline';
// ── Database singleton ─────────────────────────────────────────────────────────
let _db: IDBPDatabase | null = null;
async function getDb(): Promise<IDBPDatabase> {
if (_db) return _db;
_db = await openDB(DB_NAME, DB_VERSION, {
upgrade(db, oldVersion) {
// v1 → create initial stores (preserved for migration from v1)
if (oldVersion < 1) {
if (!db.objectStoreNames.contains(STORES.splits)) {
db.createObjectStore(STORES.splits, { keyPath: 'id' });
}
if (!db.objectStoreNames.contains(STORES.queuedPayments)) {
db.createObjectStore(STORES.queuedPayments, { keyPath: 'id' });
}
}
// v2 → ensure stores exist if upgrading from an older schema
if (oldVersion < 2) {
if (!db.objectStoreNames.contains(STORES.splits)) {
db.createObjectStore(STORES.splits, { keyPath: 'id' });
}
if (!db.objectStoreNames.contains(STORES.queuedPayments)) {
db.createObjectStore(STORES.queuedPayments, { keyPath: 'id' });
}
}
},
});
return _db;
}
// ── Split repository ───────────────────────────────────────────────────────────
export const splitRepository = {
async save(split: OfflineSplit): Promise<void> {
const db = await getDb();
await db.put(STORES.splits, split);
},
async get(id: string): Promise<OfflineSplit | undefined> {
const db = await getDb();
return db.get(STORES.splits, id);
},
async getAll(): Promise<OfflineSplit[]> {
const db = await getDb();
return db.getAll(STORES.splits);
},
async getPendingSync(): Promise<OfflineSplit[]> {
const all = await splitRepository.getAll();
return all.filter((s) => s.pendingSync);
},
async markSynced(id: string): Promise<void> {
const db = await getDb();
const split = await db.get(STORES.splits, id) as OfflineSplit | undefined;
if (split) {
await db.put(STORES.splits, { ...split, pendingSync: false });
}
},
async delete(id: string): Promise<void> {
const db = await getDb();
await db.delete(STORES.splits, id);
},
async clear(): Promise<void> {
const db = await getDb();
await db.clear(STORES.splits);
},
};
// ── Queued payment repository ─────────────────────────────────────────────────
export const queuedPaymentRepository = {
async enqueue(payment: QueuedPayment): Promise<void> {
const db = await getDb();
await db.put(STORES.queuedPayments, payment);
},
async get(id: string): Promise<QueuedPayment | undefined> {
const db = await getDb();
return db.get(STORES.queuedPayments, id);
},
async getAll(): Promise<QueuedPayment[]> {
const db = await getDb();
return db.getAll(STORES.queuedPayments);
},
async recordAttempt(id: string, error?: string): Promise<void> {
const db = await getDb();
const payment = await db.get(STORES.queuedPayments, id) as QueuedPayment | undefined;
if (payment) {
await db.put(STORES.queuedPayments, {
...payment,
attempts: payment.attempts + 1,
lastError: error,
});
}
},
async dequeue(id: string): Promise<void> {
const db = await getDb();
await db.delete(STORES.queuedPayments, id);
},
async clear(): Promise<void> {
const db = await getDb();
await db.clear(STORES.queuedPayments);
},
};