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

@bwt-st/storage

v0.2.1

Published

Framework-agnostic browser storage client for BWT-ST projects.

Downloads

229

Readme

@bwt-st/storage

无框架浏览器存储库,支持 localStorage、sessionStorage、内存存储和自定义适配器,并提供命名空间、版本隔离、JSON 序列化和 TTL 过期控制。

安装

pnpm add @bwt-st/storage

快速使用

建议在业务项目的基础设施层只创建一次实例并统一导出,使 namespace、version、驱动和序列化规则保持一致:

// src/services/storage.ts
import { createLocalStorage } from '@bwt-st/storage'

export const storage = createLocalStorage({
  namespace: 'bwt-admin',
  version: 1,
})

业务模块直接复用实例:

import { storage } from '@/services/storage'

storage.set('user', { id: 1, name: 'Ada' })
const user = storage.get<{ id: number; name: string }>('user')

创建函数

| 函数 | 说明 | | -------------------------------- | ------------------------------------------ | | createLocalStorage(options?) | 创建浏览器 localStorage 客户端。 | | createSessionStorage(options?) | 创建浏览器 sessionStorage 客户端。 | | createMemoryStorage(options?) | 创建内存客户端,适合 SSR、测试和临时数据。 | | createStorage(options) | 使用自定义适配器创建客户端。 |

浏览器驱动会在第一次读写时获取浏览器对象,因此可以在 SSR 模块顶层创建实例;但 SSR 环境实际读写时会抛出 StorageUnavailableError。SSR 和测试环境应使用 createMemoryStorage。

创建配置

interface BrowserStorageOptions {
  namespace?: string
  version?: string | number
  serializer?: StorageSerializer
  now?: () => number
}

interface StorageOptions extends BrowserStorageOptions {
  adapter: StorageAdapter | (() => StorageAdapter)
}

| 配置 | 默认值 | 说明 | | ------------ | ----------------------- | ---------------------------------------- | | namespace | bwt-st | 物理键命名空间,不能为空且不能包含 :。 | | version | 1 | 数据版本,不能为空且不能包含 :。 | | serializer | jsonSerializer | 自定义序列化器。 | | now | Date.now | 当前时间函数,主要用于测试。 | | adapter | 必填(createStorage) | Web Storage 兼容适配器或延迟创建函数。 |

物理键格式为 <namespace>:v<version>:<key>。例如 bwt-admin:v1:user。不同命名空间或版本相互隔离,clear() 只清理当前命名空间和版本,不会自动删除旧版本数据。

客户端 API

interface StorageClient {
  get<T>(key: string): T | null
  set<T>(key: string, value: T, options?: SetOptions): void
  has(key: string): boolean
  remove(key: string): void
  keys(): string[]
  clear(): void
}

interface SetOptions {
  ttl?: number
}
  • get<T>(key):读取值。键不存在或已过期时返回 null。
  • set<T>(key, value, options?):写入值;ttl 单位为毫秒,必须是非负有限数值,0 表示立即过期。
  • has(key):判断键是否存在且未过期,可区分“存储的值为 null”和“键不存在”。
  • remove(key):删除当前命名空间和版本下的指定键。
  • keys():返回当前命名空间和版本下所有未过期的逻辑键名。
  • clear():清理当前命名空间和版本下的全部数据。
storage.set('preferences', { theme: 'dark' })
storage.set('toast', '保存成功', { ttl: 5_000 })

storage.has('preferences') // true
storage.get<{ theme: string }>('preferences')
storage.keys() // ['preferences', 'toast']
storage.remove('toast')

常见场景

登录态

export function saveToken(token: string) {
  storage.set('access-token', token)
}

export function getToken() {
  return storage.get<string>('access-token')
}

export function clearAuth() {
  storage.remove('access-token')
  storage.remove('current-user')
}

HTTP 客户端可以从同一个实例读取 Token:

import { createHttpClient } from '@bwt-st/http'

const http = createHttpClient({
  baseURL: '/api',
  hooks: {
    getAccessToken: () => storage.get<string>('access-token'),
  },
})

用户偏好和临时草稿

主题、语言、表格分页大小等低敏感偏好适合持久化;提示、验证码状态和表单草稿可以设置 TTL:

storage.set('preferences', {
  theme: 'dark',
  locale: 'zh-CN',
  pageSize: 20,
})

storage.set('order-draft', draft, {
  ttl: 24 * 60 * 60 * 1000,
})

应用和版本隔离

不同应用使用不同命名空间;数据结构发生不兼容变化时提升版本:

const adminStorage = createLocalStorage({
  namespace: 'bwt-admin',
  version: 2,
})

const portalStorage = createLocalStorage({
  namespace: 'bwt-portal',
  version: 1,
})

自定义适配器和序列化器

interface StorageAdapter {
  readonly length: number
  clear(): void
  getItem(key: string): string | null
  key(index: number): string | null
  removeItem(key: string): void
  setItem(key: string, value: string): void
}

interface StorageSerializer {
  serialize(value: unknown): string
  deserialize<T>(value: string): T
}

createStorage 可以接收任意实现了 StorageAdapter 的对象。默认的 jsonSerializer 适合普通 JSON 数据,也可以注入业务自己的稳定编码协议。

错误和边界行为

| 错误 | 触发场景 | | --------------------------- | ---------------------------------------- | | StorageError | 存储操作失败的基类。 | | StorageUnavailableError | 当前环境无法使用指定驱动。 | | StorageQuotaError | 浏览器存储空间不足。 | | StorageSerializationError | 数据无法序列化、反序列化或记录格式无效。 |

存储值默认必须能被 JSON 稳定序列化。函数、Symbol、顶层 undefined 和循环引用会失败。不要将密码、私钥等高敏感信息直接存入浏览器存储。Cookie、IndexedDB、跨标签页订阅和数据迁移不属于当前版本范围。

运行环境

  • Node.js >=20.19.0
  • 浏览器环境需要可用的 Web Storage API
  • SSR、单元测试和临时数据使用 createMemoryStorage
  • 详细 API 与场景示例可参阅仓库的 docs/storage/index.md