Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
The idb npm package is a small library that mirrors IndexedDB, but features a more user-friendly API. It allows developers to interact with IndexedDB using promises instead of events, which simplifies the code and improves readability and maintainability. It's particularly useful for applications that need to store large amounts of data on the client side.
Database Creation and Versioning
This code sample demonstrates how to create a new IndexedDB database and an object store within it using idb. The `openDB` function is used to open a database, and it takes the database name, version number, and an upgrade callback as arguments. The upgrade callback is executed when the database is created or upgraded.
const dbPromise = idb.openDB('my-database', 1, {
upgrade(db) {
db.createObjectStore('keyval');
}
});
Adding and Retrieving Data
This code sample shows how to add data to and retrieve data from an object store in IndexedDB using idb. The `addData` function creates a transaction, accesses the object store, and uses the `put` method to add data. The `getData` function retrieves data using the `get` method.
const dbPromise = idb.openDB('my-database', 1);
async function addData(key, val) {
const db = await dbPromise;
const tx = db.transaction('keyval', 'readwrite');
const store = tx.objectStore('keyval');
store.put(val, key);
await tx.done;
}
async function getData(key) {
const db = await dbPromise;
return db.transaction('keyval').objectStore('keyval').get(key);
}
Cursor Iteration
This code sample illustrates how to iterate over entries in an object store using a cursor. The `iterateCursor` function opens a read-only transaction, accesses the object store, and uses `openCursor` to start the iteration. The cursor is advanced using the `continue` method.
const dbPromise = idb.openDB('my-database', 1);
async function iterateCursor() {
const db = await dbPromise;
const tx = db.transaction('keyval', 'readonly');
const store = tx.objectStore('keyval');
let cursor = await store.openCursor();
while (cursor) {
console.log(cursor.key, cursor.value);
cursor = await cursor.continue();
}
}
Dexie.js is a wrapper library for IndexedDB that allows for simpler syntax and complex queries. It provides a more powerful query language and schema handling compared to idb, which makes it suitable for more complex applications that require advanced database features.
PouchDB is an open-source JavaScript database inspired by Apache CouchDB that is designed to run well within the browser. It enables applications to store data locally while offline, then synchronize it with CouchDB and compatible servers when the application is back online, unlike idb which is purely a client-side solution.
This is a tiny library that mirrors IndexedDB, but replaces the weird IDBRequest
objects with promises, plus a couple of other small changes.
This is very similar to localStorage
, but async. If this is all you need, you may be interested in idb-keyval, you can always upgrade to this library later.
const dbPromise = idb.open('keyval-store', 1, upgradeDB => {
upgradeDB.createObjectStore('keyval');
});
const idbKeyval = {
get(key) {
return dbPromise.then(db => {
return db.transaction('keyval')
.objectStore('keyval').get(key);
});
},
set(key, val) {
return dbPromise.then(db => {
const tx = db.transaction('keyval', 'readwrite');
tx.objectStore('keyval').put(val, key);
return tx.complete;
});
},
delete(key) {
return dbPromise.then(db => {
const tx = db.transaction('keyval', 'readwrite');
tx.objectStore('keyval').delete(key);
return tx.complete;
});
},
clear() {
return dbPromise.then(db => {
const tx = db.transaction('keyval', 'readwrite');
tx.objectStore('keyval').clear(key);
return tx.complete;
});
},
keys() {
return dbPromise.then(db => {
const tx = db.transaction('keyval');
const keys = [];
const store = tx.objectStore('keyval');
// This would be store.getAllKeys(), but it isn't supported by Edge or Safari.
// openKeyCursor isn't supported by Safari, so we fall back
(store.iterateKeyCursor || store.iterateCursor).call(store, cursor => {
if (!cursor) return;
keys.push(cursor.key);
cursor.continue();
});
return tx.complete.then(() => keys);
});
}
};
keyValStore.set('foo', {hello: 'world'});
// logs: {hello: 'world'}
keyValStore.get('foo').then(val => console.log(val));
Imagine we had a set of objects like…
{
"id": 123456,
"data": {"foo": "bar"}
}
const dbPromise = idb.open('keyval-store', 2, upgradeDB => {
// Note: we don't use 'break' in this switch statement,
// the fall-through behaviour is what we want.
switch (upgradeDB.oldVersion) {
case 0:
upgradeDB.createObjectStore('keyval');
case 1:
upgradeDB.createObjectStore('objs', {keyPath: 'id'});
}
});
dbPromise.then(db => {
const tx = db.transaction('objs', 'readwrite');
tx.objectStore('objs').put({
id: 123456,
data: {foo: "bar"}
});
return tx.complete;
});
dbPromise.then(db => {
return db.transaction('objs')
.objectStore('objs').getAll();
}).then(allObjs => console.log(allObjs));
dbPromise.then(db => {
return db.transaction('objs')
.objectStore('objs').get(123456);
}).then(obj => console.log(obj));
At time of writing, all browsers aside from Chrome don't treat promise callbacks as microtasks, or call microtasks incorrectly. This means transactions end by the time promise callbacks are called. In practice, this means you cannot perform transactions that involve waiting for a value, then using it within the same transaction.
const tx = db.transaction('store', 'readwrite');
const store = tx.objectStore('store');
store.get('hello').then(val => store.put(val, 'foo'));
The above will fail in browsers other than Chrome, because the transaction has closed by the time we get to the .put
.
You can work around this in Firefox by using a promise polyfill that correctly uses microtasks, such as es6-promise.
This is a simple wrapper library, so you're exposed to bugs in the underlying implementation. Unfortunately Safari has a lot of these.
idb
This is your entry point to the API. It's exposed to the global scope unless you're using a module system such as browserify, in which case it's the exported object.
idb.open(name, version, upgradeCallback)
This method returns a promise that resolves to a DB
.
name
and version
behave as they do in indexedDB.open
.
upgradeCallback
is called if version
is greater than the version last opened. It's similar to IDB's onupgradeneeded
. The callback receives an instance of UpgradeDB
.
idb.open('keyval-store', 2, upgradeDB => {
// Note: we don't use 'break' in this switch statement,
// the fall-through behaviour is what we want.
switch (upgradeDB.oldVersion) {
case 0:
upgradeDB.createObjectStore('keyval');
case 1:
upgradeDB.createObjectStore('stuff', {keyPath: ''});
}
}).then(db => console.log("DB opened!", db));
idb.delete(name)
Behaves like indexedDB.deleteDatabase
, but returns a promise.
idb.delete('keyval-store').then(() => console.log('done!'));
DB
Properties:
IDBDatabase
:
name
version
objectStoreNames
Methods:
close
- as idbDatabase.close
transaction
- as idbDatabase.transaction
, but returns a Transaction
UpgradeDB
As DB
, except:
Properties:
transaction
- this is a property rather than a method. It's a Transaction
representing the upgrade transactionoldVersion
- the previous version of the DB seen by the browser, or 0 if it's newMethods:
createObjectStore
- as idbDatabase.createObjectStore
, but returns an ObjectStore
deleteObjectStore
- as idbDatabase.deleteObjectStore
Transaction
Properties:
complete
- a promise. Resolves when transaction completes, rejects if transaction aborts or errorsIDBTransaction
:
objectStoreNames
mode
Methods:
abort
- as idbTransaction.abort
objectStore
- as idbTransaction.objectStore
, but returns an ObjectStore
idb.open('keyval-store', 1, upgradeDB => {
switch (upgradeDB.oldVersion) {
case 0:
upgradeDB.createObjectStore('keyval');
}
}).then(db => {
const tx = db.transaction('keyval', 'readwrite');
tx.objectStore('keyval').put('hello', 'world');
return tx.complete;
}).then(() => console.log("Done!"));
ObjectStore
Properties:
IDBObjectStore
:
name
keyPath
indexNames
autoIncrement
Methods:
IDBObjectStore
, but returns a promise that resolves/rejects based on operation success/failure:
put
add
delete
clear
get
getAll
getAllKeys
count
IDBObjectStore
, but returns a promise that resolves with a Cursor
:
openCursor
openKeyCursor
deleteIndex
- as idbObjectStore.deleteIndex
IDBObjectStore
, but returns an Index
:
createIndex
index
iterateCursor
- see belowiterateKeyCursor
- see belowiterateCursor
& iterateKeyCursor
Due to the microtask issues in some browsers, iterating over a cursor using promises doesn't always work:
const tx = db.transaction('stuff');
tx.objectStore('stuff').openCursor().then(function cursorIterate(cursor) {
if (!cursor) return;
console.log(cursor.value);
return cursor.continue().then(cursorIterate);
});
tx.complete.then(() => console.log('done'));
So in the mean time, iterateCursor
and iterateKeyCursor
map to openCursor
& openKeyCursor
, take identical arguments, plus an additional callback that receives an IDBCursor
, so the above example becomes:
const tx = db.transaction('stuff');
tx.objectStore('stuff').iterateCursor(cursor => {
if (!cursor) return;
console.log(cursor.value);
cursor.continue();
});
tx.complete.then(() => console.log('done'));
The intent is to remove iterateCursor
and iterateKeyCursor
from the library once browsers support promises and microtasks correctly.
Index
Properties:
IDBIndex
:
name
keyPath
multiEntry
unique
Methods:
IDBIndex
, but returns a promise that resolves/rejects based on operation success/failure:
get
getKey
getAll
getAllKeys
count
IDBIndex
, but returns a promise that resolves with a Cursor
:
openCursor
openKeyCursor
iterateCursor
- as objectStore.iterateCursor
but over the indexiterateKeyCursor
- as objectStore.iterateKeyCursor
but over the indexProperties:
IDBCursor
:
direction
key
primaryKey
value
Methods:
IDBCursor
, but returns a promise that resolves/rejects based on operation success/failure:
update
delete
IDBCursor
, but returns a promise that resolves with a Cursor
:
advance
continue
continuePrimaryKey
FAQs
A small wrapper that makes IndexedDB usable
The npm package idb receives a total of 2,696,157 weekly downloads. As such, idb popularity was classified as popular.
We found that idb demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.