tiny-idb 1.2.1 → 1.3.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
@@ -10,6 +10,15 @@ It is designed for developers who require the reliability and capacity of Indexe
10
10
  [![License](https://img.shields.io/npm/l/tiny-idb.svg)](LICENSE)
11
11
  [![Size](https://img.shields.io/bundlephobia/minzip/tiny-idb)](https://bundlephobia.com/package/tiny-idb)
12
12
 
13
+ ## Why tiny-idb?
14
+
15
+ There are many IndexedDB wrappers, but `tiny-idb` is built with a specific philosophy: **Smallest possible footprint without sacrificing data integrity.**
16
+
17
+ - **Smaller than most icons**: At less than 1KB (gzipped), it's lighter than a 16x16 PNG.
18
+ - **Atomic Operations**: Built-in `update`, `push`, and `merge` are ACID-compliant and race-condition safe. No more partial updates or data loss.
19
+ - **Zero dependencies**: Built on pure vanilla JS. No external bloat.
20
+ - **Drop-in localStorage replacement**: Use the same `getItem`, `setItem`, `removeItem` calls, but with `await`.
21
+
13
22
  ## Core Advantages
14
23
 
15
24
  ### Architectural Simplicity
@@ -46,13 +55,14 @@ npm install tiny-idb
46
55
 
47
56
  ## Technical Comparison
48
57
 
49
- | Feature | localStorage | tiny-idb |
58
+ | Feature | `localStorage` | `tiny-idb` |
50
59
  |---------|--------------|----------|
51
60
  | **Execution** | Synchronous (Blocks UI) | Asynchronous (Non-blocking) |
52
- | **Storage Limit** | ~5-10MB | Virtually unlimited (until disk is full) |
53
- | **Data Types** | Strings only | Objects, Blobs, Arrays, Numbers |
61
+ | **Storage Limit** | ~5-10MB (Fixed) | Virtually unlimited (80%+ of disk) |
62
+ | **Data Types** | Strings only (Requires `JSON.parse`) | Objects, Blobs, Arrays, Numbers, Files |
54
63
  | **Data Integrity** | Basic | ACID Compliant |
55
64
  | **Race Condition Safety** | None | Atomic `update`/`push`/`merge` |
65
+ | **Tab Sync** | No | Automatic |
56
66
 
57
67
  ## API Reference
58
68
 
@@ -65,13 +75,24 @@ npm install tiny-idb
65
75
  | `clear()` | Removes all data from the store. |
66
76
  | `keys()` | Returns an array of all keys. |
67
77
  | `values()` | Returns an array of all values. |
78
+ | `entries()` | Returns an array of `[key, value]` pairs. |
68
79
  | `count()` | Returns the total number of entries. |
69
- | `update(key, fn)` | Performs an atomic read-modify-write operation. |
70
- | `push(key, value)` | Atomically appends a value to an array. |
71
- | `merge(key, patch)` | Atomically shallow-merges an object. |
80
+ | `update(key, fn)` | Performs an **atomic** read-modify-write. |
81
+ | `push(key, value)` | **Atomically** appends to an array. |
82
+ | `merge(key, patch)` | **Atomically** shallow-merges an object. |
72
83
 
73
84
  ## Example Use Cases
74
85
 
86
+ ### Iterating over Data
87
+ Use `entries()` to easily process all stored key-value pairs.
88
+ ```javascript
89
+ const allEntries = await tinyIDB.entries();
90
+
91
+ for (const [key, value] of allEntries) {
92
+ console.log(`${key}:`, value);
93
+ }
94
+ ```
95
+
75
96
  ### User Settings Management
76
97
  Easily manage and update partial user preferences without worrying about race conditions.
77
98
  ```javascript
@@ -86,6 +107,19 @@ await tinyIDB.merge('settings', { notifications: false, language: 'en' });
86
107
  // Result: { theme: 'dark', notifications: false, language: 'en' }
87
108
  ```
88
109
 
110
+ ### Storing Binary Data (Blobs/Files)
111
+ Unlike `localStorage`, `tiny-idb` can store binary data directly.
112
+ ```javascript
113
+ const response = await fetch('/profile-picture.jpg');
114
+ const blob = await response.blob();
115
+
116
+ await tinyIDB.set('user_avatar', blob);
117
+
118
+ // Later...
119
+ const avatar = await tinyIDB.get('user_avatar');
120
+ document.querySelector('img').src = URL.createObjectURL(avatar);
121
+ ```
122
+
89
123
  ### Persistent Shopping Cart
90
124
  Atomically add items to a list, ensuring no items are lost during concurrent updates.
91
125
  ```javascript
@@ -102,7 +136,7 @@ Safely increment values using the `update` method.
102
136
  ```javascript
103
137
  await tinyIDB.set('page_views', 0);
104
138
 
105
- // Increment safely
139
+ // Increment safely - even if multiple tabs do it at once
106
140
  await tinyIDB.update('page_views', count => (count || 0) + 1);
107
141
  ```
108
142
 
@@ -136,6 +170,15 @@ await settings.set('theme', 'dark');
136
170
  await cache.set('temp_data', { id: 1 });
137
171
  ```
138
172
 
173
+ ## Browser Support
174
+
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)
179
+
180
+ If you need to support legacy browsers (IE11), you will need to transpile and polyfill.
181
+
139
182
  ## Development
140
183
 
141
184
  `tiny-idb` is written in pure vanilla JavaScript. No compilation is required for development.
@@ -150,10 +193,10 @@ npm test
150
193
  npm run test:min
151
194
  ```
152
195
 
153
- ### Minification
196
+ ### Building & Minification
154
197
  Generate the production-ready minified file:
155
198
  ```bash
156
- npm run minify
199
+ npm run build
157
200
  ```
158
201
 
159
202
  ## License
package/index.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ /** tiny-idb - MIT © Jelodar */
2
+
3
+ export interface TinyIDBInstance {
4
+ /**
5
+ * Creates or retrieves a cached instance of a database and store.
6
+ * @param dbName Name of the IndexedDB database.
7
+ * @param storeName Name of the object store (defaults to dbName).
8
+ */
9
+ open(dbName: string, storeName?: string): TinyIDBInstance;
10
+
11
+ /**
12
+ * Persists a value to the store.
13
+ */
14
+ set(key: any, value: any): Promise<void>;
15
+ /** Alias for set() */
16
+ setItem(key: any, value: any): Promise<void>;
17
+
18
+ /**
19
+ * Retrieves a value; returns undefined if not found.
20
+ */
21
+ get<T = any>(key: any): Promise<T | undefined>;
22
+ /** Alias for get() */
23
+ getItem<T = any>(key: any): Promise<T | undefined>;
24
+
25
+ /**
26
+ * Deletes a specific key.
27
+ */
28
+ remove(key: any): Promise<void>;
29
+ /** Alias for remove() */
30
+ removeItem(key: any): Promise<void>;
31
+
32
+ /**
33
+ * Removes all data from the store.
34
+ */
35
+ clear(): Promise<void>;
36
+
37
+ /**
38
+ * Returns an array of all keys.
39
+ */
40
+ keys(): Promise<any[]>;
41
+
42
+ /**
43
+ * Returns an array of all values.
44
+ */
45
+ values<T = any>(): Promise<T[]>;
46
+
47
+ /**
48
+ * Returns an array of [key, value] pairs.
49
+ */
50
+ entries<K = any, V = any>(): Promise<[K, V][]>;
51
+
52
+ /**
53
+ * Returns the total number of entries.
54
+ */
55
+ count(): Promise<number>;
56
+
57
+ /**
58
+ * Performs an atomic read-modify-write operation within a single transaction.
59
+ * Note: The function 'fn' must be synchronous or microtask-only (no await on fetch/setTimeout)
60
+ * to prevent the IndexedDB transaction from auto-committing.
61
+ * @param key The key to update.
62
+ * @param fn A function that receives the current value and returns the new value.
63
+ */
64
+ update<T = any>(key: any, fn: (currentValue: T | undefined) => T | Promise<T>): Promise<void>;
65
+
66
+ /**
67
+ * Atomically appends a value to an array. Initializes as [value] if key doesn't exist.
68
+ */
69
+ push(key: any, value: any): Promise<void>;
70
+
71
+ /**
72
+ * Atomically shallow-merges an object. Initializes as patch if key doesn't exist.
73
+ */
74
+ merge(key: any, patch: object): Promise<void>;
75
+ }
76
+
77
+ export const tinyIDB: TinyIDBInstance;
78
+ export default tinyIDB;
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "tiny-idb",
3
- "version": "1.2.1",
3
+ "version": "1.3.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
+ "types": "index.d.ts",
7
8
  "type": "module",
8
9
  "repository": {
9
10
  "type": "git",
@@ -19,7 +20,8 @@
19
20
  "browser",
20
21
  "persistent",
21
22
  "nosql",
22
- "key-value"
23
+ "key-value",
24
+ "typescript"
23
25
  ],
24
26
  "author": "Jelodar",
25
27
  "license": "MIT",
@@ -30,6 +32,7 @@
30
32
  "files": [
31
33
  "tiny-idb.js",
32
34
  "tiny-idb.min.js",
35
+ "index.d.ts",
33
36
  "LICENSE",
34
37
  "README.md"
35
38
  ],
@@ -40,6 +43,7 @@
40
43
  "scripts": {
41
44
  "test": "node test.js",
42
45
  "test:min": "TEST_MIN=1 node test.js",
46
+ "build": "npm run minify",
43
47
  "minify": "terser tiny-idb.js -o tiny-idb.min.js -c toplevel,unsafe -m toplevel --comments '/tiny-idb/'"
44
48
  }
45
49
  }
package/tiny-idb.js CHANGED
@@ -47,6 +47,10 @@ const getAPI = (dbName = 'tiny-idb', storeName = undefined) => {
47
47
  clear: () => tx(RW, s => prom(s.clear())),
48
48
  keys: () => tx(RO, s => prom(s.getAllKeys())),
49
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())]);
52
+ return k.map((key, i) => [key, v[i]]);
53
+ }),
50
54
  count: () => tx(RO, s => prom(s.count())),
51
55
  update,
52
56
  push: (key, val) => update(key, (c = []) => [...(Array.isArray(c) ? c : []), val]),
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",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;
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;