OfflineOutbox class
Append-only event log of pending Supabase writes that the device couldn't (or won't) flush online immediately.
Each enqueued row represents one logical write intent — e.g. "insert this conversation_messages row" or "upsert this user_topic_progress row". The SyncWorker drains the log when connectivity returns, replaying each event against the live Supabase client.
The schema is deliberately generic (a single outbox_events table with
a payload JSON blob) rather than mirroring every Supabase table.
Reasons:
- Phase 3 only needs the write path to survive offline; reads remain online-first (the chat notifier keeps messages in memory during a session). Denormalized per-table mirrors land later if and when read-path offline support is required.
- Adding a new table to the outbox means a new
tableName/payload shape, not a schema migration on the local DB. - The original plan used Drift; the current riverpod_lint pin made
its analyzer-10 requirement incompatible, so this is the raw
sqlite3equivalent. Seepubspec.yamlfor the resolution history.
Web has no native sqlite — local_vector_store_stub.dart set the
precedent; the matching offline_outbox_stub.dart returns no-op
instances and the Riverpod provider yields null under kIsWeb.
Constructors
Properties
Methods
-
delete(
int id) → void -
Permanently remove an event. Used by the "Needs attention" UI when
the user explicitly discards a row, and for periodic cleanup of
syncedrows older than a retention window (not yet implemented). -
dispose(
) → void -
enqueue(
{required String localId, required String tableName, required String operation, required Map< String, dynamic> payload, DateTime? clientUpdatedAt}) → Future<int> -
Append a write intent. Returns the autoincrement row id.
clientUpdatedAtis the wall-clock at the time of the user action, used by SyncWorker for last-write-wins conflict resolution. -
failedEvents(
{int limit = 50}) → List< OutboxEvent> -
Just the
failedrows — convenience for the "Needs attention" list, which doesn't want to show pending/syncing rows because those resolve on their own. -
initialize(
) → Future< void> -
markFailed(
int id, String error) → void -
Mark an event as failed; SyncWorker will retry with backoff next
cycle. After enough attempts the row stays in
failedand is surfaced in the "Needs attention" UI. -
markPending(
int id) → void -
Flip a
failedrow back topendingso the next SyncWorker drain attempts it again. Used by the "Needs attention" UI's retry button. Resetslast_errorso a stale message doesn't keep showing while the row is back in flight. -
markSynced(
int id, {String? serverId}) → void - Mark an event as successfully replayed. Records the server-assigned id (if any) so future re-emits (e.g. an update after an insert) can reference the right row.
-
markSyncing(
int id) → void - Mark an event as in-flight to a Supabase write. Prevents the SyncWorker from picking it up again if it crashes mid-call.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
pendingAndFailed(
{int limit = 100}) → List< OutboxEvent> -
Oldest-first list of events that haven't synced yet.
failedrows are surfaced too so the SyncWorker can retry them (with backoff) and the "Needs attention" UI can show them. -
pendingCount(
) → int -
Count of unsynced rows. Used by Settings to surface a "N pending"
hint and by
SyncWorkerto short-circuit when empty. -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited