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 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. |
@@ -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
- ## Example Use Cases
71
+ ## Examples (Easy to Advanced)
85
72
 
86
- ### Iterating over Data
87
- Use `entries()` to easily process all stored key-value pairs.
73
+ ### 1. localStorage Compatibility
74
+ Use `tiny-idb` as a drop-in replacement for `localStorage`. Just add `await`.
88
75
  ```javascript
89
- const allEntries = await tinyIDB.entries();
76
+ import { tinyIDB as db } from 'tiny-idb';
90
77
 
91
- for (const [key, value] of allEntries) {
92
- console.log(`${key}:`, value);
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 tinyIDB.set('settings', { theme: 'dark', notifications: true });
110
+ await db.set('settings', { theme: 'dark', notifications: true });
103
111
 
104
112
  // Later, merge new settings
105
- await tinyIDB.merge('settings', { notifications: false, language: 'en' });
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
- ### 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)
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 tinyIDB.set('user_avatar', blob);
135
+ await db.set('user_avatar', blob);
117
136
 
118
- // Later...
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
- ### Persistent Shopping Cart
124
- 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.
125
143
  ```javascript
126
- // Add items from different parts of the UI
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 cart = await tinyIDB.get('cart');
131
- 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
+ }
132
150
  ```
133
151
 
134
- ### Atomic Counters
135
- Safely increment values using the `update` method.
152
+ ### 8. Multi-Instance Support
153
+ Use `open` to create isolated storage instances.
136
154
  ```javascript
137
- await tinyIDB.set('page_views', 0);
155
+ import { tinyIDB as db } from 'tiny-idb';
138
156
 
139
- // Increment safely - even if multiple tabs do it at once
140
- await tinyIDB.update('page_views', count => (count || 0) + 1);
141
- ```
157
+ const settings = db.open('app-db', 'settings');
158
+ const cache = db.open('app-db', 'cache');
142
159
 
143
- ### localStorage Compatibility
144
- `tiny-idb` provides aliases for `get`, `set`, and `remove` to match the `localStorage` API.
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
- ### Simple Custom Database
152
- 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.
153
166
  ```javascript
154
- // Creates/retrieves a DB named 'my-store' with an internal store also named 'my-store'
155
- const store = tinyIDB.open('my-store');
156
-
157
- await store.set('key', 'value');
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
- ### Multi-Instance Support
161
- 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.
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
- await settings.set('theme', 'dark');
170
- await cache.set('temp_data', { id: 1 });
189
+ // Disable batching for a specific instance
190
+ const debugDB = db.open('debug-db', false);
171
191
  ```
172
192
 
173
- ## 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
+ > ```
174
205
 
175
- `tiny-idb` targets modern browsers that support:
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
- 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+
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.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,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', 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())),
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=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())),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;