SyncKit is a comprehensive offline-first synchronization solution for web applications.
Find a file
Ersin KOÇ b7aa3b68d7
Merge pull request #1 from ersinkoc/claude/npm-llm-docs-generator-ZW5qg
Generate LLM-optimized documentation from NPM packages
2025-12-28 17:31:27 +02:00
.github/workflows simplify website build workflow and relax TypeScript strictness 2025-12-28 14:00:13 +02:00
examples init 2025-12-28 13:38:19 +02:00
src init 2025-12-28 13:38:19 +02:00
tests remove test setup mocks and simplify prepublishOnly script 2025-12-28 13:49:43 +02:00
website simplify website build workflow and relax TypeScript strictness 2025-12-28 14:00:13 +02:00
.eslintrc.json init 2025-12-28 13:38:19 +02:00
.gitignore init 2025-12-28 13:38:19 +02:00
.prettierrc init 2025-12-28 13:38:19 +02:00
CHANGELOG.md init 2025-12-28 13:38:19 +02:00
IMPLEMENTATION.md init 2025-12-28 13:38:19 +02:00
LICENSE init 2025-12-28 13:38:19 +02:00
LLMS.md Add comprehensive LLM-ready documentation 2025-12-28 13:36:21 +00:00
package.json remove test setup mocks and simplify prepublishOnly script 2025-12-28 13:49:43 +02:00
PROJECT.md init 2025-12-28 13:38:19 +02:00
README.md init 2025-12-28 13:38:19 +02:00
SPECIFICATION.md init 2025-12-28 13:38:19 +02:00
TASKS.md init 2025-12-28 13:38:19 +02:00
tsconfig.json init 2025-12-28 13:38:19 +02:00
tsup.config.ts init 2025-12-28 13:38:19 +02:00
vitest.config.ts init 2025-12-28 13:38:19 +02:00

SyncKit

Zero-dependency offline-first data sync toolkit with micro-kernel plugin architecture

npm version License: MIT TypeScript Bundle Size

SyncKit is a comprehensive offline-first synchronization solution for web applications. It queues operations when offline, automatically syncs when back online, handles conflicts with multiple resolution strategies, supports optimistic updates, and persists the queue to IndexedDB—all without any runtime dependencies.

Features

Offline-First: Queue operations when offline, auto-sync when back online 🔄 Conflict Resolution: Multiple strategies (last-write-wins, server-wins, client-wins, manual, custom) Optimistic Updates: Apply changes immediately with rollback capability 🎯 Priority Queue: Critical operations processed first 🔁 Automatic Retry: Configurable backoff strategies (exponential, linear, fibonacci) 💾 Persistent Storage: IndexedDB for reliable queue persistence 🧩 Plugin Architecture: Micro-kernel design with powerful plugin system ⚛️ Framework Adapters: First-class support for React, Vue, and Svelte 📦 Zero Dependencies: Everything implemented from scratch 🔒 Type-Safe: Full TypeScript support with strict mode 🌳 Tree-Shakeable: Only bundle what you use

Installation

npm install @oxog/synckit
yarn add @oxog/synckit
pnpm add @oxog/synckit

Quick Start

import { createSyncKit } from '@oxog/synckit'

// Create instance
const sync = createSyncKit({
  name: 'my-app',
  storage: 'indexeddb',
  executor: async (operation) => {
    const response = await fetch(`/api/${operation.resource}`, {
      method: operation.method,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(operation.payload)
    })
    return response.json()
  },
  conflictStrategy: 'last-write-wins',
  retry: {
    maxAttempts: 5,
    backoff: 'exponential'
  }
})

// Initialize
await sync.init()

// Push operations
const { operationId, rollback } = sync.push({
  resource: 'posts',
  method: 'POST',
  payload: { title: 'Hello', body: 'World' },
  priority: 'high',
  optimistic: true,
  onSuccess: (result) => console.log('Synced!', result),
  onError: (error) => {
    console.error('Failed:', error)
    rollback() // Revert optimistic update
  }
})

// Listen to events
sync.on('sync-success', (event) => {
  console.log('Operation synced:', event.operation)
})

sync.on('offline', () => {
  console.log('Gone offline, operations will be queued')
})

sync.on('online', () => {
  console.log('Back online, syncing queued operations')
})

// Check status
const status = sync.getStatus()
console.log(`${status.pending} pending, ${status.failed} failed`)

Framework Integration

React

import { SyncKitProvider, useSync, useSyncStatus } from '@oxog/synckit/react'

function App() {
  return (
    <SyncKitProvider config={{ name: 'my-app', storage: 'indexeddb', executor: ... }}>
      <MyApp />
    </SyncKitProvider>
  )
}

