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

fxxy-indexeddb

v0.0.1

Published

indexedDB 封装:支持动态升级 stores、空闲自动关闭、批量原子操作

Readme

fxxy-indexeddb

IndexedDB 操作工具类(支持动态升级 stores),提供增删改查及数据库结构升级能力。

license

特性

  • Promise 化 API:所有方法返回 Promise,原生支持 async/await
  • 动态结构升级:通过 upgradeDB 在版本升级时创建新的 store / 索引
  • 跨标签页安全:监听 onversionchange,其他标签页升级时自动让出连接,避免阻塞
  • 空闲自动关闭:可配置 idleTimeout,长时间无操作自动关闭连接释放资源
  • 懒打开:CRUD 方法自动保证连接已建立,无需手动 openDB
  • 批量原子操作:bulkSave 单事务执行,任一失败则整体 reject
  • 索引范围查询:queryByIndex 支持 IDBKeyRange 与数量限制
  • 零依赖:纯原生 IndexedDB 封装,体积小
  • 同构兼容:UMD 风格,CommonJS / ESM / 浏览器全局均可引入

安装

npm

npm install fxxy-indexeddb

yarn / pnpm

yarn add fxxy-indexeddb
# 或
pnpm add fxxy-indexeddb

引入方式

ES Modules(推荐)

import IndexedDBHelper from 'fxxy-indexeddb';

CommonJS

const IndexedDBHelper = require('fxxy-indexeddb');

浏览器直接引入(UMD)

通过 <script> 引入后,类挂载到全局 window.IndexedDBHelper。CDN 默认指向压缩版 dist/index.min.js(约 3.5KB):

<!-- CDN(推荐,自动使用压缩版) -->
<script src="https://unpkg.com/fxxy-indexeddb"></script>
<!-- 或 jsdelivr -->
<script src="https://cdn.jsdelivr.net/npm/fxxy-indexeddb"></script>
<script>
  const helper = new IndexedDBHelper('appDB', 1, { users: { keyPath: 'id' } });
</script>

本地引入时优先使用构建产物:

<!-- 压缩版(生产环境推荐) -->
<script src="./node_modules/fxxy-indexeddb/dist/index.min.js"></script>
<!-- 或源码(带注释,便于调试) -->
<script src="./node_modules/fxxy-indexeddb/index.js"></script>

Node 环境

Node 中无原生 indexedDB,需提供 polyfill(如 fake-indexeddb):

require('fake-indexeddb/auto');  // 注入全局 indexedDB / IDBKeyRange
const IndexedDBHelper = require('fxxy-indexeddb');

快速开始

const helper = new IndexedDBHelper('appDB', 1, {
  users: {
    keyPath: 'id',
    autoIncrement: true,
    indexes: [
      { name: 'idx_name',  keyPath: 'name',  options: { unique: false } },
      { name: 'idx_email', keyPath: 'email', options: { unique: true } }
    ]
  }
}, { idleTimeout: 10 * 60 * 1000 }); // 10 分钟空闲关闭

// 增
const id = await helper.add('users', { name: 'Tom', email: '[email protected]' });

// 查
const tom = await helper.get('users', id);
const all = await helper.getAll('users');

// 改
await helper.put('users', { id, name: 'Tom2', email: '[email protected]' });

// 删
await helper.delete('users', id);

// 关闭
await helper.closeDB();

构造参数

new IndexedDBHelper(dbName, version, stores, options)

| 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | dbName | string | 是 | 数据库名称(同源下唯一标识) | | version | number | 是 | 数据库版本,正整数,只能递增 | | stores | Object | 否 | 初始对象存储配置,见下表 | | options | Object | 否 | 其他选项 |

stores 配置结构

{
  <storeName>: {
    keyPath: 'id',              // 主键路径
    autoIncrement: false,       // 是否自增主键
    indexes: [                  // 索引列表(可选)
      {
        name: 'idx_name',       // 索引名
        keyPath: 'name',         // 索引字段
        options: { unique: false } // IDBIndex 参数
      }
    ]
  }
}

