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

@syncflow-db/core

v0.3.6

Published

Core client library for SyncFlow

Readme

@syncflow-db/core

Local-first database with event sourcing and vector clock synchronization

npm version License: MIT TypeScript

A lightweight, type-safe client library for building offline-first applications with automatic synchronization. @syncflow-db/core provides event sourcing, vector clock conflict detection, and seamless cloud sync.

Features

Event Sourcing - Every database change is captured as an operation with full history
🔄 Vector Clocks - Sophisticated causal consistency tracking across multiple devices
📱 Offline-First - Works completely offline with automatic sync when reconnected
🔁 Auto-Sync - Optional continuous bidirectional synchronization
🚀 Type-Safe - Full TypeScript support with exported types
Lightweight - Minimal dependencies (only uuid)
🗄️ Flexible Storage - SQLite backend (wa-sqlite) with fallback to memory

Installation

npm install @syncflow-db/core wa-sqlite

Or with pnpm:

pnpm add @syncflow-db/core wa-sqlite

wa-sqlite is optional—@syncflow-db/core will fall back to in-memory storage if not installed.

Quick Start

Basic Usage

import { createDatabase } from '@syncflow-db/core';

// Initialize a local database
const { db } = await createDatabase({
  name: 'my-app',
});

// Insert a document
await db.insert('todos', {
  title: 'Build offline-first app',
  completed: false,
});

// Query documents
const todos = await db.find('todos');
console.log(todos);

// Update a document
await db.update('todos', 'doc-id', {
  completed: true,
});

// Delete a document
await db.delete('todos', 'doc-id');

With Server Sync

import { createDatabase } from '@syncflow-db/core';

const { db, sync } = await createDatabase({
  name: 'my-app',
  serverUrl: 'https://api.example.com',
  syncInterval: 5000, // Auto-sync every 5 seconds
});

// Manual sync on demand
const result = await sync?.sync();
console.log(`Synced: ${result?.pushed} pushed, ${result?.pulled} pulled`);

// Handle sync progress
sync?.onProgress((progress) => {
  console.log(`${progress.phase}: ${progress.current}/${progress.total}`);
});

// Handle sync errors
sync?.onError((error) => {
  console.error('Sync failed:', error);
});

API Reference

createDatabase(options)

Initialize a new local-first database instance.

Options:

{
  name: string;              // Unique database name
  serverUrl?: string;        // Optional server URL for sync
  syncInterval?: number;     // Auto-sync interval in ms (requires serverUrl)
}

Returns:

{
  db: LocalFirstDB;          // Database instance
  sync?: SyncEngine;         // Sync engine (if serverUrl provided)
}

LocalFirstDB Class

Methods

insert(collection: string, data: any): Promise<Document>

Insert a new document into a collection.

const doc = await db.insert('users', {
  name: 'Alice',
  email: '[email protected]',
});
// { _id: 'uuid', _rev: 1, name: 'Alice', email: '[email protected]' }

find(collection: string): Promise<Document[]>

Retrieve all documents from a collection (non-deleted only).

const users = await db.find('users');

findById(collection: string, id: string): Promise<Document | null>

Retrieve a single document by ID.

const user = await db.findById('users', 'user-123');

update(collection: string, id: string, data: any): Promise<Document>

Update an existing document. Increments the revision number.

const updated = await db.update('users', 'user-123', {
  email: '[email protected]',
});

delete(collection: string, id: string): Promise<void>

Soft-delete a document (marks _deleted: true, preserves history).

await db.delete('users', 'user-123');

batch(operations: Operation[]): Promise<void>

Perform multiple operations atomically (tracked as single batch op).

await db.batch([
  { type: 'insert', collection: 'users', data: { name: 'Bob' } },
  { type: 'update', collection: 'users', id: 'user-123', data: { role: 'admin' } },
]);

SyncEngine Class

Methods

sync(): Promise<SyncResult>

Perform a single bidirectional sync cycle.

const result = await sync?.sync();
// { success: true, pushed: 5, pulled: 3, conflicts: 0, errors: [] }

startContinuousSync(intervalMs: number): void

Start automatic sync on an interval.

sync?.startContinuousSync(5000); // Sync every 5 seconds

stopContinuousSync(): void

Stop automatic sync.

sync?.stopContinuousSync();

onProgress(callback: (progress: SyncProgress) => void): void

