tiny-idb 1.0.0 → 1.1.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
@@ -17,7 +17,7 @@ Native IndexedDB requires managing requests, transactions, and version upgrades.
17
17
  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.
18
18
 
19
19
  ### Resource Efficiency
20
- At only **596 bytes** (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.
20
+ At only **611 bytes** (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.
21
21
 
22
22
  ### Intelligent Lifecycle Management
23
23
  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.
@@ -39,7 +39,7 @@ npm install tiny-idb
39
39
  </script>
40
40
  ```
41
41
 
42
- * **Minified Module**: `https://unpkg.com/tiny-idb/tiny-idb.min.js` (596 bytes gzipped)
42
+ * **Minified Module**: `https://unpkg.com/tiny-idb/tiny-idb.min.js` (598 bytes gzipped)
43
43
  * **Source**: `https://unpkg.com/tiny-idb/tiny-idb.js`
44
44
 
45
45
  ## Technical Comparison
@@ -65,7 +65,68 @@ npm install tiny-idb
65
65
  | `count()` | Returns the total number of entries. |
66
66
  | `update(key, fn)` | Performs an atomic read-modify-write operation. |
67
67
  | `push(key, value)` | Atomically appends a value to an array. |
68
- | `merge(key, object)` | Atomically shallow-merges an object. |
68
+ | `merge(key, patch)` | Atomically shallow-merges an object. |
69
+
70
+ ## Example Use Cases
71
+
72
+ ### User Settings Management
73
+ Easily manage and update partial user preferences without worrying about race conditions.
74
+ ```javascript
75
+ import { tinyIDB } from 'tiny-idb';
76
+
77
+ // Initial setup
78
+ await tinyIDB.set('settings', { theme: 'dark', notifications: true });
79
+
80
+ // Later, merge new settings
81
+ await tinyIDB.merge('settings', { notifications: false, language: 'en' });
82
+
83
+ // Result: { theme: 'dark', notifications: false, language: 'en' }
84
+ ```
85
+
86
+ ### Persistent Shopping Cart
87
+ Atomically add items to a list, ensuring no items are lost during concurrent updates.
88
+ ```javascript
89
+ // Add items from different parts of the UI
90
+ await tinyIDB.push('cart', { id: 101, qty: 1 });
91
+ await tinyIDB.push('cart', { id: 202, qty: 2 });
92
+
93
+ const cart = await tinyIDB.get('cart');
94
+ console.log(`Items in cart: ${cart.length}`);
95
+ ```
96
+
97
+ ### Atomic Counters
98
+ Safely increment values using the `update` method.
99
+ ```javascript
100
+ await tinyIDB.set('page_views', 0);
101
+
102
+ // Increment safely
103
+ await tinyIDB.update('page_views', count => (count || 0) + 1);
104
+ ```
105
+
106
+ ### localStorage Compatibility
107
+ `tiny-idb` provides aliases for `get`, `set`, and `remove` to match the `localStorage` API.
108
+ ```javascript
109
+ await tinyIDB.setItem('session_id', 'xyz-123');
110
+ const sid = await tinyIDB.getItem('session_id');
111
+ await tinyIDB.removeItem('session_id');
112
+ ```
113
+
114
+ ## Development
115
+
116
+ ### Running Tests
117
+ ```bash
118
+ npm test
119
+ ```
120
+
121
+ ### Running Tests on Minified Build
122
+ ```bash
123
+ npm run test:min
124
+ ```
125
+
126
+ ### Build
127
+ ```bash
128
+ npm run build
129
+ ```
69
130
 
70
131
  ## License
71
132
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-idb",
3
- "version": "1.0.0",
3
+ "version": "1.1.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",
@@ -38,6 +38,8 @@
38
38
  "terser": "^5.46.1"
39
39
  },
40
40
  "scripts": {
41
- "test": "node test.js"
41
+ "test": "node test.js",
42
+ "test:min": "TEST_MIN=1 node test.js",
43
+ "build": "terser tiny-idb.js -o tiny-idb.min.js -c toplevel,unsafe -m toplevel --comments false"
42
44
  }
43
45
  }