options 选项

| 字段 | 类型 | 默认值 | 说明 | |------|------|--------|------| | idleTimeout | number | 1800000(30 分钟) | 空闲自动关闭连接时长(毫秒);传 0 禁用;每次 CRUD 操作都会重置计时器 |

idleTimeout 三种用法

// 1) 默认 30 分钟空闲关闭
new IndexedDBHelper('appDB', 1, { users: { keyPath: 'id' } });

// 2) 自定义 10 分钟
new IndexedDBHelper('appDB', 1, { users: { keyPath: 'id' } },
  { idleTimeout: 10 * 60 * 1000 });

// 3) 禁用(常驻连接)
new IndexedDBHelper('appDB', 1, { users: { keyPath: 'id' } },
  { idleTimeout: 0 });

API

连接管理

setStores(newStores)

更新 stores 配置(仅内存)。结构变更需配合 upgradeDB 才能生效。

helper.setStores({
  users: { keyPath: 'id', indexes: [{ name: 'idx_name', keyPath: 'name' }] },
  logs:  { keyPath: 'id', autoIncrement: true }
});
await helper.upgradeDB(2);

openDB() → Promise<IDBDatabase>

打开数据库连接,已打开则直接返回。内部触发 onupgradeneeded 创建缺失的 store / 索引。

const db = await helper.openDB();

closeDB()

关闭连接并清理空闲计时器,幂等操作。

await helper.closeDB();

upgradeDB(newVersion, newStores?) → Promise<void>

升级数据库版本并应用新配置。内部流程:closeDB → 更新 stores/version → openDB。

await helper.upgradeDB(2, {
  users: { keyPath: 'id' },
  logs:  { keyPath: 'id', autoIncrement: true } // 新增 store
});

基础 CRUD

| 方法 | 签名 | 返回值 | 说明 | |------|------|--------|------| | add | (storeName, data) → Promise<any> | 新记录主键 | 主键冲突会 reject | | put | (storeName, data) → Promise<any> | 记录主键 | 存在则覆盖 | | get | (storeName, key) → Promise<any> | 记录对象 / undefined | 未命中返回 undefined | | getAll | (storeName) → Promise<Array> | 记录数组 | 空 store 返回 [] | | delete | (storeName, key) → Promise<void> | - | 主键不存在也会 resolve | | clear | (storeName) → Promise<void> | - | 清空记录,保留 store 结构与索引 |

// 新增
const id = await helper.add('users', { name: 'Tom', age: 20 });

// 查询
const user = await helper.get('users', 1);
if (!user) console.log('not found');

const all = await helper.getAll('users');

// 更新
await helper.put('users', { id: 1, name: 'Tom2', age: 21 });

// 删除
await helper.delete('users', 1);

// 清空
await helper.clear('users');

索引查询

queryByIndex(storeName, indexName, range?, limit?) → Promise<Array>

通过索引游标查询,支持 IDBKeyRange 范围与数量限制。

| 参数 | 类型 | 默认 | 说明 | |------|------|------|------| | storeName | string | - | 对象存储名 | | indexName | string | - | 索引名(必须已创建) | | range | IDBKeyRange \| null | null | 键范围,null 表示全量遍历 | | limit | number \| null | null | 最大返回条数,null 不限制 |

常用 IDBKeyRange 工厂方法:

  • IDBKeyRange.only(v) — 精确匹配
  • IDBKeyRange.lowerBound(v) — >= v
  • IDBKeyRange.upperBound(v) — <= v
  • IDBKeyRange.bound(lower, upper) — 区间 [lower, upper]
// 查询 age >= 18 的前 10 条
const adults = await helper.queryByIndex(
  'users', 'idx_age',
  IDBKeyRange.lowerBound(18),
  10
);

// 查询 name == 'Tom' 的所有记录
const toms = await helper.queryByIndex(
  'users', 'idx_name',
  IDBKeyRange.only('Tom')
);

批量操作

