A pure JS in-memory implementation of the IndexedDB API for testing IndexedDB-dependent code in Node.js environments
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Core database lifecycle operations including opening, creating, upgrading, and deleting databases with full version management support.
The main factory interface for creating and managing database connections.
/**
* Opens a database connection with optional version upgrade
* @param name - Database name
* @param version - Optional version number (defaults to 1)
* @returns IDBOpenDBRequest for handling success/upgrade events
*/
open(name: string, version?: number): IDBOpenDBRequest;
/**
* Deletes a database completely
* @param name - Database name to delete
* @returns IDBOpenDBRequest for handling completion
*/
deleteDatabase(name: string): IDBOpenDBRequest;
/**
* Lists all available databases
* @returns Promise resolving to array of database info
*/
databases(): Promise<Array<{ name: string; version: number }>>;Usage Examples:
import "fake-indexeddb/auto";
// Open database (creates if doesn't exist)
const request = indexedDB.open("myapp", 2);
request.onsuccess = (event) => {
const db = event.target.result;
console.log("Database opened:", db.name, "version", db.version);
};
request.onerror = (event) => {
console.error("Database error:", event.target.error);
};
// Delete database
const deleteRequest = indexedDB.deleteDatabase("oldapp");
deleteRequest.onsuccess = () => console.log("Database deleted");
// List all databases
indexedDB.databases().then(databases => {
console.log("Available databases:", databases);
});Represents an active database connection with object stores and transactions.
interface IDBDatabase extends EventTarget {
/** Database name (readonly) */
readonly name: string;
/** Current database version (readonly) */
readonly version: number;
/** List of object store names (readonly) */
readonly objectStoreNames: DOMStringList;
/**
* Creates a new object store (only during versionchange transaction)
* @param name - Object store name
* @param options - Store configuration options
* @returns Created object store
*/
createObjectStore(name: string, options?: {
keyPath?: string | string[];
autoIncrement?: boolean;
}): IDBObjectStore;
/**
* Deletes an object store (only during versionchange transaction)
* @param name - Object store name to delete
*/
deleteObjectStore(name: string): void;
/**
* Creates a new transaction
* @param storeNames - Object store names to include in transaction
* @param mode - Transaction mode (default: "readonly")
* @param options - Transaction options
* @returns New transaction
*/
transaction(
storeNames: string | string[],
mode?: "readonly" | "readwrite" | "versionchange",
options?: { durability?: "default" | "strict" | "relaxed" }
): IDBTransaction;
/**
* Closes the database connection
*/
close(): void;
// Event handlers
onabort: ((event: Event) => void) | null;
onclose: ((event: Event) => void) | null;
onerror: ((event: Event) => void) | null;
onversionchange: ((event: IDBVersionChangeEvent) => void) | null;
}Usage Examples:
// Database upgrade handling
const request = indexedDB.open("ecommerce", 3);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const transaction = event.target.transaction;
const oldVersion = event.oldVersion;
const newVersion = event.newVersion;
console.log(`Upgrading from version ${oldVersion} to ${newVersion}`);
// Create object stores based on version
if (oldVersion < 1) {
const productsStore = db.createObjectStore("products", {
keyPath: "id",
autoIncrement: true
});
productsStore.createIndex("by_category", "category");
productsStore.createIndex("by_price", "price");
}
if (oldVersion < 2) {
const ordersStore = db.createObjectStore("orders", {
keyPath: "orderId"
});
ordersStore.createIndex("by_customer", "customerId");
ordersStore.createIndex("by_date", "orderDate");
}
if (oldVersion < 3) {
// Add new index to existing store
const productsStore = transaction.objectStore("products");
productsStore.createIndex("by_name", "name", { unique: false });
}
};
request.onsuccess = (event) => {
const db = event.target.result;
// Handle version change from other connections
db.onversionchange = () => {
console.log("Database version changed, closing connection");
db.close();
};
// Use database...
const tx = db.transaction(["products", "orders"], "readonly");
// ... perform operations
// Always close when done
db.close();
};Extended request interface for database opening operations with upgrade events.
interface IDBOpenDBRequest extends IDBRequest {
/**
* Fired when database needs to be upgraded or created
*/
onupgradeneeded: ((event: IDBVersionChangeEvent) => void) | null;
/**
* Fired when database opening is blocked by other connections
*/
onblocked: ((event: Event) => void) | null;
}Usage Examples:
const request = indexedDB.open("analytics", 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// First time or version upgrade
console.log("Setting up database schema");
const eventsStore = db.createObjectStore("events", {
keyPath: "id",
autoIncrement: true
});
eventsStore.createIndex("by_timestamp", "timestamp");
eventsStore.createIndex("by_type", "eventType");
eventsStore.createIndex("by_user", "userId");
};
request.onblocked = (event) => {
console.warn("Database opening blocked - close other connections");
// Optionally show user message to close other tabs
alert("Please close other tabs using this application");
};
request.onsuccess = (event) => {
const db = event.target.result;
console.log("Database ready for use");
};
request.onerror = (event) => {
console.error("Failed to open database:", event.target.error);
};// Handle multiple version upgrades gracefully
const request = indexedDB.open("app_data", 5);
request.onupgradeneeded = (event) => {
const db = event.target.result;
const transaction = event.target.transaction;
const oldVersion = event.oldVersion;
// Progressive upgrades
if (oldVersion < 1) {
// Initial schema
const usersStore = db.createObjectStore("users", { keyPath: "id" });
usersStore.createIndex("email", "email", { unique: true });
}
if (oldVersion < 2) {
// Add new store
const settingsStore = db.createObjectStore("settings", { keyPath: "key" });
}
if (oldVersion < 3) {
// Modify existing store
const usersStore = transaction.objectStore("users");
usersStore.createIndex("created_at", "createdAt");
}
if (oldVersion < 4) {
// Data migration
const usersStore = transaction.objectStore("users");
usersStore.openCursor().onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
const user = cursor.value;
// Add new field with default value
user.lastLogin = user.lastLogin || new Date().toISOString();
cursor.update(user);
cursor.continue();
}
};
}
if (oldVersion < 5) {
// Remove old index, add new compound index
const usersStore = transaction.objectStore("users");
try {
usersStore.deleteIndex("old_index");
} catch (e) {
// Index might not exist
}
usersStore.createIndex("email_status", ["email", "status"]);
}
};Common database management errors and handling:
const request = indexedDB.open("example", 1);
request.onerror = (event) => {
const error = event.target.error;
switch (error.name) {
case "VersionError":
console.error("Invalid version number");
break;
case "InvalidStateError":
console.error("Invalid operation state");
break;
case "AbortError":
console.error("Operation was aborted");
break;
default:
console.error("Database error:", error.message);
}
};
// Handle blocked database deletion
const deleteRequest = indexedDB.deleteDatabase("example");
deleteRequest.onblocked = () => {
console.log("Database deletion blocked - connections still open");
};
deleteRequest.onsuccess = () => {
console.log("Database successfully deleted");
};