Skip to content

A framework-agnostic, local-first state and sync engine. Powerful IndexedDB wrapper provides reactive subscriptions, offline-first syncing, and type-safe queries.

License

Notifications You must be signed in to change notification settings

smithg09/zenithdb

Repository files navigation

ZenithDB

A framework-agnostic, local-first state and sync engine that provides a powerful wrapper around IndexedDB with advanced features like reactive subscriptions, offline-first sync, and type-safe queries.

Key Features

  • 🗄️ Enhanced IndexedDB: A powerful wrapper around IndexedDB with a clean, intuitive API
  • 🔄 Offline-First: Built-in sync engine with conflict resolution and offline queue management
  • Type-Safe: Full TypeScript support with schema definition and query inference
  • 🔌 Framework-Agnostic: Works with React, Vue, Svelte, or vanilla JavaScript
  • 📱 Reactive: Observable subscriptions for real-time UI updates
  • 🎯 Fluent Queries: Chainable query API with support for complex operations
  • 🚀 Sync Engine: Built-in bidirectional synchronization with retry logic and exponential backoff
  • 🔧 Pluggable: Adapter-based architecture supporting indexedDB and more in the future (WebSQL/SQLlite)
  • 🛡️ Validation: Runtime schema validation with custom error messages

Packages

Documentation

Installation

NPM

# Complete package (recommended)
npm install @zenithdb/kit

# Or install individual packages
npm install @zenithdb/core @zenithdb/storage @zenithdb/sync @zenithdb/types

Note: The @zenithdb/kit package installs everything you need to get started with Zenith, including core functionality, storage adapters, and sync engine.

Quick Start

import { createDatabase, createSchema, fields } from "@zenithdb/core";
import { IndexedDBAdapter } from "@zenithdb/storage";
import { ZenithSyncEngine } from "@zenithdb/sync";

// Define your schema
const schema = createSchema({
  name: "MyApp",
  version: 1,
  tables: {
    users: {
      primaryKey: "id",
      schema: {
        id: fields.string({ required: true }),
        name: fields.string({ required: true }),
        email: fields.string({ unique: true }),
        createdAt: fields.timestamp({ defaultValue: () => Date.now() }),
      },
    },
  },
  adapter: "indexeddb",
});

// Create database
const db = await createDatabase(schema);

// Create a user
const user = await db.users.add({
  id: "user-1",
  name: "John Doe",
  email: "john@example.com",
});

// Query with fluent API
const users = await db.users
  .where("name")
  .contains("John")
  .sortBy("createdAt", "desc")
  .limit(10)
  .toArray();

// Subscribe to changes
db.users.subscribe((users) => {
  console.log("Users updated:", users);
});

// Set up sync engine (optional)
const syncEngine = new ZenithSyncEngine(transport, adapter, {
  conflictResolution: "server-wins",
  autoSyncInterval: 30000,
});

await syncEngine.start();

Sync Integration

Basic Sync Integration

import { createDatabase, createSchema, fields } from "@zenithdb/core";
import { createRestTransport } from "@zenithdb/sync";

const transport = createRestTransport({
  baseUrl: "https://api.yourapp.com",
  endpoints: {
    push: "/sync/push",
    pull: "/sync/pull",
  },
  headers: {
    Authorization: "Bearer your-token",
  },
});

// Create sync-enabled database schema
const schema = createSchema({
  name: "SyncIntegrationTest",
  version: 1,
  tables: {
    users: {
      primaryKey: "id",
      schema: {
        id: fields.string({ required: true }),
        name: fields.string({ required: true }),
        email: fields.string({ required: true }),
        createdAt: fields.timestamp({ defaultValue: () => Date.now() }),
        updatedAt: fields.timestamp({ defaultValue: () => Date.now() }),
      },
      indexes: [{ name: "email", field: "email", unique: true }],
    },
  },
  sync: {
    transport,
    config: {
      conflictResolution: "server-wins",
      autoSyncInterval: 5000,
      batchSize: 10,
      immediateSync: true,
      immediateSyncDebounce: 100,
    },
    autoStart: false,
  },
});

