tiny-idb 1.4.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 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. `store` defaults to `db` name. |
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. |
@@ -82,121 +68,148 @@ npm install tiny-idb
82
68
  | `push(key, value)` | **Atomically** appends to an array. |
83
69
  | `merge(key, patch)` | **Atomically** shallow-merges an object. |
84
70
 
85
- ## Example Use Cases
71
+ ## Examples (Easy to Advanced)
86
72
 
87
- ### Direct IndexedDB Access (Cursors & Search)
88
- For large datasets where loading everything via `entries()` is inefficient, use `raw()` to perform cursor-based searches or filtered queries.
73
+ ### 1. localStorage Compatibility
74
+ Use `tiny-idb` as a drop-in replacement for `localStorage`. Just add `await`.
89
75
  ```javascript
90
- const fruits = await tinyIDB.raw(store => {
91
- return new Promise((resolve) => {
92
- const matches = [];
93
- const request = store.openCursor();
94
- request.onsuccess = () => {
95
- const cursor = request.result;
96
- if (cursor) {
97
- if (cursor.value.type === 'fruit') matches.push(cursor.value);
98
- cursor.continue();
99
- } else resolve(matches);
100
- };
101
- });
102
- });
76
+ import { tinyIDB as db } from 'tiny-idb';
77
+
78
+ await db.setItem('session_id', 'xyz-123');
79
+ const sid = await db.getItem('session_id');
80
+ await db.removeItem('session_id');
103
81
  ```
104
82
 
105
- ### Iterating over Data
106
- Use `entries()` to easily process all stored key-value pairs.
83
+ ### 2. Simple Custom Database
84
+ If you only need one store per database, you can omit the `storeName`.
107
85
  ```javascript
108
- const allEntries = await tinyIDB.entries();
86
+ import { tinyIDB as db } from 'tiny-idb';
109
87
 
110
- for (const [key, value] of allEntries) {
111
- console.log(`${key}:`, value);
112
- }
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);
113
102
  ```
114
103
 
115
- ### User Settings Management
104
+ ### 4. User Settings Management (Atomic Merge)
116
105
  Easily manage and update partial user preferences without worrying about race conditions.
117
106
  ```javascript
118
- import { tinyIDB } from 'tiny-idb';
107
+ import { tinyIDB as db } from 'tiny-idb';
119
108
 
120
109
  // Initial setup
121
- await tinyIDB.set('settings', { theme: 'dark', notifications: true });
110
+ await db.set('settings', { theme: 'dark', notifications: true });
122
111
 
123
112
  // Later, merge new settings
124
- await tinyIDB.merge('settings', { notifications: false, language: 'en' });
113
+ await db.merge('settings', { notifications: false, language: 'en' });
125
114
 
126
115
  // Result: { theme: 'dark', notifications: false, language: 'en' }
127
116
  ```
128
117
 
129
- ### Storing Binary Data (Blobs/Files)
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)
130
128
  Unlike `localStorage`, `tiny-idb` can store binary data directly.
131
129
  ```javascript
130
+ import { tinyIDB as db } from 'tiny-idb';
131
+
132
132
  const response = await fetch('/profile-picture.jpg');
133
133
  const blob = await response.blob();
134
134
 
135
- await tinyIDB.set('user_avatar', blob);
135
+ await db.set('user_avatar', blob);
136
136
 
137
- // Later...
138
- const avatar = await tinyIDB.get('user_avatar');
137
+ const avatar = await db.get('user_avatar');
139
138
  document.querySelector('img').src = URL.createObjectURL(avatar);
140
139
  ```
141
140
 
142
- ### Persistent Shopping Cart
143
- Atomically add items to a list, ensuring no items are lost during concurrent updates.
141
+ ### 7. Iterating over Data
142
+ Use `entries()` to process all stored key-value pairs efficiently.
144
143
  ```javascript
145
- // Add items from different parts of the UI
146
- await tinyIDB.push('cart', { id: 101, qty: 1 });
147
- await tinyIDB.push('cart', { id: 202, qty: 2 });
144
+ import { tinyIDB as db } from 'tiny-idb';
148
145
 
149
- const cart = await tinyIDB.get('cart');
150
- console.log(`Items in cart: ${cart.length}`);
146
+ const allEntries = await db.entries();
147
+ for (const [key, value] of allEntries) {
148
+ console.log(`${key}:`, value);
149
+ }
151
150
  ```
