@firtoz/drizzle-indexeddb 4.0.1 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +9 -1
- package/dist/bin/generate-migrations.d.ts +15 -0
- package/dist/bin/generate-migrations.js +184 -0
- package/dist/bin/generate-migrations.js.map +1 -0
- package/dist/chunk-5KCMKETG.js +212 -0
- package/dist/chunk-5KCMKETG.js.map +1 -0
- package/dist/chunk-7X4EIKN4.js +128 -0
- package/dist/chunk-7X4EIKN4.js.map +1 -0
- package/dist/chunk-CPLA7X66.js +129 -0
- package/dist/chunk-CPLA7X66.js.map +1 -0
- package/dist/chunk-HJFI7QKW.js +28 -0
- package/dist/chunk-HJFI7QKW.js.map +1 -0
- package/dist/chunk-JVUF63L6.js +27 -0
- package/dist/chunk-JVUF63L6.js.map +1 -0
- package/dist/chunk-OSOLYU2M.js +126 -0
- package/dist/chunk-OSOLYU2M.js.map +1 -0
- package/dist/chunk-WMCUJFEC.js +311 -0
- package/dist/chunk-WMCUJFEC.js.map +1 -0
- package/dist/chunk-Y6XE3FVT.js +147 -0
- package/dist/chunk-Y6XE3FVT.js.map +1 -0
- package/dist/collections/drizzle-indexeddb-collection.d.ts +62 -0
- package/dist/collections/drizzle-indexeddb-collection.js +3 -0
- package/dist/collections/drizzle-indexeddb-collection.js.map +1 -0
- package/dist/context/DrizzleIndexedDBProvider.d.ts +35 -0
- package/dist/context/DrizzleIndexedDBProvider.js +7 -0
- package/dist/context/DrizzleIndexedDBProvider.js.map +1 -0
- package/dist/context/useDrizzleIndexedDB.d.ts +17 -0
- package/dist/context/useDrizzleIndexedDB.js +8 -0
- package/dist/context/useDrizzleIndexedDB.js.map +1 -0
- package/dist/function-migrator.d.ts +56 -0
- package/dist/function-migrator.js +5 -0
- package/dist/function-migrator.js.map +1 -0
- package/dist/idb-interceptor.d.ts +68 -0
- package/dist/idb-interceptor.js +3 -0
- package/dist/idb-interceptor.js.map +1 -0
- package/dist/idb-operations.d.ts +13 -0
- package/dist/idb-operations.js +4 -0
- package/dist/idb-operations.js.map +1 -0
- package/dist/idb-types.d.ts +82 -0
- package/dist/idb-types.js +3 -0
- package/dist/idb-types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumented-idb-database.d.ts +17 -0
- package/dist/instrumented-idb-database.js +4 -0
- package/dist/instrumented-idb-database.js.map +1 -0
- package/dist/native-idb-database.d.ts +9 -0
- package/dist/native-idb-database.js +3 -0
- package/dist/native-idb-database.js.map +1 -0
- package/dist/standalone-collection.d.ts +154 -0
- package/dist/standalone-collection.js +7 -0
- package/dist/standalone-collection.js.map +1 -0
- package/package.json +34 -29
- package/src/collections/drizzle-indexeddb-collection.ts +4 -4
- package/src/context/DrizzleIndexedDBProvider.tsx +1 -1
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import { exhaustiveGuard } from '@firtoz/maybe-error';
|
|
2
|
+
|
|
3
|
+
// src/native-idb-database.ts
|
|
4
|
+
function createKeyRange(spec) {
|
|
5
|
+
switch (spec.type) {
|
|
6
|
+
case "only":
|
|
7
|
+
return IDBKeyRange.only(spec.value);
|
|
8
|
+
case "lowerBound":
|
|
9
|
+
return IDBKeyRange.lowerBound(spec.lower, spec.lowerOpen);
|
|
10
|
+
case "upperBound":
|
|
11
|
+
return IDBKeyRange.upperBound(spec.upper, spec.upperOpen);
|
|
12
|
+
case "bound":
|
|
13
|
+
return IDBKeyRange.bound(
|
|
14
|
+
spec.lower,
|
|
15
|
+
spec.upper,
|
|
16
|
+
spec.lowerOpen,
|
|
17
|
+
spec.upperOpen
|
|
18
|
+
);
|
|
19
|
+
default:
|
|
20
|
+
exhaustiveGuard(spec.type);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
var NativeIDBDatabase = class {
|
|
24
|
+
constructor(db) {
|
|
25
|
+
this.db = db;
|
|
26
|
+
this.db.onversionchange = () => {
|
|
27
|
+
this.db.close();
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
get version() {
|
|
31
|
+
return this.db.version;
|
|
32
|
+
}
|
|
33
|
+
hasStore(storeName) {
|
|
34
|
+
return this.db.objectStoreNames.contains(storeName);
|
|
35
|
+
}
|
|
36
|
+
getStoreNames() {
|
|
37
|
+
return Array.from(this.db.objectStoreNames);
|
|
38
|
+
}
|
|
39
|
+
createStore(storeName, options) {
|
|
40
|
+
this.db.createObjectStore(storeName, options);
|
|
41
|
+
}
|
|
42
|
+
deleteStore(storeName) {
|
|
43
|
+
this.db.deleteObjectStore(storeName);
|
|
44
|
+
}
|
|
45
|
+
createIndex(storeName, indexName, keyPath, options) {
|
|
46
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
47
|
+
const store = transaction.objectStore(storeName);
|
|
48
|
+
store.createIndex(indexName, keyPath, options);
|
|
49
|
+
}
|
|
50
|
+
deleteIndex(storeName, indexName) {
|
|
51
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
52
|
+
const store = transaction.objectStore(storeName);
|
|
53
|
+
store.deleteIndex(indexName);
|
|
54
|
+
}
|
|
55
|
+
getStoreIndexes(storeName) {
|
|
56
|
+
if (!this.hasStore(storeName)) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
60
|
+
const store = transaction.objectStore(storeName);
|
|
61
|
+
const indexes = [];
|
|
62
|
+
for (const indexName of Array.from(store.indexNames)) {
|
|
63
|
+
const index = store.index(indexName);
|
|
64
|
+
indexes.push({
|
|
65
|
+
name: indexName,
|
|
66
|
+
keyPath: index.keyPath
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return indexes;
|
|
70
|
+
}
|
|
71
|
+
async getAll(storeName) {
|
|
72
|
+
if (!this.hasStore(storeName)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
try {
|
|
77
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
78
|
+
const store = transaction.objectStore(storeName);
|
|
79
|
+
const request = store.getAll();
|
|
80
|
+
request.onsuccess = () => resolve(request.result);
|
|
81
|
+
request.onerror = () => reject(request.error);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("Error getting all items", error);
|
|
84
|
+
reject(error);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async getAllByIndex(storeName, indexName, keyRange) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
try {
|
|
91
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
92
|
+
const store = transaction.objectStore(storeName);
|
|
93
|
+
const index = store.index(indexName);
|
|
94
|
+
const range = keyRange ? createKeyRange(keyRange) : void 0;
|
|
95
|
+
const request = index.getAll(range);
|
|
96
|
+
request.onsuccess = () => resolve(request.result);
|
|
97
|
+
request.onerror = () => reject(request.error);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error("Error getting all items by index", error);
|
|
100
|
+
reject(error);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async get(storeName, key) {
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
try {
|
|
107
|
+
const transaction = this.db.transaction(storeName, "readonly");
|
|
108
|
+
const store = transaction.objectStore(storeName);
|
|
109
|
+
const request = store.get(key);
|
|
110
|
+
request.onsuccess = () => resolve(request.result);
|
|
111
|
+
request.onerror = () => reject(request.error);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("Error getting item", error);
|
|
114
|
+
reject(error);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async add(storeName, items) {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
try {
|
|
121
|
+
const transaction = this.db.transaction(storeName, "readwrite");
|
|
122
|
+
const store = transaction.objectStore(storeName);
|
|
123
|
+
for (const item of items) {
|
|
124
|
+
store.add(item);
|
|
125
|
+
}
|
|
126
|
+
transaction.oncomplete = () => resolve();
|
|
127
|
+
transaction.onerror = () => reject(transaction.error);
|
|
128
|
+
transaction.onabort = () => reject(new Error("Transaction aborted"));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error("Error adding items", error);
|
|
131
|
+
reject(error);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async put(storeName, items) {
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
try {
|
|
138
|
+
const transaction = this.db.transaction(storeName, "readwrite");
|
|
139
|
+
const store = transaction.objectStore(storeName);
|
|
140
|
+
for (const item of items) {
|
|
141
|
+
store.put(item);
|
|
142
|
+
}
|
|
143
|
+
transaction.oncomplete = () => resolve();
|
|
144
|
+
transaction.onerror = () => reject(transaction.error);
|
|
145
|
+
transaction.onabort = () => reject(new Error("Transaction aborted"));
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error("Error putting items", error);
|
|
148
|
+
reject(error);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async delete(storeName, keys) {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
try {
|
|
155
|
+
const transaction = this.db.transaction(storeName, "readwrite");
|
|
156
|
+
const store = transaction.objectStore(storeName);
|
|
157
|
+
for (const key of keys) {
|
|
158
|
+
store.delete(key);
|
|
159
|
+
}
|
|
160
|
+
transaction.oncomplete = () => resolve();
|
|
161
|
+
transaction.onerror = () => reject(transaction.error);
|
|
162
|
+
transaction.onabort = () => reject(new Error("Transaction aborted"));
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.error("Error deleting items", error);
|
|
165
|
+
reject(error);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async clear(storeName) {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
try {
|
|
172
|
+
const transaction = this.db.transaction(storeName, "readwrite");
|
|
173
|
+
const store = transaction.objectStore(storeName);
|
|
174
|
+
const request = store.clear();
|
|
175
|
+
request.onsuccess = () => resolve();
|
|
176
|
+
request.onerror = () => reject(request.error);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error("Error clearing store", error);
|
|
179
|
+
reject(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
close() {
|
|
184
|
+
console.log("Closing database");
|
|
185
|
+
this.db.close();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
var UpgradeModeDatabase = class {
|
|
189
|
+
constructor(db, transaction) {
|
|
190
|
+
this.db = db;
|
|
191
|
+
this.transaction = transaction;
|
|
192
|
+
this.createdStores = /* @__PURE__ */ new Map();
|
|
193
|
+
}
|
|
194
|
+
get version() {
|
|
195
|
+
return this.db.version;
|
|
196
|
+
}
|
|
197
|
+
hasStore(storeName) {
|
|
198
|
+
return this.db.objectStoreNames.contains(storeName);
|
|
199
|
+
}
|
|
200
|
+
getStoreNames() {
|
|
201
|
+
return Array.from(this.db.objectStoreNames);
|
|
202
|
+
}
|
|
203
|
+
createStore(storeName, options) {
|
|
204
|
+
const store = this.db.createObjectStore(storeName, options);
|
|
205
|
+
this.createdStores.set(storeName, store);
|
|
206
|
+
}
|
|
207
|
+
deleteStore(storeName) {
|
|
208
|
+
this.db.deleteObjectStore(storeName);
|
|
209
|
+
this.createdStores.delete(storeName);
|
|
210
|
+
}
|
|
211
|
+
createIndex(storeName, indexName, keyPath, options) {
|
|
212
|
+
let store = this.createdStores.get(storeName);
|
|
213
|
+
if (!store) {
|
|
214
|
+
try {
|
|
215
|
+
store = this.transaction.objectStore(storeName);
|
|
216
|
+
} catch {
|
|
217
|
+
throw new Error(`Cannot create index - store "${storeName}" not found`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
store.createIndex(indexName, keyPath, options);
|
|
221
|
+
}
|
|
222
|
+
deleteIndex(storeName, indexName) {
|
|
223
|
+
let store = this.createdStores.get(storeName);
|
|
224
|
+
if (!store) {
|
|
225
|
+
try {
|
|
226
|
+
store = this.transaction.objectStore(storeName);
|
|
227
|
+
} catch {
|
|
228
|
+
throw new Error(`Cannot delete index - store "${storeName}" not found`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
store.deleteIndex(indexName);
|
|
232
|
+
}
|
|
233
|
+
getStoreIndexes(storeName) {
|
|
234
|
+
if (!this.hasStore(storeName)) return [];
|
|
235
|
+
let store = this.createdStores.get(storeName);
|
|
236
|
+
if (!store) {
|
|
237
|
+
try {
|
|
238
|
+
store = this.transaction.objectStore(storeName);
|
|
239
|
+
} catch {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return Array.from(store.indexNames).map((name) => ({
|
|
244
|
+
name,
|
|
245
|
+
keyPath: store.index(name).keyPath
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
// Data operations not available during upgrade
|
|
249
|
+
async getAll() {
|
|
250
|
+
throw new Error("getAll not available during upgrade");
|
|
251
|
+
}
|
|
252
|
+
async getAllByIndex() {
|
|
253
|
+
throw new Error("getAllByIndex not available during upgrade");
|
|
254
|
+
}
|
|
255
|
+
async get() {
|
|
256
|
+
throw new Error("get not available during upgrade");
|
|
257
|
+
}
|
|
258
|
+
async add() {
|
|
259
|
+
throw new Error("add not available during upgrade");
|
|
260
|
+
}
|
|
261
|
+
async put() {
|
|
262
|
+
throw new Error("put not available during upgrade");
|
|
263
|
+
}
|
|
264
|
+
async delete() {
|
|
265
|
+
throw new Error("delete not available during upgrade");
|
|
266
|
+
}
|
|
267
|
+
async clear() {
|
|
268
|
+
throw new Error("clear not available during upgrade");
|
|
269
|
+
}
|
|
270
|
+
close() {
|
|
271
|
+
this.db.close();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var defaultIDBCreator = (name, options) => {
|
|
275
|
+
return new Promise((resolve, reject) => {
|
|
276
|
+
try {
|
|
277
|
+
const request = options?.version ? indexedDB.open(name, options.version) : indexedDB.open(name);
|
|
278
|
+
request.onerror = () => reject(request.error);
|
|
279
|
+
request.onblocked = () => {
|
|
280
|
+
setTimeout(() => {
|
|
281
|
+
reject(new Error("Database upgrade blocked - close other tabs"));
|
|
282
|
+
}, 3e3);
|
|
283
|
+
};
|
|
284
|
+
request.onupgradeneeded = (event) => {
|
|
285
|
+
if (options?.onUpgrade) {
|
|
286
|
+
const db = request.result;
|
|
287
|
+
const transaction = event.target.transaction;
|
|
288
|
+
if (!transaction) {
|
|
289
|
+
reject(new Error("No transaction during upgrade"));
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const upgradeDb = new UpgradeModeDatabase(db, transaction);
|
|
293
|
+
try {
|
|
294
|
+
options.onUpgrade(upgradeDb);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
transaction.abort();
|
|
297
|
+
reject(error);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
request.onsuccess = () => resolve(new NativeIDBDatabase(request.result));
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error("Error creating database", error);
|
|
304
|
+
reject(error);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export { defaultIDBCreator };
|
|
310
|
+
//# sourceMappingURL=chunk-WMCUJFEC.js.map
|
|
311
|
+
//# sourceMappingURL=chunk-WMCUJFEC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/native-idb-database.ts"],"names":[],"mappings":"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","file":"chunk-WMCUJFEC.js","sourcesContent":["import { exhaustiveGuard } from \"@firtoz/maybe-error\";\nimport type { KeyRangeSpec } from \"@firtoz/idb-collections\";\nimport type {\n\tIDBDatabaseLike,\n\tIDBCreator,\n\tIDBOpenOptions,\n\tIndexInfo,\n\tCreateStoreOptions,\n\tCreateIndexOptions,\n} from \"./idb-types\";\n\n/**\n * Creates a KeyRange from a KeyRangeSpec\n */\nfunction createKeyRange(spec: KeyRangeSpec): IDBKeyRange {\n\tswitch (spec.type) {\n\t\tcase \"only\":\n\t\t\treturn IDBKeyRange.only(spec.value);\n\t\tcase \"lowerBound\":\n\t\t\treturn IDBKeyRange.lowerBound(spec.lower, spec.lowerOpen);\n\t\tcase \"upperBound\":\n\t\t\treturn IDBKeyRange.upperBound(spec.upper, spec.upperOpen);\n\t\tcase \"bound\":\n\t\t\treturn IDBKeyRange.bound(\n\t\t\t\tspec.lower,\n\t\t\t\tspec.upper,\n\t\t\t\tspec.lowerOpen,\n\t\t\t\tspec.upperOpen,\n\t\t\t);\n\t\tdefault:\n\t\t\texhaustiveGuard(spec.type);\n\t}\n}\n\n/**\n * Default implementation that wraps native IndexedDB\n */\nclass NativeIDBDatabase implements IDBDatabaseLike {\n\tconstructor(private db: IDBDatabase) {\n\t\t// Listen for version change events - close connection when another tab/process\n\t\t// wants to upgrade the database. This prevents blocking issues.\n\t\tthis.db.onversionchange = () => {\n\t\t\tthis.db.close();\n\t\t};\n\t}\n\n\tget version(): number {\n\t\treturn this.db.version;\n\t}\n\n\thasStore(storeName: string): boolean {\n\t\treturn this.db.objectStoreNames.contains(storeName);\n\t}\n\n\tgetStoreNames(): string[] {\n\t\treturn Array.from(this.db.objectStoreNames);\n\t}\n\n\tcreateStore(storeName: string, options?: CreateStoreOptions): void {\n\t\tthis.db.createObjectStore(storeName, options);\n\t}\n\n\tdeleteStore(storeName: string): void {\n\t\tthis.db.deleteObjectStore(storeName);\n\t}\n\n\tcreateIndex(\n\t\tstoreName: string,\n\t\tindexName: string,\n\t\tkeyPath: string | string[],\n\t\toptions?: CreateIndexOptions,\n\t): void {\n\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\tconst store = transaction.objectStore(storeName);\n\t\tstore.createIndex(indexName, keyPath, options);\n\t}\n\n\tdeleteIndex(storeName: string, indexName: string): void {\n\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\tconst store = transaction.objectStore(storeName);\n\t\tstore.deleteIndex(indexName);\n\t}\n\n\tgetStoreIndexes(storeName: string): IndexInfo[] {\n\t\tif (!this.hasStore(storeName)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\tconst store = transaction.objectStore(storeName);\n\t\tconst indexes: IndexInfo[] = [];\n\n\t\tfor (const indexName of Array.from(store.indexNames)) {\n\t\t\tconst index = store.index(indexName);\n\t\t\tindexes.push({\n\t\t\t\tname: indexName,\n\t\t\t\tkeyPath: index.keyPath,\n\t\t\t});\n\t\t}\n\n\t\treturn indexes;\n\t}\n\n\tasync getAll<T = unknown>(storeName: string): Promise<T[]> {\n\t\tif (!this.hasStore(storeName)) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\t\t\t\tconst request = store.getAll();\n\n\t\t\t\trequest.onsuccess = () => resolve(request.result as T[]);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error getting all items\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync getAllByIndex<T = unknown>(\n\t\tstoreName: string,\n\t\tindexName: string,\n\t\tkeyRange?: KeyRangeSpec,\n\t): Promise<T[]> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\t\t\t\tconst index = store.index(indexName);\n\t\t\t\tconst range = keyRange ? createKeyRange(keyRange) : undefined;\n\t\t\t\tconst request = index.getAll(range);\n\n\t\t\t\trequest.onsuccess = () => resolve(request.result as T[]);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error getting all items by index\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync get<T = unknown>(\n\t\tstoreName: string,\n\t\tkey: IDBValidKey,\n\t): Promise<T | undefined> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readonly\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\t\t\t\tconst request = store.get(key);\n\n\t\t\t\trequest.onsuccess = () => resolve(request.result as T | undefined);\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error getting item\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync add(storeName: string, items: unknown[]): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readwrite\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\n\t\t\t\tfor (const item of items) {\n\t\t\t\t\tstore.add(item);\n\t\t\t\t}\n\n\t\t\t\ttransaction.oncomplete = () => resolve();\n\t\t\t\ttransaction.onerror = () => reject(transaction.error);\n\t\t\t\ttransaction.onabort = () => reject(new Error(\"Transaction aborted\"));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error adding items\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync put(storeName: string, items: unknown[]): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readwrite\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\n\t\t\t\tfor (const item of items) {\n\t\t\t\t\tstore.put(item);\n\t\t\t\t}\n\n\t\t\t\ttransaction.oncomplete = () => resolve();\n\t\t\t\ttransaction.onerror = () => reject(transaction.error);\n\t\t\t\ttransaction.onabort = () => reject(new Error(\"Transaction aborted\"));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error putting items\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync delete(storeName: string, keys: IDBValidKey[]): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readwrite\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\n\t\t\t\tfor (const key of keys) {\n\t\t\t\t\tstore.delete(key);\n\t\t\t\t}\n\n\t\t\t\ttransaction.oncomplete = () => resolve();\n\t\t\t\ttransaction.onerror = () => reject(transaction.error);\n\t\t\t\ttransaction.onabort = () => reject(new Error(\"Transaction aborted\"));\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error deleting items\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tasync clear(storeName: string): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tconst transaction = this.db.transaction(storeName, \"readwrite\");\n\t\t\t\tconst store = transaction.objectStore(storeName);\n\t\t\t\tconst request = store.clear();\n\n\t\t\t\trequest.onsuccess = () => resolve();\n\t\t\t\trequest.onerror = () => reject(request.error);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\"Error clearing store\", error);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n\n\tclose(): void {\n\t\tconsole.log(\"Closing database\");\n\t\tthis.db.close();\n\t}\n}\n\n/**\n * Upgrade-mode database wrapper used during version changes.\n * Provides IDBDatabaseLike interface with schema modification capabilities.\n */\nclass UpgradeModeDatabase implements IDBDatabaseLike {\n\tprivate createdStores: Map<string, IDBObjectStore> = new Map();\n\n\tconstructor(\n\t\tprivate db: IDBDatabase,\n\t\tprivate transaction: IDBTransaction,\n\t) {}\n\n\tget version(): number {\n\t\treturn this.db.version;\n\t}\n\n\thasStore(storeName: string): boolean {\n\t\treturn this.db.objectStoreNames.contains(storeName);\n\t}\n\n\tgetStoreNames(): string[] {\n\t\treturn Array.from(this.db.objectStoreNames);\n\t}\n\n\tcreateStore(storeName: string, options?: CreateStoreOptions): void {\n\t\tconst store = this.db.createObjectStore(storeName, options);\n\t\tthis.createdStores.set(storeName, store);\n\t}\n\n\tdeleteStore(storeName: string): void {\n\t\tthis.db.deleteObjectStore(storeName);\n\t\tthis.createdStores.delete(storeName);\n\t}\n\n\tcreateIndex(\n\t\tstoreName: string,\n\t\tindexName: string,\n\t\tkeyPath: string | string[],\n\t\toptions?: CreateIndexOptions,\n\t): void {\n\t\tlet store = this.createdStores.get(storeName);\n\t\tif (!store) {\n\t\t\ttry {\n\t\t\t\tstore = this.transaction.objectStore(storeName);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Cannot create index - store \"${storeName}\" not found`);\n\t\t\t}\n\t\t}\n\t\tstore.createIndex(indexName, keyPath, options);\n\t}\n\n\tdeleteIndex(storeName: string, indexName: string): void {\n\t\tlet store = this.createdStores.get(storeName);\n\t\tif (!store) {\n\t\t\ttry {\n\t\t\t\tstore = this.transaction.objectStore(storeName);\n\t\t\t} catch {\n\t\t\t\tthrow new Error(`Cannot delete index - store \"${storeName}\" not found`);\n\t\t\t}\n\t\t}\n\t\tstore.deleteIndex(indexName);\n\t}\n\n\tgetStoreIndexes(storeName: string): IndexInfo[] {\n\t\tif (!this.hasStore(storeName)) return [];\n\t\tlet store = this.createdStores.get(storeName);\n\t\tif (!store) {\n\t\t\ttry {\n\t\t\t\tstore = this.transaction.objectStore(storeName);\n\t\t\t} catch {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t}\n\t\treturn Array.from(store.indexNames).map((name) => ({\n\t\t\tname,\n\t\t\tkeyPath: store.index(name).keyPath,\n\t\t}));\n\t}\n\n\t// Data operations not available during upgrade\n\tasync getAll<T = unknown>(): Promise<T[]> {\n\t\tthrow new Error(\"getAll not available during upgrade\");\n\t}\n\tasync getAllByIndex<T = unknown>(): Promise<T[]> {\n\t\tthrow new Error(\"getAllByIndex not available during upgrade\");\n\t}\n\tasync get<T = unknown>(): Promise<T | undefined> {\n\t\tthrow new Error(\"get not available during upgrade\");\n\t}\n\tasync add(): Promise<void> {\n\t\tthrow new Error(\"add not available during upgrade\");\n\t}\n\tasync put(): Promise<void> {\n\t\tthrow new Error(\"put not available during upgrade\");\n\t}\n\tasync delete(): Promise<void> {\n\t\tthrow new Error(\"delete not available during upgrade\");\n\t}\n\tasync clear(): Promise<void> {\n\t\tthrow new Error(\"clear not available during upgrade\");\n\t}\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n}\n\n/**\n * Default IDB creator that uses the native IndexedDB API.\n */\nexport const defaultIDBCreator: IDBCreator = (\n\tname: string,\n\toptions?: IDBOpenOptions,\n): Promise<IDBDatabaseLike> => {\n\treturn new Promise((resolve, reject) => {\n\t\ttry {\n\t\t\tconst request = options?.version\n\t\t\t\t? indexedDB.open(name, options.version)\n\t\t\t\t: indexedDB.open(name);\n\n\t\t\trequest.onerror = () => reject(request.error);\n\n\t\t\trequest.onblocked = () => {\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\treject(new Error(\"Database upgrade blocked - close other tabs\"));\n\t\t\t\t}, 3000);\n\t\t\t};\n\n\t\t\trequest.onupgradeneeded = (event) => {\n\t\t\t\tif (options?.onUpgrade) {\n\t\t\t\t\tconst db = request.result;\n\t\t\t\t\tconst transaction = (event.target as IDBOpenDBRequest).transaction;\n\t\t\t\t\tif (!transaction) {\n\t\t\t\t\t\treject(new Error(\"No transaction during upgrade\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Create an upgrade-mode database wrapper\n\t\t\t\t\tconst upgradeDb = new UpgradeModeDatabase(db, transaction);\n\t\t\t\t\ttry {\n\t\t\t\t\t\toptions.onUpgrade(upgradeDb);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\ttransaction.abort();\n\t\t\t\t\t\treject(error);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\trequest.onsuccess = () => resolve(new NativeIDBDatabase(request.result));\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error creating database\", error);\n\t\t\treject(error);\n\t\t}\n\t});\n};\n"]}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { drizzleIndexedDBCollectionOptions } from './chunk-5KCMKETG.js';
|
|
2
|
+
import { migrateIndexedDBWithFunctions } from './chunk-7X4EIKN4.js';
|
|
3
|
+
import { openIndexedDb } from './chunk-JVUF63L6.js';
|
|
4
|
+
import { createContext, useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
5
|
+
import { createCollection } from '@tanstack/db';
|
|
6
|
+
import { getTableName } from 'drizzle-orm';
|
|
7
|
+
import { jsx } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var DrizzleIndexedDBContext = (
|
|
10
|
+
// biome-ignore lint/suspicious/noExplicitAny: Context needs to accept any schema type
|
|
11
|
+
createContext(null)
|
|
12
|
+
);
|
|
13
|
+
function DrizzleIndexedDBProvider({
|
|
14
|
+
children,
|
|
15
|
+
dbName,
|
|
16
|
+
schema,
|
|
17
|
+
migrations = [],
|
|
18
|
+
migrateFunction = migrateIndexedDBWithFunctions,
|
|
19
|
+
debug = false,
|
|
20
|
+
syncMode = "eager",
|
|
21
|
+
dbCreator
|
|
22
|
+
}) {
|
|
23
|
+
const [indexedDB, setIndexedDB] = useState(null);
|
|
24
|
+
const indexedDBRef = useRef(null);
|
|
25
|
+
const [readyPromise] = useState(() => {
|
|
26
|
+
let resolveReady;
|
|
27
|
+
const promise = new Promise((resolve) => {
|
|
28
|
+
resolveReady = resolve;
|
|
29
|
+
});
|
|
30
|
+
return { promise, resolve: resolveReady };
|
|
31
|
+
});
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
let db = null;
|
|
34
|
+
const initDB = async () => {
|
|
35
|
+
try {
|
|
36
|
+
if (migrations.length === 0) {
|
|
37
|
+
db = await openIndexedDb(dbName, dbCreator);
|
|
38
|
+
} else {
|
|
39
|
+
db = await migrateFunction(dbName, migrations, debug, dbCreator);
|
|
40
|
+
}
|
|
41
|
+
indexedDBRef.current = db;
|
|
42
|
+
setIndexedDB(db);
|
|
43
|
+
readyPromise.resolve();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(
|
|
46
|
+
`[DrizzleIndexedDBProvider] Failed to initialize database ${dbName}:`,
|
|
47
|
+
error
|
|
48
|
+
);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
initDB();
|
|
53
|
+
return () => {
|
|
54
|
+
if (db) {
|
|
55
|
+
db.close();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}, [dbName, migrations, migrateFunction, debug, readyPromise, dbCreator]);
|
|
59
|
+
const collections = useMemo(
|
|
60
|
+
() => /* @__PURE__ */ new Map(),
|
|
61
|
+
[]
|
|
62
|
+
);
|
|
63
|
+
const getCollection = useCallback(
|
|
64
|
+
(tableName) => {
|
|
65
|
+
const cacheKey = tableName;
|
|
66
|
+
if (!collections.has(cacheKey)) {
|
|
67
|
+
const table = schema[tableName];
|
|
68
|
+
if (!table) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Table "${tableName}" not found in schema. Available tables: ${Object.keys(schema).join(", ")}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const actualTableName = getTableName(table);
|
|
74
|
+
const collectionConfig = drizzleIndexedDBCollectionOptions({
|
|
75
|
+
indexedDBRef,
|
|
76
|
+
table,
|
|
77
|
+
storeName: actualTableName,
|
|
78
|
+
readyPromise: readyPromise.promise,
|
|
79
|
+
debug,
|
|
80
|
+
syncMode
|
|
81
|
+
});
|
|
82
|
+
const collection = createCollection(
|
|
83
|
+
collectionConfig
|
|
84
|
+
);
|
|
85
|
+
collections.set(cacheKey, {
|
|
86
|
+
collection,
|
|
87
|
+
refCount: 0
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return collections.get(cacheKey).collection;
|
|
91
|
+
},
|
|
92
|
+
[collections, schema, readyPromise.promise, debug, syncMode]
|
|
93
|
+
);
|
|
94
|
+
const incrementRefCount = useCallback(
|
|
95
|
+
(tableName) => {
|
|
96
|
+
const entry = collections.get(tableName);
|
|
97
|
+
if (entry) {
|
|
98
|
+
entry.refCount++;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
[collections]
|
|
102
|
+
);
|
|
103
|
+
const decrementRefCount = useCallback(
|
|
104
|
+
(tableName) => {
|
|
105
|
+
const entry = collections.get(tableName);
|
|
106
|
+
if (entry) {
|
|
107
|
+
entry.refCount--;
|
|
108
|
+
if (entry.refCount <= 0) {
|
|
109
|
+
collections.delete(tableName);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
[collections]
|
|
114
|
+
);
|
|
115
|
+
const contextValue = useMemo(
|
|
116
|
+
() => ({
|
|
117
|
+
indexedDB,
|
|
118
|
+
getCollection,
|
|
119
|
+
incrementRefCount,
|
|
120
|
+
decrementRefCount
|
|
121
|
+
}),
|
|
122
|
+
[indexedDB, getCollection, incrementRefCount, decrementRefCount]
|
|
123
|
+
);
|
|
124
|
+
return /* @__PURE__ */ jsx(DrizzleIndexedDBContext.Provider, { value: contextValue, children });
|
|
125
|
+
}
|
|
126
|
+
function useIndexedDBCollection(context, tableName) {
|
|
127
|
+
const { collection, unsubscribe } = useMemo(() => {
|
|
128
|
+
const col = context.getCollection(tableName);
|
|
129
|
+
context.incrementRefCount(tableName);
|
|
130
|
+
return {
|
|
131
|
+
collection: col,
|
|
132
|
+
unsubscribe: () => {
|
|
133
|
+
context.decrementRefCount(tableName);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}, [context, tableName]);
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
return () => {
|
|
139
|
+
unsubscribe();
|
|
140
|
+
};
|
|
141
|
+
}, [unsubscribe]);
|
|
142
|
+
return collection;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export { DrizzleIndexedDBContext, DrizzleIndexedDBProvider, useIndexedDBCollection };
|
|
146
|
+
//# sourceMappingURL=chunk-Y6XE3FVT.js.map
|
|
147
|
+
//# sourceMappingURL=chunk-Y6XE3FVT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context/DrizzleIndexedDBProvider.tsx"],"names":[],"mappings":"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","file":"chunk-Y6XE3FVT.js","sourcesContent":["import type { PropsWithChildren } from \"react\";\nimport {\n\tcreateContext,\n\tuseMemo,\n\tuseCallback,\n\tuseEffect,\n\tuseState,\n\tuseRef,\n} from \"react\";\nimport {\n\tcreateCollection,\n\ttype InferSchemaInput,\n\ttype Collection,\n\ttype InferSchemaOutput,\n\ttype SyncMode,\n} from \"@tanstack/db\";\nimport { getTableName, type Table } from \"drizzle-orm\";\nimport {\n\tdrizzleIndexedDBCollectionOptions,\n\ttype DrizzleIndexedDBCollectionConfig,\n} from \"../collections/drizzle-indexeddb-collection\";\nimport type { CollectionUtils } from \"@firtoz/db-helpers\";\nimport type {\n\tIdOf,\n\tInsertSchema,\n\tSelectSchema,\n\tGetTableFromSchema,\n\tInferCollectionFromTable,\n} from \"@firtoz/drizzle-utils\";\nimport {\n\ttype Migration,\n\tmigrateIndexedDBWithFunctions,\n} from \"../function-migrator\";\nimport type { IDBCreator, IDBDatabaseLike } from \"../idb-types\";\nimport { openIndexedDb } from \"../idb-operations\";\n\ninterface CollectionCacheEntry {\n\t// biome-ignore lint/suspicious/noExplicitAny: Cache needs to store collections of various types\n\tcollection: Collection<any, string, CollectionUtils<any>, any, any>;\n\trefCount: number;\n}\n\n// Type for migration functions (generated by Drizzle)\n\nexport type IndexedDbCollection<\n\tTSchema extends Record<string, unknown>,\n\tTTableName extends keyof TSchema & string,\n> = Collection<\n\tInferSchemaOutput<SelectSchema<GetTableFromSchema<TSchema, TTableName>>>,\n\tIdOf<GetTableFromSchema<TSchema, TTableName>>,\n\tCollectionUtils<\n\t\tInferSchemaOutput<SelectSchema<GetTableFromSchema<TSchema, TTableName>>>\n\t>,\n\tSelectSchema<GetTableFromSchema<TSchema, TTableName>>,\n\tInferSchemaInput<InsertSchema<GetTableFromSchema<TSchema, TTableName>>>\n>;\n\nexport type DrizzleIndexedDBContextValue<\n\tTSchema extends Record<string, unknown>,\n> = {\n\tindexedDB: IDBDatabaseLike | null;\n\tgetCollection: <TTableName extends keyof TSchema & string>(\n\t\ttableName: TTableName,\n\t) => IndexedDbCollection<TSchema, TTableName>;\n\tincrementRefCount: (tableName: string) => void;\n\tdecrementRefCount: (tableName: string) => void;\n};\n\nexport const DrizzleIndexedDBContext =\n\t// biome-ignore lint/suspicious/noExplicitAny: Context needs to accept any schema type\n\tcreateContext<DrizzleIndexedDBContextValue<any> | null>(null);\n\ntype DrizzleIndexedDBProviderProps<TSchema extends Record<string, unknown>> =\n\tPropsWithChildren<{\n\t\tdbName: string;\n\t\tschema: TSchema;\n\t\tmigrations?: Migration[];\n\t\tmigrateFunction?: (\n\t\t\tdbName: string,\n\t\t\tmigrations: Migration[],\n\t\t\tdebug?: boolean,\n\t\t\tdbCreator?: IDBCreator,\n\t\t) => Promise<IDBDatabaseLike>;\n\t\tdebug?: boolean;\n\t\tsyncMode?: SyncMode;\n\t\t/**\n\t\t * Optional custom database creator for testing/mocking.\n\t\t * Use createInstrumentedDbCreator() to track IndexedDB operations.\n\t\t */\n\t\tdbCreator?: IDBCreator;\n\t}>;\n\nexport function DrizzleIndexedDBProvider<\n\tTSchema extends Record<string, unknown>,\n>({\n\tchildren,\n\tdbName,\n\tschema,\n\tmigrations = [],\n\tmigrateFunction = migrateIndexedDBWithFunctions,\n\tdebug = false,\n\tsyncMode = \"eager\",\n\tdbCreator,\n}: DrizzleIndexedDBProviderProps<TSchema>) {\n\tconst [indexedDB, setIndexedDB] = useState<IDBDatabaseLike | null>(null);\n\tconst indexedDBRef = useRef<IDBDatabaseLike | null>(null);\n\tconst [readyPromise] = useState(() => {\n\t\tlet resolveReady: () => void;\n\t\tconst promise = new Promise<void>((resolve) => {\n\t\t\tresolveReady = resolve;\n\t\t});\n\t\t// biome-ignore lint/style/noNonNullAssertion: resolveReady is guaranteed to be set\n\t\treturn { promise, resolve: resolveReady! };\n\t});\n\n\tuseEffect(() => {\n\t\tlet db: IDBDatabaseLike | null = null;\n\t\tconst initDB = async () => {\n\t\t\ttry {\n\t\t\t\tif (migrations.length === 0) {\n\t\t\t\t\t// Open database directly without migration logic\n\t\t\t\t\tdb = await openIndexedDb(dbName, dbCreator);\n\t\t\t\t} else {\n\t\t\t\t\tdb = await migrateFunction(dbName, migrations, debug, dbCreator);\n\t\t\t\t}\n\n\t\t\t\tindexedDBRef.current = db;\n\t\t\t\tsetIndexedDB(db);\n\t\t\t\treadyPromise.resolve();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(\n\t\t\t\t\t`[DrizzleIndexedDBProvider] Failed to initialize database ${dbName}:`,\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\n\t\tinitDB();\n\n\t\t// Cleanup on unmount\n\t\treturn () => {\n\t\t\tif (db) {\n\t\t\t\tdb.close();\n\t\t\t}\n\t\t};\n\t}, [dbName, migrations, migrateFunction, debug, readyPromise, dbCreator]);\n\n\t// Collection cache with ref counting\n\tconst collections = useMemo<Map<string, CollectionCacheEntry>>(\n\t\t() => new Map(),\n\t\t[],\n\t);\n\n\tconst getCollection = useCallback<\n\t\tDrizzleIndexedDBContextValue<TSchema>[\"getCollection\"]\n\t>(\n\t\t<TTableName extends keyof TSchema & string>(tableName: TTableName) => {\n\t\t\tconst cacheKey = tableName;\n\n\t\t\t// Check if collection already exists in cache\n\t\t\tif (!collections.has(cacheKey)) {\n\t\t\t\t// Get the table definition from schema\n\t\t\t\tconst table = schema[tableName] as Table;\n\n\t\t\t\tif (!table) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Table \"${tableName}\" not found in schema. Available tables: ${Object.keys(schema).join(\", \")}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Extract the actual store/table name from the table definition\n\t\t\t\tconst actualTableName = getTableName(table);\n\n\t\t\t\t// Create collection options\n\t\t\t\tconst collectionConfig = drizzleIndexedDBCollectionOptions({\n\t\t\t\t\tindexedDBRef,\n\t\t\t\t\ttable,\n\t\t\t\t\tstoreName: actualTableName,\n\t\t\t\t\treadyPromise: readyPromise.promise,\n\t\t\t\t\tdebug,\n\t\t\t\t\tsyncMode,\n\t\t\t\t} as DrizzleIndexedDBCollectionConfig<Table>);\n\n\t\t\t\t// Create new collection and cache it with ref count 0\n\t\t\t\t// The collection will wait for readyPromise before accessing the database\n\t\t\t\t// Cast is safe: our collectionConfig provides CollectionUtils, but createCollection types it as UtilsRecord\n\t\t\t\tconst collection = createCollection(\n\t\t\t\t\tcollectionConfig,\n\t\t\t\t) as CollectionCacheEntry[\"collection\"];\n\n\t\t\t\tcollections.set(cacheKey, {\n\t\t\t\t\tcollection,\n\t\t\t\t\trefCount: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: We just ensured the collection exists\n\t\t\treturn collections.get(cacheKey)!\n\t\t\t\t.collection as unknown as IndexedDbCollection<TSchema, TTableName>;\n\t\t},\n\t\t[collections, schema, readyPromise.promise, debug, syncMode],\n\t);\n\n\tconst incrementRefCount: DrizzleIndexedDBContextValue<TSchema>[\"incrementRefCount\"] =\n\t\tuseCallback(\n\t\t\t(tableName: string) => {\n\t\t\t\tconst entry = collections.get(tableName);\n\t\t\t\tif (entry) {\n\t\t\t\t\tentry.refCount++;\n\t\t\t\t}\n\t\t\t},\n\t\t\t[collections],\n\t\t);\n\n\tconst decrementRefCount: DrizzleIndexedDBContextValue<TSchema>[\"decrementRefCount\"] =\n\t\tuseCallback(\n\t\t\t(tableName: string) => {\n\t\t\t\tconst entry = collections.get(tableName);\n\t\t\t\tif (entry) {\n\t\t\t\t\tentry.refCount--;\n\n\t\t\t\t\t// If ref count reaches 0, remove from cache\n\t\t\t\t\tif (entry.refCount <= 0) {\n\t\t\t\t\t\tcollections.delete(tableName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\t[collections],\n\t\t);\n\n\tconst contextValue: DrizzleIndexedDBContextValue<TSchema> = useMemo(\n\t\t() => ({\n\t\t\tindexedDB,\n\t\t\tgetCollection,\n\t\t\tincrementRefCount,\n\t\t\tdecrementRefCount,\n\t\t}),\n\t\t[indexedDB, getCollection, incrementRefCount, decrementRefCount],\n\t);\n\n\treturn (\n\t\t<DrizzleIndexedDBContext.Provider value={contextValue}>\n\t\t\t{children}\n\t\t</DrizzleIndexedDBContext.Provider>\n\t);\n}\n\n// Hook that components use to get a collection with automatic ref counting\nexport function useIndexedDBCollection<\n\tTSchema extends Record<string, unknown>,\n\tTTableName extends keyof TSchema & string,\n>(\n\tcontext: DrizzleIndexedDBContextValue<TSchema>,\n\ttableName: TTableName,\n): InferCollectionFromTable<GetTableFromSchema<TSchema, TTableName>> {\n\tconst { collection, unsubscribe } = useMemo(() => {\n\t\t// Get the collection and increment ref count\n\t\tconst col = context.getCollection(tableName);\n\t\tcontext.incrementRefCount(tableName);\n\n\t\t// Return collection and unsubscribe function\n\t\treturn {\n\t\t\tcollection: col,\n\t\t\tunsubscribe: () => {\n\t\t\t\tcontext.decrementRefCount(tableName);\n\t\t\t},\n\t\t};\n\t}, [context, tableName]);\n\n\t// Cleanup on unmount\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tunsubscribe();\n\t\t};\n\t}, [unsubscribe]);\n\n\treturn collection as unknown as InferCollectionFromTable<\n\t\tGetTableFromSchema<TSchema, TTableName>\n\t>;\n}\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { SyncMode, CollectionConfig, InferSchemaOutput, Collection, InferSchemaInput } from '@tanstack/db';
|
|
2
|
+
import { Table } from 'drizzle-orm';
|
|
3
|
+
import { IdOf, SelectSchema, InsertToSelectSchema, TableWithRequiredFields } from '@firtoz/drizzle-utils';
|
|
4
|
+
import { CollectionUtils } from '@firtoz/db-helpers';
|
|
5
|
+
import { IDBDatabaseLike } from '../idb-types.js';
|
|
6
|
+
import '@firtoz/idb-collections';
|
|
7
|
+
|
|
8
|
+
type AnyId = IdOf<any>;
|
|
9
|
+
/**
|
|
10
|
+
* Type for items stored in IndexedDB (must have required sync fields)
|
|
11
|
+
*/
|
|
12
|
+
type DrizzleIndexedDBSyncItem = {
|
|
13
|
+
id: AnyId;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
deletedAt: Date | null;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
interface DrizzleIndexedDBCollectionConfig<TTable extends Table> {
|
|
20
|
+
/**
|
|
21
|
+
* Ref to the IndexedDB database instance
|
|
22
|
+
*/
|
|
23
|
+
indexedDBRef: React.RefObject<IDBDatabaseLike | null>;
|
|
24
|
+
/**
|
|
25
|
+
* The Drizzle table definition (used for schema and type inference only)
|
|
26
|
+
*/
|
|
27
|
+
table: TTable;
|
|
28
|
+
/**
|
|
29
|
+
* The name of the IndexedDB object store (should match the table name)
|
|
30
|
+
*/
|
|
31
|
+
storeName: string;
|
|
32
|
+
/**
|
|
33
|
+
* Promise that resolves when the database is ready
|
|
34
|
+
*/
|
|
35
|
+
readyPromise: Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Sync mode: 'eager' (immediate) or 'on-demand'
|
|
38
|
+
*/
|
|
39
|
+
syncMode?: SyncMode;
|
|
40
|
+
/**
|
|
41
|
+
* Enable debug logging for index discovery and query optimization
|
|
42
|
+
*/
|
|
43
|
+
debug?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* When set, local mutations confirm TanStack sync immediately and persist to IndexedDB on a
|
|
46
|
+
* coalesced timer (`createGenericSyncFunction` in `@firtoz/db-helpers`).
|
|
47
|
+
*/
|
|
48
|
+
deferLocalPersistence?: boolean | {
|
|
49
|
+
flushIntervalMs?: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
type DrizzleIndexedDBCollectionConfigResult<TTable extends Table> = Omit<CollectionConfig<InferSchemaOutput<SelectSchema<TTable>>, IdOf<TTable>, InsertToSelectSchema<TTable>, CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>>, "utils"> & {
|
|
53
|
+
schema: InsertToSelectSchema<TTable>;
|
|
54
|
+
utils: CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>;
|
|
55
|
+
};
|
|
56
|
+
type DrizzleIndexedDBCollection<TTable extends TableWithRequiredFields> = Collection<InferSchemaOutput<SelectSchema<TTable>>, IdOf<TTable>, CollectionUtils<InferSchemaOutput<SelectSchema<TTable>>>, InsertToSelectSchema<TTable>, InferSchemaInput<InsertToSelectSchema<TTable>>>;
|
|
57
|
+
/**
|
|
58
|
+
* Creates a TanStack DB collection config for IndexedDB backed by Drizzle ORM.
|
|
59
|
+
*/
|
|
60
|
+
declare function drizzleIndexedDBCollectionOptions<const TTable extends Table>(config: DrizzleIndexedDBCollectionConfig<TTable>): DrizzleIndexedDBCollectionConfigResult<TTable>;
|
|
61
|
+
|
|
62
|
+
export { type DrizzleIndexedDBCollection, type DrizzleIndexedDBCollectionConfig, type DrizzleIndexedDBCollectionConfigResult, type DrizzleIndexedDBSyncItem, drizzleIndexedDBCollectionOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"drizzle-indexeddb-collection.js"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { PropsWithChildren } from 'react';
|
|
4
|
+
import { Collection, InferSchemaOutput, InferSchemaInput, SyncMode } from '@tanstack/db';
|
|
5
|
+
import { CollectionUtils } from '@firtoz/db-helpers';
|
|
6
|
+
import { SelectSchema, GetTableFromSchema, IdOf, InsertSchema, InferCollectionFromTable } from '@firtoz/drizzle-utils';
|
|
7
|
+
import { Migration } from '../function-migrator.js';
|
|
8
|
+
import { IDBDatabaseLike, IDBCreator } from '../idb-types.js';
|
|
9
|
+
import '@firtoz/idb-collections';
|
|
10
|
+
|
|
11
|
+
type IndexedDbCollection<TSchema extends Record<string, unknown>, TTableName extends keyof TSchema & string> = Collection<InferSchemaOutput<SelectSchema<GetTableFromSchema<TSchema, TTableName>>>, IdOf<GetTableFromSchema<TSchema, TTableName>>, CollectionUtils<InferSchemaOutput<SelectSchema<GetTableFromSchema<TSchema, TTableName>>>>, SelectSchema<GetTableFromSchema<TSchema, TTableName>>, InferSchemaInput<InsertSchema<GetTableFromSchema<TSchema, TTableName>>>>;
|
|
12
|
+
type DrizzleIndexedDBContextValue<TSchema extends Record<string, unknown>> = {
|
|
13
|
+
indexedDB: IDBDatabaseLike | null;
|
|
14
|
+
getCollection: <TTableName extends keyof TSchema & string>(tableName: TTableName) => IndexedDbCollection<TSchema, TTableName>;
|
|
15
|
+
incrementRefCount: (tableName: string) => void;
|
|
16
|
+
decrementRefCount: (tableName: string) => void;
|
|
17
|
+
};
|
|
18
|
+
declare const DrizzleIndexedDBContext: react.Context<DrizzleIndexedDBContextValue<any> | null>;
|
|
19
|
+
type DrizzleIndexedDBProviderProps<TSchema extends Record<string, unknown>> = PropsWithChildren<{
|
|
20
|
+
dbName: string;
|
|
21
|
+
schema: TSchema;
|
|
22
|
+
migrations?: Migration[];
|
|
23
|
+
migrateFunction?: (dbName: string, migrations: Migration[], debug?: boolean, dbCreator?: IDBCreator) => Promise<IDBDatabaseLike>;
|
|
24
|
+
debug?: boolean;
|
|
25
|
+
syncMode?: SyncMode;
|
|
26
|
+
/**
|
|
27
|
+
* Optional custom database creator for testing/mocking.
|
|
28
|
+
* Use createInstrumentedDbCreator() to track IndexedDB operations.
|
|
29
|
+
*/
|
|
30
|
+
dbCreator?: IDBCreator;
|
|
31
|
+
}>;
|
|
32
|
+
declare function DrizzleIndexedDBProvider<TSchema extends Record<string, unknown>>({ children, dbName, schema, migrations, migrateFunction, debug, syncMode, dbCreator, }: DrizzleIndexedDBProviderProps<TSchema>): react_jsx_runtime.JSX.Element;
|
|
33
|
+
declare function useIndexedDBCollection<TSchema extends Record<string, unknown>, TTableName extends keyof TSchema & string>(context: DrizzleIndexedDBContextValue<TSchema>, tableName: TTableName): InferCollectionFromTable<GetTableFromSchema<TSchema, TTableName>>;
|
|
34
|
+
|
|
35
|
+
export { DrizzleIndexedDBContext, type DrizzleIndexedDBContextValue, DrizzleIndexedDBProvider, type IndexedDbCollection, useIndexedDBCollection };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { DrizzleIndexedDBContext, DrizzleIndexedDBProvider, useIndexedDBCollection } from '../chunk-Y6XE3FVT.js';
|
|
2
|
+
import '../chunk-5KCMKETG.js';
|
|
3
|
+
import '../chunk-7X4EIKN4.js';
|
|
4
|
+
import '../chunk-JVUF63L6.js';
|
|
5
|
+
import '../chunk-WMCUJFEC.js';
|
|
6
|
+
//# sourceMappingURL=DrizzleIndexedDBProvider.js.map
|
|
7
|
+
//# sourceMappingURL=DrizzleIndexedDBProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"DrizzleIndexedDBProvider.js"}
|