Listen to sync progress updates.

sync?.onProgress((progress) => {
  console.log(`${progress.phase}: ${progress.current}/${progress.total}`);
  // phase: 'pull' | 'push' | 'idle'
  // total, current: operation counts
  // errors: error count
});

onError(callback: (error: Error) => void): void

Listen to sync errors.

sync?.onError((error) => {
  console.error('Sync error:', error.message);
});

Exported Types

import type {
  Document,           // Database document with _id, _rev, _deleted?
  Operation,          // Event sourced operation
  OperationType,      // 'insert' | 'update' | 'delete' | 'batch'
  VectorClock,        // Client causality tracking
  SyncOptions,        // Sync configuration
  SyncProgress,       // Sync progress info
  SyncResult,         // Sync completion result
  ClockRelation,      // Vector clock comparison result
} from '@syncflow-db/core';

Vector Clock Comparison

import { compareVectorClocks } from '@syncflow-db/core';

const result = compareVectorClocks(clock1, clock2);
// 'happens-before' | 'happens-after' | 'concurrent'

Event Sourcing

All database operations are captured as events with full metadata:

interface Operation {
  id: string;                    // Unique operation ID
  type: 'insert' | 'update' | 'delete' | 'batch';
  collection: string;            // Collection name
  docId: string;                 // Document ID
  data?: any;                    // Operation data
  timestamp: number;             // Unix timestamp
  clientId: string;              // Source client ID
  synced: boolean;               // Sync status
  vectorClock: Record<string, number>; // Causal metadata
}

This enables:

  • Complete audit trails
  • Conflict detection via vector clocks
  • Reliable synchronization
  • Time-travel debugging

Offline Support

@syncflow-db/core works entirely offline:

  1. Local Persistence - All data stored locally via SQLite (wa-sqlite)
  2. Operation Buffering - Changes queued automatically for sync
  3. Auto-Reconnection - Resumes sync when connection restored
  4. Conflict Resolution - Vector clocks detect and resolve conflicts
// Works offline
await db.insert('todos', { title: 'Offline entry' });

// Auto-syncs when network returns

Examples

React Integration

import { useEffect, useState } from 'react';
import { createDatabase } from '@syncflow-db/core';
import type { Document } from '@syncflow-db/core';

export function useSyncFlow(dbName: string) {
  const [docs, setDocs] = useState<Document[]>([]);
  const [syncing, setSyncing] = useState(false);

  useEffect(() => {
    let db: any;

    (async () => {
      const { db: instance, sync } = await createDatabase({
        name: dbName,
        serverUrl: process.env.REACT_APP_SERVER_URL,
        syncInterval: 5000,
      });

      db = instance;

      sync?.onProgress(() => setSyncing(true));
      sync?.onProgress(() => setSyncing(false));
    })();

    return () => {
      // Cleanup
    };
  }, [dbName]);

  const insert = async (collection: string, data: any) => {
    await db.insert(collection, data);
    const updated = await db.find(collection);
    setDocs(updated);
  };

  return { docs, syncing, insert };
}

Batch Operations

// Efficient multi-document operations
await db.batch([
  {
    type: 'insert',
    collection: 'users',
    data: { name: 'Alice', role: 'admin' },
  },
  {
    type: 'insert',
    collection: 'users',
    data: { name: 'Bob', role: 'user' },
  },
]);

Server Implementation

@syncflow-db/core is designed to work with @syncflow-db/server. See the main repository for server setup and integration examples.

Performance

  • Local Queries: <1ms for in-memory, <10ms for SQLite
  • Sync: ~10-100x less bandwidth than traditional sync approaches
  • Vector Clocks: O(n) space and O(n) time for n clients
  • Batch Operations: Grouped as single event for efficiency

Limitations

  • Vector Clock Comparison: Basic implementation; full partial-order semantics in v0.4.0+
  • Encryption: No built-in encryption at rest (planned for v0.4.0+)
  • Batch Atomicity: Operations are sequential, not atomic
  • Conflict Resolution: Last-write-wins by default; custom resolvers in v0.4.0+

Browser Support

  • Chrome 90+
  • Firefox 88+
  • Safari 14+
  • Edge 90+

Requires wa-sqlite for persistent storage; falls back to memory-only mode if unavailable.

Contributing

Contributions welcome! Please see the main repository for guidelines.

License

MIT © SyncFlow

Support