tiny-idb 1.3.0 → 1.5.0
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/README.md +106 -80
- package/index.d.ts +14 -1
- package/package.json +10 -1
- package/tiny-idb.js +41 -28
- package/tiny-idb.min.js +1 -1
package/README.md
CHANGED
|
@@ -27,15 +27,15 @@ Native IndexedDB requires managing requests, transactions, and version upgrades.
|
|
|
27
27
|
### Guaranteed Atomicity
|
|
28
28
|
The primary weakness of most storage wrappers is the "read-modify-write" race condition. If two parts of an application attempt to update the same key simultaneously, data loss often occurs. `tiny-idb` addresses this by executing `update`, `push`, and `merge` operations within a single IndexedDB transaction, ensuring that updates are processed sequentially and reliably.
|
|
29
29
|
|
|
30
|
+
### Automatic Transaction Batching (Pipelining)
|
|
31
|
+
`tiny-idb` automatically batches multiple operations (`set`, `get`, `update`, etc.) called in the same microtask (event loop tick) into a **single IndexedDB transaction**. This provides a **10x to 100x performance boost** for concurrent operations (like `Promise.all`) without changing any code.
|
|
32
|
+
|
|
30
33
|
### Resource Efficiency
|
|
31
34
|
At **less than 1KB** (gzipped), the library introduces negligible overhead to your bundle. It is dependency-free and written in modern vanilla JavaScript, ensuring high performance across all environments that support IndexedDB.
|
|
32
35
|
|
|
33
36
|
### Intelligent Lifecycle Management
|
|
34
37
|
The library handles database connection pooling, tab synchronization, and error recovery automatically. If a database connection is blocked by another tab or fails due to an environmental error, `tiny-idb` gracefully resets and recovers without requiring a page reload.
|
|
35
38
|
|
|
36
|
-
### Zero-Configuration Portability
|
|
37
|
-
Beyond npm installation, `tiny-idb` is designed for maximum portability. As a single-file, dependency-free module, it can be integrated into any environment by simply dropping `tiny-idb.js` into a project directory. **No build step, compilation, or transpilation is required.** This makes it an ideal solution for rapid prototyping, legacy system upgrades, and environments where complex build pipelines are unavailable.
|
|
38
|
-
|
|
39
39
|
## Installation
|
|
40
40
|
|
|
41
41
|
```bash
|
|
@@ -46,29 +46,15 @@ npm install tiny-idb
|
|
|
46
46
|
|
|
47
47
|
```html
|
|
48
48
|
<script type="module">
|
|
49
|
-
import { tinyIDB } from 'https://unpkg.com/tiny-idb/tiny-idb.min.js';
|
|
49
|
+
import { tinyIDB as db } from 'https://unpkg.com/tiny-idb/tiny-idb.min.js';
|
|
50
50
|
</script>
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
* **Minified Module**: `https://unpkg.com/tiny-idb/tiny-idb.min.js` (less than 1KB gzipped)
|
|
54
|
-
* **Source**: `https://unpkg.com/tiny-idb/tiny-idb.js`
|
|
55
|
-
|
|
56
|
-
## Technical Comparison
|
|
57
|
-
|
|
58
|
-
| Feature | `localStorage` | `tiny-idb` |
|
|
59
|
-
|---------|--------------|----------|
|
|
60
|
-
| **Execution** | Synchronous (Blocks UI) | Asynchronous (Non-blocking) |
|
|
61
|
-
| **Storage Limit** | ~5-10MB (Fixed) | Virtually unlimited (80%+ of disk) |
|
|
62
|
-
| **Data Types** | Strings only (Requires `JSON.parse`) | Objects, Blobs, Arrays, Numbers, Files |
|
|
63
|
-
| **Data Integrity** | Basic | ACID Compliant |
|
|
64
|
-
| **Race Condition Safety** | None | Atomic `update`/`push`/`merge` |
|
|
65
|
-
| **Tab Sync** | No | Automatic |
|
|
66
|
-
|
|
67
53
|
## API Reference
|
|
68
54
|
|
|
69
55
|
| Method | Description |
|
|
70
56
|
|--------|-------------|
|
|
71
|
-
| `open(db, store?)` | Creates or retrieves a cached instance. `
|
|
57
|
+
| `open(db, store?, batch?)` | Creates or retrieves a cached instance. `batch` defaults to `true`. |
|
|
72
58
|
| `get(key)` | Retrieves a value; returns `undefined` if not found. |
|
|
73
59
|
| `set(key, value)` | Persists a value to the store. |
|
|
74
60
|
| `remove(key)` | Deletes a specific key. |
|
|
@@ -77,107 +63,153 @@ npm install tiny-idb
|
|
|
77
63
|
| `values()` | Returns an array of all values. |
|
|
78
64
|
| `entries()` | Returns an array of `[key, value]` pairs. |
|
|
79
65
|
| `count()` | Returns the total number of entries. |
|
|
66
|
+
| `raw(cb, mode?)` | Provides direct access to the `IDBObjectStore`. |
|
|
80
67
|
| `update(key, fn)` | Performs an **atomic** read-modify-write. |
|
|
81
68
|
| `push(key, value)` | **Atomically** appends to an array. |
|
|
82
69
|
| `merge(key, patch)` | **Atomically** shallow-merges an object. |
|
|
83
70
|
|
|
84
|
-
##
|
|
71
|
+
## Examples (Easy to Advanced)
|
|
85
72
|
|
|
86
|
-
###
|
|
87
|
-
Use `
|
|
73
|
+
### 1. localStorage Compatibility
|
|
74
|
+
Use `tiny-idb` as a drop-in replacement for `localStorage`. Just add `await`.
|
|
88
75
|
```javascript
|
|
89
|
-
|
|
76
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
await db.setItem('session_id', 'xyz-123');
|
|
79
|
+
const sid = await db.getItem('session_id');
|
|
80
|
+
await db.removeItem('session_id');
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Simple Custom Database
|
|
84
|
+
If you only need one store per database, you can omit the `storeName`.
|
|
85
|
+
```javascript
|
|
86
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
87
|
+
|
|
88
|
+
// Creates/retrieves a DB named 'my-store' with an internal store also named 'my-store'
|
|
89
|
+
const store = db.open('my-store');
|
|
90
|
+
await store.set('key', 'value');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. Atomic Counters
|
|
94
|
+
Safely increment values using the `update` method.
|
|
95
|
+
```javascript
|
|
96
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
97
|
+
|
|
98
|
+
await db.set('page_views', 0);
|
|
99
|
+
|
|
100
|
+
// Increment safely - even if multiple tabs do it at once
|
|
101
|
+
await db.update('page_views', count => (count || 0) + 1);
|
|
94
102
|
```
|
|
95
103
|
|
|
96
|
-
### User Settings Management
|
|
104
|
+
### 4. User Settings Management (Atomic Merge)
|
|
97
105
|
Easily manage and update partial user preferences without worrying about race conditions.
|
|
98
106
|
```javascript
|
|
99
|
-
import { tinyIDB } from 'tiny-idb';
|
|
107
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
100
108
|
|
|
101
109
|
// Initial setup
|
|
102
|
-
await
|
|
110
|
+
await db.set('settings', { theme: 'dark', notifications: true });
|
|
103
111
|
|
|
104
112
|
// Later, merge new settings
|
|
105
|
-
await
|
|
113
|
+
await db.merge('settings', { notifications: false, language: 'en' });
|
|
106
114
|
|
|
107
115
|
// Result: { theme: 'dark', notifications: false, language: 'en' }
|
|
108
116
|
```
|
|
109
117
|
|
|
110
|
-
###
|
|
118
|
+
### 5. Persistent Shopping Cart (Atomic Push)
|
|
119
|
+
Atomically add items to a list, ensuring no items are lost during concurrent updates.
|
|
120
|
+
```javascript
|
|
121
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
122
|
+
|
|
123
|
+
await db.push('cart', { id: 101, qty: 1 });
|
|
124
|
+
await db.push('cart', { id: 202, qty: 2 });
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 6. Storing Binary Data (Blobs/Files)
|
|
111
128
|
Unlike `localStorage`, `tiny-idb` can store binary data directly.
|
|
112
129
|
```javascript
|
|
130
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
131
|
+
|
|
113
132
|
const response = await fetch('/profile-picture.jpg');
|
|
114
133
|
const blob = await response.blob();
|
|
115
134
|
|
|
116
|
-
await
|
|
135
|
+
await db.set('user_avatar', blob);
|
|
117
136
|
|
|
118
|
-
|
|
119
|
-
const avatar = await tinyIDB.get('user_avatar');
|
|
137
|
+
const avatar = await db.get('user_avatar');
|
|
120
138
|
document.querySelector('img').src = URL.createObjectURL(avatar);
|
|
121
139
|
```
|
|
122
140
|
|
|
123
|
-
###
|
|
124
|
-
|
|
141
|
+
### 7. Iterating over Data
|
|
142
|
+
Use `entries()` to process all stored key-value pairs efficiently.
|
|
125
143
|
```javascript
|
|
126
|
-
|
|
127
|
-
await tinyIDB.push('cart', { id: 101, qty: 1 });
|
|
128
|
-
await tinyIDB.push('cart', { id: 202, qty: 2 });
|
|
144
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
129
145
|
|
|
130
|
-
const
|
|
131
|
-
|
|
146
|
+
const allEntries = await db.entries();
|
|
147
|
+
for (const [key, value] of allEntries) {
|
|
148
|
+
console.log(`${key}:`, value);
|
|
149
|
+
}
|
|
132
150
|
```
|
|
133
151
|
|
|
134
|
-
###
|
|
135
|
-
|
|
152
|
+
### 8. Multi-Instance Support
|
|
153
|
+
Use `open` to create isolated storage instances.
|
|
136
154
|
```javascript
|
|
137
|
-
|
|
155
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
138
156
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
```
|
|
157
|
+
const settings = db.open('app-db', 'settings');
|
|
158
|
+
const cache = db.open('app-db', 'cache');
|
|
142
159
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
```javascript
|
|
146
|
-
await tinyIDB.setItem('session_id', 'xyz-123');
|
|
147
|
-
const sid = await tinyIDB.getItem('session_id');
|
|
148
|
-
await tinyIDB.removeItem('session_id');
|
|
160
|
+
await settings.set('theme', 'dark');
|
|
161
|
+
await cache.set('temp_data', { id: 1 });
|
|
149
162
|
```
|
|
150
163
|
|
|
151
|
-
###
|
|
152
|
-
|
|
164
|
+
### 9. Advanced: Direct IndexedDB Access (Cursors & Search)
|
|
165
|
+
Use `raw()` for custom searches or when working with extremely large datasets.
|
|
153
166
|
```javascript
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
167
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
168
|
+
|
|
169
|
+
const results = await db.raw(store => {
|
|
170
|
+
return new Promise((resolve) => {
|
|
171
|
+
const matches = [];
|
|
172
|
+
const request = store.openCursor();
|
|
173
|
+
request.onsuccess = () => {
|
|
174
|
+
const cursor = request.result;
|
|
175
|
+
if (cursor) {
|
|
176
|
+
if (cursor.value.type === 'urgent') matches.push(cursor.value);
|
|
177
|
+
cursor.continue();
|
|
178
|
+
} else resolve(matches);
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
});
|
|
158
182
|
```
|
|
159
183
|
|
|
160
|
-
###
|
|
161
|
-
|
|
184
|
+
### 10. Advanced: Disabling Batching
|
|
185
|
+
If you need strict one-transaction-per-operation behavior (e.g., for debugging), you can disable the default batching.
|
|
162
186
|
```javascript
|
|
163
|
-
import { tinyIDB } from 'tiny-idb';
|
|
164
|
-
|
|
165
|
-
// Create isolated storage instances
|
|
166
|
-
const settings = tinyIDB.open('app-db', 'settings');
|
|
167
|
-
const cache = tinyIDB.open('app-db', 'cache');
|
|
187
|
+
import { tinyIDB as db } from 'tiny-idb';
|
|
168
188
|
|
|
169
|
-
|
|
170
|
-
|
|
189
|
+
// Disable batching for a specific instance
|
|
190
|
+
const debugDB = db.open('debug-db', false);
|
|
171
191
|
```
|
|
172
192
|
|
|
173
|
-
|
|
193
|
+
> **Optimization Note:** While `entries()` is sufficient for most apps, developers working with **extremely large datasets** (100k+ records) should use `raw()` with a cursor to minimize memory overhead.
|
|
194
|
+
> ```javascript
|
|
195
|
+
> // Memory-efficient search for a massive dataset
|
|
196
|
+
> const activeUser = await db.raw(store => new Promise(res => {
|
|
197
|
+
> const req = store.openCursor();
|
|
198
|
+
> req.onsuccess = () => {
|
|
199
|
+
> const cursor = req.result;
|
|
200
|
+
> if (!cursor || cursor.value.status === 'active') res(cursor?.value);
|
|
201
|
+
> else cursor.continue();
|
|
202
|
+
> };
|
|
203
|
+
> }));
|
|
204
|
+
> ```
|
|
174
205
|
|
|
175
|
-
|
|
176
|
-
- [IndexedDB](https://caniuse.com/indexeddb) (98%+)
|
|
177
|
-
- [ES Modules](https://caniuse.com/es6-module)
|
|
178
|
-
- [Async/Await](https://caniuse.com/async-functions)
|
|
206
|
+
## Browser Support
|
|
179
207
|
|
|
180
|
-
|
|
208
|
+
Supported by virtually all browsers in use today (99%+ market share). Since [May 2018](https://caniuse.com/es6-module), this feature works across the latest devices and major browser versions:
|
|
209
|
+
- **Chrome** 61+
|
|
210
|
+
- **Firefox** 60+
|
|
211
|
+
- **Safari** 11+
|
|
212
|
+
- **Edge** 16+
|
|
181
213
|
|
|
182
214
|
## Development
|
|
183
215
|
|
|
@@ -188,13 +220,7 @@ If you need to support legacy browsers (IE11), you will need to transpile and po
|
|
|
188
220
|
npm test
|
|
189
221
|
```
|
|
190
222
|
|
|
191
|
-
### Running Tests on Minified Build
|
|
192
|
-
```bash
|
|
193
|
-
npm run test:min
|
|
194
|
-
```
|
|
195
|
-
|
|
196
223
|
### Building & Minification
|
|
197
|
-
Generate the production-ready minified file:
|
|
198
224
|
```bash
|
|
199
225
|
npm run build
|
|
200
226
|
```
|
package/index.d.ts
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
export interface TinyIDBInstance {
|
|
4
4
|
/**
|
|
5
5
|
* Creates or retrieves a cached instance of a database and store.
|
|
6
|
+
* Note: Multiple calls in the same microtask (tick) are automatically batched
|
|
7
|
+
* into a single IndexedDB transaction for 10x-100x performance.
|
|
6
8
|
* @param dbName Name of the IndexedDB database.
|
|
7
9
|
* @param storeName Name of the object store (defaults to dbName).
|
|
10
|
+
* @param batching Set to false to disable automatic batching (defaults to true).
|
|
8
11
|
*/
|
|
9
|
-
open(dbName: string, storeName?: string): TinyIDBInstance;
|
|
12
|
+
open(dbName: string, storeName?: string, batching?: boolean): TinyIDBInstance;
|
|
13
|
+
/** Shorthand for open(dbName, dbName, batching) */
|
|
14
|
+
open(dbName: string, batching?: boolean): TinyIDBInstance;
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Persists a value to the store.
|
|
@@ -54,6 +59,14 @@ export interface TinyIDBInstance {
|
|
|
54
59
|
*/
|
|
55
60
|
count(): Promise<number>;
|
|
56
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Provides direct access to the IDBObjectStore within a transaction.
|
|
64
|
+
* This provides an "escape hatch" to use native IndexedDB features like cursors, ranges, and search.
|
|
65
|
+
* @param cb A callback that receives the IDBObjectStore.
|
|
66
|
+
* @param mode The transaction mode ('readonly' or 'readwrite').
|
|
67
|
+
*/
|
|
68
|
+
raw<T = any>(cb: (store: IDBObjectStore) => T | Promise<T>, mode?: IDBTransactionMode): Promise<T>;
|
|
69
|
+
|
|
57
70
|
/**
|
|
58
71
|
* Performs an atomic read-modify-write operation within a single transaction.
|
|
59
72
|
* Note: The function 'fn' must be synchronous or microtask-only (no await on fetch/setTimeout)
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-idb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "An extremely fast, super simple, and dependency-free IndexedDB wrapper. A drop-in replacement for localStorage with reliability and durability.",
|
|
5
5
|
"main": "tiny-idb.js",
|
|
6
6
|
"module": "tiny-idb.js",
|
|
7
|
+
"unpkg": "tiny-idb.min.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./tiny-idb.js",
|
|
10
|
+
"./min": "./tiny-idb.min.js"
|
|
11
|
+
},
|
|
7
12
|
"types": "index.d.ts",
|
|
8
13
|
"type": "module",
|
|
9
14
|
"repository": {
|
|
@@ -25,6 +30,10 @@
|
|
|
25
30
|
],
|
|
26
31
|
"author": "Jelodar",
|
|
27
32
|
"license": "MIT",
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16.0.0"
|
|
36
|
+
},
|
|
28
37
|
"bugs": {
|
|
29
38
|
"url": "https://github.com/Jelodar/tiny-idb/issues"
|
|
30
39
|
},
|
package/tiny-idb.js
CHANGED
|
@@ -7,51 +7,64 @@ const prom = (req) => new Promise((res, rej) => {
|
|
|
7
7
|
});
|
|
8
8
|
const RO = 'readonly', RW = 'readwrite';
|
|
9
9
|
|
|
10
|
-
const getAPI = (dbName = 'tiny-idb',
|
|
11
|
-
|
|
12
|
-
const key = dbName + '\0' +
|
|
10
|
+
const getAPI = (dbName = 'tiny-idb', s = dbName, b = true) => {
|
|
11
|
+
if (s === !!s) [b, s] = [s, dbName];
|
|
12
|
+
const key = dbName + '\0' + s + '\0' + b;
|
|
13
13
|
if (instances.has(key)) return instances.get(key);
|
|
14
14
|
|
|
15
|
-
let dbPromise;
|
|
15
|
+
let dbPromise, queue = [];
|
|
16
|
+
const flush = async () => {
|
|
17
|
+
const items = queue; queue = [];
|
|
18
|
+
try {
|
|
19
|
+
const mode = items.some(i => i.m === RW) ? RW : RO;
|
|
20
|
+
await tx(mode, async store => {
|
|
21
|
+
for (const {c, r} of items) r(await c(store));
|
|
22
|
+
});
|
|
23
|
+
} catch (e) {
|
|
24
|
+
items.forEach(i => i.j(e));
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
16
28
|
const tx = async (mode, cb) => {
|
|
17
29
|
const db = await (dbPromise || (dbPromise = new Promise((resolve, reject) => {
|
|
18
30
|
const req = indexedDB.open(dbName, 1);
|
|
19
|
-
req.onupgradeneeded = () => req.result.createObjectStore(
|
|
31
|
+
req.onupgradeneeded = () => req.result.createObjectStore(s);
|
|
20
32
|
req.onsuccess = () => {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
resolve(
|
|
33
|
+
const d = req.result;
|
|
34
|
+
d.onversionchange = () => { d.close(); dbPromise = 0; };
|
|
35
|
+
resolve(d);
|
|
24
36
|
};
|
|
25
|
-
req.onerror = () => { dbPromise =
|
|
37
|
+
req.onerror = () => { dbPromise = 0; reject(req.error); };
|
|
26
38
|
})));
|
|
27
|
-
return new Promise(
|
|
28
|
-
const t = db.transaction(
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const t = db.transaction(s, mode);
|
|
41
|
+
t.oncomplete = () => resolve();
|
|
29
42
|
t.onabort = t.onerror = () => reject(t.error || new DOMException('Aborted'));
|
|
30
|
-
try {
|
|
31
|
-
const res = await cb(t.objectStore(storeName));
|
|
32
|
-
t.oncomplete = () => resolve(res);
|
|
33
|
-
} catch (e) {
|
|
34
|
-
try { t.abort(); } catch {}
|
|
35
|
-
reject(e);
|
|
36
|
-
}
|
|
43
|
+
cb(t.objectStore(s)).catch(e => { try { t.abort(); } catch {} reject(e); });
|
|
37
44
|
});
|
|
38
45
|
};
|
|
39
46
|
|
|
40
|
-
const
|
|
47
|
+
const op = (m, c) => new Promise((r, j) => {
|
|
48
|
+
queue.push({ m, c, r, j });
|
|
49
|
+
if (queue.length < 2) b ? queueMicrotask(flush) : flush();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const update = (key, fn) => op(RW, async store => prom(store.put(await fn(await prom(store.get(key))), key)));
|
|
41
53
|
|
|
42
54
|
const api = {
|
|
43
55
|
open: getAPI,
|
|
44
|
-
set: (key, value) =>
|
|
45
|
-
get: key =>
|
|
46
|
-
remove: key =>
|
|
47
|
-
clear: () =>
|
|
48
|
-
keys: () =>
|
|
49
|
-
values: () =>
|
|
50
|
-
entries: () =>
|
|
51
|
-
const [k, v] = await Promise.all([prom(
|
|
56
|
+
set: (key, value) => op(RW, store => prom(store.put(value, key))),
|
|
57
|
+
get: key => op(RO, store => prom(store.get(key))),
|
|
58
|
+
remove: key => op(RW, store => prom(store.delete(key))),
|
|
59
|
+
clear: () => op(RW, store => prom(store.clear())),
|
|
60
|
+
keys: () => op(RO, store => prom(store.getAllKeys())),
|
|
61
|
+
values: () => op(RO, store => prom(store.getAll())),
|
|
62
|
+
entries: () => op(RO, async store => {
|
|
63
|
+
const [k, v] = await Promise.all([prom(store.getAllKeys()), prom(store.getAll())]);
|
|
52
64
|
return k.map((key, i) => [key, v[i]]);
|
|
53
65
|
}),
|
|
54
|
-
count: () =>
|
|
66
|
+
count: () => op(RO, store => prom(store.count())),
|
|
67
|
+
raw: (cb, mode = RO) => op(mode, cb),
|
|
55
68
|
update,
|
|
56
69
|
push: (key, val) => update(key, (c = []) => [...(Array.isArray(c) ? c : []), val]),
|
|
57
70
|
merge: (key, obj) => update(key, (c = {}) => ({ ...(c && typeof c === 'object' ? c : {}), ...obj }))
|
package/tiny-idb.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** tiny-idb - MIT © Jelodar */
|
|
2
|
-
const e=new Map,t=e=>new Promise((t,r)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>r(e.error)}),r="readonly",o="readwrite",n=(s="tiny-idb",a
|
|
2
|
+
const e=new Map,t=e=>new Promise((t,r)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>r(e.error)}),r="readonly",o="readwrite",n=(s="tiny-idb",c=s,a=!0)=>{c===!!c&&([a,c]=[c,s]);const i=s+"\0"+c+"\0"+a;if(e.has(i))return e.get(i);let l,u=[];const y=async()=>{const e=u;u=[];try{const t=e.some(e=>e.m===o)?o:r;await p(t,async t=>{for(const{c:r,r:o}of e)o(await r(t))})}catch(t){e.forEach(e=>e.j(t))}},p=async(e,t)=>{const r=await(l||(l=new Promise((e,t)=>{const r=indexedDB.open(s,1);r.onupgradeneeded=()=>r.result.createObjectStore(c),r.onsuccess=()=>{const t=r.result;t.onversionchange=()=>{t.close(),l=0},e(t)},r.onerror=()=>{l=0,t(r.error)}})));return new Promise((o,n)=>{const s=r.transaction(c,e);s.oncomplete=()=>o(),s.onabort=s.onerror=()=>n(s.error||new DOMException("Aborted")),t(s.objectStore(c)).catch(e=>{try{s.abort()}catch{}n(e)})})},m=(e,t)=>new Promise((r,o)=>{u.push({m:e,c:t,r:r,j:o}),u.length<2&&(a?queueMicrotask(y):y())}),w=(e,r)=>m(o,async o=>t(o.put(await r(await t(o.get(e))),e))),g={open:n,set:(e,r)=>m(o,o=>t(o.put(r,e))),get:e=>m(r,r=>t(r.get(e))),remove:e=>m(o,r=>t(r.delete(e))),clear:()=>m(o,e=>t(e.clear())),keys:()=>m(r,e=>t(e.getAllKeys())),values:()=>m(r,e=>t(e.getAll())),entries:()=>m(r,async e=>{const[r,o]=await Promise.all([t(e.getAllKeys()),t(e.getAll())]);return r.map((e,t)=>[e,o[t]])}),count:()=>m(r,e=>t(e.count())),raw:(e,t=r)=>m(t,e),update:w,push:(e,t)=>w(e,(e=[])=>[...Array.isArray(e)?e:[],t]),merge:(e,t)=>w(e,(e={})=>({...e&&"object"==typeof e?e:{},...t}))};return["get","set","remove"].forEach(e=>g[e+"Item"]=g[e]),e.set(i,g),g};export const tinyIDB=n();export default tinyIDB;
|