Flutter Sync Client

pub package License: MIT

Real-time data synchronization plugin for Flutter with Hive and Socket.IO. Supports both untyped and type-safe collections with fast O(1) indexed searching.

Features

  • Real-time synchronization with Socket.IO
  • Offline support with Hive local storage
  • Type-safe collections with generics and optimized caching
  • Fast O(1) searching with in-memory indexing
  • Bulk Operations for efficient batch processing
  • Error Handling with a dedicated error stream
  • Automatic reconnection and conflict resolution
  • Authentication support with JWT tokens
  • Flutter Web support - works in browsers

Installation

Add to your pubspec.yaml:

dependencies:
  flutter_sync_client: ^0.2.0

Then run:

flutter pub get

Usage

1. Initialize Client

final syncClient = SyncClient(
  serverUrl: 'http://your-server.com:3000',
);
await syncClient.initialize();

2. Get Collection Reference

final todosCollection = syncClient.collection('todos');

3. Listen to Changes

StreamBuilder<List<Map<String, dynamic>>>(
  stream: todosCollection.stream,
  builder: (context, snapshot) {
    final todos = snapshot.data ?? [];
    return ListView.builder(
      itemCount: todos.length,
      itemBuilder: (context, index) {
        return ListTile(title: Text(todos[index]['title']));
      },
    );
  },
)

4. CRUD Operations

// Insert
await todosCollection.insert({
  'id': '1', // Optional: server can generate ID
  'title': 'Buy milk',
  'completed': false,
});

// Update
await todosCollection.update('1', {
  'completed': true,
});

// Delete
await todosCollection.delete('1');

5. Connection & Error Handling

Monitor the connection status and listen for errors.

// Listen to connection status
syncClient.connectionStream.listen((isConnected) {
  print(isConnected ? 'Connected' : 'Disconnected');
});

// Listen for errors
syncClient.onError.listen((error) {
  print("Sync Error: $error");
  // Show a SnackBar or dialog
});

Type-Safe Collections

Work with your own model classes and enjoy O(1) fast searches with indexed fields!

1. Define Your Model

class Todo {
  final String id;
  final String title;
  final bool completed;

  Todo({required this.id, required this.title, required this.completed});

  factory Todo.fromJson(Map<String, dynamic> json) => Todo(
    id: json['id'].toString(),
    title: json['title'] as String,
    completed: json['completed'] as bool,
  );

  Map<String, dynamic> toJson() => {
    'id': id,
    'title': title,
    'completed': completed,
  };
}

2. Create Typed Collection

final todos = syncClient.typedCollection<Todo>(
  'todos',
  fromJson: Todo.fromJson,
  toJson: (todo) => todo.toJson(),
  getId: (todo) => todo.id,
  indexedFields: ['completed'],  // Fast O(1) search by completion status!
);

3. Use Type-Safe API

// Insert with type safety
await todos.insert(Todo(id: '1', title: 'Buy milk', completed: false));

// Fast O(1) indexed search
final completed = await todos.findByField('completed', true);

// Custom queries with optimized cache
final pending = await todos.where((todo) => !todo.completed);

// Get by ID (O(1) from cache)
final todo = await todos.get('1');

// Real-time typed stream
todos.stream.listen((List<Todo> todoList) {
  print('Todos updated: ${todoList.length}');
});

Bulk Operations

Efficiently insert, update, or delete multiple items at once. This reduces network overhead and is significantly faster for large batches.

insertMany

// Untyped
await todosCollection.insertMany([
  {'title': 'Task 1', 'completed': false},
  {'title': 'Task 2', 'completed': false},
]);

// Typed
await todos.insertMany([
  Todo(id: '3', title: 'Task 3', completed: false),
  Todo(id: '4', title: 'Task 4', completed: false),
]);

updateMany

// Untyped
await todosCollection.updateMany([
  {'id': '1', 'completed': true},
  {'id': '2', 'completed': true},
]);

// Typed
final itemsToUpdate = await todos.where((t) => !t.completed);
final updatedItems = itemsToUpdate.map((t) =>
  Todo(id: t.id, title: t.title, completed: true)
).toList();
await todos.updateMany(updatedItems);

deleteMany

// Both untyped and typed collections support this
await todos.deleteMany(['1', '2']);

Authentication

Support for JWT token authentication:

final client = SyncClient(
  serverUrl: 'http://your-server.com:3000',
  authToken: 'your-jwt-token',
);

// Or set token later
client.setAuthToken('new-token');

// Or use token provider for automatic refresh
client.setTokenProvider(() async {
  // This function will be called to get a fresh token
  return await getTokenFromStorage();
});

Platform Support

Platform Status Notes
Android ✅ Full Support Native Hive + Socket.IO
iOS ✅ Full Support Native Hive + Socket.IO
Web Full Support IndexedDB + Socket.IO
Windows ⚠️ Partial Hive limitations
macOS ⚠️ Partial Hive limitations
Linux ⚠️ Partial Hive limitations

See WEB_SUPPORT.md for web-specific details and CORS configuration.

Documentation

Example App

The example app has been updated to demonstrate all the new features, including:

  • Type-safe collections with a data model
  • Bulk operations (add, update, delete)
  • Connection status and error handling

To run it:

cd example
flutter run

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE file for details.