bulkSave(storeName, items, isPut?) → Promise<Array>

单事务批量新增/更新,任一失败则整体 reject。

| 参数 | 类型 | 默认 | 说明 | |------|------|------|------| | storeName | string | - | 对象存储名 | | items | Array<Object> | - | 记录数组 | | isPut | boolean | true | true=put 覆盖;false=add 主键冲突会失败 |

返回值:与 items 同序的主键数组;items 为空时返回 []。

// 1) 批量 put(存在则覆盖)
const keys = await helper.bulkSave('users', [
  { id: 1, name: 'A' },
  { id: 2, name: 'B' }
]);
// keys => [1, 2]

// 2) 批量 add(自增主键)
const ids = await helper.bulkSave('logs', [
  { msg: 'a' },
  { msg: 'b' }
], false);

完整使用样例

import IndexedDBHelper from 'fxxy-indexeddb';
// 或:const IndexedDBHelper = require('fxxy-indexeddb');

async function main() {
  // 1. 创建实例:定义 users store,含 name/email 两个索引
  const helper = new IndexedDBHelper('appDB', 1, {
    users: {
      keyPath: 'id',
      autoIncrement: true,
      indexes: [
        { name: 'idx_name',  keyPath: 'name',  options: { unique: false } },
        { name: 'idx_email', keyPath: 'email', options: { unique: true } }
      ]
    }
  }, { idleTimeout: 5 * 60 * 1000 }); // 5 分钟空闲关闭

  try {
    // 2. 批量插入
    const ids = await helper.bulkSave('users', [
      { name: 'Tom', email: '[email protected]', age: 20 },
      { name: 'Bob', email: '[email protected]', age: 25 },
      { name: 'Lucy', email: '[email protected]', age: 17 }
    ], false);
    console.log('插入的 id:', ids);

    // 3. 主键查询
    const tom = await helper.get('users', ids[0]);
    console.log('Tom:', tom);

    // 4. 索引范围查询:age >= 18
    const adults = await helper.queryByIndex(
      'users', 'idx_age',  // 注意:本样例未声明 idx_age,实际使用需在 stores 中配置
      IDBKeyRange.lowerBound(18)
    );
    console.log('成年人:', adults);

    // 5. 索引精确查询:name == 'Bob'
    const bobs = await helper.queryByIndex(
      'users', 'idx_name',
      IDBKeyRange.only('Bob')
    );
    console.log('Bob:', bobs);

    // 6. 更新
    await helper.put('users', { id: ids[0], name: 'Tom2', email: '[email protected]', age: 21 });

    // 7. 删除
    await helper.delete('users', ids[2]);

    // 8. 全量查询
    const all = await helper.getAll('users');
    console.log('剩余记录:', all);

    // 9. 升级版本:新增 logs store
    await helper.upgradeDB(2, {
      users: {
        keyPath: 'id', autoIncrement: true,
        indexes: [
          { name: 'idx_name',  keyPath: 'name' },
          { name: 'idx_email', keyPath: 'email', options: { unique: true } }
        ]
      },
      logs: { keyPath: 'id', autoIncrement: true }
    });

    // 10. 写入新 store
    await helper.add('logs', { msg: 'app started', ts: Date.now() });

  } catch (err) {
    console.error('操作失败:', err);
  } finally {
    // 11. 显式关闭
    await helper.closeDB();
  }
}

main();

注意事项

  1. 版本号只能递增:upgradeDB(newVersion) 中 newVersion 必须大于当前版本,否则抛错。
  2. stores 配置不会自动删除结构:openDB / upgradeDB 只创建缺失的 store / 索引,不会删除已有的,确保数据安全。
  3. 跨标签页冲突:当其他标签页要求升级版本时,本实例会自动关闭连接(onversionchange),下次操作时自动重开。
  4. idleTimeout 语义:每次 CRUD 操作完成(无论成功或失败)都会重置计时器;仅在「长时间无任何操作」时才会触发关闭。
  5. bulkSave 原子性:所有 items 在同一事务内执行,任一失败则整体 reject,已成功的也会回滚。
  6. add vs put:add 主键冲突会失败;put 存在则覆盖。批量场景按需选择 isPut 参数。
  7. 索引必须先配置:queryByIndex 使用的索引名必须在 stores 配置中声明并通过 openDB / upgradeDB 创建。
  8. get 未命中:主键不存在时返回 undefined,不会抛错。
  9. Node 环境需 polyfill:浏览器原生支持 indexedDB;Node 中需先注入 fake-indexeddb 等全局 polyfill。

