tiny-idb 1.2.1 → 1.4.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 +71 -9
- package/index.d.ts +86 -0
- package/package.json +6 -2
- package/tiny-idb.js +5 -0
- package/tiny-idb.min.js +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,15 @@ It is designed for developers who require the reliability and capacity of Indexe
|
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](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 (
|
|
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,43 @@ 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
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
80
|
+
| `raw(cb, mode?)` | Provides direct access to the `IDBObjectStore`. |
|
|
81
|
+
| `update(key, fn)` | Performs an **atomic** read-modify-write. |
|
|
82
|
+
| `push(key, value)` | **Atomically** appends to an array. |
|
|
83
|
+
| `merge(key, patch)` | **Atomically** shallow-merges an object. |
|
|
72
84
|
|
|
73
85
|
## Example Use Cases
|
|
74
86
|
|
|
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.
|
|
89
|
+
```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
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Iterating over Data
|
|
106
|
+
Use `entries()` to easily process all stored key-value pairs.
|
|
107
|
+
```javascript
|
|
108
|
+
const allEntries = await tinyIDB.entries();
|
|
109
|
+
|
|
110
|
+
for (const [key, value] of allEntries) {
|
|
111
|
+
console.log(`${key}:`, value);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
75
115
|
### User Settings Management
|
|
76
116
|
Easily manage and update partial user preferences without worrying about race conditions.
|
|
77
117
|
```javascript
|
|
@@ -86,6 +126,19 @@ await tinyIDB.merge('settings', { notifications: false, language: 'en' });
|
|
|
86
126
|
// Result: { theme: 'dark', notifications: false, language: 'en' }
|
|
87
127
|
```
|
|
88
128
|
|
|
129
|
+
### Storing Binary Data (Blobs/Files)
|
|
130
|
+
Unlike `localStorage`, `tiny-idb` can store binary data directly.
|
|
131
|
+
```javascript
|
|
132
|
+
const response = await fetch('/profile-picture.jpg');
|
|
133
|
+
const blob = await response.blob();
|
|
134
|
+
|
|
135
|
+
await tinyIDB.set('user_avatar', blob);
|
|
136
|
+
|
|
137
|
+
// Later...
|
|
138
|
+
const avatar = await tinyIDB.get('user_avatar');
|
|
139
|
+
document.querySelector('img').src = URL.createObjectURL(avatar);
|
|
140
|
+
```
|
|
141
|
+
|
|
89
142
|
### Persistent Shopping Cart
|
|
90
143
|
Atomically add items to a list, ensuring no items are lost during concurrent updates.
|
|
91
144
|
```javascript
|
|
@@ -102,7 +155,7 @@ Safely increment values using the `update` method.
|
|
|
102
155
|
```javascript
|
|
103
156
|
await tinyIDB.set('page_views', 0);
|
|
104
157
|
|
|
105
|
-
// Increment safely
|
|
158
|
+
// Increment safely - even if multiple tabs do it at once
|
|
106
159
|
await tinyIDB.update('page_views', count => (count || 0) + 1);
|
|
107
160
|
```
|
|
108
161
|
|
|
@@ -136,6 +189,15 @@ await settings.set('theme', 'dark');
|
|
|
136
189
|
await cache.set('temp_data', { id: 1 });
|
|
137
190
|
```
|
|
138
191
|
|
|
192
|
+
## Browser Support
|
|
193
|
+
|
|
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)
|
|
198
|
+
|
|
199
|
+
If you need to support legacy browsers (IE11), you will need to transpile and polyfill.
|
|
200
|
+
|
|
139
201
|
## Development
|
|
140
202
|
|
|
141
203
|
`tiny-idb` is written in pure vanilla JavaScript. No compilation is required for development.
|
|
@@ -150,10 +212,10 @@ npm test
|
|
|
150
212
|
npm run test:min
|
|
151
213
|
```
|
|
152
214
|
|
|
153
|
-
### Minification
|
|
215
|
+
### Building & Minification
|
|
154
216
|
Generate the production-ready minified file:
|
|
155
217
|
```bash
|
|
156
|
-
npm run
|
|
218
|
+
npm run build
|
|
157
219
|
```
|
|
158
220
|
|
|
159
221
|
## License
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
* Direct access to the IDBObjectStore within a transaction.
|
|
59
|
+
* This provides an "escape hatch" to use native IndexedDB features like cursors, ranges, and search.
|
|
60
|
+
* @param cb A callback that receives the IDBObjectStore.
|
|
61
|
+
* @param mode The transaction mode ('readonly' or 'readwrite').
|
|
62
|
+
*/
|
|
63
|
+
raw<T = any>(cb: (store: IDBObjectStore) => T | Promise<T>, mode?: IDBTransactionMode): Promise<T>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Performs an atomic read-modify-write operation within a single transaction.
|
|
67
|
+
* Note: The function 'fn' must be synchronous or microtask-only (no await on fetch/setTimeout)
|
|
68
|
+
* to prevent the IndexedDB transaction from auto-committing.
|
|
69
|
+
* @param key The key to update.
|
|
70
|
+
* @param fn A function that receives the current value and returns the new value.
|
|
71
|
+
*/
|
|
72
|
+
update<T = any>(key: any, fn: (currentValue: T | undefined) => T | Promise<T>): Promise<void>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Atomically appends a value to an array. Initializes as [value] if key doesn't exist.
|
|
76
|
+
*/
|
|
77
|
+
push(key: any, value: any): Promise<void>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Atomically shallow-merges an object. Initializes as patch if key doesn't exist.
|
|
81
|
+
*/
|
|
82
|
+
merge(key: any, patch: object): Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const tinyIDB: TinyIDBInstance;
|
|
86
|
+
export default tinyIDB;
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tiny-idb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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,7 +47,12 @@ 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())),
|
|
55
|
+
raw: (cb, mode = RO) => tx(mode, cb),
|
|
51
56
|
update,
|
|
52
57
|
push: (key, val) => update(key, (c = []) => [...(Array.isArray(c) ? c : []), val]),
|
|
53
58
|
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",
|
|
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;
|