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

idb-ts

v3.9.1

Published

Easy CRUD for indexed-db, written in TypeScript

Readme

🚀 idb-ts

📌 Introduction

idb-ts is a lightweight, declarative, and type-safe way to work with IndexedDB using TypeScript. Effortlessly perform CRUD operations on your database with clean, structured code! 🔥

📦 Installation

Install via npm and start using IndexedDB like a pro! ⚡

npm i idb-ts

✨ Features

  • Declarative & Type-Safe - Define your data models with decorators.
  • Easy CRUD Operations - Perform create, read, update, and delete seamlessly.
  • 🚀 Fully Typed API - Benefit from TypeScript’s powerful type system.
  • 🏎️ Performance Optimized - Minimal overhead with IndexedDB's native capabilities.
  • 🔄 Schema Versioning - Manage database schema evolution with automatic migration support.
  • 🔑 Advanced Key Management - Auto-increment, UUID, timestamp, custom generators, and composite keys.

📖 Example Usage

🏗️ Declaring Entities

Use decorators to define your data models. Each class must have exactly one @KeyPath() and be decorated with @DataClass().

import { Database, DataClass, KeyPath, Index } from "idb-ts";

@DataClass()
class User {
  @KeyPath()
  id!: string;

  @Index()
  email!: string;

  name!: string;
  age!: number;

  constructor(id: string, name: string, age: number, email?: string) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.email = email || `${name.toLowerCase()}@example.com`;
  }
}

@DataClass()
class Location {
  @KeyPath()
  id!: string;

  @Index()
  city!: string;

  country!: string;

  constructor(id: string, city: string, country: string) {
    this.id = id;
    this.city = city;
    this.country = country;
  }
}

🔄 CRUD Operations

Perform database operations using the repository API:

const db = await Database.build("idb-crud", [User, Location]);

const alice = new User("u1", "Alice", 25);
const bob = new User("u2", "Bob", 30);
const nyc = new Location("1", "New York", "USA");
const sf = new Location("2", "San Francisco", "USA");

await db.User.create(alice);
await db.User.create(bob);
await db.Location.create(nyc);
await db.Location.create(sf);

const readAlice = await db.User.read("u1");
console.log("👤 Read user:", readAlice);

alice.age = 26;
await db.User.update(alice);

const users = await db.User.list();
console.log("📋 All users:", users);

// Pagination
const page1 = await db.User.listPaginated(1, 2); // page 1, 2 users per page
console.log("📄 Page 1:", page1);

await db.User.delete("u1");
console.log("❌ User Alice deleted.");

const remainingUsers = await db.User.list();
console.log("🔍 Remaining users:", remainingUsers);

const locations = await db.Location.list();
console.log("🌍 All locations:", locations);

🔍 Indexing Support

Create indexes on fields for fast querying. Query indexes using the repository API:

@DataClass()
class Product {
  @KeyPath()
  id!: string;

  @Index()
  category!: string;

  @Index()
  price!: number;

  name!: string;
  description!: string;

  constructor(id: string, category: string, price: number, name: string, description: string) {
    this.id = id;
    this.category = category;
    this.price = price;
    this.name = name;
    this.description = description;
  }
}

const db = await Database.build("products-db", [Product]);

const electronics = await db.Product.findByIndex('category', 'Electronics');
const expensiveItems = await db.Product.findByIndex('price', 999.99);
const firstElectronic = await db.Product.findOneByIndex('category', 'Electronics');

Index Methods:

  • findByIndex(indexName, value): Promise<T[]> - Find all records matching the index value
  • findOneByIndex(indexName, value): Promise<T | undefined> - Find the first record matching the index value

Error Handling

  • If you query a non-existent index, an error is thrown:
    await db.Product.findByIndex('nonexistent', 'value'); // throws

🔑 Multi-Field & Composite Key Support

idb-ts provides flexible key management options including auto-increment keys, key generators, and composite keys for complex data relationships.

Auto-Increment Keys

Perfect for entities where you want the database to automatically generate sequential IDs:

@DataClass()
class Task {
  @KeyPath({ autoIncrement: true })
  id!: number;

  title!: string;
  completed!: boolean;

  constructor(title: string, completed = false) {
    this.title = title;
    this.completed = completed;
  }
}

const db = await Database.build("tasks-db", [Task]);

// IDs are automatically generated: 1, 2, 3, etc.
const task1 = await db.Task.create(new Task("Learn TypeScript"));
const task2 = await db.Task.create(new Task("Build amazing apps"));
console.log(task1.id); // 1
console.log(task2.id); // 2

Key Generators

Generate keys automatically using built-in generators:

UUID Keys

@DataClass()
class Document {
  @KeyPath({ generator: 'uuid' })
  uuid!: string;

  @Index()
  category!: string;

  title!: string;
  content!: string;

  constructor(category: string, title: string, content: string) {
    this.category = category;
    this.title = title;
    this.content = content;
  }
}

const db = await Database.build("docs-db", [Document]);

