@pixagram/lacerta-db
v0.9.1
Published
Lacerta-DB is a Javascript IndexedDB Database for Web Browsers. Simple, Fast, Secure.
Maintainers
Readme
"Store your data like a lizard stores heat — efficiently, locally, and securely."
LacertaDB is a zero-dependency, browser-only document database designed for Web3 applications, offline-first PWAs, and any browser application requiring robust local storage with encryption capabilities.
Table of Contents
| Section | Description | |---------|-------------| | Features | What LacertaDB offers | | Installation | How to install | | Quick Start | Get running in 2 minutes | | Architecture | System design overview | | API Reference | Complete method documentation | | Query Operators | MongoDB-style query syntax | | Aggregation Pipeline | Data transformation stages | | Indexing | B-Tree, Hash, Text, Geo indexes | | Encryption | AES-GCM-256 security | | Caching | LRU, LFU, TTL strategies | | Migrations | Schema version management | | Performance | Metrics and optimization | | Error Codes | Error handling reference | | Examples | Real-world usage patterns |
Features
🗄️ Storage
- IndexedDB backend with connection pooling
- OPFS for binary attachments
- localStorage QuickStore for fast access
- Automatic space management
🔐 Security
- AES-GCM-256 encryption
- PBKDF2 key derivation (100k iterations)
- HMAC integrity verification
- Private key vault storage
🔍 Querying
- MongoDB-style query syntax
- 20+ operators ($eq, $gt, $in, $regex...)
- Aggregation pipeline with 7 stages
- Full-text and geospatial search
⚡ Performance
- B-Tree indexes for range queries
- LRU/LFU/TTL caching strategies
- Compression via CompressionStream
- Async mutex for thread safety
Installation
npm install @pixagram/lacertadbDependencies (installed automatically):
npm install @pixagram/turboserial @pixagram/turbobase64Quick Start
import { LacertaDB } from '@pixagram/lacertadb';
// Initialize
const lacerta = new LacertaDB();
// Get or create a database
const db = await lacerta.getDatabase('myapp');
// Create a collection
const users = await db.createCollection('users');
// Add documents
const userId = await users.add({
name: 'Alice',
email: '[email protected]',
age: 28
});
// Query documents
const results = await users.query({ age: { $gte: 18 } });
// Update
await users.update(userId, { age: 29 });
// Delete
await users.delete(userId);// Create encrypted database
const secureDb = await lacerta.getSecureDatabase('vault', '123456');
// All documents are automatically encrypted
const secrets = await secureDb.createCollection('secrets');
await secrets.add({ apiKey: 'sk-xxx-secret' });
// Change PIN (re-encrypts all data)
await secureDb.changePin('123456', 'newSecurePin!');Architecture
LacertaDB follows a fractal architecture where each layer encapsulates complexity while exposing a simple interface.
┌─────────────────────────────────────────────────────────────────┐
│ LacertaDB │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Database │ │
│ │ ┌─────────────────────────────────────────────────────┐ │ │
│ │ │ Collection │ │ │
│ │ │ ┌───────────────────────────────────────────────┐ │ │ │
│ │ │ │ Document │ │ │ │
│ │ │ │ • Data (serialized) │ │ │ │
│ │ │ │ • Metadata (_id, _created, _modified) │ │ │ │
│ │ │ │ • Attachments (OPFS references) │ │ │ │
│ │ │ └───────────────────────────────────────────────┘ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ IndexManager│ │CacheStrategy│ │ EventBus │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────┘ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │
│ │ │ QuickStore │ │ Encryption │ │ MigrationManager │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Shared Infrastructure ││
│ │ ConnectionPool │ AsyncMutex │ QueryEngine │ Serializer ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘| Component | Responsibility | Storage |
|-----------|---------------|---------|
| LacertaDB | Instance manager, backup/restore | Memory |
| Database | Collection manager, encryption, settings | localStorage |
| Collection | CRUD operations, queries, indexes | IndexedDB |
| Document | Data container, pack/unpack | IndexedDB |
| QuickStore | Fast key-value access | localStorage |
| OPFSUtility | Binary file attachments | OPFS |
User Data → Serialize → Compress → Encrypt → Store
↓
User Data ← Deserialize ← Decompress ← Decrypt ← Retrieve| Stage | Technology | Optional | |-------|------------|----------| | Serialize | TurboSerial (CBOR-like) | No | | Compress | CompressionStream (deflate) | Yes | | Encrypt | AES-GCM-256 | Yes | | Store | IndexedDB / OPFS | No |
API Reference
LacertaDB (Main Entry Point)
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| getDatabase | name, options? | Promise<Database> | Get or create database |
| getSecureDatabase | name, pin, salt?, config? | Promise<Database> | Get encrypted database |
| dropDatabase | name | Promise<void> | Delete database completely |
| listDatabases | — | string[] | List all database names |
| createBackup | password? | Promise<string> | Export all databases |
| restoreBackup | data, password? | Promise<Object> | Import backup data |
| close | — | void | Close all connections |
| destroy | — | void | Clean up all resources |
Database
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| createCollection | name, options? | Promise<Collection> | Create new collection |
| getCollection | name | Promise<Collection> | Get existing collection |
| dropCollection | name | Promise<void> | Delete collection |
| listCollections | — | string[] | List collection names |
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| verifyPin | pin | Promise<boolean> | Verify PIN is correct |
| changePin | oldPin, newPin | Promise<string> | Change PIN, re-encrypt data |
| getEncryptionStatus | — | Object | Get encryption state info |
| storePrivateKey | name, key, auth? | Promise<boolean> | Store encrypted key |
| getPrivateKey | name, auth? | Promise<string> | Retrieve decrypted key |
| listPrivateKeys | — | Promise<Array> | List stored key names |
| deletePrivateKey | name | Promise<boolean> | Delete stored key |
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| getStats | — | Object | Database statistics |
| updateSettings | settings | void | Update database settings |
| export | format?, password? | Promise<string> | Export database |
| import | data, format?, password? | Promise<Object> | Import data |
| clearAll | — | Promise<void> | Clear all collections |
| destroy | — | Promise<void> | Destroy database |
| Property | Type | Description |
|----------|------|-------------|
| name | string | Database name |
| isEncrypted | boolean | Encryption status |
| metadata | DatabaseMetadata | Size, document counts |
| settings | Settings | Configuration |
| quickStore | QuickStore | Fast localStorage access |
| performanceMonitor | PerformanceMonitor | Metrics collector |
Collection
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| add | data, options? | Promise<string> | Add document |
| get | docId, options? | Promise<Object> | Get by ID |
| getAll | options? | Promise<Array> | Get all documents |
| update | docId, updates, options? | Promise<string> | Update document |
| delete | docId, options? | Promise<void> | Delete document |
Add Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| id | string | auto | Custom document ID |
| compressed | boolean | true | Enable compression |
| permanent | boolean | false | Protect from auto-cleanup |
| attachments | Array<File\|Blob> | [] | Binary attachments |
Get Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| includeAttachments | boolean | false | Load binary attachments |
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| batchAdd | documents, options? | Promise<string[]> | Add multiple |
| batchUpdate | updates | Promise<string[]> | Update multiple |
| batchDelete | docIds | Promise<void> | Delete multiple |
// Batch add
const ids = await collection.batchAdd([
{ name: 'Alice' },
{ name: 'Bob' },
{ name: 'Charlie' }
]);
// Batch update
await collection.batchUpdate([
{ id: 'doc1', updates: { status: 'active' } },
{ id: 'doc2', updates: { status: 'active' } }
]);
// Batch delete
await collection.batchDelete(['doc1', 'doc2', 'doc3']);| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| query | filter, options? | Promise<Array> | Query documents |
| aggregate | pipeline | Promise<Array> | Run aggregation |
| count | filter? | Promise<number> | Count documents |
Query Options:
| Option | Type | Description |
|--------|------|-------------|
| sort | Object | Sort specification { field: 1 } or { field: -1 } |
| skip | number | Skip N documents |
| limit | number | Limit results |
| projection | Object | Field selection |
const results = await collection.query(
{ status: 'active', age: { $gte: 18 } },
{
sort: { createdAt: -1 },
skip: 10,
limit: 20,
projection: { name: 1, email: 1 }
}
);| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| createIndex | fieldPath, options? | Promise<string> | Create index |
| dropIndex | indexName | Promise<void> | Remove index |
| getIndexes | — | Promise<Object> | List indexes with stats |
| verifyIndexes | — | Promise<Object> | Verify index integrity |
| Method | Parameters | Returns | Description |
|--------|------------|---------|-------------|
| on | event, callback | void | Subscribe to event |
| off | event, callback? | void | Unsubscribe |
Available Events:
| Event | Payload | Description |
|-------|---------|-------------|
| beforeAdd | documentData | Before document insert |
| afterAdd | document | After document insert |
| beforeUpdate | { docId, updates } | Before update |
| afterUpdate | document | After update |
| beforeDelete | docId | Before deletion |
| afterDelete | docId | After deletion |
| beforeGet | docId | Before retrieval |
| afterGet | document | After retrieval |
collection.on('afterAdd', async (doc) => {
console.log(`Document ${doc._id} created`);
await notifyWebhook(doc);
});Query Operators
LacertaDB supports MongoDB-compatible query operators.
Comparison Operators
| Operator | Description | Example |
|----------|-------------|---------|
| $eq | Equal | { status: { $eq: 'active' } } |
| $ne | Not equal | { status: { $ne: 'deleted' } } |
| $gt | Greater than | { age: { $gt: 18 } } |
| $gte | Greater or equal | { score: { $gte: 90 } } |
| $lt | Less than | { price: { $lt: 100 } } |
| $lte | Less or equal | { qty: { $lte: 10 } } |
| $in | In array | { status: { $in: ['a', 'b'] } } |
| $nin | Not in array | { role: { $nin: ['guest'] } } |
Logical Operators
| Operator | Description | Example |
|----------|-------------|---------|
| $and | Logical AND | { $and: [{ a: 1 }, { b: 2 }] } |
| $or | Logical OR | { $or: [{ a: 1 }, { b: 2 }] } |
| $not | Logical NOT | { $not: { status: 'deleted' } } |
| $nor | Neither | { $nor: [{ a: 1 }, { b: 2 }] } |
Element Operators
| Operator | Description | Example |
|----------|-------------|---------|
| $exists | Field exists | { email: { $exists: true } } |
| $type | Type check | { age: { $type: 'number' } } |
Array Operators
| Operator | Description | Example |
|----------|-------------|---------|
| $all | Contains all | { tags: { $all: ['a', 'b'] } } |
| $elemMatch | Element match | { items: { $elemMatch: { qty: { $gt: 5 } } } } |
| $size | Array size | { tags: { $size: 3 } } |
String Operators
| Operator | Description | Example |
|----------|-------------|---------|
| $regex | Regex match | { name: { $regex: '^John' } } |
| $text | Text search | { bio: { $text: 'developer' } } |
// Find active users over 18 with verified email
const users = await collection.query({
$and: [
{ status: 'active' },
{ age: { $gte: 18 } },
{ emailVerified: { $exists: true } }
]
});
// Find products in price range with specific tags
const products = await collection.query({
$and: [
{ price: { $gte: 10, $lte: 100 } },
{ tags: { $all: ['sale', 'featured'] } },
{ category: { $in: ['electronics', 'accessories'] } }
]
});
// Text search with regex
const articles = await collection.query({
$or: [
{ title: { $regex: 'blockchain' } },
{ content: { $text: 'cryptocurrency' } }
]
});Aggregation Pipeline
Transform and analyze data using pipeline stages.
| Stage | Description | Example |
|-------|-------------|---------|
| $match | Filter documents | { $match: { status: 'active' } } |
| $project | Shape output | { $project: { name: 1, email: 1 } } |
| $sort | Order results | { $sort: { date: -1 } } |
| $limit | Limit results | { $limit: 10 } |
| $skip | Skip results | { $skip: 20 } |
| $group | Group & aggregate | { $group: { _id: '$category', count: { $count: 1 } } } |
| $lookup | Join collections | See example below |
Group Accumulators
| Accumulator | Description |
|-------------|-------------|
| $sum | Sum values |
| $avg | Average values |
| $min | Minimum value |
| $max | Maximum value |
| $count | Count documents |
// Sales report by category
const report = await orders.aggregate([
{ $match: { status: 'completed' } },
{ $group: {
_id: '$category',
totalSales: { $sum: '$amount' },
avgOrder: { $avg: '$amount' },
orderCount: { $count: 1 }
}},
{ $sort: { totalSales: -1 } },
{ $limit: 10 }
]);
// Join users with their orders
const usersWithOrders = await users.aggregate([
{ $lookup: {
from: 'orders',
localField: '_id',
foreignField: 'userId',
as: 'orders'
}},
{ $project: {
name: 1,
email: 1,
orderCount: { $size: '$orders' }
}}
]);
// Top customers this month
const topCustomers = await orders.aggregate([
{ $match: {
date: { $gte: startOfMonth }
}},
{ $group: {
_id: '$customerId',
total: { $sum: '$amount' },
orders: { $count: 1 }
}},
{ $sort: { total: -1 } },
{ $limit: 5 }
]);Indexing
Indexes dramatically improve query performance for large collections.
Index Types
| Type | Best For | Example |
|------|----------|---------|
| btree | Range queries, sorting | { type: 'btree' } |
| hash | Exact match lookups | { type: 'hash' } |
| text | Full-text search | { type: 'text' } |
| geo | Location queries | { type: 'geo' } |
Creating Indexes
// B-Tree index (default)
await collection.createIndex('email', { unique: true });
// Hash index for fast lookups
await collection.createIndex('userId', { type: 'hash' });
// Text index for search
await collection.createIndex('content', { type: 'text' });
// Geo index for locations
await collection.createIndex('location', { type: 'geo' });
// Sparse index (skip null values)
await collection.createIndex('optionalField', { sparse: true });Index Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| name | string | fieldPath | Custom index name |
| type | string | 'btree' | Index type |
| unique | boolean | false | Enforce uniqueness |
| sparse | boolean | false | Skip null/undefined |
// Create geo index
await places.createIndex('coordinates', { type: 'geo' });
// Find nearby (within 10km)
const nearby = await places.query({
coordinates: {
$near: {
coordinates: { lat: 47.3769, lng: 8.5417 },
maxDistance: 10 // kilometers
}
}
});
// Find within bounds
const inArea = await places.query({
coordinates: {
$within: {
minLat: 47.0,
maxLat: 48.0,
minLng: 8.0,
maxLng: 9.0
}
}
});Encryption
LacertaDB provides AES-GCM-256 encryption with PBKDF2 key derivation.
Security Specifications
| Parameter | Value | |-----------|-------| | Algorithm | AES-GCM-256 | | Key Derivation | PBKDF2 | | Iterations | 100,000 | | Hash | SHA-256 | | Salt Length | 32 bytes | | IV Length | 12 bytes |
Usage
// Create encrypted database
const db = await lacerta.getSecureDatabase('vault', 'mySecretPin123');
// All documents are automatically encrypted
const secrets = await db.createCollection('secrets');
await secrets.add({
apiKey: 'sk-live-xxx',
privateData: 'sensitive information'
});
// Verify PIN
const isValid = await db.verifyPin('mySecretPin123'); // true
// Change PIN (re-encrypts ALL data)
await db.changePin('mySecretPin123', 'newStrongerPin!');
// Check encryption status
const status = db.getEncryptionStatus();
// { isEncrypted: true, initialized: true, algorithm: 'AES-GCM-256', kdf: 'PBKDF2' }Private Key Vault
Store cryptographic keys securely:
// Store a private key
await db.storePrivateKey('wallet-main', privateKeyString, 'optionalAuth');
// Retrieve
const key = await db.getPrivateKey('wallet-main', 'optionalAuth');
// List stored keys
const keys = await db.listPrivateKeys();
// [{ name: 'wallet-main', createdAt: 1699..., updatedAt: null }]
// Delete
await db.deletePrivateKey('wallet-main');Caching
Configure caching to optimize read performance.
Cache Strategies
| Strategy | Description | Best For |
|----------|-------------|----------|
| lru | Least Recently Used | General purpose |
| lfu | Least Frequently Used | Hot data patterns |
| ttl | Time To Live | Expiring data |
| none | Disabled | Write-heavy workloads |
Configuration
// Configure cache per collection
collection.configureCacheStrategy({
type: 'lru', // 'lru' | 'lfu' | 'ttl' | 'none'
maxSize: 200, // Max cached items
ttl: 120000, // TTL in milliseconds
enabled: true
});
// Clear cache manually
collection.clearCache();Migrations
Manage schema changes across versions.
const migration = new MigrationManager(db);
// Define migrations
migration.addMigration({
version: '1.1.0',
name: 'Add user roles',
up: async (doc) => ({
...doc,
role: doc.role || 'user',
permissions: doc.permissions || []
}),
down: async (doc) => {
const { role, permissions, ...rest } = doc;
return rest;
}
});
migration.addMigration({
version: '1.2.0',
name: 'Normalize email',
up: async (doc) => ({
...doc,
email: doc.email?.toLowerCase()
}),
down: async (doc) => doc // No rollback needed
});
// Run migrations
await migration.runMigrations('1.2.0');
// Rollback if needed
await migration.rollback('1.0.0');Performance Monitoring
Built-in performance tracking and optimization.
// Start monitoring
lacerta.performanceMonitor.startMonitoring();
// Get statistics
const stats = lacerta.performanceMonitor.getStats();
console.log(stats);
// {
// opsPerSec: 150,
// avgLatency: '2.34',
// cacheHitRate: '87.5',
// memoryUsageMB: '45.20'
// }
// Get optimization suggestions
const tips = lacerta.performanceMonitor.getOptimizationTips();
// ['Performance is optimal. No issues detected.']
// Stop monitoring
lacerta.performanceMonitor.stopMonitoring();Error Codes
| Code | Description | Solution |
|------|-------------|----------|
| DOCUMENT_NOT_FOUND | Document doesn't exist | Verify document ID |
| COLLECTION_NOT_FOUND | Collection doesn't exist | Create collection first |
| COLLECTION_EXISTS | Collection already exists | Use getCollection instead |
| ENCRYPTION_NOT_INITIALIZED | Encryption required but not set up | Use getSecureDatabase |
| ENCRYPTION_REQUIRED | Document encrypted, db not unlocked | Unlock with correct PIN |
| INVALID_PIN | Wrong PIN provided | Verify PIN |
| NOT_ENCRYPTED | Operation requires encryption | Use encrypted database |
| PERMANENT_DOCUMENT_PROTECTION | Cannot delete permanent document | Use force: true |
| QUOTA_EXCEEDED | Storage limit reached | Free up space |
| MUTEX_TIMEOUT | Operation timed out | Retry or check deadlock |
| TRANSACTION_FAILED | IndexedDB transaction failed | Retry operation |
| INDEX_EXISTS | Index already exists | Drop existing index first |
| UNIQUE_CONSTRAINT_VIOLATION | Duplicate value in unique index | Use unique values |
Error Handling
import { LacertaDBError } from '@pixagram/lacertadb';
try {
await collection.get('nonexistent');
} catch (error) {
if (error instanceof LacertaDBError) {
console.log(error.code); // 'DOCUMENT_NOT_FOUND'
console.log(error.message); // 'Document with id...'
console.log(error.timestamp); // ISO date string
}
}Examples
const lacerta = new LacertaDB();
const db = await lacerta.getSecureDatabase('app', 'adminPin123');
// Create collections
const users = await db.createCollection('users');
const sessions = await db.createCollection('sessions');
// Create indexes
await users.createIndex('email', { unique: true });
await users.createIndex('username', { unique: true });
await sessions.createIndex('userId');
await sessions.createIndex('expiresAt');
// Register user
async function registerUser(data) {
const userId = await users.add({
...data,
email: data.email.toLowerCase(),
createdAt: Date.now(),
status: 'pending'
});
return userId;
}
// Login
async function login(email, password) {
const [user] = await users.query({
email: email.toLowerCase(),
status: 'active'
});
if (!user || !verifyPassword(password, user.passwordHash)) {
throw new Error('Invalid credentials');
}
const sessionId = await sessions.add({
userId: user._id,
createdAt: Date.now(),
expiresAt: Date.now() + 24 * 60 * 60 * 1000
});
return { user, sessionId };
}
// Cleanup expired sessions
async function cleanupSessions() {
const expired = await sessions.query({
expiresAt: { $lt: Date.now() }
});
await sessions.batchDelete(expired.map(s => s._id));
}const db = await lacerta.getDatabase('shop');
const carts = await db.createCollection('carts');
const products = await db.createCollection('products');
// Add to cart
async function addToCart(userId, productId, quantity) {
const [existing] = await carts.query({
userId,
productId
});
if (existing) {
await carts.update(existing._id, {
quantity: existing.quantity + quantity,
updatedAt: Date.now()
});
} else {
await carts.add({
userId,
productId,
quantity,
addedAt: Date.now()
});
}
}
// Get cart with product details
async function getCart(userId) {
const cartItems = await carts.query({ userId });
const enriched = await Promise.all(
cartItems.map(async (item) => {
const product = await products.get(item.productId);
return {
...item,
product,
subtotal: product.price * item.quantity
};
})
);
return {
items: enriched,
total: enriched.reduce((sum, i) => sum + i.subtotal, 0)
};
}
// Cart analytics
async function getCartAnalytics() {
return await carts.aggregate([
{ $group: {
_id: '$productId',
totalQuantity: { $sum: '$quantity' },
cartCount: { $count: 1 }
}},
{ $sort: { totalQuantity: -1 } },
{ $limit: 10 }
]);
}const db = await lacerta.getDatabase('geo');
const places = await db.createCollection('places');
// Create geo index
await places.createIndex('location', { type: 'geo' });
await places.createIndex('name', { type: 'text' });
// Add place
async function addPlace(data) {
return await places.add({
name: data.name,
location: { lat: data.lat, lng: data.lng },
category: data.category,
rating: data.rating || 0,
createdAt: Date.now()
});
}
// Find nearby restaurants
async function findNearbyRestaurants(lat, lng, radiusKm = 5) {
return await places.query({
location: {
$near: {
coordinates: { lat, lng },
maxDistance: radiusKm
}
},
category: 'restaurant'
}, {
sort: { rating: -1 }
});
}
// Search places by name
async function searchPlaces(query, bounds) {
return await places.query({
$and: [
{ name: { $text: query } },
{ location: { $within: bounds } }
]
});
}const db = await lacerta.getSecureDatabase('wallet', userPin);
// Store wallet keys
async function storeWallet(walletName, privateKey, mnemonic) {
await db.storePrivateKey(`${walletName}-key`, privateKey);
await db.storePrivateKey(`${walletName}-mnemonic`, mnemonic);
// Store metadata (not the actual keys)
const wallets = await db.getCollection('wallets');
await wallets.add({
name: walletName,
address: deriveAddress(privateKey),
createdAt: Date.now()
}, { id: walletName, permanent: true });
}
// Sign transaction
async function signTransaction(walletName, tx) {
const privateKey = await db.getPrivateKey(`${walletName}-key`);
return signWithKey(tx, privateKey);
}
// Export wallet (encrypted)
async function exportWallet(walletName, exportPassword) {
const privateKey = await db.getPrivateKey(`${walletName}-key`);
const mnemonic = await db.getPrivateKey(`${walletName}-mnemonic`);
const wallets = await db.getCollection('wallets');
const metadata = await wallets.get(walletName);
return await db.export('encrypted', exportPassword);
}QuickStore
For simple, fast key-value access using localStorage:
const quick = db.quickStore;
// CRUD operations
quick.add('user-pref', { theme: 'dark', language: 'en' });
const prefs = quick.get('user-pref');
quick.update('user-pref', { ...prefs, theme: 'light' });
quick.delete('user-pref');
// Query (supports same operators as Collection)
const results = quick.query({ theme: 'dark' });
// Get all
const all = quick.getAll();
// Clear
quick.clear();
// Size
console.log(quick.size); // number of items⚠️ Note: QuickStore uses localStorage which has ~5-10MB limit. Use Collections for larger datasets.
Browser Compatibility
| Browser | IndexedDB | OPFS | CompressionStream | |---------|-----------|------|-------------------| | Chrome 86+ | ✅ | ✅ | ✅ | | Firefox 111+ | ✅ | ✅ | ✅ | | Safari 15.4+ | ✅ | ⚠️ Partial | ✅ | | Edge 86+ | ✅ | ✅ | ✅ |
License
MIT © Pixagram SA
