Tiny local JSON database for Node, Electron and the browser
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Browser storage adapters and presets for localStorage and sessionStorage integration. These adapters provide seamless integration with browser storage APIs while maintaining the same lowdb interface for consistent data management across environments.
Pre-configured database instances with browser storage adapters for immediate use.
/**
* Create a LowSync instance with LocalStorage adapter for persistent browser storage
* @param key - Storage key for localStorage
* @param defaultData - Default data structure
* @returns Configured LowSync instance with data pre-loaded from localStorage
*/
function LocalStoragePreset<Data>(key: string, defaultData: Data): LowSync<Data>;
/**
* Create a LowSync instance with SessionStorage adapter for session-only browser storage
* @param key - Storage key for sessionStorage
* @param defaultData - Default data structure
* @returns Configured LowSync instance with data pre-loaded from sessionStorage
*/
function SessionStoragePreset<Data>(key: string, defaultData: Data): LowSync<Data>;Usage Examples:
import { LocalStoragePreset, SessionStoragePreset } from "lowdb/browser";
// Persistent storage across browser sessions
type AppData = {
user: { id: number; name: string; preferences: object };
settings: { theme: string; language: string };
};
const defaultData: AppData = {
user: { id: 0, name: "", preferences: {} },
settings: { theme: "light", language: "en" }
};
const db = LocalStoragePreset("myapp-data", defaultData);
// Update user preferences
db.update((data) => {
data.user.name = "Alice";
data.settings.theme = "dark";
});
// Session-only storage (cleared when tab closes)
const sessionDb = SessionStoragePreset("session-data", { cart: [] });
sessionDb.update(({ cart }) => cart.push({ id: 1, name: "Product" }));Synchronous adapter for browser localStorage with automatic JSON serialization.
/**
* Sync adapter for browser localStorage with automatic JSON parsing/stringifying
* @template T - The type of data stored in localStorage
*/
class LocalStorage<T> implements SyncAdapter<T> {
constructor(key: string);
/** Read and parse data from localStorage, returns null if key doesn't exist */
read(): T | null;
/** Stringify and store data in localStorage */
write(obj: T): void;
}Usage Examples:
import { LowSync } from "lowdb";
import { LocalStorage } from "lowdb/browser";
// Direct adapter usage
const adapter = new LocalStorage<{ count: number }>("app-counter");
const db = new LowSync(adapter, { count: 0 });
// Initialize from localStorage
db.read();
// Update and persist
db.data.count++;
db.write(); // Immediately saved to localStorage
// Data persists across browser sessions
console.log(localStorage.getItem("app-counter")); // {"count":1}Synchronous adapter for browser sessionStorage with automatic JSON serialization.
/**
* Sync adapter for browser sessionStorage with automatic JSON parsing/stringifying
* @template T - The type of data stored in sessionStorage
*/
class SessionStorage<T> implements SyncAdapter<T> {
constructor(key: string);
/** Read and parse data from sessionStorage, returns null if key doesn't exist */
read(): T | null;
/** Stringify and store data in sessionStorage */
write(obj: T): void;
}Usage Examples:
import { LowSync } from "lowdb";
import { SessionStorage } from "lowdb/browser";
// Session-only storage
const adapter = new SessionStorage<string[]>("temp-notes");
const notesDb = new LowSync(adapter, []);
notesDb.read();
notesDb.data.push("Temporary note");
notesDb.write(); // Saved to sessionStorage
// Data is cleared when tab closes
console.log(sessionStorage.getItem("temp-notes")); // ["Temporary note"]Base class for browser storage adapters (not directly exported, but used internally).
/**
* Base sync adapter for browser storage APIs (localStorage/sessionStorage)
* @template T - The type of data stored
*/
class WebStorage<T> implements SyncAdapter<T> {
constructor(key: string, storage: Storage);
/** Read and parse JSON from storage, returns null if key doesn't exist */
read(): T | null;
/** Stringify and store JSON in storage */
write(obj: T): void;
}LocalStorage:
SessionStorage:
Browser storage has size limitations:
import { LocalStoragePreset } from "lowdb/browser";
try {
const db = LocalStoragePreset("large-dataset", { data: [] });
// Add large amounts of data
db.update(({ data }) => {
for (let i = 0; i < 100000; i++) {
data.push({ id: i, content: "Large content string..." });
}
});
} catch (error) {
if (error.name === "QuotaExceededError") {
console.error("Storage quota exceeded");
// Handle storage limit reached
}
}Storage is isolated by origin (protocol + domain + port):
// Each origin has separate storage
// https://app.example.com - separate storage
// https://api.example.com - separate storage
// http://app.example.com - separate storage
const db = LocalStoragePreset("shared-data", {});
// This data is only accessible from the current originLocalStorage data is shared between tabs and can be synchronized:
import { LocalStoragePreset } from "lowdb/browser";
const db = LocalStoragePreset("shared-state", { count: 0 });
// Listen for storage changes from other tabs
window.addEventListener("storage", (event) => {
if (event.key === "shared-state" && event.newValue) {
// Reload data when changed by another tab
db.read();
console.log("Data updated by another tab:", db.data);
}
});
// Update data (will trigger storage event in other tabs)
db.update((data) => {
data.count++;
});Example integration with React for reactive updates:
import { useEffect, useState } from "react";
import { LocalStoragePreset } from "lowdb/browser";
function useLocalStorageDb<T>(key: string, defaultData: T) {
const [db] = useState(() => LocalStoragePreset(key, defaultData));
const [data, setData] = useState(db.data);
useEffect(() => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === key) {
db.read();
setData({ ...db.data });
}
};
window.addEventListener("storage", handleStorageChange);
return () => window.removeEventListener("storage", handleStorageChange);
}, [db, key]);
const updateData = (updater: (data: T) => void) => {
db.update(updater);
setData({ ...db.data });
};
return [data, updateData] as const;
}
// Usage in component
function App() {
const [data, updateData] = useLocalStorageDb("app-data", { todos: [] });
const addTodo = (todo: string) => {
updateData((data) => {
data.todos.push({ id: Date.now(), text: todo, done: false });
});
};
return <div>{/* Component JSX */}</div>;
}Browser storage adapters may encounter various errors:
import { LocalStoragePreset } from "lowdb/browser";
try {
const db = LocalStoragePreset("my-data", { items: [] });
db.update(({ items }) => {
// Add large object that might exceed quota
items.push({ id: 1, largeData: "...".repeat(1000000) });
});
} catch (error) {
// Handle different storage errors
switch (error.name) {
case "QuotaExceededError":
console.error("Storage quota exceeded");
// Could implement cleanup or user notification
break;
case "SecurityError":
console.error("Storage access denied (private browsing?)");
break;
default:
console.error("Storage error:", error);
}
}
// Handle JSON parsing errors for corrupted data
try {
const db = LocalStoragePreset("potentially-corrupted", {});
db.read(); // Might fail if localStorage contains invalid JSON
} catch (error) {
if (error instanceof SyntaxError) {
console.error("Corrupted data in localStorage");
// Could clear corrupted data and reinitialize
localStorage.removeItem("potentially-corrupted");
}
}Browser storage adapters are synchronous and may block the main thread:
// For large datasets, consider batching updates
const db = LocalStoragePreset("large-dataset", { items: [] });
// Instead of multiple individual updates
// for (let i = 0; i < 1000; i++) {
// db.update(({ items }) => items.push({ id: i })); // 1000 storage writes
// }
// Use single batch update
db.update(({ items }) => {
for (let i = 0; i < 1000; i++) {
items.push({ id: i });
}
}); // 1 storage writeBrowser storage loads all data into memory. For large datasets:
Some browsers restrict storage in private/incognito mode:
function isStorageAvailable() {
try {
const test = "__storage_test__";
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch {
return false;
}
}
if (isStorageAvailable()) {
const db = LocalStoragePreset("app-data", {});
} else {
// Fallback to memory storage
const db = new LowSync(new MemorySync(), {});
}Browser storage adapters work in all modern browsers that support:
For older browser support, ensure your build process includes appropriate polyfills and transpilation.