152
151
 
153
- ### Atomic Counters
154
- Safely increment values using the `update` method.
152
+ ### 8. Multi-Instance Support
153
+ Use `open` to create isolated storage instances.
155
154
  ```javascript
156
- await tinyIDB.set('page_views', 0);
155
+ import { tinyIDB as db } from 'tiny-idb';
157
156
 
158
- // Increment safely - even if multiple tabs do it at once
159
- await tinyIDB.update('page_views', count => (count || 0) + 1);
160
- ```
157
+ const settings = db.open('app-db', 'settings');
158
+ const cache = db.open('app-db', 'cache');
161
159
 
162
- ### localStorage Compatibility
163
- `tiny-idb` provides aliases for `get`, `set`, and `remove` to match the `localStorage` API.
164
- ```javascript
165
- await tinyIDB.setItem('session_id', 'xyz-123');
166
- const sid = await tinyIDB.getItem('session_id');
167
- await tinyIDB.removeItem('session_id');
160
+ await settings.set('theme', 'dark');
161
+ await cache.set('temp_data', { id: 1 });
168
162
  ```
169
163
 
170
- ### Simple Custom Database
171
- If you only need one store per database, you can omit the `storeName`. It will automatically default to the same name as the database.
164
+ ### 9. Advanced: Direct IndexedDB Access (Cursors & Search)
165
+ Use `raw()` for custom searches or when working with extremely large datasets.
172
166
  ```javascript
173
- // Creates/retrieves a DB named 'my-store' with an internal store also named 'my-store'
174
- const store = tinyIDB.open('my-store');
167
+ import { tinyIDB as db } from 'tiny-idb';
175
168
 
176
- await store.set('key', 'value');
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
+ });
177
182
  ```
178
183
 
179
- ### Multi-Instance Support
180
- Use `open` to create isolated storage instances. Instances are cached internally.
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.
181
186
  ```javascript
182
- import { tinyIDB } from 'tiny-idb';
187
+ import { tinyIDB as db } from 'tiny-idb';
183
188
 
184
- // Create isolated storage instances
185
- const settings = tinyIDB.open('app-db', 'settings');
186
- const cache = tinyIDB.open('app-db', 'cache');
187
-
188
- await settings.set('theme', 'dark');
189
- await cache.set('temp_data', { id: 1 });
189
+ // Disable batching for a specific instance
190
+ const debugDB = db.open('debug-db', false);
190
191
  ```
191
192
 
192
- ## Browser Support
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
+ > ```
193
205
 
194
- `tiny-idb` targets modern browsers that support:
195
- - [IndexedDB](https://caniuse.com/indexeddb) (98%+)
196
- - [ES Modules](https://caniuse.com/es6-module)
197
- - [Async/Await](https://caniuse.com/async-functions)
206
+ ## Browser Support
198
207
 
199
- If you need to support legacy browsers (IE11), you will need to transpile and polyfill.
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+
200
213
 
201
214
  ## Development
202
215
 
@@ -207,13 +220,7 @@ If you need to support legacy browsers (IE11), you will need to transpile and po
207
220
  npm test
208
221
  ```
209
222
 
210
- ### Running Tests on Minified Build
211
- ```bash
212
- npm run test:min
213
- ```
214
-
215
223
  ### Building & Minification
