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

mv3-storage

v1.0.0

Published

Chrome extension storage wrapper for Manifest V3 (MV3) — type-safe chrome.storage with defaults, subscriptions, and atomic updates. Zero dependencies, fully typed.

Readme

mv3-storage

Chrome extension storage wrapper for Manifest V3 (MV3) — a type-safe wrapper over chrome.storage with defaults, atomic updates, and typed subscriptions. Works with local, sync, and session areas. Zero dependencies.

interface MyStore {
  count: number;
  user: { id: string; name: string } | null;
  prefs: { theme: "light" | "dark"; lang: string };
}

import { createStorage } from "mv3-storage";

const store = createStorage<MyStore>({
  area: "local",
  defaults: {
    count: 0,
    user: null,
    prefs: { theme: "light", lang: "en" },
  },
});

const count = await store.get("count");                 // typed: number
await store.set("user", { id: "1", name: "Ada" });      // typed: User | null
await store.update("count", (n) => n + 1);              // typed: number → number
const all = await store.getAll();                       // typed: MyStore

const off = store.subscribe("user", (next, prev) => {
  console.log("user changed", prev, "→", next);
});

Why

chrome.storage.local.get returns Promise<unknown>. Reading anything back means casting or hand-rolling type assertions on every call site. This package wraps the API with a single typed schema, automatic defaults, atomic update(key, fn), and a properly-typed subscription API.

Install

pnpm add mv3-storage
# or: npm i mv3-storage
# or: yarn add mv3-storage

Usage

Declare your schema

// src/shared/store.ts
import { createStorage } from "mv3-storage";

export interface AppStore {
  authToken: string | null;
  recentSearches: string[];
  preferences: { theme: "light" | "dark"; notifications: boolean };
}

export const store = createStorage<AppStore>({
  area: "sync",  // or "local" or "session"
  defaults: {
    authToken: null,
    recentSearches: [],
    preferences: { theme: "light", notifications: true },
  },
});

Use it anywhere

import { store } from "@/shared/store";

const token = await store.get("authToken");                  // string | null
await store.set("authToken", "xyz");
await store.update("recentSearches", (arr) => [...arr, "react", "vite"].slice(-10));

// React to changes
const off = store.subscribe("preferences", (next) => {
  document.body.dataset.theme = next.theme;
});

API

createStorage<S>(options) → Storage<S>

| Option | Type | Default | Notes | | --- | --- | --- | --- | | area | "local" \| "sync" \| "session" | "local" | Which chrome.storage area to use. | | defaults | S | required | Returned when a key has no stored value. Defines the schema's keys. |

Storage<S>

| Method | Returns | Notes | | --- | --- | --- | | get(key) | Promise<S[K]> | Returns the default when no value is stored. | | set(key, value) | Promise<void> | | | update(key, fn) | Promise<S[K]> | fn receives the current value and returns (or resolves to) the next. | | remove(key) | Promise<void> | Subsequent get returns the default. | | getAll() | Promise<S> | All keys merged with defaults. | | clear() | Promise<void> | Clears the entire area — including keys not in your schema. Use carefully. | | subscribe(key, fn) | () => void | Notified on every change to key in the chosen area. | | subscribeAll(fn) | () => void | Notified once per change batch with a Partial<S> of the new values. |

Storage area choice

| Area | Persistence | Quota | Notes | | --- | --- | --- | --- | | local | Until uninstall | ~10 MB | Per-device. The usual choice. | | sync | Synced via Google account | ~100 KB | Smaller quota; synced across devices. | | session | Cleared on browser restart | ~10 MB | In-memory; useful for ephemeral state. MV3-only. |

Caveat: update is not lock-protected

store.update(key, fn) reads, calls fn, then writes. If two callers race on the same key, the second wins. For most extension use cases this is fine (popup-only edits, single-SW writes); for genuinely concurrent writes, do the merge in your handler.

Demo extension

A runnable demo lives in example/. The popup edits a typed counter and preference settings; changes persist across popup re-opens and surface in the SW console via subscribe.

cd example
pnpm install
pnpm build
# then load example/dist/ via chrome://extensions → "Load unpacked"

See example/README.md for full instructions.

Related packages

Part of a small MV3 toolkit for Chrome / Edge / Firefox extensions by @graybearo:

License

MIT — see LICENSE.