// Create and use sync-enabled database
const db = await createDatabase(schema);

// Start sync engine
await db.startSync();

// Perform operations that will be automatically synced
const user = await db.users.add({
  id: "user-1",
  name: "John Doe",
  email: "john@example.com",
});

// Update operation
await db.users.update("user-1", { name: "John Smith" });

// Manual sync trigger
await db.syncNow();

// Check sync status
const status = db.getSyncStatus();
console.log("Sync status:", status);

Table-Level Sync Control

import { createDatabase, createSchema, fields } from "@zenithdb/core";
import { createGraphQLTransport } from "@zenithdb/sync";

const graphqlTransport = createGraphQLTransport({
  endpoint: "https://api.example.com/graphql",
  headers: {
    Authorization: "Bearer token",
  },
  mutations: {
    pushData: `
      mutation SyncPush($operations: [SyncOperationInput!]!) {
        syncPush(operations: $operations) {
          success
          conflicts { id table localValue remoteValue }
        }
      }
    `,
  },
  queries: {
    pullData: `
      query SyncPull($lastSync: DateTime) {
        syncPull(since: $lastSync) {
          operations { id table data timestamp }
          cursor
        }
      }
    `,
  },
});

// Create schema with table-specific sync settings
const schema = createSchema({
  name: "TableSyncControlTest",
  version: 1,
  tables: {
    users: {
      primaryKey: "id",
      schema: {
        id: fields.string({ required: true }),
        name: fields.string({ required: true }),
        email: fields.string({ required: true }),
        createdAt: fields.timestamp({ defaultValue: () => Date.now() }),
      },
    },
    posts: {
      primaryKey: "id",
      schema: {
        id: fields.string({ required: true }),
        title: fields.string({ required: true }),
        content: fields.string({ required: true }),
        authorId: fields.string({ required: true }),
        published: fields.boolean({ defaultValue: false }),
        createdAt: fields.timestamp({ defaultValue: () => Date.now() }),
      },
    },
  },
  sync: {
    transport: graphqlTransport,
    config: {
      conflictResolution: "server-wins",
      autoSyncInterval: 5000,
    },
    tableSettings: {
      users: {
        enabled: true,
        autoSync: true,
        syncDirection: "bidirectional", // Can sync both ways
      },
      posts: {
        enabled: true,
        autoSync: true,
        syncDirection: "push-only", // Only push to server
      },
    },
    autoStart: true,
  },
});

const db = await createDatabase(schema);

// Operations on different tables with different sync behaviors
await db.users.add({
  id: "user-1",
  name: "Bob",
  email: "bob@example.com",
});

await db.posts.add({
  id: "post-1",
  title: "Test Post",
  content: "This is a test post",
  authorId: "user-1",
});

// Both operations will be synced according to their table settings

Performance Tips

  1. Use Indexes: Define indexes on frequently queried fields
  2. Batch Operations: Use bulkAdd() for multiple records
  3. Subscribe Wisely: Unsubscribe from unused subscriptions
  4. Transaction Scope: Keep transactions as small as possible
  5. Query Optimization: Use specific queries instead of filtering large datasets

Contributing

We welcome contributions! Please see our contributing guidelines for details.

Development Setup

# Clone the repository
git clone https://github.com/smithg09/zenithdb.git
cd zenithdb

# Install dependencies
pnpm install

# Instll types
pnpm build --filter=@zenithdb/types

# Build all packages
pnpm build

# Start development mode
pnpm dev

Monorepo Structure

This project uses a monorepo structure with multiple packages:

  • Each package has its own package.json and build configuration
  • Shared TypeScript configuration and build tools
  • Turborepo for efficient task running
  • Changesets for version management and publishing

License

MIT © Smith Gajjar

About

A framework-agnostic, local-first state and sync engine. Powerful IndexedDB wrapper provides reactive subscriptions, offline-first syncing, and type-safe queries.

Topics

Resources

License

Stars

Watchers

Forks