216
- Generate the production-ready minified file:
217
224
  ```bash
218
225
  npm run build
219
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.
@@ -55,7 +60,7 @@ export interface TinyIDBInstance {
55
60
  count(): Promise<number>;
56
61
 
57
62
  /**
58
- * Direct access to the IDBObjectStore within a transaction.
63
+ * Provides direct access to the IDBObjectStore within a transaction.
59
64
  * This provides an "escape hatch" to use native IndexedDB features like cursors, ranges, and search.
60
65
  * @param cb A callback that receives the IDBObjectStore.
61
66
  * @param mode The transaction mode ('readonly' or 'readwrite').
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "tiny-idb",
3
- "version": "1.4.0",
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,52 +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', storeName = undefined) => {
11
- storeName = storeName || dbName;
12
- const key = dbName + '\0' + storeName;
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(storeName);
31
+ req.onupgradeneeded = () => req.result.createObjectStore(s);
20
32
  req.onsuccess = () => {
21
- const db = req.result;
22
- db.onversionchange = () => { db.close(); dbPromise = null; };
23
- resolve(db);
33
+ const d = req.result;
34
+ d.onversionchange = () => { d.close(); dbPromise = 0; };
35
+ resolve(d);
24
36
  };
25
- req.onerror = () => { dbPromise = null; reject(req.error); };
37
+ req.onerror = () => { dbPromise = 0; reject(req.error); };
26
38
  })));
27
- return new Promise(async (resolve, reject) => {
28
- const t = db.transaction(storeName, mode);
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 update = (key, fn) => tx(RW, async s => prom(s.put(await fn(await prom(s.get(key))), key)));
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) => tx(RW, s => prom(s.put(value, key))),
45
- get: key => tx(RO, s => prom(s.get(key))),
46
- remove: key => tx(RW, s => prom(s.delete(key))),
47
- clear: () => tx(RW, s => prom(s.clear())),
48
- keys: () => tx(RO, s => prom(s.getAllKeys())),
49
- values: () => tx(RO, s => prom(s.getAll())),
50
- entries: () => tx(RO, async s => {
51
- const [k, v] = await Promise.all([prom(s.getAllKeys()), prom(s.getAll())]);
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: () => tx(RO, s => prom(s.count())),
55
- raw: (cb, mode = RO) => tx(mode, cb),
66
+ count: () => op(RO, store => prom(store.count())),
67
+ raw: (cb, mode = RO) => op(mode, cb),
56
68
  update,
57
69
  push: (key, val) => update(key, (c = []) => [...(Array.isArray(c) ? c : []), val]),
58
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=void 0)=>{const c=s+"\0"+(a=a||s);if(e.has(c))return e.get(c);let l;const i=async(e,t)=>{const r=await(l||(l=new Promise((e,t)=>{const r=indexedDB.open(s,1);r.onupgradeneeded=()=>r.result.createObjectStore(a),r.onsuccess=()=>{const t=r.result;t.onversionchange=()=>{t.close(),l=null},e(t)},r.onerror=()=>{l=null,t(r.error)}})));return new Promise(async(o,n)=>{const s=r.transaction(a,e);s.onabort=s.onerror=()=>n(s.error||new DOMException("Aborted"));try{const e=await t(s.objectStore(a));s.oncomplete=()=>o(e)}catch(e){try{s.abort()}catch{}n(e)}})},u=(e,r)=>i(o,async o=>t(o.put(await r(await t(o.get(e))),e))),y={open:n,set:(e,r)=>i(o,o=>t(o.put(r,e))),get:e=>i(r,r=>t(r.get(e))),remove:e=>i(o,r=>t(r.delete(e))),clear:()=>i(o,e=>t(e.clear())),keys:()=>i(r,e=>t(e.getAllKeys())),values:()=>i(r,e=>t(e.getAll())),entries:()=>i(r,async e=>{const[r,o]=await Promise.all([t(e.getAllKeys()),t(e.getAll())]);return r.map((e,t)=>[e,o[t]])}),count:()=>i(r,e=>t(e.count())),raw:(e,t=r)=>i(t,e),update:u,push:(e,t)=>u(e,(e=[])=>[...Array.isArray(e)?e:[],t]),merge:(e,t)=>u(e,(e={})=>({...e&&"object"==typeof e?e:{},...t}))};return["get","set","remove"].forEach(e=>y[e+"Item"]=y[e]),e.set(c,y),y};export const tinyIDB=n();export default tinyIDB;
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;