@oxyhq/services
Version:
Reusable OxyHQ module to handle authentication, user management, karma system, device-based session management and more 🚀
171 lines (157 loc) • 5.24 kB
JavaScript
;
/**
* Client-side device management utility
* Handles persistent device identification across app sessions
*/
export class DeviceManager {
static DEVICE_KEY = 'oxy_device_info';
/**
* Check if we're in React Native environment
*/
static isReactNative() {
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
}
/**
* Get appropriate storage for the platform
*/
static async getStorage() {
if (this.isReactNative()) {
try {
const asyncStorageModule = await import('@react-native-async-storage/async-storage');
const storage = asyncStorageModule.default;
return {
getItem: storage.getItem.bind(storage),
setItem: storage.setItem.bind(storage),
removeItem: storage.removeItem.bind(storage)
};
} catch (error) {
console.error('AsyncStorage not available in React Native:', error);
throw new Error('AsyncStorage is required in React Native environment');
}
} else {
// Use localStorage for web
return {
getItem: async key => localStorage.getItem(key),
setItem: async (key, value) => localStorage.setItem(key, value),
removeItem: async key => localStorage.removeItem(key)
};
}
}
/**
* Get or create device fingerprint for current device
*/
static getDeviceFingerprint() {
const fingerprint = {
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',
language: typeof navigator !== 'undefined' ? navigator.language : undefined,
timezone: typeof Intl !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : undefined
};
// Add screen info if available
if (typeof screen !== 'undefined') {
fingerprint.screen = {
width: screen.width,
height: screen.height,
colorDepth: screen.colorDepth
};
}
return fingerprint;
}
/**
* Get stored device info or create new one
*/
static async getDeviceInfo() {
try {
const storage = await this.getStorage();
const stored = await storage.getItem(this.DEVICE_KEY);
if (stored) {
const deviceInfo = JSON.parse(stored);
// Update last used timestamp
deviceInfo.lastUsed = new Date().toISOString();
await this.saveDeviceInfo(deviceInfo);
return deviceInfo;
}
// Create new device info
return await this.createNewDeviceInfo();
} catch (error) {
console.error('Error getting device info:', error);
return await this.createNewDeviceInfo();
}
}
/**
* Create new device info and store it
*/
static async createNewDeviceInfo() {
const deviceInfo = {
deviceId: this.generateDeviceId(),
fingerprint: JSON.stringify(this.getDeviceFingerprint()),
createdAt: new Date().toISOString(),
lastUsed: new Date().toISOString()
};
await this.saveDeviceInfo(deviceInfo);
return deviceInfo;
}
/**
* Save device info to storage
*/
static async saveDeviceInfo(deviceInfo) {
try {
const storage = await this.getStorage();
await storage.setItem(this.DEVICE_KEY, JSON.stringify(deviceInfo));
} catch (error) {
console.error('Error saving device info:', error);
}
}
/**
* Update device name
*/
static async updateDeviceName(deviceName) {
try {
const deviceInfo = await this.getDeviceInfo();
deviceInfo.deviceName = deviceName;
await this.saveDeviceInfo(deviceInfo);
} catch (error) {
console.error('Error updating device name:', error);
}
}
/**
* Clear stored device info (useful for testing or reset)
*/
static async clearDeviceInfo() {
try {
const storage = await this.getStorage();
await storage.removeItem(this.DEVICE_KEY);
} catch (error) {
console.error('Error clearing device info:', error);
}
}
/**
* Generate a unique device ID
*/
static generateDeviceId() {
// Use crypto.getRandomValues if available, otherwise fallback to Math.random
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
} else {
// Fallback for environments without crypto.getRandomValues
return 'device_' + Date.now().toString(36) + Math.random().toString(36).substr(2);
}
}
/**
* Get a user-friendly device name based on platform
*/
static getDefaultDeviceName() {
const fingerprint = this.getDeviceFingerprint();
const platform = (fingerprint.platform || '').toLowerCase();
if (platform.includes('win')) return 'Windows Computer';
if (platform.includes('mac')) return 'Mac Computer';
if (platform.includes('linux')) return 'Linux Computer';
if (platform.includes('iphone')) return 'iPhone';
if (platform.includes('ipad')) return 'iPad';
if (platform.includes('android')) return 'Android Device';
return 'Unknown Device';
}
}
//# sourceMappingURL=deviceManager.js.map