33import 'dart:async' ;
44import 'dart:convert' ;
55import 'dart:ffi' ;
6- import 'dart:io' show Platform;
76
87import 'package:ffi/ffi.dart' ;
98import 'package:flutter_secure_storage/flutter_secure_storage.dart' ;
@@ -105,8 +104,8 @@ class DartBridgeAuth {
105104 static void reset () {
106105 try {
107106 final lib = PlatformLoader .loadCommons ();
108- final resetFn =
109- lib .lookupFunction< Void Function (), void Function ()> ('rac_auth_reset' );
107+ final resetFn = lib
108+ .lookupFunction< Void Function (), void Function ()> ('rac_auth_reset' );
110109 resetFn ();
111110 } catch (e) {
112111 _logger.debug ('rac_auth_reset not available: $e ' );
@@ -204,7 +203,8 @@ class DartBridgeAuth {
204203 try {
205204 const storage = FlutterSecureStorage (
206205 aOptions: AndroidOptions (encryptedSharedPreferences: true ),
207- iOptions: IOSOptions (accessibility: KeychainAccessibility .first_unlock),
206+ iOptions:
207+ IOSOptions (accessibility: KeychainAccessibility .first_unlock),
208208 );
209209 deviceId = await storage.read (key: 'com.runanywhere.sdk.deviceId' );
210210 if (deviceId != null && deviceId.isNotEmpty) {
@@ -244,7 +244,8 @@ class DartBridgeAuth {
244244 'Accept' : 'application/json' ,
245245 };
246246
247- final response = await http.post (url, headers: headers, body: requestJson);
247+ final response =
248+ await http.post (url, headers: headers, body: requestJson);
248249
249250 if (response.statusCode == 200 || response.statusCode == 201 ) {
250251 final authData = _parseAuthResponse (response.body);
@@ -285,7 +286,8 @@ class DartBridgeAuth {
285286 _logger.debug ('Token needs refresh' );
286287 final result = await refreshToken ();
287288 if (! result.isSuccess) {
288- _logger.warning ('Token refresh failed' , metadata: {'error' : result.error});
289+ _logger
290+ .warning ('Token refresh failed' , metadata: {'error' : result.error});
289291 // Return cached token anyway, server will reject if invalid
290292 return cachedToken ?? getAccessToken ();
291293 }
@@ -300,8 +302,8 @@ class DartBridgeAuth {
300302 Future <void > clearAuth () async {
301303 try {
302304 final lib = PlatformLoader .loadCommons ();
303- final clearFn =
304- lib .lookupFunction< Void Function (), void Function ()> ('rac_auth_clear' );
305+ final clearFn = lib
306+ .lookupFunction< Void Function (), void Function ()> ('rac_auth_clear' );
305307 clearFn ();
306308
307309 // Also clear via state bridge
@@ -331,8 +333,9 @@ class DartBridgeAuth {
331333 bool needsRefresh () {
332334 try {
333335 final lib = PlatformLoader .loadCommons ();
334- final needsRefreshFn = lib.lookupFunction< Int32 Function (), int Function ()> (
335- 'rac_auth_needs_refresh' );
336+ final needsRefreshFn =
337+ lib.lookupFunction< Int32 Function (), int Function ()> (
338+ 'rac_auth_needs_refresh' );
336339 return needsRefreshFn () != 0 ;
337340 } catch (e) {
338341 return false ;
@@ -412,19 +415,23 @@ class DartBridgeAuth {
412415 try {
413416 final lib = PlatformLoader .loadCommons ();
414417 final buildRequest = lib.lookupFunction<
415- Pointer <Utf8 > Function (Pointer <RacSdkConfigStruct >),
416- Pointer <Utf8 > Function (
417- Pointer < RacSdkConfigStruct >) > ( 'rac_auth_build_authenticate_request' );
418+ Pointer <Utf8 > Function (Pointer <RacSdkConfigStruct >),
419+ Pointer <Utf8 > Function ( Pointer < RacSdkConfigStruct >) > (
420+ 'rac_auth_build_authenticate_request' );
418421
419422 final config = calloc <RacSdkConfigStruct >();
420423 final apiKeyPtr = apiKey.toNativeUtf8 ();
421424 final deviceIdPtr = deviceId.toNativeUtf8 ();
422- final buildTokenPtr = buildToken? .toNativeUtf8 () ?? nullptr;
425+ final platformPtr = SDKConstants .platform.toNativeUtf8 ();
426+ final sdkVersionPtr = SDKConstants .version.toNativeUtf8 ();
423427
424428 try {
429+ config.ref.environment = 0 ;
425430 config.ref.apiKey = apiKeyPtr;
431+ config.ref.baseURL = nullptr;
426432 config.ref.deviceId = deviceIdPtr;
427- config.ref.buildToken = buildTokenPtr.cast <Utf8 >();
433+ config.ref.platform = platformPtr;
434+ config.ref.sdkVersion = sdkVersionPtr;
428435
429436 final result = buildRequest (config);
430437 if (result == nullptr) return null ;
@@ -440,18 +447,18 @@ class DartBridgeAuth {
440447 } finally {
441448 calloc.free (apiKeyPtr);
442449 calloc.free (deviceIdPtr);
443- if (buildTokenPtr != nullptr) calloc.free (buildTokenPtr);
450+ calloc.free (platformPtr);
451+ calloc.free (sdkVersionPtr);
444452 calloc.free (config);
445453 }
446454 } catch (e) {
447455 _logger.debug ('rac_auth_build_authenticate_request error: $e ' );
448456 // Fallback: build JSON manually (must match C++ rac_auth_request_to_json format)
449457 // Backend expects snake_case keys: api_key, device_id, platform, sdk_version
450- final platform = Platform .isAndroid ? 'android' : 'ios' ;
451458 final json = {
452459 'api_key' : apiKey,
453460 'device_id' : deviceId,
454- 'platform' : platform,
461+ 'platform' : SDKConstants . platform,
455462 'sdk_version' : SDKConstants .version,
456463 };
457464 _logger.debug ('Auth request JSON: $json ' );
@@ -564,17 +571,17 @@ class DartBridgeAuth {
564571 data['access_token' ] as String ? ?? data['accessToken' ] as String ? ;
565572 final refreshToken =
566573 data['refresh_token' ] as String ? ?? data['refreshToken' ] as String ? ;
567- final deviceId = data['device_id' ] as String ? ?? data['deviceId' ] as String ? ;
574+ final deviceId =
575+ data['device_id' ] as String ? ?? data['deviceId' ] as String ? ;
568576 final userId = data['user_id' ] as String ? ?? data['userId' ] as String ? ;
569- final organizationId =
570- data['organization_id' ] as String ? ?? data[ ' organizationId' ] as String ? ;
577+ final organizationId = data[ 'organization_id' ] as String ? ??
578+ data['organizationId' ] as String ? ;
571579
572580 // Parse expiry - API returns expires_in (seconds until expiry)
573581 int ? expiresAt;
574582 final expiresIn = data['expires_in' ] as int ? ;
575583 if (expiresIn != null ) {
576- expiresAt =
577- DateTime .now ().millisecondsSinceEpoch ~ / 1000 + expiresIn;
584+ expiresAt = DateTime .now ().millisecondsSinceEpoch ~ / 1000 + expiresIn;
578585 } else {
579586 expiresAt = data['expires_at' ] as int ? ?? data['expiresAt' ] as int ? ;
580587 }
@@ -623,17 +630,22 @@ class DartBridgeAuth {
623630
624631 if (authData.accessToken != null && authData.accessToken! .isNotEmpty) {
625632 await storage.write (
626- key: 'com.runanywhere.sdk.accessToken' , value: authData.accessToken);
633+ key: 'com.runanywhere.sdk.accessToken' ,
634+ value: authData.accessToken);
627635 _secureCache['com.runanywhere.sdk.accessToken' ] = authData.accessToken! ;
628636 storedCount++ ;
629- _logger.debug ('Stored access token (${authData .accessToken !.length } chars)' );
637+ _logger.debug (
638+ 'Stored access token (${authData .accessToken !.length } chars)' );
630639 }
631640 if (authData.refreshToken != null && authData.refreshToken! .isNotEmpty) {
632641 await storage.write (
633- key: 'com.runanywhere.sdk.refreshToken' , value: authData.refreshToken);
634- _secureCache['com.runanywhere.sdk.refreshToken' ] = authData.refreshToken! ;
642+ key: 'com.runanywhere.sdk.refreshToken' ,
643+ value: authData.refreshToken);
644+ _secureCache['com.runanywhere.sdk.refreshToken' ] =
645+ authData.refreshToken! ;
635646 storedCount++ ;
636- _logger.debug ('Stored refresh token (${authData .refreshToken !.length } chars)' );
647+ _logger.debug (
648+ 'Stored refresh token (${authData .refreshToken !.length } chars)' );
637649 }
638650 if (authData.deviceId != null && authData.deviceId! .isNotEmpty) {
639651 await storage.write (
@@ -643,19 +655,23 @@ class DartBridgeAuth {
643655 _logger.debug ('Stored device ID: ${authData .deviceId }' );
644656 }
645657 if (authData.userId != null && authData.userId! .isNotEmpty) {
646- await storage.write (key: 'com.runanywhere.sdk.userId' , value: authData.userId);
658+ await storage.write (
659+ key: 'com.runanywhere.sdk.userId' , value: authData.userId);
647660 _secureCache['com.runanywhere.sdk.userId' ] = authData.userId! ;
648661 storedCount++ ;
649662 }
650- if (authData.organizationId != null && authData.organizationId! .isNotEmpty) {
663+ if (authData.organizationId != null &&
664+ authData.organizationId! .isNotEmpty) {
651665 await storage.write (
652- key: 'com.runanywhere.sdk.organizationId' , value: authData.organizationId);
666+ key: 'com.runanywhere.sdk.organizationId' ,
667+ value: authData.organizationId);
653668 _secureCache['com.runanywhere.sdk.organizationId' ] =
654669 authData.organizationId! ;
655670 storedCount++ ;
656671 }
657672
658- _logger.debug ('Auth tokens stored in secure storage ($storedCount items)' );
673+ _logger
674+ .debug ('Auth tokens stored in secure storage ($storedCount items)' );
659675 } catch (e) {
660676 _logger.debug ('Failed to store auth tokens: $e ' );
661677 }
@@ -680,11 +696,14 @@ class DartBridgeAuth {
680696 iOptions: IOSOptions (accessibility: KeychainAccessibility .first_unlock),
681697 );
682698
683- final accessToken = await storage.read (key: 'com.runanywhere.sdk.accessToken' );
684- final refreshToken = await storage.read (key: 'com.runanywhere.sdk.refreshToken' );
699+ final accessToken =
700+ await storage.read (key: 'com.runanywhere.sdk.accessToken' );
701+ final refreshToken =
702+ await storage.read (key: 'com.runanywhere.sdk.refreshToken' );
685703 final deviceId = await storage.read (key: 'com.runanywhere.sdk.deviceId' );
686704 final userId = await storage.read (key: 'com.runanywhere.sdk.userId' );
687- final organizationId = await storage.read (key: 'com.runanywhere.sdk.organizationId' );
705+ final organizationId =
706+ await storage.read (key: 'com.runanywhere.sdk.organizationId' );
688707
689708 if (accessToken != null ) {
690709 _secureCache['com.runanywhere.sdk.accessToken' ] = accessToken;
@@ -761,8 +780,8 @@ int _secureStoreCallback(
761780}
762781
763782/// Retrieve callback
764- int _secureRetrieveCallback (
765- Pointer < Utf8 > key, Pointer < Utf8 > outValue, int bufferSize, Pointer <Void > context) {
783+ int _secureRetrieveCallback (Pointer < Utf8 > key, Pointer < Utf8 > outValue,
784+ int bufferSize, Pointer <Void > context) {
766785 if (key == nullptr || outValue == nullptr) return - 1 ;
767786
768787 try {
@@ -845,8 +864,8 @@ typedef RacSecureStoreCallbackNative = Int32 Function(
845864 Pointer <Utf8 > key, Pointer <Utf8 > value, Pointer <Void > context);
846865
847866/// Secure storage retrieve callback
848- typedef RacSecureRetrieveCallbackNative = Int32 Function (
849- Pointer <Utf8 > key, Pointer < Utf8 > outValue, IntPtr bufferSize, Pointer <Void > context);
867+ typedef RacSecureRetrieveCallbackNative = Int32 Function (Pointer < Utf8 > key,
868+ Pointer <Utf8 > outValue, IntPtr bufferSize, Pointer <Void > context);
850869
851870/// Secure storage delete callback
852871typedef RacSecureDeleteCallbackNative = Int32 Function (
@@ -861,10 +880,16 @@ base class RacSecureStorageCallbacksStruct extends Struct {
861880}
862881
863882/// SDK config struct for auth requests
883+ /// Must exactly match C++ `rac_sdk_config_t` .
864884base class RacSdkConfigStruct extends Struct {
885+ @Int 32()
886+ external int environment;
887+
865888 external Pointer <Utf8 > apiKey;
889+ external Pointer <Utf8 > baseURL;
866890 external Pointer <Utf8 > deviceId;
867- external Pointer <Utf8 > buildToken;
891+ external Pointer <Utf8 > platform;
892+ external Pointer <Utf8 > sdkVersion;
868893}
869894
870895// =============================================================================
0 commit comments