From 79130a6dd7cba1fd0b59648f6b6678d27dda987b Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sat, 22 Aug 2026 18:47:10 +0200 Subject: [PATCH] Require desktopClientId rather than defaulting it to empty An optional '' default reads as "this parameter is usually irrelevant", and it made `avoid_redundant_argument_values` fire in the first app to pass '' explicitly -- pushing that app toward deleting the argument, which is exactly the line that must stay for when the Desktop client id arrives. Requiring it forces each app to state which halves it configured. Passing '' still means "not configured"; it just has to be said out loud. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CFSGeWxHPY5rHUGrPqhcmG --- crdt_sync_flutter/README.md | 2 +- .../lib/src/google_any_sign_in.dart | 10 +++--- crdt_sync_flutter/pubspec.yaml | 2 +- .../test/google_any_sign_in_test.dart | 33 +++++++++++++++---- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/crdt_sync_flutter/README.md b/crdt_sync_flutter/README.md index c07997f..54d4808 100644 --- a/crdt_sync_flutter/README.md +++ b/crdt_sync_flutter/README.md @@ -26,7 +26,7 @@ dependencies: crdt_sync_flutter: git: url: https://github.com/kuhyx/utils - ref: crdt_sync_flutter-v0.2.0 + ref: crdt_sync_flutter-v0.2.1 path: crdt_sync_flutter ``` diff --git a/crdt_sync_flutter/lib/src/google_any_sign_in.dart b/crdt_sync_flutter/lib/src/google_any_sign_in.dart index b890c31..0e61a08 100644 --- a/crdt_sync_flutter/lib/src/google_any_sign_in.dart +++ b/crdt_sync_flutter/lib/src/google_any_sign_in.dart @@ -22,10 +22,12 @@ import 'package:crdt_sync_flutter/src/google_sign_in.dart'; /// /// [serverClientId] is the **Web** OAuth client id (the audience for the /// plugin's tokens); [desktopClientId] is a **Desktop**-type client, the only -/// type permitted to redirect to loopback. +/// type permitted to redirect to loopback. Both are required, and passing '' +/// is how an app says it has not configured that half -- explicit, because a +/// silently-defaulted '' is how a button that can never succeed gets shipped. bool googleAnySignInSupported({ required String serverClientId, - String desktopClientId = '', + required String desktopClientId, }) => googleSignInSupported(serverClientId) || desktopSignInSupported(desktopClientId); @@ -59,7 +61,7 @@ enum GoogleFlow { /// Picks the flow for this platform and configuration. GoogleFlow googleFlowFor({ required String serverClientId, - String desktopClientId = '', + required String desktopClientId, }) { if (googleSignInSupported(serverClientId)) return GoogleFlow.plugin; if (desktopSignInSupported(desktopClientId)) return GoogleFlow.desktop; @@ -72,7 +74,7 @@ GoogleFlow googleFlowFor({ /// back to the password path either way. Future googleAnyIdToken({ required String serverClientId, - String desktopClientId = '', + required String desktopClientId, }) async { switch (googleFlowFor( serverClientId: serverClientId, diff --git a/crdt_sync_flutter/pubspec.yaml b/crdt_sync_flutter/pubspec.yaml index 7f0881a..af83800 100644 --- a/crdt_sync_flutter/pubspec.yaml +++ b/crdt_sync_flutter/pubspec.yaml @@ -4,7 +4,7 @@ description: >- persisted per-install device id, and a one-call bootstrap. Removes the ~150 lines of firebase_backend.dart every consuming app was copying. publish_to: 'none' -version: 0.2.0 +version: 0.2.1 environment: sdk: ^3.12.2 diff --git a/crdt_sync_flutter/test/google_any_sign_in_test.dart b/crdt_sync_flutter/test/google_any_sign_in_test.dart index eb6e96d..c7a5abd 100644 --- a/crdt_sync_flutter/test/google_any_sign_in_test.dart +++ b/crdt_sync_flutter/test/google_any_sign_in_test.dart @@ -29,13 +29,22 @@ void main() { }); test('is false when neither half is configured', () { - expect(googleAnySignInSupported(serverClientId: ''), isFalse); + expect( + googleAnySignInSupported(serverClientId: '', desktopClientId: ''), + isFalse, + ); }); test('is false on this host when only the plugin half is configured', () { // The plugin does not run on Linux, so a Web client id alone buys // nothing here -- and the button must not appear. - expect(googleAnySignInSupported(serverClientId: 'web-cid'), isFalse); + expect( + googleAnySignInSupported( + serverClientId: 'web-cid', + desktopClientId: '', + ), + isFalse, + ); }); }); @@ -48,25 +57,37 @@ void main() { }); test('picks nothing when neither half is configured', () { - expect(googleFlowFor(serverClientId: ''), GoogleFlow.none); + expect( + googleFlowFor(serverClientId: '', desktopClientId: ''), + GoogleFlow.none, + ); }); test('picks nothing when only the plugin half is configured here', () { // The plugin does not run on Linux, so a Web client id alone must not // route anywhere -- that would be a button that cannot succeed. - expect(googleFlowFor(serverClientId: 'web-cid'), GoogleFlow.none); + expect( + googleFlowFor(serverClientId: 'web-cid', desktopClientId: ''), + GoogleFlow.none, + ); }); }); group('googleAnyIdToken', () { test('returns null when no flow is available', () async { - expect(await googleAnyIdToken(serverClientId: ''), isNull); + expect( + await googleAnyIdToken(serverClientId: '', desktopClientId: ''), + isNull, + ); }); test('returns null when the plugin half alone is configured', () async { // Would reach the plugin's platform channel if the gate were wrong, // which throws rather than returning null. - expect(await googleAnyIdToken(serverClientId: 'web-cid'), isNull); + expect( + await googleAnyIdToken(serverClientId: 'web-cid', desktopClientId: ''), + isNull, + ); }); }); }