react-native-iap
Version:
React Native In-App Purchases module for iOS and Android using Nitro
98 lines (88 loc) • 2.82 kB
text/typescript
/**
* Error utilities for parsing platform-specific error responses
*/
import {ErrorCode} from '../types';
export interface IapError {
code: string;
message: string;
responseCode?: number;
debugMessage?: string;
productId?: string;
[key: string]: any; // Allow additional platform-specific fields
}
/**
* Parses error string from native modules into a structured error object
*
* Native modules return errors in different formats:
* - Android: JSON string like '{"code":"E_USER_CANCELLED","message":"User cancelled the purchase","responseCode":1}'
* - iOS: JSON string or plain message
* - Legacy: "CODE: message" format
*
* @param errorString - The error string from native module
* @returns Parsed error object with code and message
*/
export function parseErrorStringToJsonObj(
errorString: string | Error | unknown,
): IapError {
// Handle Error objects
if (errorString instanceof Error) {
errorString = errorString.message;
}
// Handle non-string inputs
if (typeof errorString !== 'string') {
return {
code: ErrorCode.Unknown,
message: 'Unknown error occurred',
};
}
// Try to parse as JSON first
try {
const parsed = JSON.parse(errorString);
if (typeof parsed === 'object' && parsed !== null) {
// Ensure it has at least code and message
return {
code: parsed.code || ErrorCode.Unknown,
message: parsed.message || errorString,
...parsed,
};
}
} catch {
// Not JSON, continue with other formats
}
// Try to parse "CODE: message" format
const colonIndex = errorString.indexOf(':');
if (colonIndex > 0 && colonIndex < 50) {
// Reasonable position for error code
const potentialCode = errorString.substring(0, colonIndex).trim();
// Check if it looks like an error code (starts with E_ or contains uppercase)
if (potentialCode.startsWith('E_') || /^[A-Z_]+$/.test(potentialCode)) {
return {
code: potentialCode,
message: errorString.substring(colonIndex + 1).trim(),
};
}
}
// Fallback: treat entire string as message
return {
code: ErrorCode.Unknown,
message: errorString,
};
}
/**
* Checks if an error code indicates user cancellation
* @param error - Error object or string
* @returns true if the error is a user cancellation
*/
export function isUserCancelledError(
error: IapError | string | Error | unknown,
): boolean {
const errorObj =
typeof error === 'object' && error !== null && 'code' in error
? (error as IapError)
: parseErrorStringToJsonObj(error);
return (
errorObj.code === ErrorCode.UserCancelled ||
errorObj.code === 'E_USER_CANCELED' || // Alternative spelling
errorObj.responseCode === 1
); // Android BillingClient.BillingResponseCode.USER_CANCELED
}