tiny-idb 1.1.0 → 1.2.1

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
@@ -2,7 +2,9 @@
2
2
 
3
3
  **A minimalist, high-performance IndexedDB wrapper for modern web applications.**
4
4
 
5
- `tiny-idb` provides a non-blocking, asynchronous alternative to `localStorage`. It is designed for developers who require the durability and capacity of IndexedDB without the complexity of its native API. By focusing on a single-store, key-value architecture, it eliminates the need for database versioning and boilerplate configuration.
5
+ `tiny-idb` provides a non-blocking, asynchronous alternative to `localStorage`. While `localStorage` is capped at ~5-10MB and can be cleared by the browser under memory pressure, `tiny-idb` leverages IndexedDB to offer virtually unlimited storage (up to 80% of disk space) with much higher durability.
6
+
7
+ It is designed for developers who require the reliability and capacity of IndexedDB without the complexity of its native API. By focusing on a single-store, key-value architecture, it eliminates the need for database versioning and boilerplate configuration.
6
8
 
7
9
  [![NPM Version](https://img.shields.io/npm/v/tiny-idb.svg)](https://www.npmjs.com/package/tiny-idb)
8
10
  [![License](https://img.shields.io/npm/l/tiny-idb.svg)](LICENSE)
@@ -17,13 +19,13 @@ Native IndexedDB requires managing requests, transactions, and version upgrades.
17
19
  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
20
 
19
21
  ### Resource Efficiency
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.
22
+ 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.
21
23
 
22
24
  ### Intelligent Lifecycle Management
23
25
  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.
24
26
 
25
27
  ### Zero-Configuration Portability
26
- 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. This makes it an ideal solution for rapid prototyping, legacy system upgrades, and environments where complex build pipelines are unavailable.
28
+ 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.
27
29
 
28
30
  ## Installation
29
31
 
@@ -39,7 +41,7 @@ npm install tiny-idb
39
41
  </script>
40
42
  ```
41
43
 
42
- * **Minified Module**: `https://unpkg.com/tiny-idb/tiny-idb.min.js` (598 bytes gzipped)
44
+ * **Minified Module**: `https://unpkg.com/tiny-idb/tiny-idb.min.js` (less than 1KB gzipped)
43
45
  * **Source**: `https://unpkg.com/tiny-idb/tiny-idb.js`
44
46
 
45
47
  ## Technical Comparison
@@ -47,7 +49,7 @@ npm install tiny-idb
47
49
  | Feature | localStorage | tiny-idb |
48
50
  |---------|--------------|----------|
49
51
  | **Execution** | Synchronous (Blocks UI) | Asynchronous (Non-blocking) |
50
- | **Storage Limit** | ~5-10MB | Disk-limited |
52
+ | **Storage Limit** | ~5-10MB | Virtually unlimited (until disk is full) |
51
53
  | **Data Types** | Strings only | Objects, Blobs, Arrays, Numbers |
52
54
  | **Data Integrity** | Basic | ACID Compliant |
53
55
  | **Race Condition Safety** | None | Atomic `update`/`push`/`merge` |
@@ -56,6 +58,7 @@ npm install tiny-idb
56
58
 
57
59
  | Method | Description |
58
60
  |--------|-------------|
61
+ | `open(db, store?)` | Creates or retrieves a cached instance. `store` defaults to `db` name. |
59
62
  | `get(key)` | Retrieves a value; returns `undefined` if not found. |
60
63
  | `set(key, value)` | Persists a value to the store. |
61
64
  | `remove(key)` | Deletes a specific key. |
@@ -111,8 +114,32 @@ const sid = await tinyIDB.getItem('session_id');
111
114
  await tinyIDB.removeItem('session_id');
112
115
  ```
113
116
 
117
+ ### Simple Custom Database
118
+ If you only need one store per database, you can omit the `storeName`. It will automatically default to the same name as the database.
119
+ ```javascript
120
+ // Creates/retrieves a DB named 'my-store' with an internal store also named 'my-store'
121
+ const store = tinyIDB.open('my-store');
122
+
123
+ await store.set('key', 'value');
124
+ ```
125
+
126
+ ### Multi-Instance Support
127
+ Use `open` to create isolated storage instances. Instances are cached internally.
128
+ ```javascript
129
+ import { tinyIDB } from 'tiny-idb';
130
+
131
+ // Create isolated storage instances
132
+ const settings = tinyIDB.open('app-db', 'settings');
133
+ const cache = tinyIDB.open('app-db', 'cache');
134
+
135
+ await settings.set('theme', 'dark');
136
+ await cache.set('temp_data', { id: 1 });
137
+ ```
138
+
114
139
  ## Development
115
140
 
141
+ `tiny-idb` is written in pure vanilla JavaScript. No compilation is required for development.
142
+
116
143
  ### Running Tests
117
144
  ```bash
118
145
  npm test
@@ -123,9 +150,10 @@ npm test
123
150
  npm run test:min
124
151
  ```
125
152
 
126
- ### Build
153
+ ### Minification
154
+ Generate the production-ready minified file:
127
155
  ```bash
128
- npm run build
156
+ npm run minify
129
157
  ```
130
158
 
131
159
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-idb",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
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",
@@ -40,6 +40,6 @@
40
40
  "scripts": {
41
41
  "test": "node test.js",
42
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"
43
+ "minify": "terser tiny-idb.js -o tiny-idb.min.js -c toplevel,unsafe -m toplevel --comments '/tiny-idb/'"
44
44
  }
45
45
  }
package/tiny-idb.js CHANGED
@@ -1,61 +1,62 @@
1
- /**
2
- * tiny-idb - A super simple, fast, and dependency-free IndexedDB wrapper.
3
- * Designed as a drop-in replacement for localStorage with durability and performance.
4
- *
5
- * @author Jelodar
6
- * @license MIT
7
- */
8
-
9
- const DB_NAME = 'tiny-idb', STORE_NAME = 's', READ_WRITE = 'readwrite', READ_ONLY = 'readonly';
10
- let dbPromise;
11
-
12
- const getDB = () => dbPromise || (dbPromise = new Promise((resolve, reject) => {
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
- db.onversionchange = () => { db.close(); dbPromise = null; };
18
- resolve(db);
19
- };
20
- req.onerror = () => { dbPromise = null; reject(req.error); };
21
- }));
1
+ /** tiny-idb - MIT © Jelodar */
22
2
 
3
+ const instances = new Map();
23
4
  const prom = (req) => new Promise((res, rej) => {
24
5
  req.onsuccess = () => res(req.result);
25
6
  req.onerror = () => rej(req.error);
26
7
  });
8
+ const RO = 'readonly', RW = 'readwrite';
27
9
 
28
- const tx = async (mode, cb) => {
29
- const db = await getDB();
30
- return new Promise(async (resolve, reject) => {
31
- const t = db.transaction(STORE_NAME, mode);
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
- }
40
- });
41
- };
10
+ const getAPI = (dbName = 'tiny-idb', storeName = undefined) => {
11
+ storeName = storeName || dbName;
12
+ const key = dbName + '\0' + storeName;
13
+ if (instances.has(key)) return instances.get(key);
42
14
 
43
- export const tinyIDB = {
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));
54
- }),
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 }))
57
- };
15
+ let dbPromise;
16
+ const tx = async (mode, cb) => {
17
+ const db = await (dbPromise || (dbPromise = new Promise((resolve, reject) => {
18
+ const req = indexedDB.open(dbName, 1);
19
+ req.onupgradeneeded = () => req.result.createObjectStore(storeName);
20
+ req.onsuccess = () => {
21
+ const db = req.result;
22
+ db.onversionchange = () => { db.close(); dbPromise = null; };
23
+ resolve(db);
24
+ };
25
+ req.onerror = () => { dbPromise = null; reject(req.error); };
26
+ })));
27
+ return new Promise(async (resolve, reject) => {
28
+ const t = db.transaction(storeName, mode);
29
+ 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
+ }
37
+ });
38
+ };
39
+
40
+ const update = (key, fn) => tx(RW, async s => prom(s.put(await fn(await prom(s.get(key))), key)));
58
41
 
59
- ['get', 'set', 'remove'].forEach(method => tinyIDB[method + 'Item'] = tinyIDB[method]);
42
+ const api = {
43
+ 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
+ count: () => tx(RO, s => prom(s.count())),
51
+ update,
52
+ push: (key, val) => update(key, (c = []) => [...(Array.isArray(c) ? c : []), val]),
53
+ merge: (key, obj) => update(key, (c = {}) => ({ ...(c && typeof c === 'object' ? c : {}), ...obj }))
54
+ };
55
+
56
+ ['get', 'set', 'remove'].forEach(m => api[m + 'Item'] = api[m]);
57
+ instances.set(key, api);
58
+ return api;
59
+ };
60
60
 
61
+ export const tinyIDB = getAPI();
61
62
  export default tinyIDB;
package/tiny-idb.min.js CHANGED
@@ -1 +1,2 @@
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;
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",c=void 0)=>{const a=s+"\0"+(c=c||s);if(e.has(a))return e.get(a);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(c),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(c,e);s.onabort=s.onerror=()=>n(s.error||new DOMException("Aborted"));try{const e=await t(s.objectStore(c));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())),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(a,y),y};export const tinyIDB=n();export default tinyIDB;