magically-sdk
Version:
Official SDK for Magically - Build mobile apps with AI
204 lines (175 loc) • 6.04 kB
text/typescript
/**
* Platform detection and abstraction layer
* Provides environment-specific implementations
*/
interface StorageInterface {
getItem: (key: string) => Promise<string | null>;
setItem: (key: string, value: string) => Promise<void>;
removeItem: (key: string) => Promise<void>;
}
interface WebBrowserInterface {
openBrowserAsync: (url: string) => Promise<any>;
openAuthSessionAsync?: (url: string, redirectUri: string) => Promise<any>;
maybeCompleteAuthSession: () => { type: string };
}
interface PlatformInterface {
OS: string;
select: (obj: any) => any;
}
interface LinkingInterface {
createURL: (path?: string, options?: { scheme?: string; queryParams?: Record<string, string>; isTripleSlashed?: boolean }) => string;
}
interface SecureStoreInterface {
getItemAsync: (key: string) => Promise<string | null>;
setItemAsync: (key: string, value: string) => Promise<void>;
deleteItemAsync: (key: string) => Promise<void>;
}
class EdgeStorage implements StorageInterface {
async getItem(key: string): Promise<string | null> {
// In edge environment, return null (no persistent storage)
return null;
}
async setItem(key: string, value: string): Promise<void> {
// No-op in edge environment
}
async removeItem(key: string): Promise<void> {
// No-op in edge environment
}
}
class EdgeWebBrowser implements WebBrowserInterface {
async openBrowserAsync(url: string): Promise<any> {
// Can't open browser in edge environment
return { type: 'cancel' };
}
maybeCompleteAuthSession() {
return { type: 'success' };
}
}
class EdgePlatform implements PlatformInterface {
OS = 'web';
select(obj: any) {
return obj.web || obj.default;
}
}
class EdgeLinking implements LinkingInterface {
createURL(path?: string, options?: { scheme?: string; queryParams?: Record<string, string>; isTripleSlashed?: boolean }): string {
// In edge environment, return a simple URL
return path ? `exp://auth/${path}` : 'exp://auth/callback';
}
}
class EdgeSecureStore implements SecureStoreInterface {
async getItemAsync(key: string): Promise<string | null> {
// No secure storage in edge environment
return null;
}
async setItemAsync(key: string, value: string): Promise<void> {
// No-op in edge environment
}
async deleteItemAsync(key: string): Promise<void> {
// No-op in edge environment
}
}
class WebSecureStore implements SecureStoreInterface {
async getItemAsync(key: string): Promise<string | null> {
try {
// Safe localStorage access for web
if (typeof window !== 'undefined' && window.localStorage) {
return window.localStorage.getItem(key);
}
return null;
} catch (error) {
console.warn('WebSecureStore: Failed to get item', error);
return null;
}
}
async setItemAsync(key: string, value: string): Promise<void> {
try {
// Safe localStorage access for web
if (typeof window !== 'undefined' && window.localStorage) {
window.localStorage.setItem(key, value);
}
} catch (error) {
console.warn('WebSecureStore: Failed to set item', error);
}
}
async deleteItemAsync(key: string): Promise<void> {
try {
// Safe localStorage access for web
if (typeof window !== 'undefined' && window.localStorage) {
window.localStorage.removeItem(key);
}
} catch (error) {
console.warn('WebSecureStore: Failed to delete item', error);
}
}
}
// Detect environment
function isEdgeEnvironment(): boolean {
// Most reliable check: caches.default is UNIQUE to Cloudflare Workers
if (typeof caches !== 'undefined' && typeof (caches as any).default !== 'undefined') {
return true;
}
// Secondary check: navigator.userAgent (requires global_navigator compatibility flag)
if (typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') {
return true;
}
// Default to false - assume React Native/Expo if not detected as Cloudflare Workers
return false;
}
// Export platform-specific implementations
export let AsyncStorage: StorageInterface;
export let WebBrowser: WebBrowserInterface;
export let Platform: PlatformInterface;
export let SecureStore: SecureStoreInterface;
export let Linking: LinkingInterface;
// Initialize based on environment
if (isEdgeEnvironment()) {
// Edge environment - use stubs
AsyncStorage = new EdgeStorage();
WebBrowser = new EdgeWebBrowser();
Platform = new EdgePlatform();
SecureStore = new EdgeSecureStore();
Linking = new EdgeLinking();
} else {
// React Native environment - use actual implementations
// These will be replaced by the bundler in React Native apps
// Import core dependencies first (these should always be available)
try {
AsyncStorage = require('@react-native-async-storage/async-storage').default;
} catch (e) {
AsyncStorage = new EdgeStorage();
}
try {
WebBrowser = require('expo-web-browser');
} catch (e) {
WebBrowser = new EdgeWebBrowser();
}
try {
Platform = require('react-native').Platform;
} catch (e) {
Platform = new EdgePlatform();
}
// Import optional dependencies (may not be installed)
// Check if we're on web platform first
if (Platform.OS === 'web') {
// Web platform uses localStorage through WebSecureStore
SecureStore = new WebSecureStore();
} else {
// Native platforms use expo-secure-store
try {
SecureStore = require('expo-secure-store');
} catch (e) {
// Fallback to AsyncStorage wrapped in SecureStore interface if expo-secure-store not available
SecureStore = {
getItemAsync: async (key: string) => AsyncStorage.getItem(key),
setItemAsync: async (key: string, value: string) => AsyncStorage.setItem(key, value),
deleteItemAsync: async (key: string) => AsyncStorage.removeItem(key),
};
}
}
try {
Linking = require('expo-linking');
} catch (e) {
Linking = new EdgeLinking();
}
}