const doc = await db.Document.create(new Document("tutorial", "Getting Started", "Welcome..."));
console.log(doc.uuid); // e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Timestamp Keys

@DataClass()
class Event {
  @KeyPath({ generator: 'timestamp' })
  timestamp!: number;

  @Index()
  type!: string;

  data!: any;

  constructor(type: string, data: any) {
    this.type = type;
    this.data = data;
  }
}

const event = await db.Event.create(new Event("user_login", { userId: "123" }));
console.log(event.timestamp); // e.g., 1696118400000

Random Keys

@DataClass()
class Session {
  @KeyPath({ generator: 'random' })
  sessionId!: string;

  userId!: string;
  expiresAt!: Date;

  constructor(userId: string, expiresAt: Date) {
    this.userId = userId;
    this.expiresAt = expiresAt;
  }
}

const session = await db.Session.create(new Session("user123", new Date()));
console.log(session.sessionId); // e.g., "xyz789abc123"

Custom Key Generators

Create your own key generation logic:

@DataClass()
class Invoice {
  @KeyPath({ generator: (entity: any) => `INV-${entity.year}-${String(entity.number).padStart(4, '0')}` })
  invoiceId!: string;

  year!: number;
  number!: number;
  amount!: number;

  constructor(year: number, number: number, amount: number) {
    this.year = year;
    this.number = number;
    this.amount = amount;
  }
}

const invoice = await db.Invoice.create(new Invoice(2024, 1, 1500.00));
console.log(invoice.invoiceId); // "INV-2024-0001"

Composite Keys

Handle many-to-many relationships with composite keys using the @CompositeKeyPath decorator:

import { CompositeKeyPath } from "idb-ts";

@CompositeKeyPath(['userId', 'projectId'])
@DataClass()
class UserProject {
  userId!: string;
  projectId!: string;

  @Index()
  role!: string;

  joinedAt!: Date;

  constructor(userId: string, projectId: string, role: string) {
    this.userId = userId;
    this.projectId = projectId;
    this.role = role;
    this.joinedAt = new Date();
  }
}

const db = await Database.build("collaboration-db", [UserProject]);

// Create relationships
await db.UserProject.create(new UserProject("user123", "project456", "developer"));
await db.UserProject.create(new UserProject("user123", "project789", "admin"));
await db.UserProject.create(new UserProject("user456", "project456", "viewer"));

// Read with composite key
const relationship = await db.UserProject.read(['user123', 'project456']);
console.log(relationship?.role); // "developer"

// Update relationship
if (relationship) {
  relationship.role = "maintainer";
  await db.UserProject.update(relationship);
}

// Delete with composite key
await db.UserProject.delete(['user123', 'project789']);

// Query by role index
const developers = await db.UserProject.findByIndex('role', 'developer');

Key Generation Utilities

Access key generators directly for your custom logic:

import { KeyGenerators } from "idb-ts";

const uuid = KeyGenerators.uuid();        // Generate UUID
const timestamp = KeyGenerators.timestamp(); // Current timestamp
const random = KeyGenerators.random();    // Random string

🔄 Schema Versioning

idb-ts supports schema versioning to manage database evolution over time. Version your entities and let the library handle automatic migration!

Basic Usage

@DataClass({ version: 1 })
class User {
  @KeyPath() id!: string;
  @Index() email!: string;
  name!: string;
}

@DataClass({ version: 2 })
class Post {
  @KeyPath() id!: string;
  @Index() authorId!: string;
  title!: string;
  content!: string;
}

@DataClass({ version: 3 })
class Comment {
  @KeyPath() id!: string;
  @Index() postId!: string;
  @Index() authorId!: string;
  text!: string;
}

// Database version will be 3 (highest entity version)
const db = await Database.build("blog", [User, Post, Comment]);

console.log(db.getDatabaseVersion()); // 3
console.log(db.getEntityVersions()); // Map with entity versions

Key Features

  • Automatic Version Calculation: Database version = highest entity version
  • Seamless Migration: Only new/updated entities are processed during upgrades
  • Backward Compatibility: Entities without version default to version 1
  • Index Evolution: New indexes are automatically created during migration

Version Management

// Check versions
const dbVersion = db.getDatabaseVersion();
const entityVersions = db.getEntityVersions();
const userVersion = db.getEntityVersion('User');

// Version upgrade flow:
// v1.0: User(v1) → Database v1
// v1.1: User(v1), Post(v2) → Database v2  
// v1.2: User(v1), Post(v2), Comment(v3) → Database v3

📖 Complete Schema Versioning Guide - Detailed documentation with examples and best practices.


🔗 Useful Links

  • 📂 GitHub: maifeeulasad/idb-ts
  • 📦 NPM: idb-ts
  • Demo: https://maifeeulasad.github.io/idb-ts/
  • Code Coverage report: https://maifeeulasad.github.io/idb-ts/coverage/lcov-report/

🎉 Enjoy seamless IndexedDB integration with TypeScript! Happy coding! 🚀