npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

localspace

v1.1.0

Published

A library that unifies the APIs of IndexedDB, localStorage and other storage types into a consistent API

Readme

localspace

Node CI npm license

localspace — modern storage toolkit that keeps localForage compatibility while using async/await, TypeScript, and zero legacy baggage.

Motivation

The industry still leans on localForage's familiar API, yet modern apps crave stronger typing, async ergonomics, and multi-platform reliability without a painful rewrite. localspace exists to bridge that gap: it honors the old contract while delivering first-class TypeScript types, native async/await, reliable IndexedDB cleanup, and a clean driver architecture.

Why rebuild instead of fork? Starting fresh let us eliminate technical debt while maintaining API compatibility. Teams can migrate from localForage without changing application code, then unlock better developer experience and future extensibility.

Quick Start

Get started in 5 minutes:

1. Install

npm install localspace
# or: yarn add localspace / pnpm add localspace

2. Basic Usage

import localspace from 'localspace';

// Store and retrieve data
await localspace.setItem('user', { name: 'Ada', role: 'admin' });
const user = await localspace.getItem<{ name: string; role: string }>('user');

// TypeScript generics for type safety
interface User {
  name: string;
  role: string;
}
const typedUser = await localspace.getItem<User>('user');

3. Create Isolated Instances

const cache = localspace.createInstance({
  name: 'my-app',
  storeName: 'cache',
});

await cache.setItem('token', 'abc123');

4. Batch Operations

// Write multiple items in one transaction (IndexedDB)
await localspace.setItems([
  { key: 'user:1', value: { name: 'Ada' } },
  { key: 'user:2', value: { name: 'Grace' } },
]);

// Read multiple items
const users = await localspace.getItems(['user:1', 'user:2']);

5. Use Plugins

import localspace, { ttlPlugin, encryptionPlugin } from 'localspace';

const secureStore = localspace.createInstance({
  name: 'secure',
  plugins: [
    ttlPlugin({ defaultTTL: 60_000 }), // Auto-expire after 1 minute
    encryptionPlugin({ key: 'your-32-byte-key' }), // Encrypt data
  ],
});

That's it! For more details, see the sections below.


Table of Contents


Installation

npm install localspace
# or
yarn add localspace
# or
pnpm add localspace
import localspace from 'localspace';

Bundles included: ES modules, CommonJS, UMD, plus .d.ts files.


Core API

Storage Methods

// Set and get items
await localspace.setItem('key', value);
const value = await localspace.getItem<T>('key');

// Remove items
await localspace.removeItem('key');
await localspace.clear();

// Query
const count = await localspace.length();
const keys = await localspace.keys();

// Iterate
await localspace.iterate<T, void>((value, key, index) => {
  console.log(key, value);
});

Callbacks (Legacy Support)

localspace.getItem('user', (error, value) => {
  if (error) return console.error(error);
  console.log(value);
});

Driver Selection

// Web fallback order (default bundled drivers)
await localspace.setDriver([localspace.INDEXEDDB, localspace.LOCALSTORAGE]);

// Check current driver
console.log(localspace.driver());
// 'asyncStorage' | 'localStorageWrapper'

React Native AsyncStorage

import AsyncStorage from '@react-native-async-storage/async-storage';
import localspace from 'localspace';
import { createReactNativeInstance } from 'localspace/react-native';

const mobileStore = await createReactNativeInstance(localspace, {
  name: 'myapp',
  storeName: 'kv',
  reactNativeAsyncStorage: AsyncStorage,
});

The default localspace entry does not bundle the React Native driver; it is included only when importing localspace/react-native. Explicit reactNativeAsyncStorage injection is recommended.

Advanced usage is still available:

import localspace from 'localspace';
import { installReactNativeAsyncStorageDriver } from 'localspace/react-native';

await installReactNativeAsyncStorageDriver(localspace);
await localspace.setDriver(localspace.REACTNATIVEASYNCSTORAGE);

Integration smoke (official AsyncStorage Jest mock):

yarn test:rn:integration

See integration/react-native-jest/README.md for details.

GitHub Actions Detox workflow template (real simulator/emulator runtime):

  • Workflow: .github/workflows/detox-mobile.yml
  • Fixture app folder: integration/react-native-detox/
  • Fixture README: integration/react-native-detox/README.md

📖 Full API Reference: docs/api-reference.md


Batch Operations

Use batch APIs for better performance with IndexedDB:

// Single transaction write
await localspace.setItems([
  { key: 'user:1', value: { name: 'Ada' } },
  { key: 'user:2', value: { name: 'Lin' } },
]);

// Ordered bulk read
const result = await localspace.getItems(['user:1', 'user:2']);
// [{ key: 'user:1', value: {...} }, { key: 'user:2', value: {...} }]

// Single transaction delete
await localspace.removeItems(['user:1', 'user:2']);

Transactions

For atomic multi-step operations:

await localspace.runTransaction('readwrite', async (tx) => {
  const current = (await tx.get<number>('counter')) ?? 0;
  await tx.set('counter', current + 1);
  await tx.set('lastUpdated', Date.now());
});

