Deprecated compatibility wrapper that provides backward compatibility for applications migrating from legacy Unimodules infrastructure to Expo Modules API
—
Standardized error classes for consistent error handling across Expo modules with error codes and platform-specific messaging.
General-purpose error class that provides consistent error handling with error codes for easy categorization and handling.
/**
* General error class for all errors in Expo modules
* Guarantees a code field for error differentiation
*/
class CodedError extends Error {
/**
* Error code for categorizing error types
*/
code: string;
/**
* Additional error information
*/
info?: any;
/**
* Create a coded error
* @param code - Error code for identification
* @param message - Human-readable error message
*/
constructor(code: string, message: string);
}Usage Examples:
import { CodedError } from "@unimodules/core";
// Create custom errors
function validateInput(data: unknown) {
if (!data) {
throw new CodedError('INVALID_INPUT', 'Input data is required');
}
if (typeof data !== 'object') {
throw new CodedError('INVALID_TYPE', 'Input must be an object');
}
}
// Handle coded errors
try {
await someNativeOperation();
} catch (error) {
if (error instanceof CodedError) {
switch (error.code) {
case 'PERMISSION_DENIED':
showPermissionDialog();
break;
case 'NETWORK_ERROR':
showRetryButton();
break;
case 'INVALID_ARGUMENT':
showValidationError(error.message);
break;
default:
showGenericError(error.message);
}
} else {
// Handle non-coded errors
showGenericError('An unexpected error occurred');
}
}
// Add additional error information
function createDetailedError(code: string, message: string, details: any) {
const error = new CodedError(code, message);
error.info = details;
return error;
}
const error = createDetailedError(
'API_ERROR',
'Failed to fetch user data',
{
endpoint: '/api/users/123',
statusCode: 404,
timestamp: new Date().toISOString()
}
);Specialized error class for features that are unavailable, unsupported, or not implemented on the current platform.
/**
* Error for unavailable, unsupported, or unimplemented properties
* Automatically includes platform information
*/
class UnavailabilityError extends CodedError {
/**
* Create an unavailability error
* @param moduleName - Name of the module
* @param propertyName - Name of the unavailable property/method
*/
constructor(moduleName: string, propertyName: string);
}Usage Examples:
import { UnavailabilityError, Platform } from "@unimodules/core";
// Throw for unsupported features
class CameraModule {
static async takePictureAsync() {
if (Platform.OS === 'web') {
throw new UnavailabilityError('Camera', 'takePictureAsync');
}
// Native implementation
return NativeModulesProxy.Camera.takePictureAsync();
}
static async recordVideoAsync() {
if (!Platform.select({ ios: true, android: true, default: false })) {
throw new UnavailabilityError('Camera', 'recordVideoAsync');
}
return NativeModulesProxy.Camera.recordVideoAsync();
}
}
// Handle unavailability errors
try {
await CameraModule.takePictureAsync();
} catch (error) {
if (error instanceof UnavailabilityError) {
console.warn(`Feature not available: ${error.message}`);
// Show alternative UI or disable feature
showFeatureUnavailableMessage();
}
}
// Conditional feature checking
function createFeatureProxy(moduleName: string) {
return new Proxy({}, {
get(target, propertyName: string) {
const module = NativeModulesProxy[moduleName];
if (!module || !(propertyName in module)) {
throw new UnavailabilityError(moduleName, propertyName);
}
return module[propertyName];
}
});
}Common error codes used throughout the Expo ecosystem:
/**
* Standard error codes used across Expo modules
*/
type StandardErrorCodes =
| 'ERR_UNAVAILABLE' // Feature not available on platform
| 'ERR_DEPRECATED_API' // API has been deprecated/removed
| 'ERR_INVALID_ARGUMENT' // Invalid argument provided
| 'ERR_PERMISSION_DENIED' // Permission required but not granted
| 'ERR_NETWORK_ERROR' // Network operation failed
| 'ERR_FILE_NOT_FOUND' // File system operation failed
| 'ERR_OPERATION_CANCELLED' // User cancelled operation
| 'ERR_TIMEOUT' // Operation timed out
| 'ERR_INITIALIZATION' // Module failed to initialize
| 'ERR_PLATFORM_SPECIFIC'; // Platform-specific errorUsage Examples:
import { CodedError } from "@unimodules/core";
// Use standard error codes
function validatePermission(permission: string) {
if (!permission) {
throw new CodedError('ERR_INVALID_ARGUMENT', 'Permission name is required');
}
}
async function requestWithTimeout<T>(operation: Promise<T>, timeout: number): Promise<T> {
const timeoutPromise = new Promise<never>((_, reject) => {
setTimeout(() => {
reject(new CodedError('ERR_TIMEOUT', `Operation timed out after ${timeout}ms`));
}, timeout);
});
return Promise.race([operation, timeoutPromise]);
}
// Handle standard error codes
function handleStandardError(error: CodedError) {
switch (error.code) {
case 'ERR_PERMISSION_DENIED':
return 'Permission required. Please grant access in settings.';
case 'ERR_NETWORK_ERROR':
return 'Network error. Please check your connection.';
case 'ERR_TIMEOUT':
return 'Operation timed out. Please try again.';
case 'ERR_UNAVAILABLE':
return 'This feature is not available on your device.';
default:
return `Error: ${error.message}`;
}
}import { CodedError, UnavailabilityError } from "@unimodules/core";
class ErrorFactory {
static createPermissionError(permission: string): CodedError {
return new CodedError(
'ERR_PERMISSION_DENIED',
`${permission} permission is required but not granted`
);
}
static createNetworkError(details?: any): CodedError {
const error = new CodedError('ERR_NETWORK_ERROR', 'Network request failed');
if (details) {
error.info = details;
}
return error;
}
static createValidationError(field: string, value: any): CodedError {
const error = new CodedError(
'ERR_INVALID_ARGUMENT',
`Invalid value for field '${field}'`
);
error.info = { field, value };
return error;
}
static createUnavailableError(module: string, method: string): UnavailabilityError {
return new UnavailabilityError(module, method);
}
}
// Usage
throw ErrorFactory.createPermissionError('CAMERA');
throw ErrorFactory.createNetworkError({ statusCode: 500, endpoint: '/api/data' });import { CodedError, UnavailabilityError } from "@unimodules/core";
class ErrorRecovery {
static async withRetry<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
delay: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error;
// Don't retry certain error types
if (error instanceof UnavailabilityError ||
(error instanceof CodedError && error.code === 'ERR_PERMISSION_DENIED')) {
throw error;
}
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, delay * attempt));
}
}
}
throw new CodedError('ERR_MAX_RETRIES_EXCEEDED',
`Operation failed after ${maxRetries} attempts: ${lastError.message}`);
}
static async withFallback<T>(
primary: () => Promise<T>,
fallback: () => Promise<T>
): Promise<T> {
try {
return await primary();
} catch (error) {
if (error instanceof UnavailabilityError) {
console.warn(`Primary method unavailable, using fallback: ${error.message}`);
return await fallback();
}
throw error;
}
}
}
// Usage
const result = await ErrorRecovery.withRetry(async () => {
return await fetch('/api/data');
});
const data = await ErrorRecovery.withFallback(
() => NativeModulesProxy.Storage.getSecureItem('key'),
() => AsyncStorage.getItem('key')
);interface ErrorInfo {
[key: string]: any;
}
interface CodedErrorConstructor {
new (code: string, message: string): CodedError;
prototype: CodedError;
}
interface UnavailabilityErrorConstructor {
new (moduleName: string, propertyName: string): UnavailabilityError;
prototype: UnavailabilityError;
}Install with Tessl CLI
npx tessl i tessl/npm-unimodules--core