package/tiny-idb.js CHANGED
@@ -6,14 +6,14 @@
6
6
  * @license MIT
7
7
  */
8
8
 
9
- const DB_NAME = 'tiny-idb', STORE_NAME = 's', VERSION = 1;
9
+ const DB_NAME = 'tiny-idb', STORE_NAME = 's', READ_WRITE = 'readwrite', READ_ONLY = 'readonly';
10
10
  let dbPromise;
11
11
 
12
12
  const getDB = () => dbPromise || (dbPromise = new Promise((resolve, reject) => {
13
- const req = indexedDB.open(DB_NAME, VERSION);
14
- req.onupgradeneeded = e => e.target.result.createObjectStore(STORE_NAME);
15
- req.onsuccess = e => {
16
- const db = e.target.result;
13
+ const req = indexedDB.open(DB_NAME, 1);
14
+ req.onupgradeneeded = () => req.result.createObjectStore(STORE_NAME);
15
+ req.onsuccess = () => {
16
+ const db = req.result;
17
17
  db.onversionchange = () => { db.close(); dbPromise = null; };
18
18
  resolve(db);
19
19
  };
@@ -27,29 +27,35 @@ const prom = (req) => new Promise((res, rej) => {
27
27
 
28
28
  const tx = async (mode, cb) => {
29
29
  const db = await getDB();
30
- return new Promise((resolve, reject) => {
30
+ return new Promise(async (resolve, reject) => {
31
31
  const t = db.transaction(STORE_NAME, mode);
32
- let res;
33
- try { res = cb(t.objectStore(STORE_NAME)); } catch (e) { t.abort(); return reject(e); }
34
- t.oncomplete = () => resolve(res);
35
- t.onerror = () => reject(t.error);
32
+ t.onabort = t.onerror = () => reject(t.error || new DOMException('Aborted'));
33
+ try {
34
+ const res = await cb(t.objectStore(STORE_NAME));
35
+ t.oncomplete = () => resolve(res);
36
+ } catch (e) {
37
+ try { t.abort(); } catch {}
38
+ reject(e);
39
+ }
36
40
  });
37
41
  };
38
42
 
39
43
  export const tinyIDB = {
40
- set: (k, v) => tx('readwrite', s => prom(s.put(v, k))),
41
- get: k => tx('readonly', s => prom(s.get(k))),
42
- remove: k => tx('readwrite', s => prom(s.delete(k))),
43
- clear: () => tx('readwrite', s => prom(s.clear())),
44
- keys: () => tx('readonly', s => prom(s.getAllKeys())),
45
- values: () => tx('readonly', s => prom(s.getAll())),
46
- count: () => tx('readonly', s => prom(s.count())),
47
- update: async (k, fn) => tx('readwrite', async s => {
48
- const n = await fn(await prom(s.get(k)));
49
- return prom(s.put(n, k));
44
+ set: (key, value) => tx(READ_WRITE, s => prom(s.put(value, key))),
45
+ get: key => tx(READ_ONLY, s => prom(s.get(key))),
46
+ remove: k => tx(READ_WRITE, s => prom(s.delete(k))),
47
+ clear: () => tx(READ_WRITE, s => prom(s.clear())),
48
+ keys: () => tx(READ_ONLY, s => prom(s.getAllKeys())),
49
+ values: () => tx(READ_ONLY, s => prom(s.getAll())),
50
+ count: () => tx(READ_ONLY, s => prom(s.count())),
51
+ update: async (key, fn) => tx(READ_WRITE, async s => {
52
+ const n = await fn(await prom(s.get(key)));
53
+ return prom(s.put(n, key));
50
54
  }),
51
- push: (k, v) => tinyIDB.update(k, c => [...(Array.isArray(c) ? c : []), v]),
52
- merge: (k, p) => tinyIDB.update(k, c => ({ ...(c && typeof c === 'object' ? c : {}), ...p }))
55
+ push: (key, value) => tinyIDB.update(key, c => [...(Array.isArray(c) ? c : []), value]),
56
+ merge: (key, patch) => tinyIDB.update(key, c => ({ ...(c && typeof c === 'object' ? c : {}), ...patch }))
53
57
  };
54
58
 
59
+ ['get', 'set', 'remove'].forEach(method => tinyIDB[method + 'Item'] = tinyIDB[method]);
60
+
55
61
  export default tinyIDB;
package/tiny-idb.min.js CHANGED
@@ -1 +1 @@
1
- const DB_NAME="tiny-idb",STORE_NAME="s",VERSION=1;let dbPromise;const getDB=()=>dbPromise||(dbPromise=new Promise((e,r)=>{const t=indexedDB.open(DB_NAME,1);t.onupgradeneeded=e=>e.target.result.createObjectStore("s"),t.onsuccess=r=>{const t=r.target.result;t.onversionchange=()=>{t.close(),dbPromise=null},e(t)},t.onerror=()=>{dbPromise=null,r(t.error)}})),prom=e=>new Promise((r,t)=>{e.onsuccess=()=>r(e.result),e.onerror=()=>t(e.error)}),tx=async(e,r)=>{const t=await getDB();return new Promise((o,n)=>{const s=t.transaction("s",e);let a;try{a=r(s.objectStore("s"))}catch(e){return s.abort(),n(e)}s.oncomplete=()=>o(a),s.onerror=()=>n(s.error)})};export const tinyIDB={set:(e,r)=>tx("readwrite",t=>prom(t.put(r,e))),get:e=>tx("readonly",r=>prom(r.get(e))),remove:e=>tx("readwrite",r=>prom(r.delete(e))),clear:()=>tx("readwrite",e=>prom(e.clear())),keys:()=>tx("readonly",e=>prom(e.getAllKeys())),values:()=>tx("readonly",e=>prom(e.getAll())),count:()=>tx("readonly",e=>prom(e.count())),update:async(e,r)=>tx("readwrite",async t=>{const o=await r(await prom(t.get(e)));return prom(t.put(o,e))}),push:(e,r)=>tinyIDB.update(e,e=>[...Array.isArray(e)?e:[],r]),merge:(e,r)=>tinyIDB.update(e,e=>({...e&&"object"==typeof e?e:{},...r}))};export default tinyIDB;
1
+ const e="readwrite",t="readonly";let r;const o=e=>new Promise((t,r)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>r(e.error)}),n=async(e,t)=>{const o=await(r||(r=new Promise((e,t)=>{const o=indexedDB.open("tiny-idb",1);o.onupgradeneeded=()=>o.result.createObjectStore("s"),o.onsuccess=()=>{const t=o.result;t.onversionchange=()=>{t.close(),r=null},e(t)},o.onerror=()=>{r=null,t(o.error)}})));return new Promise(async(r,n)=>{const s=o.transaction("s",e);s.onabort=s.onerror=()=>n(s.error||new DOMException("Aborted"));try{const e=await t(s.objectStore("s"));s.oncomplete=()=>r(e)}catch(e){try{s.abort()}catch{}n(e)}})};export const tinyIDB={set:(t,r)=>n(e,e=>o(e.put(r,t))),get:e=>n(t,t=>o(t.get(e))),remove:t=>n(e,e=>o(e.delete(t))),clear:()=>n(e,e=>o(e.clear())),keys:()=>n(t,e=>o(e.getAllKeys())),values:()=>n(t,e=>o(e.getAll())),count:()=>n(t,e=>o(e.count())),update:async(t,r)=>n(e,async e=>{const n=await r(await o(e.get(t)));return o(e.put(n,t))}),push:(e,t)=>tinyIDB.update(e,e=>[...Array.isArray(e)?e:[],t]),merge:(e,t)=>tinyIDB.update(e,e=>({...e&&"object"==typeof e?e:{},...t}))};["get","set","remove"].forEach(e=>tinyIDB[e+"Item"]=tinyIDB[e]);export default tinyIDB;