todo-app/lib/sync/run_sync.dart
Krzysztof kuhy Rudnicki d316563015
Some checks are pending
release-apk / release (APK) (push) Waiting to run
Fix desktop Firebase sync: seed a Google-derived session, not a dead password
The account's password grant is retired fleet-wide (see link_google.py /
seed_session.py in ~/utils/crdt-sync), so desktop's Firebase form could never
have connected regardless of provisioning. Desktop-as-web can't use the
in-browser Google Sign-In button either (google_platform_web.dart hard-codes
googleSignInSupported = false), so it needs the same session-seeding path the
Python daemons already use: seed_session.py now includes todo, and the
wrapper's new /sync-credentials route serves that seeded session to
loadAccount() once per launch, then closes for the rest of the process.

Also stops the status line reporting a bare "Synced" while running over the
GitHub mirror alone with Firebase disconnected -- SyncResult now carries
firebaseConnected so the UI can say "GitHub-only (Firebase not connected)".

Includes the prior session's Google Sign-In one-tap addition
(google_sign_in_backend.dart and friends), which this builds on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FPsyKQRX8ZwJpUqg37jp83
2026-08-12 19:35:18 +02:00

64 lines
2.3 KiB
Dart

/// One place that decides *how* a sync runs, for every screen that
/// triggers one.
///
/// The capture screen syncs on a timer and on demand, the settings screen on a
/// button; before this they each built their own client, so a change to the
/// backend meant editing four call sites and hoping none was missed.
library;
import 'package:crdt_sync/crdt_sync.dart';
import 'package:http/http.dart' as http;
import 'package:todo/data/note_repository.dart';
import 'package:todo/sync/firebase_backend.dart';
import 'package:todo/sync/sync_service.dart';
import 'package:todo/sync/sync_settings.dart';
import 'package:todo/sync/sync_state_factory.dart';
/// Runs one sync, choosing the backend and carrying the revision cache.
///
/// Firebase is the primary when this device has been set up for it, with
/// GitHub kept as a mirror so a device that has not moved yet still
/// converges. Not being set up is a normal state, not an error — sync runs
/// over GitHub exactly as it did before.
///
/// [firebaseFactory] and [stateStore] exist for tests, which must not reach
/// the OS keystore or an application-support directory.
Future<SyncResult> runSync(
NoteRepository repository,
SyncSettings settings, {
http.Client? httpClient,
Future<FirebaseRestClient?> Function()? firebaseFactory,
SyncStateStore? stateStore,
}) async {
final github = GitHubClient(
owner: settings.owner,
repo: settings.repo,
token: settings.token,
httpClient: httpClient,
);
final factory = firebaseFactory ?? openFirebase;
final firebase = await factory();
try {
final service = SyncService(
// The production default resolves a real application-support directory
// through path_provider, which has no binding under `flutter test`;
// every test injects a store instead.
// coverage:ignore-start
stateStore: stateStore ?? await openSyncStateStore(),
// coverage:ignore-end
);
final result = await service.sync(
repository,
firebase == null
? github
: MirrorStore(primary: firebase, mirror: github),
);
return result.withFirebaseConnected(value: firebase != null);
} finally {
// Close both: unlike the long-lived desktop callers, each screen builds
// these per run.
github.close();
firebase?.close();
}
}