๐Ÿ“ฆ Offline Outbox Sync for Flutter (ObjectBox + Isolate + Retry + Multipart Support)

A powerful and lightweight offline-first outbox queue system for Flutter apps. Designed for real-world enterprise use cases where network instability, large payloads, and token expiry must be handled automatically.

Supports:

    โœ… JSON API requests

    โœ… Multipart file uploads

    โœ… Multiple files per request

    โœ… Empty multipart field names

    โœ… Automatic retry with priority

    โœ… Automatic token refresh (401 handling)

    โœ… Runs in Isolate for non-blocking UI

    โœ… ObjectBox storage for fast persistence

    โœ… Fully background-safe
Feature Status
JSON request outbox โœ…
Multipart upload (files/images/docs) โœ…
Multiple files with dynamic field names โœ…
Empty file field name ("") support โœ…
Priority-based queue (1 โ†’ 4) โœ…
Automatic retry on failures โœ…
Retry with new token on 401 โœ…
Save status code + response โœ…
RootIsolateToken support โœ…
Zero UI freeze Isolate-based
Production-ready ๐Ÿ”ฅ

๐Ÿ“ฆ Installation

Add to pubspec.yaml:

  dependencies:
    ma_ng_outbox: latest

Make sure ObjectBox is installed:

  dependencies:
    objectbox: any
    objectbox_flutter_libs: any

๐Ÿ›  Basic Setup 1๏ธโƒฃ Initialize Outbox in main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await OutboxBootstrap.setup();
  runApp(MyApp());
}

๐Ÿงฑ How Outbox Works

Every API call is stored as an OutboxItem:


await objectBox.addToOutbox(
  operation: "POST",
  url: "https://api.server.com/save",
  payload: {"title": "Offline Save"},
  priority: Priority.high,
  primaryKey: "local-123",
  filePathsJson: [''],
  fileFieldsJson: ['']
);


Then Outbox will:

    โœ” Automatically sync when online

    โœ” Retry failed requests

    โœ” Retry 401 using refresh token

    โœ” Save response & status code

    โœ” Process highest priority first

๐Ÿงต Architecture Overview

UI Layer โ”€โ”€โ–บ addToOutbox() โ”€โ”€โ–บ ObjectBox storage
                   โ”‚
                   โ–ผ
          Background Sync Trigger
                   โ”‚
                   โ–ผ
             Isolate Spawned
                   โ”‚
                   โ–ผ
       outboxIsolateEntry() processing
                   โ”‚
   โ”œโ”€โ”€โ–บ JSON Request
   โ”œโ”€โ”€โ–บ Multipart Request
   โ”œโ”€โ”€โ–บ Multi-file Upload
   โ””โ”€โ”€โ–บ Retry on 401 (Refresh Token)
                   โ”‚
                   โ–ผ
       Main Isolate receives result
                   โ”‚
                   โ–ผ
   Updates ObjectBox (status + response)

๐Ÿ“ Adding File Upload Requests โญ One File

await objectBox.addToOutbox(
  operation: "POST",
  url: Api.uploadImage,
  payload: {
    "description": "Offline photo",
    "userId": 12,
  },
  filePathsJson: jsonEncode([imageFile.path]),
  fileFieldsJson: jsonEncode(["file"]), // or ""
);

โญ Multiple Files

await objectBox.addToOutbox(
  operation: "POST",
  url: Api.uploadDocuments,
  payload: {"caseId": 55},
  filePathsJson: jsonEncode([frontPath, backPath]),
  fileFieldsJson: jsonEncode(["front", "back"]),
);

๐Ÿ” Token Refresh Flow (401 Handling)
    1.If API returns 401 Unauthorized:

    2.Outbox calls refresh token API

    3.Saves new access token to OutboxItem

    4.Retries the original request automatically

    5.Continues syncing

This is built-in.

๐Ÿ”„ Manual Triggering of Sync

SyncController.runIsolateSync(
  objectBox: objectBox,
  token: "<accessToken>",
  rootToken: rootToken,
);

๐Ÿš€ Performance & Scaling

    * 25,000+ outbox items stress-tested

    * Large file uploads supported

    * Zero UI freeze due to isolate-based architecture

    * Perfect for enterprise offline-first apps