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

@tni/cache

v2.0.0

Published

localStorage、sessionStorage、Cookies、IndexedDB 统一封装

Readme

@tni/cache

浏览器缓存能力的统一封装,覆盖 localStoragesessionStorageCookieIndexedDB,并补齐过期时间、加解密和空间估算能力。

适用场景

  • 登录态、偏好设置、本地草稿缓存
  • 需要统一 TTL 和序列化行为的前端项目
  • 需要在不同存储后端之间切换但不想改业务调用方式

安装

vp add @tni/cache

快速开始

import { createLocalStorage } from "@tni/cache";

const storage = createLocalStorage({
  prefix: "admin:",
  defaultTtl: 300,
});

await storage.set("user", { id: 1, name: "duan" });
const user = await storage.get("user");
await storage.remove("user");

存储实现

| 实现 | 工厂函数 | 说明 | | --------------- | -------------------------- | -------------------------- | | Local Storage | createLocalStorage() | 持久化、同步接口、同源共享 | | Session Storage | createSessionStorage() | 会话级缓存 | | Cookie | createCookieStorage() | 适合简单键值和服务端协同 | | IndexedDB | createIndexedDBStorage() | 大容量、异步场景 |

过期时间

await storage.set("token", "xxx", { ttl: 3600 });
await storage.set("profile", data, {
  expires: new Date(Date.now() + 24 * 60 * 60 * 1000),
});

加解密

import { createEncryptor } from "@tni/cache";

const cipher = await createEncryptor("my-passphrase");
const secureStorage = createLocalStorage({ prefix: "secure:", cipher });
await secureStorage.set("secret", "sensitive");

也可以接入业务自己的加解密实现:

const storage = createLocalStorage({
  cipher: {
    encrypt: async (raw) => myEncrypt(raw),
    decrypt: async (raw) => myDecrypt(raw),
  },
});

空间与异常处理

import { estimateQuota, formatBytes, StorageQuotaExceededError } from "@tni/cache";

const quota = await estimateQuota();
if (quota) {
  console.log(formatBytes(quota.usage), formatBytes(quota.quota));
}

try {
  await storage.set("large", hugePayload);
} catch (error) {
  if (error instanceof StorageQuotaExceededError) {
    console.error("缓存空间不足");
  }
}

设计约定

  • 所有实现都统一走字符串存储
  • 复杂值先序列化,再按需加密
  • 读取时先判断是否过期,再解密、反序列化
  • 调用接口统一为异步,业务侧切换存储后端时无需改调用方式

导出

  • 存储工厂:createLocalStoragecreateSessionStoragecreateCookieStoragecreateIndexedDBStorage
  • 加解密:createEncryptorcreateBase64Cipher
  • 配额工具:estimateQuotaformatBytesisQuotaExceededError
  • 错误类型:StorageQuotaExceededError

API 速查

存储工厂

  • createLocalStorage(options?)
  • createSessionStorage(options?)
  • createCookieStorage(options?)
  • createIndexedDBStorage(options?)

它们都会返回统一风格的异步存储接口,常用方法包括:

  • get(key)
  • set(key, value, options?)
  • remove(key)
  • clear()

加解密工具

  • createEncryptor(passphrase)
  • createBase64Cipher()

适合快速给存储层补一层对称加密或轻量编码。

配额工具

  • estimateQuota(): 获取浏览器当前源估算配额
  • formatBytes(bytes): 格式化字节数
  • isQuotaExceededError(error): 判断是否为空间不足错误

关键配置项

BaseStorageOptions

  • prefix: key 前缀
  • defaultTtl: 默认过期秒数
  • serialize / deserialize: 自定义序列化方案
  • cipher / encrypt / decrypt: 自定义加解密
  • isAvailable: 当前存储实现是否可用

SetOptions

  • ttl: 相对过期秒数
  • expires: 绝对过期时间

边界与限制

  • 这是浏览器缓存抽象,不适合作为服务端通用缓存方案
  • 不同浏览器的配额和异常细节并不完全一致,空间检测只能做到尽量统一
  • 加解密只负责数据保护,不负责密钥管理
  • Cookie 后端天然不适合大对象和高频复杂读写

验证建议

  • 改动 TTL 逻辑后,重点验证过期读写行为
  • 改动加解密后,重点验证序列化和逆向解密链路
  • 改动不同存储实现时,至少验证 set/get/remove/clear