IndexedDB Adapter

IndexedDB Adapter provides persistent browser storage for URPC entities using the IndexedDB API. Perfect for client-side applications that need data persistence across browser sessions.

Installation

The IndexedDB Adapter is part of the @unilab/urpc-adapters package:

npm install @unilab/urpc-adapters

Basic Setup

import { URPC } from "@unilab/urpc";
import { IndexedDBAdapter } from "@unilab/urpc-adapters";
import { UserEntity } from "./entities/user";
import { Logging } from "@unilab/urpc-core/middleware";

const MyPlugin = {
  entities: [UserEntity],
};

URPC.init({
  plugins: [MyPlugin],
  middlewares: [Logging()],
  entityConfigs: {
    user: {
      defaultSource: "indexeddb",
    },
  },
  globalAdapters: [IndexedDBAdapter],
});

Usage Examples

Creating Data

import { repo } from "@unilab/urpc";

const newUser = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).create({
  data: {
    id: "user123",
    name: "John Doe",
    email: "[email protected]",
    avatar: "https://example.com/avatar.jpg",
  },
});
console.log("✅ User created:", newUser);

Finding Data

const user = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).findOne({
  where: { id: "user123" },
});

if (user) {
  console.log("✅ User found:", user);
  // Call entity methods
  user.greet("Welcome to IndexedDB!");
} else {
  console.log("❌ User not found");
}

Updating Data

const updatedUser = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).update({
  where: { id: "user123" },
  data: {
    name: "Jane Smith",
    email: "[email protected]",
  },
});
console.log("✅ User updated:", updatedUser);

Deleting Data

const deleted = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).delete({
  where: { id: "user123" },
});

if (deleted) {
  console.log("✅ User deleted successfully");
} else {
  console.log("❌ User not found for deletion");
}

Listing All Data

const users = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).findMany();

console.log(`Found ${users.length} users:`, users);

Clearing All Data

const allUsers = await repo({
  entity: UserEntity,
  source: "indexeddb",
}).findMany();

for (const user of allUsers) {
  await repo({
    entity: UserEntity,
    source: "indexeddb",
  }).delete({
    where: { id: user.id },
  });
}
console.log(`✅ Cleared ${allUsers.length} users`);

Default Source Configuration

Set IndexedDB as the default source for entities:

URPC.init({
  entityConfigs: {
    user: {
      defaultSource: "indexeddb",
    },
  },
  globalAdapters: [IndexedDBAdapter],
});

// Now you can omit the source parameter
const user = await repo({
  entity: UserEntity,
}).findOne({
  where: { id: "user123" },
});

Features

  • Persistent Storage: Data survives browser restarts and page reloads
  • Large Storage Capacity: Much larger storage limits than localStorage
  • Asynchronous Operations: Non-blocking database operations
  • Entity Support: Full support for Entity classes and methods
  • CRUD Operations: Complete create, read, update, delete functionality
  • Browser Native: Uses the browser's built-in IndexedDB API

Use Cases

  • Offline Applications: Store data that persists when offline
  • Client-Side Caching: Cache API responses for better performance
  • User Preferences: Store user settings and configurations
  • Progressive Web Apps: Essential for PWA data persistence
  • Large Datasets: Handle larger amounts of data than memory storage

Browser Compatibility

IndexedDB is supported in all modern browsers:

  • Chrome 23+
  • Firefox 10+
  • Safari 7+
  • Edge 12+

Development Tips

Viewing Data

Open browser DevTools → Application → Storage → IndexedDB to inspect stored data.

Error Handling

Always wrap IndexedDB operations in try-catch blocks:

try {
  const user = await repo({
    entity: UserEntity,
    source: "indexeddb",
  }).create({ data: userData });
} catch (error) {
  console.error("Failed to create user:", error);
}

Limitations

  • Browser Only: Cannot be used in Node.js environments
  • Same-Origin Policy: Data is isolated per domain
  • Storage Quotas: Subject to browser storage quotas (usually generous)
  • No Server Sync: Data is local to the browser instance

Advanced Configuration

Combine with other adapters for different entities:

URPC.init({
  plugins: [MyPlugin, WalletPlugin],
  middlewares: [Logging()],
  entityConfigs: {
    user: {
      defaultSource: "indexeddb", // Persistent user data
    },
    session: {
      defaultSource: "memory", // Temporary session data
    },
  },
  globalAdapters: [IndexedDBAdapter, MemoryAdapter],
});