https://github.com/smithg09/zenithdb
A framework-agnostic, local-first state and sync engine. Powerful IndexedDB wrapper provides reactive subscriptions, offline-first syncing, and type-safe queries.
https://github.com/smithg09/zenithdb
autosync indexeddb reactivity
Last synced: 8 months ago
JSON representation
A framework-agnostic, local-first state and sync engine. Powerful IndexedDB wrapper provides reactive subscriptions, offline-first syncing, and type-safe queries.
- Host: GitHub
- URL: https://github.com/smithg09/zenithdb
- Owner: smithg09
- License: mit
- Created: 2025-08-02T15:14:15.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-08-06T16:33:55.000Z (10 months ago)
- Last Synced: 2025-10-01T06:26:43.032Z (9 months ago)
- Topics: autosync, indexeddb, reactivity
- Language: TypeScript
- Homepage:
- Size: 356 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 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
- **[@zenithdb/core](./packages/core)** - Core database engine with schema definition and queries
- **[@zenithdb/storage](./packages/storage)** - Storage adapters (IndexedDB, and future SQL/SQLite)
- **[@zenithdb/sync](./packages/sync)** - Backend-agnostic sync engine with offline support
- **[@zenithdb/types](./packages/types)** - TypeScript type definitions
- **[@zenithdb/utils](./packages/utils)** - Utility functions and helpers
- **[@zenithdb/kit](./packages/kit)** - Meta-package that installs everything you need
## Documentation
- [Core Package](./packages/core/README.md) - Database engine documentation
- [Storage Package](./packages/storage/README.md) - Storage adapters documentation
- [Sync Package](./packages/sync/README.md) - Sync engine documentation
## Installation
### NPM
```bash
# 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
```typescript
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
```typescript
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
```typescript
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](./CONTRIBUTING.md) for details.
### Development Setup
```bash
# 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](https://www.smithgajjar.dev)