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

@imasalygin/storage

v2.0.1

Published

A type-safe localStorage wrapper

Downloads

240

Readme

A type-safe localStorage wrapper.

Features

  • 🔒 Type-safe storage operations
  • 🛠️ Customizable serialization/deserialization
  • 🔧 Configurable storage backend
  • 📦 Zero dependencies

Installation

npm install @imasalygin/storage

Usage

Basic Usage

import { StorageItem } from '@imasalygin/storage';

interface Theme {
  mode: 'light' | 'dark';
  primaryColor: string;
}

const themeStorage = new StorageItem<Theme>({
  key: 'theme',
  value: { mode: 'light', primaryColor: '#007AFF' } // Optional default value
});

// Get current value
const theme = themeStorage.get();

// Update value
themeStorage.set({ mode: 'dark', primaryColor: '#0A84FF' });

// Remove value
themeStorage.remove();

React Integration

import { useSyncExternalStore } from 'react';
import { StorageItem } from '@imasalygin/storage';

// Create storage instance
const themeStorage = new StorageItem<Theme>({
  key: 'theme',
  value: { mode: 'light', primaryColor: '#007AFF' }
});

// Use in component
function ThemeProvider() {
  const theme = useSyncExternalStore(
    themeStorage.subscribe,
    themeStorage.get
  );

  return (
    <div style={{ background: theme.mode === 'dark' ? '#000' : '#fff' }}>
      {/* Your app content */}
    </div>
  );
}

Effector Integration

The StorageItem class implements the Observable interface, making it compatible with Effector's fromObservable:

// Tab 1
const storage = new StorageItem<Theme>({ key: 'theme' });

const $theme = createStore<Theme | null>(storage.get());
const event = fromObservable<Theme>(storage);
$theme.on(event, (_, value) => value);

// Tab 2 - Changes here will update Tab 1's store
const storage = new StorageItem<Theme>({ key: 'theme', value: null });
storage.set({ mode: 'dark', primaryColor: '#000000' });

Custom Storage Backend

You can provide a custom storage implementation that follows the Web Storage API:

import { StorageItem } from '@imasalygin/storage';

// Example: Using sessionStorage instead of localStorage
const sessionTheme = new StorageItem<Theme>({
  key: 'theme',
  value: { mode: 'light', primaryColor: '#007AFF' },
  storage: sessionStorage
});

// Example: Custom storage implementation
class CustomStorage implements Storage {
  private store = new Map<string, string>();
  
  getItem(key: string): string | null {
    return this.store.get(key) ?? null;
  }
  
  setItem(key: string, value: string): void {
    this.store.set(key, value);
  }
  
  removeItem(key: string): void {
    this.store.delete(key);
  }
  
  // ... implement other required Storage methods
}

const customTheme = new StorageItem<Theme>({
  key: 'theme',
  value: { mode: 'light', primaryColor: '#007AFF' },
  storage: new CustomStorage()
});

Custom Serialization

import { StorageItem } from '@imasalygin/storage';

const dateStorage = new StorageItem<Date>({
  key: 'lastVisit',
  value: new Date(),
  parse: (str) => new Date(str),
  stringify: (date) => date.toISOString()
});

Custom Value Comparison

The StorageItem class uses Object.is by default to compare values. You can provide a custom comparison function for more efficient updates or deep equality checks:

import { deepEqual } from 'fast-equals';

// Using deep equality for complex objects
const configStorage = new StorageItem<Config>({
  key: 'config',
  value: defaultConfig,
  equals: deepEqual // Only triggers updates when values are actually different
});

API Reference

StorageItem Class

Constructor Options

interface StorageItemOptions<T> {
  key: string;              // Storage key
  value?: T;                // Initial value
  parse?: (str: string) => T;    // Custom parse function
  stringify?: (val: T) => string; // Custom stringify function
  equals?: (a: T | null, b: T | null) => boolean; // Custom comparison function
  storage?: Storage;       // Custom storage implementation
}

The options object accepts the following properties:

  • key: The key to use in storage
  • value: Initial value
  • parse: Custom function to parse stored string into value (defaults to JSON.parse)
  • stringify: Custom function to convert value to string (defaults to JSON.stringify)
  • equals: Custom function to compare values (defaults to Object.is)
    • Used to determine if a value has changed and updates should be triggered
    • Particularly useful for complex objects or when specific fields should be ignored
    • Should handle null values as they are used when storage is empty
  • storage: Custom storage implementation (defaults to localStorage)
    • Must implement the Web Storage API interface
    • Useful for using sessionStorage or custom storage implementations

Methods

  • get(): T | null - Get current value
  • set(value: T): void - Set new value
  • remove(): void - Remove value from storage
  • subscribe(handler: (value: T | null) => void): () => void - Subscribe to changes

License

MIT