@firtoz/drizzle-indexeddb 0.3.0 → 0.4.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 +44 -0
- package/README.md +162 -0
- package/package.json +11 -5
- package/src/collections/indexeddb-collection.ts +52 -204
- package/src/context/DrizzleIndexedDBProvider.tsx +374 -0
- package/src/context/useDrizzleIndexedDB.ts +1 -1
- package/src/function-migrator.ts +2 -1
- package/src/idb-interceptor.ts +75 -0
- package/src/idb-operations.ts +41 -0
- package/src/idb-types.ts +135 -0
- package/src/index.ts +51 -12
- package/src/instrumented-idb-database.ts +188 -0
- package/src/{utils.ts → native-idb-database.ts} +44 -214
- package/src/proxy/idb-proxy-client.ts +345 -0
- package/src/proxy/idb-proxy-server.ts +313 -0
- package/src/proxy/idb-proxy-transport.ts +174 -0
- package/src/proxy/idb-proxy-types.ts +77 -0
- package/src/proxy/idb-sync-adapter.ts +95 -0
- package/src/proxy/index.ts +37 -0
package/src/index.ts
CHANGED
|
@@ -8,23 +8,35 @@ export {
|
|
|
8
8
|
type DeleteIndexOperation,
|
|
9
9
|
} from "./function-migrator";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
// IDB Types
|
|
12
|
+
export type {
|
|
13
|
+
IDBCreator,
|
|
14
|
+
IDBOpenOptions,
|
|
15
|
+
IDBDatabaseLike,
|
|
16
|
+
IDBDeleter,
|
|
17
|
+
IndexInfo,
|
|
18
|
+
CreateStoreOptions,
|
|
19
|
+
CreateIndexOptions,
|
|
20
|
+
KeyRangeSpec,
|
|
21
|
+
} from "./idb-types";
|
|
22
|
+
|
|
23
|
+
// IDB Interceptor (for testing/debugging)
|
|
24
|
+
export type { IDBInterceptor, IDBOperation } from "./idb-interceptor";
|
|
25
|
+
|
|
26
|
+
// IDB Operations
|
|
27
|
+
export { openIndexedDb, deleteIndexedDB } from "./idb-operations";
|
|
28
|
+
|
|
29
|
+
// Native IDB Implementation
|
|
30
|
+
export { defaultIDBCreator } from "./native-idb-database";
|
|
21
31
|
|
|
32
|
+
// Instrumented IDB (for testing)
|
|
33
|
+
export { createInstrumentedDbCreator } from "./instrumented-idb-database";
|
|
34
|
+
|
|
35
|
+
// Collection
|
|
22
36
|
export {
|
|
23
37
|
indexedDBCollectionOptions,
|
|
24
38
|
type IndexedDBCollectionConfig,
|
|
25
39
|
type IndexedDBSyncItem,
|
|
26
|
-
type IDBInterceptor,
|
|
27
|
-
type IDBOperation,
|
|
28
40
|
} from "./collections/indexeddb-collection";
|
|
29
41
|
|
|
30
42
|
// IndexedDB Provider
|
|
@@ -39,3 +51,30 @@ export {
|
|
|
39
51
|
useDrizzleIndexedDB,
|
|
40
52
|
type UseDrizzleIndexedDBContextReturn,
|
|
41
53
|
} from "./context/useDrizzleIndexedDB";
|
|
54
|
+
|
|
55
|
+
// IDB Proxy (for Chrome extension, messaging-based IDB access)
|
|
56
|
+
export {
|
|
57
|
+
// Types
|
|
58
|
+
type IDBProxyRequest,
|
|
59
|
+
type IDBProxyRequestBody,
|
|
60
|
+
type IDBProxyResponse,
|
|
61
|
+
type IDBProxySyncMessage,
|
|
62
|
+
generateRequestId,
|
|
63
|
+
generateClientId,
|
|
64
|
+
// Transport
|
|
65
|
+
type IDBProxyClientTransport,
|
|
66
|
+
type IDBProxyServerTransport,
|
|
67
|
+
createInMemoryTransport,
|
|
68
|
+
createMultiClientTransport,
|
|
69
|
+
// Client
|
|
70
|
+
IDBProxyClient,
|
|
71
|
+
createProxyDbCreator,
|
|
72
|
+
type SyncHandler,
|
|
73
|
+
// Server
|
|
74
|
+
IDBProxyServer,
|
|
75
|
+
createProxyServer,
|
|
76
|
+
type IDBProxyServerOptions,
|
|
77
|
+
// Sync adapter (connects proxy sync to collection)
|
|
78
|
+
createCollectionSyncHandler,
|
|
79
|
+
combineSyncHandlers,
|
|
80
|
+
} from "./proxy";
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
IDBDatabaseLike,
|
|
3
|
+
IDBCreator,
|
|
4
|
+
IDBOpenOptions,
|
|
5
|
+
IndexInfo,
|
|
6
|
+
CreateStoreOptions,
|
|
7
|
+
CreateIndexOptions,
|
|
8
|
+
KeyRangeSpec,
|
|
9
|
+
} from "./idb-types";
|
|
10
|
+
import type { IDBInterceptor } from "./idb-interceptor";
|
|
11
|
+
import { defaultIDBCreator } from "./native-idb-database";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A database wrapper that intercepts operations and reports them to an interceptor.
|
|
15
|
+
* Useful for testing to verify what IndexedDB operations are actually performed.
|
|
16
|
+
*/
|
|
17
|
+
class InstrumentedIDBDatabase implements IDBDatabaseLike {
|
|
18
|
+
constructor(
|
|
19
|
+
private db: IDBDatabaseLike,
|
|
20
|
+
private interceptor: IDBInterceptor,
|
|
21
|
+
) {}
|
|
22
|
+
|
|
23
|
+
get version(): number {
|
|
24
|
+
return this.db.version;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Schema operations (pass through without interception)
|
|
28
|
+
hasStore(storeName: string): boolean {
|
|
29
|
+
return this.db.hasStore(storeName);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getStoreNames(): string[] {
|
|
33
|
+
return this.db.getStoreNames();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
createStore(storeName: string, options?: CreateStoreOptions): void {
|
|
37
|
+
this.db.createStore(storeName, options);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
deleteStore(storeName: string): void {
|
|
41
|
+
this.db.deleteStore(storeName);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
createIndex(
|
|
45
|
+
storeName: string,
|
|
46
|
+
indexName: string,
|
|
47
|
+
keyPath: string | string[],
|
|
48
|
+
options?: CreateIndexOptions,
|
|
49
|
+
): void {
|
|
50
|
+
this.db.createIndex(storeName, indexName, keyPath, options);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
deleteIndex(storeName: string, indexName: string): void {
|
|
54
|
+
this.db.deleteIndex(storeName, indexName);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getStoreIndexes(storeName: string): IndexInfo[] {
|
|
58
|
+
return this.db.getStoreIndexes(storeName);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Data operations (intercepted)
|
|
62
|
+
async getAll<T = unknown>(storeName: string): Promise<T[]> {
|
|
63
|
+
const items = await this.db.getAll<T>(storeName);
|
|
64
|
+
|
|
65
|
+
this.interceptor.onOperation?.({
|
|
66
|
+
type: "getAll",
|
|
67
|
+
storeName,
|
|
68
|
+
itemsReturned: items,
|
|
69
|
+
itemCount: items.length,
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
return items;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async getAllByIndex<T = unknown>(
|
|
77
|
+
storeName: string,
|
|
78
|
+
indexName: string,
|
|
79
|
+
keyRange?: KeyRangeSpec,
|
|
80
|
+
): Promise<T[]> {
|
|
81
|
+
const items = await this.db.getAllByIndex<T>(
|
|
82
|
+
storeName,
|
|
83
|
+
indexName,
|
|
84
|
+
keyRange,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
this.interceptor.onOperation?.({
|
|
88
|
+
type: "index-getAll",
|
|
89
|
+
storeName,
|
|
90
|
+
indexName,
|
|
91
|
+
keyRange: keyRange as unknown as IDBKeyRange | undefined,
|
|
92
|
+
itemsReturned: items,
|
|
93
|
+
itemCount: items.length,
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return items;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async get<T = unknown>(
|
|
101
|
+
storeName: string,
|
|
102
|
+
key: IDBValidKey,
|
|
103
|
+
): Promise<T | undefined> {
|
|
104
|
+
const item = await this.db.get<T>(storeName, key);
|
|
105
|
+
|
|
106
|
+
this.interceptor.onOperation?.({
|
|
107
|
+
type: "get",
|
|
108
|
+
storeName,
|
|
109
|
+
key,
|
|
110
|
+
itemReturned: item,
|
|
111
|
+
timestamp: Date.now(),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return item;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async add(storeName: string, items: unknown[]): Promise<void> {
|
|
118
|
+
await this.db.add(storeName, items);
|
|
119
|
+
|
|
120
|
+
this.interceptor.onOperation?.({
|
|
121
|
+
type: "add",
|
|
122
|
+
storeName,
|
|
123
|
+
items,
|
|
124
|
+
itemCount: items.length,
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async put(storeName: string, items: unknown[]): Promise<void> {
|
|
130
|
+
await this.db.put(storeName, items);
|
|
131
|
+
|
|
132
|
+
this.interceptor.onOperation?.({
|
|
133
|
+
type: "put",
|
|
134
|
+
storeName,
|
|
135
|
+
items,
|
|
136
|
+
itemCount: items.length,
|
|
137
|
+
timestamp: Date.now(),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async delete(storeName: string, keys: IDBValidKey[]): Promise<void> {
|
|
142
|
+
await this.db.delete(storeName, keys);
|
|
143
|
+
|
|
144
|
+
this.interceptor.onOperation?.({
|
|
145
|
+
type: "delete",
|
|
146
|
+
storeName,
|
|
147
|
+
keys,
|
|
148
|
+
keyCount: keys.length,
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async clear(storeName: string): Promise<void> {
|
|
154
|
+
await this.db.clear(storeName);
|
|
155
|
+
|
|
156
|
+
this.interceptor.onOperation?.({
|
|
157
|
+
type: "clear",
|
|
158
|
+
storeName,
|
|
159
|
+
timestamp: Date.now(),
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
close(): void {
|
|
164
|
+
this.db.close();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Creates an instrumented database creator that wraps operations with interception.
|
|
170
|
+
* Use this for testing to verify what IndexedDB operations are performed.
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* const interceptor = { onOperation: (op) => console.log(op) };
|
|
174
|
+
* const dbCreator = createInstrumentedDbCreator(interceptor);
|
|
175
|
+
*
|
|
176
|
+
* <DrizzleIndexedDBProvider dbCreator={dbCreator} ... />
|
|
177
|
+
*/
|
|
178
|
+
export function createInstrumentedDbCreator(
|
|
179
|
+
interceptor: IDBInterceptor,
|
|
180
|
+
baseCreator?: IDBCreator,
|
|
181
|
+
): IDBCreator {
|
|
182
|
+
const creator = baseCreator ?? defaultIDBCreator;
|
|
183
|
+
|
|
184
|
+
return async (name: string, options?: IDBOpenOptions) => {
|
|
185
|
+
const db = await creator(name, options);
|
|
186
|
+
return new InstrumentedIDBDatabase(db, interceptor);
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -1,128 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Index information returned by getStoreIndexes
|
|
13
|
-
*/
|
|
14
|
-
export interface IndexInfo {
|
|
15
|
-
name: string;
|
|
16
|
-
keyPath: string | string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Options for creating an object store
|
|
21
|
-
*/
|
|
22
|
-
export interface CreateStoreOptions {
|
|
23
|
-
keyPath?: string;
|
|
24
|
-
autoIncrement?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Options for creating an index
|
|
29
|
-
*/
|
|
30
|
-
export interface CreateIndexOptions {
|
|
31
|
-
unique?: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Key range specification for index queries
|
|
36
|
-
*/
|
|
37
|
-
export interface KeyRangeSpec {
|
|
38
|
-
type: "only" | "lowerBound" | "upperBound" | "bound";
|
|
39
|
-
value?: unknown;
|
|
40
|
-
lower?: unknown;
|
|
41
|
-
upper?: unknown;
|
|
42
|
-
lowerOpen?: boolean;
|
|
43
|
-
upperOpen?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Minimal database interface with high-level async operations.
|
|
48
|
-
* This is the interface that custom implementations (mocks, Chrome extension proxies, etc.) need to implement.
|
|
49
|
-
*
|
|
50
|
-
* All operations are simple async functions - no transactions, requests, or callbacks to deal with.
|
|
51
|
-
*/
|
|
52
|
-
export interface IDBDatabaseLike {
|
|
53
|
-
/** Database version number */
|
|
54
|
-
readonly version: number;
|
|
55
|
-
|
|
56
|
-
// =========================================================================
|
|
57
|
-
// Schema Operations (for migrations)
|
|
58
|
-
// =========================================================================
|
|
59
|
-
|
|
60
|
-
/** Check if a store exists */
|
|
61
|
-
hasStore(storeName: string): boolean;
|
|
62
|
-
|
|
63
|
-
/** Get list of all store names */
|
|
64
|
-
getStoreNames(): string[];
|
|
65
|
-
|
|
66
|
-
/** Create an object store (only valid during migrations) */
|
|
67
|
-
createStore(storeName: string, options?: CreateStoreOptions): void;
|
|
68
|
-
|
|
69
|
-
/** Delete an object store (only valid during migrations) */
|
|
70
|
-
deleteStore(storeName: string): void;
|
|
71
|
-
|
|
72
|
-
/** Create an index on a store (only valid during migrations) */
|
|
73
|
-
createIndex(
|
|
74
|
-
storeName: string,
|
|
75
|
-
indexName: string,
|
|
76
|
-
keyPath: string | string[],
|
|
77
|
-
options?: CreateIndexOptions,
|
|
78
|
-
): void;
|
|
79
|
-
|
|
80
|
-
/** Delete an index from a store (only valid during migrations) */
|
|
81
|
-
deleteIndex(storeName: string, indexName: string): void;
|
|
82
|
-
|
|
83
|
-
/** Get all indexes for a store (for index discovery) */
|
|
84
|
-
getStoreIndexes(storeName: string): IndexInfo[];
|
|
85
|
-
|
|
86
|
-
// =========================================================================
|
|
87
|
-
// Data Operations (all async, handle transactions internally)
|
|
88
|
-
// =========================================================================
|
|
89
|
-
|
|
90
|
-
/** Get all items from a store */
|
|
91
|
-
getAll<T = unknown>(storeName: string): Promise<T[]>;
|
|
92
|
-
|
|
93
|
-
/** Get items from a store using an index with optional key range */
|
|
94
|
-
getAllByIndex<T = unknown>(
|
|
95
|
-
storeName: string,
|
|
96
|
-
indexName: string,
|
|
97
|
-
keyRange?: KeyRangeSpec,
|
|
98
|
-
): Promise<T[]>;
|
|
99
|
-
|
|
100
|
-
/** Get a single item by key */
|
|
101
|
-
get<T = unknown>(storeName: string, key: IDBValidKey): Promise<T | undefined>;
|
|
102
|
-
|
|
103
|
-
/** Add items to a store (batch operation) */
|
|
104
|
-
add(storeName: string, items: unknown[]): Promise<void>;
|
|
105
|
-
|
|
106
|
-
/** Update items in a store (batch operation, uses put) */
|
|
107
|
-
put(storeName: string, items: unknown[]): Promise<void>;
|
|
108
|
-
|
|
109
|
-
/** Delete items from a store by keys (batch operation) */
|
|
110
|
-
delete(storeName: string, keys: IDBValidKey[]): Promise<void>;
|
|
111
|
-
|
|
112
|
-
/** Clear all items from a store */
|
|
113
|
-
clear(storeName: string): Promise<void>;
|
|
114
|
-
|
|
115
|
-
// =========================================================================
|
|
116
|
-
// Lifecycle
|
|
117
|
-
// =========================================================================
|
|
118
|
-
|
|
119
|
-
/** Close the database connection */
|
|
120
|
-
close(): void;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// ============================================================================
|
|
124
|
-
// Default Implementation (wraps native IndexedDB)
|
|
125
|
-
// ============================================================================
|
|
1
|
+
import type {
|
|
2
|
+
IDBDatabaseLike,
|
|
3
|
+
IDBCreator,
|
|
4
|
+
IDBOpenOptions,
|
|
5
|
+
IndexInfo,
|
|
6
|
+
CreateStoreOptions,
|
|
7
|
+
CreateIndexOptions,
|
|
8
|
+
KeyRangeSpec,
|
|
9
|
+
} from "./idb-types";
|
|
126
10
|
|
|
127
11
|
/**
|
|
128
12
|
* Creates a KeyRange from a KeyRangeSpec
|
|
@@ -321,69 +205,6 @@ class NativeIDBDatabase implements IDBDatabaseLike {
|
|
|
321
205
|
}
|
|
322
206
|
}
|
|
323
207
|
|
|
324
|
-
// ============================================================================
|
|
325
|
-
// IDB Creator / Opener
|
|
326
|
-
// ============================================================================
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Options for opening a database with version upgrade support.
|
|
330
|
-
*/
|
|
331
|
-
export interface IDBOpenOptions {
|
|
332
|
-
/** Target version for the database. If higher than current, triggers upgrade. */
|
|
333
|
-
version?: number;
|
|
334
|
-
/** Called during version upgrade - this is where schema changes (createStore, createIndex) are allowed. */
|
|
335
|
-
onUpgrade?: (db: IDBDatabaseLike) => void;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Function type for creating/opening an IndexedDB-like database.
|
|
340
|
-
* Custom implementations can use this to provide proxy/mock/alternative backends.
|
|
341
|
-
*/
|
|
342
|
-
export type IDBCreator = (
|
|
343
|
-
name: string,
|
|
344
|
-
options?: IDBOpenOptions,
|
|
345
|
-
) => Promise<IDBDatabaseLike>;
|
|
346
|
-
|
|
347
|
-
const defaultIDBCreator: IDBCreator = (
|
|
348
|
-
name: string,
|
|
349
|
-
options?: IDBOpenOptions,
|
|
350
|
-
): Promise<IDBDatabaseLike> => {
|
|
351
|
-
return new Promise((resolve, reject) => {
|
|
352
|
-
const request = options?.version
|
|
353
|
-
? indexedDB.open(name, options.version)
|
|
354
|
-
: indexedDB.open(name);
|
|
355
|
-
|
|
356
|
-
request.onerror = () => reject(request.error);
|
|
357
|
-
|
|
358
|
-
request.onblocked = () => {
|
|
359
|
-
setTimeout(() => {
|
|
360
|
-
reject(new Error("Database upgrade blocked - close other tabs"));
|
|
361
|
-
}, 3000);
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
request.onupgradeneeded = (event) => {
|
|
365
|
-
if (options?.onUpgrade) {
|
|
366
|
-
const db = request.result;
|
|
367
|
-
const transaction = (event.target as IDBOpenDBRequest).transaction;
|
|
368
|
-
if (!transaction) {
|
|
369
|
-
reject(new Error("No transaction during upgrade"));
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
// Create an upgrade-mode database wrapper
|
|
373
|
-
const upgradeDb = new UpgradeModeDatabase(db, transaction);
|
|
374
|
-
try {
|
|
375
|
-
options.onUpgrade(upgradeDb);
|
|
376
|
-
} catch (error) {
|
|
377
|
-
transaction.abort();
|
|
378
|
-
reject(error);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
request.onsuccess = () => resolve(new NativeIDBDatabase(request.result));
|
|
384
|
-
});
|
|
385
|
-
};
|
|
386
|
-
|
|
387
208
|
/**
|
|
388
209
|
* Upgrade-mode database wrapper used during version changes.
|
|
389
210
|
* Provides IDBDatabaseLike interface with schema modification capabilities.
|
|
@@ -490,36 +311,45 @@ class UpgradeModeDatabase implements IDBDatabaseLike {
|
|
|
490
311
|
}
|
|
491
312
|
}
|
|
492
313
|
|
|
493
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Default IDB creator that uses the native IndexedDB API.
|
|
316
|
+
*/
|
|
317
|
+
export const defaultIDBCreator: IDBCreator = (
|
|
494
318
|
name: string,
|
|
495
|
-
dbCreator?: IDBCreator,
|
|
496
319
|
options?: IDBOpenOptions,
|
|
497
|
-
): Promise<IDBDatabaseLike> {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
320
|
+
): Promise<IDBDatabaseLike> => {
|
|
321
|
+
return new Promise((resolve, reject) => {
|
|
322
|
+
const request = options?.version
|
|
323
|
+
? indexedDB.open(name, options.version)
|
|
324
|
+
: indexedDB.open(name);
|
|
501
325
|
|
|
502
|
-
|
|
503
|
-
// IDB Deleter
|
|
504
|
-
// ============================================================================
|
|
326
|
+
request.onerror = () => reject(request.error);
|
|
505
327
|
|
|
506
|
-
|
|
328
|
+
request.onblocked = () => {
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
reject(new Error("Database upgrade blocked - close other tabs"));
|
|
331
|
+
}, 3000);
|
|
332
|
+
};
|
|
507
333
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
334
|
+
request.onupgradeneeded = (event) => {
|
|
335
|
+
if (options?.onUpgrade) {
|
|
336
|
+
const db = request.result;
|
|
337
|
+
const transaction = (event.target as IDBOpenDBRequest).transaction;
|
|
338
|
+
if (!transaction) {
|
|
339
|
+
reject(new Error("No transaction during upgrade"));
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Create an upgrade-mode database wrapper
|
|
343
|
+
const upgradeDb = new UpgradeModeDatabase(db, transaction);
|
|
344
|
+
try {
|
|
345
|
+
options.onUpgrade(upgradeDb);
|
|
346
|
+
} catch (error) {
|
|
347
|
+
transaction.abort();
|
|
348
|
+
reject(error);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
request.onsuccess = () => resolve(new NativeIDBDatabase(request.result));
|
|
513
354
|
});
|
|
514
355
|
};
|
|
515
|
-
|
|
516
|
-
/**
|
|
517
|
-
* Deletes the database (useful for testing)
|
|
518
|
-
*/
|
|
519
|
-
export async function deleteIndexedDB(
|
|
520
|
-
dbName: string,
|
|
521
|
-
dbDeleter?: IDBDeleter,
|
|
522
|
-
): Promise<void> {
|
|
523
|
-
const dbDeleterToUse = dbDeleter ?? defaultIDBDeleter;
|
|
524
|
-
return dbDeleterToUse(dbName);
|
|
525
|
-
}
|