Coalesced Writes

Opt-in automatic batching of rapid writes for 3-10x performance improvement:

const store = localspace.createInstance({
  coalesceWrites: true, // Enable (default: false)
  coalesceWindowMs: 8, // 8ms merge window
});

// These are automatically batched into one transaction
await Promise.all([
  store.setItem('a', 1),
  store.setItem('b', 2),
  store.setItem('c', 3),
]);

Consistency modes:

  • 'strong' (default): Reads flush pending writes first
  • 'eventual': Reads may see stale values briefly
// Get performance stats
const stats = localspace.getPerformanceStats?.();
// { totalWrites: 150, coalescedWrites: 120, transactionsSaved: 100 }

Plugin System

localspace ships with a powerful plugin engine:

import localspace, {
  ttlPlugin,
  compressionPlugin,
  encryptionPlugin,
  syncPlugin,
  quotaPlugin,
} from 'localspace';

const store = localspace.createInstance({
  name: 'secure-store',
  plugins: [
    ttlPlugin({ defaultTTL: 60_000 }), // Auto-expire
    compressionPlugin({ threshold: 1024 }), // Compress > 1KB
    encryptionPlugin({ key: '32-byte-key-here' }), // Encrypt
    syncPlugin({ channelName: 'my-app' }), // Multi-tab sync
    quotaPlugin({ maxSize: 5 * 1024 * 1024 }), // 5MB limit
  ],
  pluginErrorPolicy: 'strict', // Recommended for encryption
});

Built-in Plugins

| Plugin | Purpose | | --------------- | ---------------------------------------------------- | | TTL | Auto-expire items with { data, expiresAt } wrapper | | Encryption | AES-GCM encryption via Web Crypto API | | Compression | LZ-string compression for large values | | Sync | Multi-tab synchronization via BroadcastChannel | | Quota | Storage limit enforcement with LRU eviction |

📖 Full Plugin Documentation: docs/plugins.md 📖 Real-World Examples: docs/examples.md


Configuration

const store = localspace.createInstance({
  // Database
  name: 'myapp', // Database name
  storeName: 'data', // Store name
  version: 1, // Schema version

  // Driver
  driver: [localspace.INDEXEDDB, localspace.LOCALSTORAGE],

  // IndexedDB performance
  durability: 'relaxed', // 'relaxed' (fast) or 'strict'
  prewarmTransactions: true, // Pre-warm connection

  // Batching
  maxBatchSize: 200, // Split large batches
  coalesceWrites: false, // Merge rapid writes

  // Plugins
  plugins: [],
  pluginErrorPolicy: 'lenient', // 'strict' for encryption
});
// React Native one-step instance
import localspace from 'localspace';
import { createReactNativeInstance } from 'localspace/react-native';

const mobileStore = await createReactNativeInstance(localspace, {
  name: 'myapp',
  storeName: 'data',
  reactNativeAsyncStorage: AsyncStorage,
});

📖 Full Configuration Options: docs/api-reference.md#configuration-options


Performance Notes

  • Batch APIs outperform loops: setItems() ~6x faster, getItems() ~7.7x faster than per-item loops
  • Coalesced writes: 3-10x faster under write bursts (opt-in)
  • Transaction helpers: runTransaction() for atomic migrations
  • IndexedDB durability: Chrome 121+ uses relaxed durability by default
  • localStorage batches are non-atomic: Prefer IndexedDB for atomic operations

Troubleshooting

| Issue | Solution | | --------------------------- | ------------------------------------------------------ | | Driver not ready | Call await localspace.ready() before first operation | | Quota errors | Check error.code === 'QUOTA_EXCEEDED' | | Plugin errors swallowed | Set pluginErrorPolicy: 'strict' | | Stale reads with coalescing | Use coalesceReadConsistency: 'strong' (default) |

Errors are LocalSpaceError with code, details, and cause properties.


Compatibility

  • Browsers: Modern Chromium/Edge, Firefox, Safari
  • Drivers: IndexedDB (primary), localStorage
  • React Native: AsyncStorage driver available via localspace/react-native opt-in entry
  • WebSQL: Not supported (migrate to IndexedDB)
  • Node/SSR: Custom driver required

Documentation

| Document | Description | | -------------------------------------------- | ------------------------------------- | | API Reference | Complete method documentation | | Plugin System | Built-in plugins & custom development | | Real-World Examples | Production-ready code patterns | | Migration Guide | Upgrading from localForage |


Roadmap

Complete ✅

  • [x] IndexedDB and localStorage drivers
  • [x] React Native AsyncStorage driver
  • [x] Full localForage API parity
  • [x] TypeScript-first implementation
  • [x] Batch operations & write coalescing
  • [x] Plugin system (TTL, Encryption, Compression, Sync, Quota)

Coming Soon

  • [ ] OPFS driver (Origin Private File System)
  • [ ] Node.js (File system, SQLite)
  • [ ] React Native SQLite driver
  • [ ] Deno (Native KV store)

License

MIT