97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { Platform } from 'react-native';
|
|
import * as SecureStore from 'expo-secure-store';
|
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
|
/**
|
|
* 🚀 Unified Storage System for biiproject
|
|
* Handles both Native (AsyncStorage/SecureStore) and Web (LocalStorage) seamlessly.
|
|
*/
|
|
const SENSITIVE_KEYS = ['user_token', 'saved_pass', 'biometric_credentials'];
|
|
|
|
// In-memory fallback for environments where storage is unavailable (e.g. some web modes or broken native modules)
|
|
const memoryStorage: Record<string, string> = {};
|
|
|
|
export const storage = {
|
|
save: async (key: string, value: string) => {
|
|
try {
|
|
if (Platform.OS === 'web') {
|
|
if (typeof localStorage !== 'undefined') {
|
|
localStorage.setItem(key, value);
|
|
} else {
|
|
memoryStorage[key] = value;
|
|
}
|
|
} else {
|
|
if (SENSITIVE_KEYS.includes(key)) {
|
|
// SecureStore might fail if biometrics are not configured or on some Android versions
|
|
try {
|
|
await SecureStore.setItemAsync(key, value);
|
|
} catch (e) {
|
|
console.warn(`[Storage] SecureStore failed for ${key}, falling back to AsyncStorage`, e);
|
|
await AsyncStorage.setItem(key, value);
|
|
}
|
|
} else {
|
|
await AsyncStorage.setItem(key, value);
|
|
}
|
|
}
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Storage Save Error [${key}]:`, error);
|
|
memoryStorage[key] = value; // Last resort
|
|
return false;
|
|
}
|
|
},
|
|
|
|
get: async (key: string) => {
|
|
try {
|
|
if (Platform.OS === 'web') {
|
|
if (typeof localStorage !== 'undefined') {
|
|
return localStorage.getItem(key);
|
|
}
|
|
return memoryStorage[key] || null;
|
|
} else {
|
|
if (SENSITIVE_KEYS.includes(key)) {
|
|
try {
|
|
const val = await SecureStore.getItemAsync(key);
|
|
if (val) return val;
|
|
} catch (e) {
|
|
console.warn(`[Storage] SecureStore read failed for ${key}`, e);
|
|
}
|
|
// Check fallback
|
|
return await AsyncStorage.getItem(key);
|
|
} else {
|
|
return await AsyncStorage.getItem(key);
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.warn(`Storage Get Error [${key}]:`, error);
|
|
return memoryStorage[key] || null;
|
|
}
|
|
},
|
|
|
|
remove: async (key: string) => {
|
|
try {
|
|
if (Platform.OS === 'web') {
|
|
if (typeof localStorage !== 'undefined') {
|
|
localStorage.removeItem(key);
|
|
}
|
|
delete memoryStorage[key];
|
|
} else {
|
|
if (SENSITIVE_KEYS.includes(key)) {
|
|
try {
|
|
await SecureStore.deleteItemAsync(key);
|
|
} catch (e) {
|
|
console.warn(`[Storage] SecureStore delete failed for ${key}`, e);
|
|
}
|
|
await AsyncStorage.removeItem(key);
|
|
} else {
|
|
await AsyncStorage.removeItem(key);
|
|
}
|
|
}
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Storage Remove Error [${key}]:`, error);
|
|
return false;
|
|
}
|
|
}
|
|
};
|