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

storage-namespaced

v1.0.0

Published

A typescript library that maintains all items in a single object that is a value of a Storage implementation (localStorage, sessionStorage, etc.)

Readme

Storage Namespaced

A TypeScript library that provides a namespaced, Map-like API for any Storage implementation (like localStorage or sessionStorage). It stores typed JSON-compatible values within a single JSON object under a specific namespace key.

Features

  • Typed Values: Store numbers, booleans, strings, arrays, objects, and null — no manual JSON.stringify/JSON.parse needed.
  • Namespacing: Keeps the global storage clean by grouping all items into a single JSON blob under one namespace key.
  • Type Safe: TypeScript generic support for defining typed storage keys.
  • Auto-Save: Automatically persist changes to the underlying storage or toggle it for performance.
  • Cross-Tab Sync: Automatically syncs in-memory data across browser tabs via the storage event. No configuration needed.
  • Resilience: Gracefully handle or reset corrupted storage data.

Installation

npm install storage-namespaced

Quick Start

Usage with Schema

import { StorageNamespaced } from 'storage-namespaced';

type MySchema = {
	theme: string;
	count: number;
	tags: string[];
};

const storage = new StorageNamespaced<MySchema>({
	namespace: 'my-app-settings',
	storage: localStorage
});

storage.setItem('theme', 'dark');
storage.setItem('count', 42);
storage.setItem('tags', ['important', 'pinned']);

const theme = storage.getItem('theme'); // "dark"
const count = storage.getItem('count'); // 42 (number)
const tags = storage.getItem('tags');   // ['important', 'pinned']

console.log(storage.length); // 3
storage.removeItem('count');

Schema values are constrained to JSON-compatible types — Function, Symbol, Map, and other non-serializable types will be rejected by TypeScript.

Usage without Schema

If you don't provide a type argument, the storage accepts any JSON-compatible key-value pairs:

const storage = new StorageNamespaced({
	namespace: 'my-app-data',
	storage: localStorage
});

storage.setItem('anything', 'value');
storage.setItem('count', 42);
storage.setItem('tags', ['a', 'b']);

const val = storage.getItem('count'); // JSONCompatible | null

Without a schema, getItem returns JSONCompatible | null and keys are not constrained at compile time.

Usage with Partial Schema (Extra Keys Allowed)

If you want typed keys for some items while still allowing arbitrary extra keys, use an intersection with an index signature:

type MySchema = {
	theme: string;
	count: number;
	tags: string[];
} & Record<string, any>;

const storage = new StorageNamespaced<MySchema>({
	namespace: 'my-app-settings',
	storage: localStorage
});

storage.getItem('theme');       // string | null
storage.getItem('count');       // number | null
storage.getItem('unknown-key'); // any | null (allowed)

Known keys return their specific types. Any extra key compiles without error.

API Reference

new StorageNamespaced(options)

Creates a new namespaced storage instance. If an instance already exists for the given namespace and storage, that instance is returned and its configuration is updated to match the new options.

  • namespace: The unique key used to store the namespaced data.
  • storage: The storage implementation to use (e.g., localStorage, sessionStorage).
  • autoSave (default: true): Automatically persist to storage on every change.
    • Performance Tip: Disable this for batch updates (e.g., in a loop) to avoid redundant JSON.stringify and disk write operations. Call .save() manually when finished.
  • resetInvalidStorage (default: true): If existing data is corrupted, reset to an empty object instead of throwing.

.length

A read-only property that returns the number of items in the namespace.

.getItem(key)

Returns the typed value for the key, or null if the key does not exist.

.setItem(key, value)

Sets the value for the specified key and persists it (if autoSave is true). Values can be any JSON-compatible type: string, number, boolean, null, arrays, or plain objects. Non-serializable values (function, Symbol, bigint, undefined, NaN, Infinity, circular references, class instances) throw TypeError.

Performance Note: For batch operations (setting 50+ keys) or large storage blobs (>100KB), disable autoSave and call .save() manually once to avoid redundant JSON.stringify calls.

.removeItem(key)

Removes the specified element from storage.

.key(index)

Returns the name of the nth key in the namespace, or null if the index is out of bounds.

.clear()

Removes all elements from the namespace.

.toObject()

Returns a deep clone of the entire namespaced storage object as a null-prototype object.

.load()

Loads the data from the underlying storage into the in-memory cache.

.save()

Manually persists the current internal state to the storage implementation.

.enableAutoSave()

Enables automatic persistence to storage and immediately saves if there are pending changes.

.disableAutoSave()

Disables automatic persistence to storage. Useful for performing batch updates to avoid redundant write operations.

Differences from Native Storage

While StorageNamespaced provides a similar API to native Storage, there are key architectural differences:

| Feature | Native Storage (localStorage) | StorageNamespaced | | :--- | :--- | :--- | | Value Types | All values coerced to strings. | Typed JSON-compatible values (strings, numbers, booleans, arrays, objects, null). | | Storage Structure | Multiple global keys in the storage area. | A single JSON blob under one namespace key. | | Persistence | Synchronous and immediate. | Synchronous. Can be immediate (autoSave) or manual. | | Shadowing Protection | Exotic: Methods and length cannot be shadowed. | Exotic: Mimics native parity (Interface-First). | | Instance Registry | Globals always available. | Singleton: same instance per namespace/storage pair. | | Memory | Handled by the browser engine. | Maintains an in-memory cache for performance. | | Key Ordering | Integer-like keys sorted first. | Uses Map (insertion order). Numeric keys reordered after save+load cycle (JSON.parse Object.keys limitation). | | __proto__ in Reflection | Included in Object.keys(), Object.getOwnPropertyNames(), Reflect.ownKeys(). | Excluded from Object.keys(), Object.getOwnPropertyNames(), Reflect.ownKeys() for prototype pollution safety. |

Cross-Tab Synchronization

When data is persisted to storage in one tab (via save() or autoSave), the browser fires a storage event in other tabs. StorageNamespaced listens for this event internally to keep its in-memory cache in sync. Note that with autoSave: false, changes are in-memory only until save() is called — other tabs won't see them until then. Sync is only available in browser environments (not Web Workers).

To react to changes from other tabs in your UI, listen for the storage event:

const NAMESPACE = 'my-app-settings';

window.addEventListener('storage', (e) => {
	if (e.key === NAMESPACE) {
		const theme = storage.getItem('theme') || 'dark';
		applyTheme(theme);
	}
});