@dumbmatter/idb 7.0.0 → 8.0.3
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 +6 -0
- package/README.md +22 -25
- package/build/entry.d.ts +55 -34
- package/build/index.cjs +230 -14
- package/build/index.d.ts +3 -2
- package/build/index.js +227 -10
- package/build/umd.js +1 -1
- package/build/util.d.ts +2 -2
- package/build/wrap-idb-value.d.ts +3 -3
- package/package.json +23 -22
- package/build/async-iterators.cjs +0 -57
- package/build/async-iterators.js +0 -55
- package/build/umd-with-async-ittr.js +0 -1
- package/build/wrap-idb-value.cjs +0 -191
- package/build/wrap-idb-value.js +0 -185
- package/with-async-ittr.cjs +0 -2
- package/with-async-ittr.d.ts +0 -1
- package/with-async-ittr.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
# Breaking changes in 8.x
|
|
2
|
+
|
|
3
|
+
- Finally dropped support for old EdgeHTML engine.
|
|
4
|
+
- Dropped support for browsers that don't support [`cursor.request`](https://caniuse.com/mdn-api_idbcursor_request).
|
|
5
|
+
- Removed separate async iterators build. It's now one build with async iterator support.
|
|
6
|
+
|
|
1
7
|
# Breaking changes in 7.x
|
|
2
8
|
|
|
3
9
|
- No longer committing `build` to GitHub.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# IndexedDB with usability.
|
|
2
2
|
|
|
3
|
-
This is a tiny (~1.
|
|
3
|
+
This is a tiny (~1.19kB brotli'd) library that mostly mirrors the IndexedDB API, but with small improvements that make a big difference to usability.
|
|
4
4
|
|
|
5
5
|
1. [Installation](#installation)
|
|
6
6
|
1. [Changes](#changes)
|
|
@@ -42,7 +42,7 @@ async function doDatabaseStuff() {
|
|
|
42
42
|
|
|
43
43
|
```html
|
|
44
44
|
<script type="module">
|
|
45
|
-
import { openDB, deleteDB, wrap, unwrap } from 'https://cdn.jsdelivr.net/npm/idb@
|
|
45
|
+
import { openDB, deleteDB, wrap, unwrap } from 'https://cdn.jsdelivr.net/npm/idb@8/+esm';
|
|
46
46
|
|
|
47
47
|
async function doDatabaseStuff() {
|
|
48
48
|
const db = await openDB(…);
|
|
@@ -53,7 +53,7 @@ async function doDatabaseStuff() {
|
|
|
53
53
|
### Using external script reference
|
|
54
54
|
|
|
55
55
|
```html
|
|
56
|
-
<script src="https://cdn.jsdelivr.net/npm/idb@
|
|
56
|
+
<script src="https://cdn.jsdelivr.net/npm/idb@8/build/umd.js"></script>
|
|
57
57
|
<script>
|
|
58
58
|
async function doDatabaseStuff() {
|
|
59
59
|
const db = await idb.openDB(…);
|
|
@@ -71,8 +71,6 @@ A global, `idb`, will be created, containing all exports of the module version.
|
|
|
71
71
|
|
|
72
72
|
This library targets modern browsers, as in Chrome, Firefox, Safari, and other browsers that use those engines, such as Edge. IE is not supported.
|
|
73
73
|
|
|
74
|
-
If you want to target much older versions of those browsers, you can transpile the library using something like [Babel](https://babeljs.io/). You can't transpile the library for IE, as it relies on a proper implementation of [JavaScript proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).
|
|
75
|
-
|
|
76
74
|
# API
|
|
77
75
|
|
|
78
76
|
## `openDB`
|
|
@@ -81,13 +79,13 @@ This method opens a database, and returns a promise for an enhanced [`IDBDatabas
|
|
|
81
79
|
|
|
82
80
|
```js
|
|
83
81
|
const db = await openDB(name, version, {
|
|
84
|
-
upgrade(db, oldVersion, newVersion, transaction) {
|
|
82
|
+
upgrade(db, oldVersion, newVersion, transaction, event) {
|
|
85
83
|
// …
|
|
86
84
|
},
|
|
87
|
-
blocked() {
|
|
85
|
+
blocked(currentVersion, blockedVersion, event) {
|
|
88
86
|
// …
|
|
89
87
|
},
|
|
90
|
-
blocking() {
|
|
88
|
+
blocking(currentVersion, blockedVersion, event) {
|
|
91
89
|
// …
|
|
92
90
|
},
|
|
93
91
|
terminated() {
|
|
@@ -103,8 +101,15 @@ const db = await openDB(name, version, {
|
|
|
103
101
|
- `oldVersion`: Last version of the database opened by the user.
|
|
104
102
|
- `newVersion`: Whatever new version you provided.
|
|
105
103
|
- `transaction`: An enhanced transaction for this upgrade. This is useful if you need to get data from other stores as part of a migration.
|
|
104
|
+
- `event`: The event object for the associated `upgradeneeded` event.
|
|
106
105
|
- `blocked` (optional): Called if there are older versions of the database open on the origin, so this version cannot open. This is similar to the [`blocked` event](https://developer.mozilla.org/en-US/docs/Web/API/IDBOpenDBRequest/blocked_event) in plain IndexedDB.
|
|
106
|
+
- `currentVersion`: Version of the database that's blocking this one.
|
|
107
|
+
- `blockedVersion`: The version of the database being blocked (whatever version you provided to `openDB`).
|
|
108
|
+
- `event`: The event object for the associated `blocked` event.
|
|
107
109
|
- `blocking` (optional): Called if this connection is blocking a future version of the database from opening. This is similar to the [`versionchange` event](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/versionchange_event) in plain IndexedDB.
|
|
110
|
+
- `currentVersion`: Version of the open database (whatever version you provided to `openDB`).
|
|
111
|
+
- `blockedVersion`: The version of the database that's being blocked.
|
|
112
|
+
- `event`: The event object for the associated `versionchange` event.
|
|
108
113
|
- `terminated` (optional): Called if the browser abnormally terminates the connection, but not on regular closures like calling `db.close()`. This is similar to the [`close` event](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/close_event) in plain IndexedDB.
|
|
109
114
|
|
|
110
115
|
## `deleteDB`
|
|
@@ -121,6 +126,8 @@ await deleteDB(name, {
|
|
|
121
126
|
|
|
122
127
|
- `name`: Name of the database.
|
|
123
128
|
- `blocked` (optional): Called if the database already exists and there are open connections that don’t close in response to a versionchange event, the request will be blocked until they all close.
|
|
129
|
+
- `currentVersion`: Version of the database that's blocking the delete operation.
|
|
130
|
+
- `event`: The event object for the associated 'versionchange' event.
|
|
124
131
|
|
|
125
132
|
## `unwrap`
|
|
126
133
|
|
|
@@ -142,8 +149,6 @@ const wrapped = wrap(unwrapped);
|
|
|
142
149
|
|
|
143
150
|
This is useful if some third party code gives you an `IDBDatabase` object and you want it to have the features of this library.
|
|
144
151
|
|
|
145
|
-
This doesn't work with `IDBCursor`, [due to missing primitives](https://github.com/w3c/IndexedDB/issues/255). Also, if you wrap an `IDBTransaction`, `tx.store` and `tx.objectStoreNames` won't work in Edge. To avoid these issues, wrap the `IDBDatabase` object, and use the wrapped object to create a new transaction.
|
|
146
|
-
|
|
147
152
|
## General enhancements
|
|
148
153
|
|
|
149
154
|
Once you've opened the database the API is the same as IndexedDB, except for a few changes to make things easier.
|
|
@@ -261,15 +266,7 @@ while (cursor) {
|
|
|
261
266
|
|
|
262
267
|
## Async iterators
|
|
263
268
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
```js
|
|
267
|
-
import { openDB } from 'idb/with-async-ittr';
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
Or `https://cdn.jsdelivr.net/npm/idb@7/build/umd-with-async-ittr.js` if you're using the non-module version.
|
|
271
|
-
|
|
272
|
-
Now you can iterate over stores, indexes, and cursors:
|
|
269
|
+
You can iterate over stores, indexes, and cursors:
|
|
273
270
|
|
|
274
271
|
```js
|
|
275
272
|
const tx = db.transaction(storeName);
|
|
@@ -320,19 +317,19 @@ const dbPromise = openDB('keyval-store', 1, {
|
|
|
320
317
|
|
|
321
318
|
export async function get(key) {
|
|
322
319
|
return (await dbPromise).get('keyval', key);
|
|
323
|
-
}
|
|
320
|
+
}
|
|
324
321
|
export async function set(key, val) {
|
|
325
322
|
return (await dbPromise).put('keyval', val, key);
|
|
326
|
-
}
|
|
323
|
+
}
|
|
327
324
|
export async function del(key) {
|
|
328
325
|
return (await dbPromise).delete('keyval', key);
|
|
329
|
-
}
|
|
326
|
+
}
|
|
330
327
|
export async function clear() {
|
|
331
328
|
return (await dbPromise).clear('keyval');
|
|
332
|
-
}
|
|
329
|
+
}
|
|
333
330
|
export async function keys() {
|
|
334
331
|
return (await dbPromise).getAllKeys('keyval');
|
|
335
|
-
}
|
|
332
|
+
}
|
|
336
333
|
```
|
|
337
334
|
|
|
338
335
|
## Article store
|
|
@@ -497,7 +494,7 @@ Note: Types like `IDBPDatabase` are used by TypeScript only. The implementation
|
|
|
497
494
|
# Developing
|
|
498
495
|
|
|
499
496
|
```sh
|
|
500
|
-
|
|
497
|
+
pnpm run dev
|
|
501
498
|
```
|
|
502
499
|
|
|
503
500
|
This will also perform type testing.
|
package/build/entry.d.ts
CHANGED
|
@@ -6,19 +6,28 @@ export interface OpenDBCallbacks<DBTypes extends DBSchema | unknown> {
|
|
|
6
6
|
* @param database A database instance that you can use to add/remove stores and indexes.
|
|
7
7
|
* @param oldVersion Last version of the database opened by the user.
|
|
8
8
|
* @param newVersion Whatever new version you provided.
|
|
9
|
-
* @param transaction The transaction for this upgrade.
|
|
10
|
-
* from other stores as part of a migration.
|
|
9
|
+
* @param transaction The transaction for this upgrade.
|
|
10
|
+
* This is useful if you need to get data from other stores as part of a migration.
|
|
11
|
+
* @param event The event object for the associated 'upgradeneeded' event.
|
|
11
12
|
*/
|
|
12
|
-
upgrade?(database: IDBPDatabase<DBTypes>, oldVersion: number, newVersion: number | null, transaction: IDBPTransaction<DBTypes, StoreNames<DBTypes>[], 'versionchange'
|
|
13
|
+
upgrade?(database: IDBPDatabase<DBTypes>, oldVersion: number, newVersion: number | null, transaction: IDBPTransaction<DBTypes, StoreNames<DBTypes>[], 'versionchange'>, event: IDBVersionChangeEvent): void;
|
|
13
14
|
/**
|
|
14
15
|
* Called if there are older versions of the database open on the origin, so this version cannot
|
|
15
16
|
* open.
|
|
17
|
+
*
|
|
18
|
+
* @param currentVersion Version of the database that's blocking this one.
|
|
19
|
+
* @param blockedVersion The version of the database being blocked (whatever version you provided to `openDB`).
|
|
20
|
+
* @param event The event object for the associated `blocked` event.
|
|
16
21
|
*/
|
|
17
|
-
blocked?(): void;
|
|
22
|
+
blocked?(currentVersion: number, blockedVersion: number | null, event: IDBVersionChangeEvent): void;
|
|
18
23
|
/**
|
|
19
24
|
* Called if this connection is blocking a future version of the database from opening.
|
|
25
|
+
*
|
|
26
|
+
* @param currentVersion Version of the open database (whatever version you provided to `openDB`).
|
|
27
|
+
* @param blockedVersion The version of the database that's being blocked.
|
|
28
|
+
* @param event The event object for the associated `versionchange` event.
|
|
20
29
|
*/
|
|
21
|
-
blocking?(): void;
|
|
30
|
+
blocking?(currentVersion: number, blockedVersion: number | null, event: IDBVersionChangeEvent): void;
|
|
22
31
|
/**
|
|
23
32
|
* Called if the browser abnormally terminates the connection.
|
|
24
33
|
* This is not called when `db.close()` is called.
|
|
@@ -36,8 +45,11 @@ export declare function openDB<DBTypes extends DBSchema | unknown = unknown>(nam
|
|
|
36
45
|
export interface DeleteDBCallbacks {
|
|
37
46
|
/**
|
|
38
47
|
* Called if there are connections to this database open, so it cannot be deleted.
|
|
48
|
+
*
|
|
49
|
+
* @param currentVersion Version of the database that's blocking the delete operation.
|
|
50
|
+
* @param event The event object for the associated `blocked` event.
|
|
39
51
|
*/
|
|
40
|
-
blocked?(): void;
|
|
52
|
+
blocked?(currentVersion: number, event: IDBVersionChangeEvent): void;
|
|
41
53
|
}
|
|
42
54
|
/**
|
|
43
55
|
* Delete a database.
|
|
@@ -45,15 +57,15 @@ export interface DeleteDBCallbacks {
|
|
|
45
57
|
* @param name Name of the database.
|
|
46
58
|
*/
|
|
47
59
|
export declare function deleteDB(name: string, { blocked }?: DeleteDBCallbacks): Promise<void>;
|
|
48
|
-
export { unwrap, wrap } from './wrap-idb-value';
|
|
49
|
-
|
|
60
|
+
export { unwrap, wrap } from './wrap-idb-value.js';
|
|
61
|
+
type KeyToKeyNoIndex<T> = {
|
|
50
62
|
[K in keyof T]: string extends K ? never : number extends K ? never : K;
|
|
51
63
|
};
|
|
52
|
-
|
|
64
|
+
type ValuesOf<T> = T extends {
|
|
53
65
|
[K in keyof T]: infer U;
|
|
54
66
|
} ? U : never;
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
type KnownKeys<T> = ValuesOf<KeyToKeyNoIndex<T>>;
|
|
68
|
+
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
|
|
57
69
|
export interface DBSchema {
|
|
58
70
|
[s: string]: DBSchemaValue;
|
|
59
71
|
}
|
|
@@ -71,38 +83,38 @@ interface DBSchemaValue {
|
|
|
71
83
|
*
|
|
72
84
|
* @template DBTypes DB schema type, or unknown if the DB isn't typed.
|
|
73
85
|
*/
|
|
74
|
-
export
|
|
86
|
+
export type StoreNames<DBTypes extends DBSchema | unknown> = DBTypes extends DBSchema ? KnownKeys<DBTypes> : string;
|
|
75
87
|
/**
|
|
76
88
|
* Extract database value types from the DB schema type.
|
|
77
89
|
*
|
|
78
90
|
* @template DBTypes DB schema type, or unknown if the DB isn't typed.
|
|
79
91
|
* @template StoreName Names of the object stores to get the types of.
|
|
80
92
|
*/
|
|
81
|
-
export
|
|
82
|
-
|
|
93
|
+
export type StoreValue<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>> = DBTypes extends DBSchema ? DBTypes[StoreName]['value'] : any;
|
|
94
|
+
type KeyPathToNestedObject<S extends string> = S extends `${infer T}.${infer U}` ? {
|
|
83
95
|
[Key in T]: KeyPathToNestedObject<U>;
|
|
84
96
|
} : S;
|
|
85
|
-
|
|
97
|
+
type OptionalNested<Type, PathToKey> = PathToKey extends object ? Omit<Type, keyof PathToKey> & {
|
|
86
98
|
[Key in Extract<keyof PathToKey, keyof Type>]: OptionalNested<Type[Key], PathToKey[Key]>;
|
|
87
99
|
} : PathToKey extends keyof Type ? Omit<Type, PathToKey> & {
|
|
88
100
|
[Key in PathToKey]?: Type[Key];
|
|
89
101
|
} : never;
|
|
90
|
-
|
|
91
|
-
export
|
|
102
|
+
type ValueWithOptionalKeyPath<Value extends unknown, KeyPath extends string> = OptionalNested<Value, KeyPathToNestedObject<KeyPath>>;
|
|
103
|
+
export type StoreValueWithOptionalKey<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>> = DBTypes extends DBSchema ? DBTypes[StoreName]['autoIncrementKeyPath'] extends string ? (ValueWithOptionalKeyPath<DBTypes[StoreName]['value'], DBTypes[StoreName]['autoIncrementKeyPath']>) : StoreValue<DBTypes, StoreName> : any;
|
|
92
104
|
/**
|
|
93
105
|
* Extract database key types from the DB schema type.
|
|
94
106
|
*
|
|
95
107
|
* @template DBTypes DB schema type, or unknown if the DB isn't typed.
|
|
96
108
|
* @template StoreName Names of the object stores to get the types of.
|
|
97
109
|
*/
|
|
98
|
-
export
|
|
110
|
+
export type StoreKey<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>> = DBTypes extends DBSchema ? DBTypes[StoreName]['key'] : IDBValidKey;
|
|
99
111
|
/**
|
|
100
112
|
* Extract the names of indexes in certain object stores from the DB schema type.
|
|
101
113
|
*
|
|
102
114
|
* @template DBTypes DB schema type, or unknown if the DB isn't typed.
|
|
103
115
|
* @template StoreName Names of the object stores to get the types of.
|
|
104
116
|
*/
|
|
105
|
-
export
|
|
117
|
+
export type IndexNames<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>> = DBTypes extends DBSchema ? keyof DBTypes[StoreName]['indexes'] & string : string;
|
|
106
118
|
/**
|
|
107
119
|
* Extract the types of indexes in certain object stores from the DB schema type.
|
|
108
120
|
*
|
|
@@ -110,10 +122,13 @@ export declare type IndexNames<DBTypes extends DBSchema | unknown, StoreName ext
|
|
|
110
122
|
* @template StoreName Names of the object stores to get the types of.
|
|
111
123
|
* @template IndexName Names of the indexes to get the types of.
|
|
112
124
|
*/
|
|
113
|
-
export
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
export type IndexKey<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName>> = DBTypes extends DBSchema ? IndexName extends keyof DBTypes[StoreName]['indexes'] ? DBTypes[StoreName]['indexes'][IndexName] : IDBValidKey : IDBValidKey;
|
|
126
|
+
type CursorSource<DBTypes extends DBSchema | unknown, TxStores extends ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown, Mode extends IDBTransactionMode = 'readonly'> = IndexName extends IndexNames<DBTypes, StoreName> ? IDBPIndex<DBTypes, TxStores, StoreName, IndexName, Mode> : IDBPObjectStore<DBTypes, TxStores, StoreName, Mode>;
|
|
127
|
+
type CursorKey<DBTypes extends DBSchema | unknown, StoreName extends StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown> = IndexName extends IndexNames<DBTypes, StoreName> ? IndexKey<DBTypes, StoreName, IndexName> : StoreKey<DBTypes, StoreName>;
|
|
128
|
+
type IDBPDatabaseExtends = Omit<IDBDatabase, 'createObjectStore' | 'deleteObjectStore' | 'transaction' | 'objectStoreNames'>;
|
|
129
|
+
export type DOMStringListSymbolIteratorType = DOMStringList extends {
|
|
130
|
+
[Symbol.iterator](): infer R;
|
|
131
|
+
} ? R : IterableIterator<string>;
|
|
117
132
|
/**
|
|
118
133
|
* A variation of DOMStringList with precise string types
|
|
119
134
|
*/
|
|
@@ -121,7 +136,11 @@ export interface TypedDOMStringList<T extends string> extends DOMStringList {
|
|
|
121
136
|
contains(string: T): boolean;
|
|
122
137
|
item(index: number): T | null;
|
|
123
138
|
[index: number]: T;
|
|
124
|
-
|
|
139
|
+
/**
|
|
140
|
+
* To resolve https://github.com/jakearchibald/idb/issues/327,
|
|
141
|
+
* and for compatibility with TypeScript >= 5.6 with ArrayIterator.
|
|
142
|
+
*/
|
|
143
|
+
[Symbol.iterator](): IterableIterator<string> extends DOMStringListSymbolIteratorType ? IterableIterator<T> : DOMStringListSymbolIteratorType & Iterator<T>;
|
|
125
144
|
}
|
|
126
145
|
interface IDBTransactionOptions {
|
|
127
146
|
/**
|
|
@@ -144,10 +163,12 @@ export interface IDBPDatabase<DBTypes extends DBSchema | unknown = unknown> exte
|
|
|
144
163
|
*
|
|
145
164
|
* Throws a "InvalidStateError" DOMException if not called within an upgrade transaction.
|
|
146
165
|
*/
|
|
147
|
-
createObjectStore<Name extends StoreNames<DBTypes>>(name: Name,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
166
|
+
createObjectStore<Name extends StoreNames<DBTypes>>(name: Name, ...args: DBTypes extends DBSchema ? DBTypes[Name]['autoIncrementKeyPath'] extends string ? [
|
|
167
|
+
optionalParameters: (IDBObjectStoreParameters & {
|
|
168
|
+
autoIncrement: true;
|
|
169
|
+
keyPath: DBTypes[Name]['autoIncrementKeyPath'];
|
|
170
|
+
})
|
|
171
|
+
] : [optionalParameters?: IDBObjectStoreParameters] : [optionalParameters?: IDBObjectStoreParameters]): IDBPObjectStore<DBTypes, ArrayLike<StoreNames<DBTypes>>, Name, 'versionchange'>;
|
|
151
172
|
/**
|
|
152
173
|
* Deletes the object store with the given name.
|
|
153
174
|
*
|
|
@@ -326,7 +347,7 @@ export interface IDBPDatabase<DBTypes extends DBSchema | unknown = unknown> exte
|
|
|
326
347
|
*/
|
|
327
348
|
put<Name extends StoreNames<DBTypes>>(storeName: Name, value: StoreValueWithOptionalKey<DBTypes, Name>, key?: StoreKey<DBTypes, Name> | IDBKeyRange): Promise<StoreKey<DBTypes, Name>>;
|
|
328
349
|
}
|
|
329
|
-
|
|
350
|
+
type IDBPTransactionExtends = Omit<IDBTransaction, 'db' | 'objectStore' | 'objectStoreNames'>;
|
|
330
351
|
export interface IDBPTransaction<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, Mode extends IDBTransactionMode = 'readonly'> extends IDBPTransactionExtends {
|
|
331
352
|
/**
|
|
332
353
|
* The transaction's mode.
|
|
@@ -353,7 +374,7 @@ export interface IDBPTransaction<DBTypes extends DBSchema | unknown = unknown, T
|
|
|
353
374
|
*/
|
|
354
375
|
objectStore<StoreName extends TxStores[number]>(name: StoreName): IDBPObjectStore<DBTypes, TxStores, StoreName, Mode>;
|
|
355
376
|
}
|
|
356
|
-
|
|
377
|
+
type IDBPObjectStoreExtends = Omit<IDBObjectStore, 'transaction' | 'add' | 'clear' | 'count' | 'createIndex' | 'delete' | 'get' | 'getAll' | 'getAllKeys' | 'getKey' | 'index' | 'openCursor' | 'openKeyCursor' | 'put' | 'indexNames'>;
|
|
357
378
|
export interface IDBPObjectStore<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, Mode extends IDBTransactionMode = 'readonly'> extends IDBPObjectStoreExtends {
|
|
358
379
|
/**
|
|
359
380
|
* The names of indexes in the store.
|
|
@@ -453,7 +474,7 @@ export interface IDBPObjectStore<DBTypes extends DBSchema | unknown = unknown, T
|
|
|
453
474
|
*/
|
|
454
475
|
iterate(query?: StoreKey<DBTypes, StoreName> | IDBKeyRange | null, direction?: IDBCursorDirection): AsyncIterableIterator<IDBPCursorWithValueIteratorValue<DBTypes, TxStores, StoreName, unknown, Mode>>;
|
|
455
476
|
}
|
|
456
|
-
|
|
477
|
+
type IDBPIndexExtends = Omit<IDBIndex, 'objectStore' | 'count' | 'get' | 'getAll' | 'getAllKeys' | 'getKey' | 'openCursor' | 'openKeyCursor'>;
|
|
457
478
|
export interface IDBPIndex<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> = IndexNames<DBTypes, StoreName>, Mode extends IDBTransactionMode = 'readonly'> extends IDBPIndexExtends {
|
|
458
479
|
/**
|
|
459
480
|
* The IDBObjectStore the index belongs to.
|
|
@@ -521,7 +542,7 @@ export interface IDBPIndex<DBTypes extends DBSchema | unknown = unknown, TxStore
|
|
|
521
542
|
*/
|
|
522
543
|
iterate(query?: IndexKey<DBTypes, StoreName, IndexName> | IDBKeyRange | null, direction?: IDBCursorDirection): AsyncIterableIterator<IDBPCursorWithValueIteratorValue<DBTypes, TxStores, StoreName, IndexName, Mode>>;
|
|
523
544
|
}
|
|
524
|
-
|
|
545
|
+
type IDBPCursorExtends = Omit<IDBCursor, 'key' | 'primaryKey' | 'source' | 'advance' | 'continue' | 'continuePrimaryKey' | 'delete' | 'update'>;
|
|
525
546
|
export interface IDBPCursor<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown = unknown, Mode extends IDBTransactionMode = 'readonly'> extends IDBPCursorExtends {
|
|
526
547
|
/**
|
|
527
548
|
* The key of the current index or object store item.
|
|
@@ -573,7 +594,7 @@ export interface IDBPCursor<DBTypes extends DBSchema | unknown = unknown, TxStor
|
|
|
573
594
|
*/
|
|
574
595
|
[Symbol.asyncIterator](): AsyncIterableIterator<IDBPCursorIteratorValue<DBTypes, TxStores, StoreName, IndexName, Mode>>;
|
|
575
596
|
}
|
|
576
|
-
|
|
597
|
+
type IDBPCursorIteratorValueExtends<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown = unknown, Mode extends IDBTransactionMode = 'readonly'> = Omit<IDBPCursor<DBTypes, TxStores, StoreName, IndexName, Mode>, 'advance' | 'continue' | 'continuePrimaryKey'>;
|
|
577
598
|
export interface IDBPCursorIteratorValue<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown = unknown, Mode extends IDBTransactionMode = 'readonly'> extends IDBPCursorIteratorValueExtends<DBTypes, TxStores, StoreName, IndexName, Mode> {
|
|
578
599
|
/**
|
|
579
600
|
* Advances the cursor a given number of records.
|
|
@@ -605,7 +626,7 @@ export interface IDBPCursorWithValue<DBTypes extends DBSchema | unknown = unknow
|
|
|
605
626
|
*/
|
|
606
627
|
[Symbol.asyncIterator](): AsyncIterableIterator<IDBPCursorWithValueIteratorValue<DBTypes, TxStores, StoreName, IndexName, Mode>>;
|
|
607
628
|
}
|
|
608
|
-
|
|
629
|
+
type IDBPCursorWithValueIteratorValueExtends<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown = unknown, Mode extends IDBTransactionMode = 'readonly'> = Omit<IDBPCursorWithValue<DBTypes, TxStores, StoreName, IndexName, Mode>, 'advance' | 'continue' | 'continuePrimaryKey'>;
|
|
609
630
|
export interface IDBPCursorWithValueIteratorValue<DBTypes extends DBSchema | unknown = unknown, TxStores extends ArrayLike<StoreNames<DBTypes>> = ArrayLike<StoreNames<DBTypes>>, StoreName extends StoreNames<DBTypes> = StoreNames<DBTypes>, IndexName extends IndexNames<DBTypes, StoreName> | unknown = unknown, Mode extends IDBTransactionMode = 'readonly'> extends IDBPCursorWithValueIteratorValueExtends<DBTypes, TxStores, StoreName, IndexName, Mode> {
|
|
610
631
|
/**
|
|
611
632
|
* Advances the cursor a given number of records.
|
package/build/index.cjs
CHANGED
|
@@ -1,8 +1,163 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
let idbProxyableTypes;
|
|
6
|
+
let cursorAdvanceMethods;
|
|
7
|
+
// This is a function to prevent it throwing up in node environments.
|
|
8
|
+
function getIdbProxyableTypes() {
|
|
9
|
+
return (idbProxyableTypes ||
|
|
10
|
+
(idbProxyableTypes = [
|
|
11
|
+
IDBDatabase,
|
|
12
|
+
IDBObjectStore,
|
|
13
|
+
IDBIndex,
|
|
14
|
+
IDBCursor,
|
|
15
|
+
IDBTransaction,
|
|
16
|
+
]));
|
|
17
|
+
}
|
|
18
|
+
// This is a function to prevent it throwing up in node environments.
|
|
19
|
+
function getCursorAdvanceMethods() {
|
|
20
|
+
return (cursorAdvanceMethods ||
|
|
21
|
+
(cursorAdvanceMethods = [
|
|
22
|
+
IDBCursor.prototype.advance,
|
|
23
|
+
IDBCursor.prototype.continue,
|
|
24
|
+
IDBCursor.prototype.continuePrimaryKey,
|
|
25
|
+
]));
|
|
26
|
+
}
|
|
27
|
+
const transactionDoneMap = new WeakMap();
|
|
28
|
+
const transformCache = new WeakMap();
|
|
29
|
+
const reverseTransformCache = new WeakMap();
|
|
30
|
+
function promisifyRequest(request) {
|
|
31
|
+
const promise = new Promise((resolve, reject) => {
|
|
32
|
+
const unlisten = () => {
|
|
33
|
+
request.removeEventListener('success', success);
|
|
34
|
+
request.removeEventListener('error', error);
|
|
35
|
+
};
|
|
36
|
+
const success = () => {
|
|
37
|
+
resolve(wrap(request.result));
|
|
38
|
+
unlisten();
|
|
39
|
+
};
|
|
40
|
+
const error = () => {
|
|
41
|
+
reject(request.error);
|
|
42
|
+
unlisten();
|
|
43
|
+
};
|
|
44
|
+
request.addEventListener('success', success);
|
|
45
|
+
request.addEventListener('error', error);
|
|
46
|
+
});
|
|
47
|
+
// This mapping exists in reverseTransformCache but doesn't exist in transformCache. This
|
|
48
|
+
// is because we create many promises from a single IDBRequest.
|
|
49
|
+
reverseTransformCache.set(promise, request);
|
|
50
|
+
return promise;
|
|
51
|
+
}
|
|
52
|
+
function cacheDonePromiseForTransaction(tx) {
|
|
53
|
+
// Early bail if we've already created a done promise for this transaction.
|
|
54
|
+
if (transactionDoneMap.has(tx))
|
|
55
|
+
return;
|
|
56
|
+
const done = new Promise((resolve, reject) => {
|
|
57
|
+
const unlisten = () => {
|
|
58
|
+
tx.removeEventListener('complete', complete);
|
|
59
|
+
tx.removeEventListener('error', error);
|
|
60
|
+
tx.removeEventListener('abort', error);
|
|
61
|
+
};
|
|
62
|
+
const complete = () => {
|
|
63
|
+
resolve();
|
|
64
|
+
unlisten();
|
|
65
|
+
};
|
|
66
|
+
const error = () => {
|
|
67
|
+
reject(tx.error || new DOMException('AbortError', 'AbortError'));
|
|
68
|
+
unlisten();
|
|
69
|
+
};
|
|
70
|
+
tx.addEventListener('complete', complete);
|
|
71
|
+
tx.addEventListener('error', error);
|
|
72
|
+
tx.addEventListener('abort', error);
|
|
73
|
+
});
|
|
74
|
+
// Cache it for later retrieval.
|
|
75
|
+
transactionDoneMap.set(tx, done);
|
|
76
|
+
}
|
|
77
|
+
let idbProxyTraps = {
|
|
78
|
+
get(target, prop, receiver) {
|
|
79
|
+
if (target instanceof IDBTransaction) {
|
|
80
|
+
// Special handling for transaction.done.
|
|
81
|
+
if (prop === 'done')
|
|
82
|
+
return transactionDoneMap.get(target);
|
|
83
|
+
// Make tx.store return the only store in the transaction, or undefined if there are many.
|
|
84
|
+
if (prop === 'store') {
|
|
85
|
+
return receiver.objectStoreNames[1]
|
|
86
|
+
? undefined
|
|
87
|
+
: receiver.objectStore(receiver.objectStoreNames[0]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Else transform whatever we get back.
|
|
91
|
+
return wrap(target[prop]);
|
|
92
|
+
},
|
|
93
|
+
set(target, prop, value) {
|
|
94
|
+
target[prop] = value;
|
|
95
|
+
return true;
|
|
96
|
+
},
|
|
97
|
+
has(target, prop) {
|
|
98
|
+
if (target instanceof IDBTransaction &&
|
|
99
|
+
(prop === 'done' || prop === 'store')) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
return prop in target;
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
function replaceTraps(callback) {
|
|
106
|
+
idbProxyTraps = callback(idbProxyTraps);
|
|
107
|
+
}
|
|
108
|
+
function wrapFunction(func) {
|
|
109
|
+
// Due to expected object equality (which is enforced by the caching in `wrap`), we
|
|
110
|
+
// only create one new func per func.
|
|
111
|
+
// Cursor methods are special, as the behaviour is a little more different to standard IDB. In
|
|
112
|
+
// IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the
|
|
113
|
+
// cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense
|
|
114
|
+
// with real promises, so each advance methods returns a new promise for the cursor object, or
|
|
115
|
+
// undefined if the end of the cursor has been reached.
|
|
116
|
+
if (getCursorAdvanceMethods().includes(func)) {
|
|
117
|
+
return function (...args) {
|
|
118
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
119
|
+
// the original object.
|
|
120
|
+
func.apply(unwrap(this), args);
|
|
121
|
+
return wrap(this.request);
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return function (...args) {
|
|
125
|
+
// Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use
|
|
126
|
+
// the original object.
|
|
127
|
+
return wrap(func.apply(unwrap(this), args));
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function transformCachableValue(value) {
|
|
131
|
+
if (typeof value === 'function')
|
|
132
|
+
return wrapFunction(value);
|
|
133
|
+
// This doesn't return, it just creates a 'done' promise for the transaction,
|
|
134
|
+
// which is later returned for transaction.done (see idbObjectHandler).
|
|
135
|
+
if (value instanceof IDBTransaction)
|
|
136
|
+
cacheDonePromiseForTransaction(value);
|
|
137
|
+
if (instanceOfAny(value, getIdbProxyableTypes()))
|
|
138
|
+
return new Proxy(value, idbProxyTraps);
|
|
139
|
+
// Return the same value back if we're not going to transform it.
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
function wrap(value) {
|
|
143
|
+
// We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because
|
|
144
|
+
// IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.
|
|
145
|
+
if (value instanceof IDBRequest)
|
|
146
|
+
return promisifyRequest(value);
|
|
147
|
+
// If we've already transformed this value before, reuse the transformed value.
|
|
148
|
+
// This is faster, but it also provides object equality.
|
|
149
|
+
if (transformCache.has(value))
|
|
150
|
+
return transformCache.get(value);
|
|
151
|
+
const newValue = transformCachableValue(value);
|
|
152
|
+
// Not all types are transformed.
|
|
153
|
+
// These may be primitive types, so they can't be WeakMap keys.
|
|
154
|
+
if (newValue !== value) {
|
|
155
|
+
transformCache.set(value, newValue);
|
|
156
|
+
reverseTransformCache.set(newValue, value);
|
|
157
|
+
}
|
|
158
|
+
return newValue;
|
|
159
|
+
}
|
|
160
|
+
const unwrap = (value) => reverseTransformCache.get(value);
|
|
6
161
|
|
|
7
162
|
/**
|
|
8
163
|
* Open a database.
|
|
@@ -13,20 +168,24 @@ var wrapIdbValue = require('./wrap-idb-value.cjs');
|
|
|
13
168
|
*/
|
|
14
169
|
function openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {
|
|
15
170
|
const request = indexedDB.open(name, version);
|
|
16
|
-
const openPromise =
|
|
171
|
+
const openPromise = wrap(request);
|
|
17
172
|
if (upgrade) {
|
|
18
173
|
request.addEventListener('upgradeneeded', (event) => {
|
|
19
|
-
upgrade(
|
|
174
|
+
upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);
|
|
20
175
|
});
|
|
21
176
|
}
|
|
22
|
-
if (blocked)
|
|
23
|
-
request.addEventListener('blocked', () => blocked(
|
|
177
|
+
if (blocked) {
|
|
178
|
+
request.addEventListener('blocked', (event) => blocked(
|
|
179
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
180
|
+
event.oldVersion, event.newVersion, event));
|
|
181
|
+
}
|
|
24
182
|
openPromise
|
|
25
183
|
.then((db) => {
|
|
26
184
|
if (terminated)
|
|
27
185
|
db.addEventListener('close', () => terminated());
|
|
28
|
-
if (blocking)
|
|
29
|
-
db.addEventListener('versionchange', () => blocking());
|
|
186
|
+
if (blocking) {
|
|
187
|
+
db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));
|
|
188
|
+
}
|
|
30
189
|
})
|
|
31
190
|
.catch(() => { });
|
|
32
191
|
return openPromise;
|
|
@@ -38,9 +197,12 @@ function openDB(name, version, { blocked, upgrade, blocking, terminated } = {})
|
|
|
38
197
|
*/
|
|
39
198
|
function deleteDB(name, { blocked } = {}) {
|
|
40
199
|
const request = indexedDB.deleteDatabase(name);
|
|
41
|
-
if (blocked)
|
|
42
|
-
request.addEventListener('blocked', () => blocked(
|
|
43
|
-
|
|
200
|
+
if (blocked) {
|
|
201
|
+
request.addEventListener('blocked', (event) => blocked(
|
|
202
|
+
// Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405
|
|
203
|
+
event.oldVersion, event));
|
|
204
|
+
}
|
|
205
|
+
return wrap(request).then(() => undefined);
|
|
44
206
|
}
|
|
45
207
|
|
|
46
208
|
const readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];
|
|
@@ -82,13 +244,67 @@ function getMethod(target, prop) {
|
|
|
82
244
|
cachedMethods.set(prop, method);
|
|
83
245
|
return method;
|
|
84
246
|
}
|
|
85
|
-
|
|
247
|
+
replaceTraps((oldTraps) => ({
|
|
86
248
|
...oldTraps,
|
|
87
249
|
get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),
|
|
88
250
|
has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),
|
|
89
251
|
}));
|
|
90
252
|
|
|
91
|
-
|
|
92
|
-
|
|
253
|
+
const advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];
|
|
254
|
+
const methodMap = {};
|
|
255
|
+
const advanceResults = new WeakMap();
|
|
256
|
+
const ittrProxiedCursorToOriginalProxy = new WeakMap();
|
|
257
|
+
const cursorIteratorTraps = {
|
|
258
|
+
get(target, prop) {
|
|
259
|
+
if (!advanceMethodProps.includes(prop))
|
|
260
|
+
return target[prop];
|
|
261
|
+
let cachedFunc = methodMap[prop];
|
|
262
|
+
if (!cachedFunc) {
|
|
263
|
+
cachedFunc = methodMap[prop] = function (...args) {
|
|
264
|
+
advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
return cachedFunc;
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
async function* iterate(...args) {
|
|
271
|
+
// tslint:disable-next-line:no-this-assignment
|
|
272
|
+
let cursor = this;
|
|
273
|
+
if (!(cursor instanceof IDBCursor)) {
|
|
274
|
+
cursor = await cursor.openCursor(...args);
|
|
275
|
+
}
|
|
276
|
+
if (!cursor)
|
|
277
|
+
return;
|
|
278
|
+
cursor = cursor;
|
|
279
|
+
const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);
|
|
280
|
+
ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);
|
|
281
|
+
// Map this double-proxy back to the original, so other cursor methods work.
|
|
282
|
+
reverseTransformCache.set(proxiedCursor, unwrap(cursor));
|
|
283
|
+
while (cursor) {
|
|
284
|
+
yield proxiedCursor;
|
|
285
|
+
// If one of the advancing methods was not called, call continue().
|
|
286
|
+
cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());
|
|
287
|
+
advanceResults.delete(proxiedCursor);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function isIteratorProp(target, prop) {
|
|
291
|
+
return ((prop === Symbol.asyncIterator &&
|
|
292
|
+
instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||
|
|
293
|
+
(prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));
|
|
294
|
+
}
|
|
295
|
+
replaceTraps((oldTraps) => ({
|
|
296
|
+
...oldTraps,
|
|
297
|
+
get(target, prop, receiver) {
|
|
298
|
+
if (isIteratorProp(target, prop))
|
|
299
|
+
return iterate;
|
|
300
|
+
return oldTraps.get(target, prop, receiver);
|
|
301
|
+
},
|
|
302
|
+
has(target, prop) {
|
|
303
|
+
return isIteratorProp(target, prop) || oldTraps.has(target, prop);
|
|
304
|
+
},
|
|
305
|
+
}));
|
|
306
|
+
|
|
93
307
|
exports.deleteDB = deleteDB;
|
|
94
308
|
exports.openDB = openDB;
|
|
309
|
+
exports.unwrap = unwrap;
|
|
310
|
+
exports.wrap = wrap;
|
package/build/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export * from './entry';
|
|
2
|
-
import './database-extras';
|
|
1
|
+
export * from './entry.js';
|
|
2
|
+
import './database-extras.js';
|
|
3
|
+
import './async-iterators.js';
|