function CreatePost() {
  const { push, isOnline } = useSync()
  const { pending, failed } = useSyncStatus()

  const handleSubmit = (data) => {
    push({
      resource: 'posts',
      method: 'POST',
      payload: data,
      optimistic: true
    })
  }

  return (
    <div>
      {!isOnline && <Badge>Offline</Badge>}
      {pending > 0 && <Badge>{pending} pending</Badge>}
      <form onSubmit={handleSubmit}>...</form>
    </div>
  )
}

Vue

<script setup>
import { useSync, useSyncStatus } from '@oxog/synckit/vue'

const { push, isOnline } = useSync()
const { pending, failed } = useSyncStatus()

const handleSubmit = (data) => {
  push({
    resource: 'posts',
    method: 'POST',
    payload: data
  })
}
</script>

<template>
  <div>
    <span v-if="!isOnline">Offline</span>
    <span v-if="pending > 0">{{ pending }} pending</span>
    <form @submit.prevent="handleSubmit">...</form>
  </div>
</template>

Svelte

<script>
  import { syncStore, statusStore, onlineStore } from '@oxog/synckit/svelte'

  function handleSubmit(data) {
    $syncStore.push({
      resource: 'posts',
      method: 'POST',
      payload: data
    })
  }
</script>

{#if !$onlineStore}
  <span>Offline</span>
{/if}

{#if $statusStore.pending > 0}
  <span>{$statusStore.pending} pending</span>
{/if}

<form on:submit|preventDefault={handleSubmit}>...</form>

Core Concepts

Offline-First Architecture

SyncKit queues all operations and syncs them when online. The queue is persisted to IndexedDB, so operations survive page reloads and browser restarts.

Conflict Resolution

When the server rejects an operation due to a conflict (HTTP 409), SyncKit can resolve it automatically using one of these strategies:

  • last-write-wins: Compare timestamps, newer wins
  • server-wins: Always accept server data
  • client-wins: Always keep client data
  • manual: Wait for user decision
  • custom: Use your own resolution logic

Optimistic Updates

Apply changes immediately for instant UI feedback, then rollback if sync fails:

const { operationId, rollback } = sync.push({
  resource: 'posts/123',
  method: 'PUT',
  payload: updatedPost,
  optimistic: true,
  onError: () => rollback()
})

Priority Queue

Operations with higher priority are synced first:

sync.push({
  resource: 'critical-data',
  method: 'POST',
  payload: data,
  priority: 'critical' // critical > high > normal > low
})

Automatic Retry

Failed operations are retried automatically with configurable backoff:

createSyncKit({
  retry: {
    maxAttempts: 5,
    backoff: 'exponential', // or 'linear', 'fibonacci', or custom function
    baseDelay: 1000,
    maxDelay: 30000,
    jitter: true
  }
})

Plugins

SyncKit uses a micro-kernel architecture where all features are plugins.

Core Plugins (Always Loaded)

  • queue-manager: Priority queue management
  • network-monitor: Online/offline detection
  • storage-indexeddb: IndexedDB persistence
  • retry-engine: Automatic retry with backoff
  • conflict-resolver: Conflict detection and resolution

Optional Plugins

import {
  localStorageAdapter,
  batching,
  compression,
  encryption,
  backgroundSync,
  syncUI,
  analytics
} from '@oxog/synckit/plugins'

const sync = createSyncKit({
  storage: localStorageAdapter({ key: 'my-queue' }),
  plugins: [
    batching({ maxBatchSize: 10 }),
    compression({ threshold: 1024 }),
    encryption({ key: 'secret' }),
    backgroundSync({ tag: 'sync' }),
    syncUI({ position: 'bottom-right' }),
    analytics({ onReport: sendToAnalytics })
  ]
})

API Reference

See the full API documentation.

Core Methods

  • init() - Initialize and load queue from storage
  • destroy() - Cleanup resources
  • push(operation) - Add operation to queue
  • remove(operationId) - Remove operation
  • clear() - Clear entire queue
  • sync() - Force sync immediately
  • retry(operationId) - Retry specific operation
  • retryAll() - Retry all failed operations
  • pause() - Pause queue processing
  • resume() - Resume queue processing
  • getQueue() - Get all operations
  • getStatus() - Get queue statistics
  • on(event, handler) - Subscribe to events
  • off(event, handler) - Unsubscribe from events

Events

  • online / offline - Network status change
  • push - Operation added
  • sync-start / sync-success / sync-error - Sync lifecycle
  • conflict - Conflict detected
  • retry - Retry scheduled
  • queue-change - Queue modified
  • status-change - Status updated

Examples

See the examples directory for complete working examples:

Documentation

Full documentation available at https://synckit.oxog.dev

Browser Support

  • Chrome >= 87
  • Firefox >= 78
  • Safari >= 14
  • Edge >= 87

Requires:

  • IndexedDB (or localStorage fallback)
  • Promises
  • ES6+ features

Contributing

This is a zero-dependency project. All features must be implemented from scratch without adding runtime dependencies.

License

MIT © Ersin KOÇ