构建产物

本项目使用零依赖的 build.js 构建多格式产物(仅使用 Node 内置模块,兼容任意 Node 版本)。源码 index.js 为 UMD 风格(运行时判断 module.exports),构建后额外生成两种格式:

| 文件 | 格式 | 体积 | 用途 | 入口字段 | |------|------|------|------|---------| | index.js | UMD(源码) | ~20KB | CommonJS / 调试 | main | | dist/index.mjs | ESM | ~20KB | 打包工具(Webpack/Rollup/Vite) | module | | dist/index.min.js | IIFE(压缩) | ~5KB | 浏览器 <script> / CDN | browser / unpkg / jsdelivr |

本地构建

# 无需 npm install,零依赖直接构建
# 完整构建:清理 + ESM + 压缩
npm run build

# 单独构建 ESM
npm run build:esm

# 单独构建压缩版
npm run build:min

# 监听源文件变化,自动重建 ESM(开发模式)
npm run watch

# 清理构建产物
npm run clean

构建脚本通过 prepublishOnly 钩子在 npm publish 前自动执行,确保发布时产物最新。

零依赖优势:无需安装任何 devDependencies,任意 Node 版本(含 Node 6+)均可直接 npm run build。压缩采用纯文本处理(移除注释 + 折叠空白 + 标点周边空格清理),体积虽不及 terser/esbuild 极致,但无版本兼容问题,对本工具类已足够。

作为 npm 包发布

本项目已按 npm 包规范组织,package.json 关键字段如下:

{
  "name": "fxxy-indexeddb",
  "version": "0.0.1",
  "description": "indexedDB 封装:支持动态升级 stores、空闲自动关闭、批量原子操作",
  "main": "index.js",                  // CommonJS 入口(源码 UMD)
  "module": "dist/index.mjs",          // ESM 入口(打包工具按此解析)
  "browser": "dist/index.min.js",      // 浏览器入口(压缩 IIFE)
  "unpkg": "dist/index.min.js",        // unpkg CDN 默认文件
  "jsdelivr": "dist/index.min.js",     // jsdelivr CDN 默认文件
  "files": ["index.js", "build.js", "dist/", "README.md"], // 发布白名单
  "scripts": {
    "clean": "node build.js clean",            // 清理 dist
    "build:esm": "node build.js esm",           // 构建 ESM
    "build:min": "node build.js min",           // 构建压缩版
    "build": "node build.js",                   // 完整构建
    "watch": "node build.js watch",              // 监听模式
    "prepublishOnly": "npm run build"            // 发布前自动构建
  },
  "keywords": ["indexeddb", "database", "storage", "promise", "browser"],
  "license": "ISC"
  // 无 devDependencies —— 零依赖构建,任意 Node 版本通用
}

发布流程

# 1. 登录 npm
npm login

# 2. 校验包名是否可用(未占用)
npm view fxxy-indexeddb

# 3. 检查即将发布的文件清单
npm pack --dry-run

# 4. 发布
npm publish

# 发布 beta 版本
npm publish --tag beta

后续建议

  • 补充 index.d.ts 类型声明文件,便于 TS 项目使用
  • 增加 .npmignore 或在 package.json 中明确 files 字段,避免发布 .history/ 等无关目录
  • 添加单元测试(如 vitest + fake-indexeddb)并接入 CI
  • 体积优化:若需更小产物,可提供 ESM 独立构建(如 dist/index.mjs)

License

ISC