Cleanup RN AsyncStorage calls (#520)

This commit is contained in:
Leendert de Borst
2025-10-10 16:35:46 +02:00
parent 4bfe69750c
commit 09f61bd7a2
4 changed files with 36 additions and 102 deletions

View File

@@ -47,17 +47,8 @@ export default function SettingsScreen() : React.ReactNode {
*/
const loadStoredSettings = useCallback(async () : Promise<void> => {
try {
// Try to get API URL from native layer first, fallback to AsyncStorage
let apiUrl: string | null = null;
try {
apiUrl = await NativeVaultManager.getApiUrl();
} catch (nativeError) {
console.warn('Failed to get API URL from native layer, falling back to AsyncStorage:', nativeError);
apiUrl = await AsyncStorage.getItem('apiUrl');
}
const apiUrl = await NativeVaultManager.getApiUrl();
const matchingOption = DEFAULT_OPTIONS.find(opt => opt.value === apiUrl);
if (matchingOption) {
setSelectedOption(matchingOption.value);
} else if (apiUrl) {
@@ -81,8 +72,6 @@ export default function SettingsScreen() : React.ReactNode {
const handleOptionChange = async (value: string) : Promise<void> => {
setSelectedOption(value);
if (value !== 'custom') {
// Sync to both AsyncStorage and native layer
await AsyncStorage.setItem('apiUrl', value);
try {
await NativeVaultManager.setApiUrl(value);
} catch (error) {

View File

@@ -126,22 +126,10 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
* Set auth tokens in storage as part of the login process. After db is initialized, the login method should be called as well.
*/
const setAuthTokens = useCallback(async (username: string, accessToken: string, refreshToken: string): Promise<void> => {
// Store username in native layer (new approach)
await NativeVaultManager.setUsername(username);
await NativeVaultManager.setAuthTokens(accessToken, refreshToken);
// Keep AsyncStorage for backward compatibility / migration
// TODO: Remove AsyncStorage username storage in future version
await AsyncStorage.setItem('username', username);
await AsyncStorage.setItem('accessToken', accessToken);
await AsyncStorage.setItem('refreshToken', refreshToken);
// Sync tokens to native layer
try {
await NativeVaultManager.setAuthTokens(accessToken, refreshToken);
} catch (error) {
console.error('Failed to sync auth tokens to native layer:', error);
}
// Update React state
setUsername(username);
}, []);
@@ -150,38 +138,51 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
* @returns object containing whether the user is logged in and enabled auth methods
*/
const initializeAuth = useCallback(async (): Promise<{ isLoggedIn: boolean; enabledAuthMethods: AuthMethod[] }> => {
const accessToken = await AsyncStorage.getItem('accessToken') as string;
const refreshToken = await AsyncStorage.getItem('refreshToken') as string;
// Sync legacy config to native layer (can be removed in future version 0.25.0+)
syncLegacyConfigToNative();
// Try to get username from native layer first (new approach)
let username = await NativeVaultManager.getUsername();
// Fallback to AsyncStorage for migration
if (!username) {
username = await AsyncStorage.getItem('username');
// Migrate to native storage
if (username) {
await NativeVaultManager.setUsername(username);
}
}
// Load offline mode from native layer
const offline = await NativeVaultManager.getOfflineMode();
setIsOffline(offline);
const accessToken = await NativeVaultManager.getAccessToken();
const username = await NativeVaultManager.getUsername();
// Update local React state
let isAuthenticated = false;
let methods: AuthMethod[] = ['password'];
if (accessToken && refreshToken && username) {
// Check if user is logged in (has both access token and username)
if (accessToken && username) {
setUsername(username);
setIsLoggedIn(true);
isAuthenticated = true;
methods = await getEnabledAuthMethods();
}
const offline = await NativeVaultManager.getOfflineMode();
setIsInitialized(true);
setIsOffline(offline);
return { isLoggedIn: isAuthenticated, enabledAuthMethods: methods };
}, [getEnabledAuthMethods]);
/**
* Sync legacy config to native layer
*/
const syncLegacyConfigToNative = useCallback(async (): Promise<void> => {
// Migrate tokens from AsyncStorage to native on first launch, then remove to prevent repeated syncs
const accessToken = await AsyncStorage.getItem('accessToken');
const refreshToken = await AsyncStorage.getItem('refreshToken');
if (accessToken && refreshToken) {
await NativeVaultManager.setAuthTokens(accessToken, refreshToken);
await AsyncStorage.multiRemove(['accessToken', 'refreshToken']);
}
const username = await AsyncStorage.getItem('username');
if (username) {
await NativeVaultManager.setUsername(username);
await AsyncStorage.removeItem('username');
}
}, []);
/**
* Set logged in status to true which refreshes the app.
*/
@@ -199,7 +200,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
await NativeVaultManager.clearAuthTokens();
// Clear from AsyncStorage (for backward compatibility)
// TODO: Remove AsyncStorage cleanup in future version
// TODO: Remove AsyncStorage cleanup in future version 0.25.0+
await AsyncStorage.removeItem('username');
await AsyncStorage.removeItem('accessToken');
await AsyncStorage.removeItem('refreshToken');

View File

@@ -1,4 +1,3 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useState } from 'react';
import { AppInfo } from '@/utils/AppInfo';
@@ -21,7 +20,6 @@ export const useApiUrl = (): {
*/
const loadApiUrl = async (): Promise<void> => {
try {
// Try to get from native layer first
const storedUrl = await NativeVaultManager.getApiUrl();
if (storedUrl && storedUrl.length > 0) {
setApiUrl(storedUrl);
@@ -29,14 +27,7 @@ export const useApiUrl = (): {
setApiUrl(AppInfo.DEFAULT_API_URL);
}
} catch (error) {
console.warn('Failed to get API URL from native layer, falling back to AsyncStorage:', error);
// Fallback to AsyncStorage
const storedUrl = await AsyncStorage.getItem('apiUrl');
if (storedUrl && storedUrl.length > 0) {
setApiUrl(storedUrl);
} else {
setApiUrl(AppInfo.DEFAULT_API_URL);
}
console.warn('Failed to get API URL from native layer:', error);
}
};

View File

@@ -1,5 +1,3 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppInfo } from '@/utils/AppInfo';
import type { StatusResponse, VaultResponse, AuthLogModel, RefreshToken } from '@/utils/dist/shared/models/webapi';
@@ -25,14 +23,6 @@ type NativeWebApiResponse = {
* This class now acts as a proxy to the native layer, where all WebAPI calls are executed.
*/
export class WebApiService {
/**
* Constructor for the WebApiService class.
*/
public constructor() {
// Initialize API URL and tokens from AsyncStorage if they exist
this.syncLegacyConfigToNative();
}
/**
* Get the base URL for the API from settings.
*/
@@ -352,44 +342,7 @@ export class WebApiService {
return apiUrl || AppInfo.DEFAULT_API_URL;
} catch (error) {
console.error('Failed to get API URL from native layer:', error);
// Fallback to AsyncStorage
const result = await AsyncStorage.getItem('apiUrl') as string;
if (result && result.length > 0) {
return result;
}
return AppInfo.DEFAULT_API_URL;
}
}
/**
* Sync configuration from AsyncStorage to native layer on initialization.
*
* This is primarily for backward compatibility / migration purposes:
* - Existing users who upgraded from a version without native WebAPI will have tokens in AsyncStorage
* - This ensures those tokens are migrated to the native layer on first launch after upgrade
* - For new installations, all tokens/config go directly to native layer, so this becomes a no-op
*
* TODO: This can be removed in a future version (e.g., after some time that 0.24.0 is released)
* and once most if not all active users have migrated.
*/
private async syncLegacyConfigToNative(): Promise<void> {
try {
// Migrate API URL from AsyncStorage to native on first launch, then remove to prevent repeated syncs
const apiUrl = await AsyncStorage.getItem('apiUrl');
if (apiUrl) {
await NativeVaultManager.setApiUrl(apiUrl);
await AsyncStorage.removeItem('apiUrl');
}
// Migrate tokens from AsyncStorage to native on first launch, then remove to prevent repeated syncs
const accessToken = await AsyncStorage.getItem('accessToken');
const refreshToken = await AsyncStorage.getItem('refreshToken');
if (accessToken && refreshToken) {
await NativeVaultManager.setAuthTokens(accessToken, refreshToken);
await AsyncStorage.multiRemove(['accessToken', 'refreshToken']);
}
} catch (error) {
console.error('Failed to sync config to native layer:', error);
}
}
}