react-native-vision-camera/src/CameraError.ts

151 lines
4.8 KiB
TypeScript
Raw Normal View History

2021-02-20 09:07:10 -07:00
export type PermissionError = 'permission/microphone-permission-denied' | 'permission/camera-permission-denied';
2021-02-19 08:07:53 -07:00
export type ParameterError =
2021-02-20 09:07:10 -07:00
| 'parameter/invalid-parameter'
| 'parameter/unsupported-os'
| 'parameter/unsupported-output'
| 'parameter/unsupported-input'
| 'parameter/invalid-combination';
2021-02-19 08:07:53 -07:00
export type DeviceError =
2021-02-20 09:07:10 -07:00
| 'device/configuration-error'
| 'device/no-device'
| 'device/invalid-device'
| 'device/torch-unavailable'
| 'device/microphone-unavailable'
| 'device/low-light-boost-not-supported'
| 'device/focus-not-supported'
| 'device/camera-not-available-on-simulator';
2021-02-19 08:07:53 -07:00
export type FormatError =
2021-02-20 09:07:10 -07:00
| 'format/invalid-fps'
| 'format/invalid-hdr'
| 'format/invalid-low-light-boost'
| 'format/invalid-format'
| 'format/invalid-preset';
export type SessionError = 'session/camera-not-ready';
2021-02-19 08:07:53 -07:00
export type CaptureError =
2021-02-20 09:07:10 -07:00
| 'capture/invalid-photo-format'
| 'capture/encoder-error'
| 'capture/muxer-error'
| 'capture/recording-in-progress'
| 'capture/no-recording-in-progress'
| 'capture/file-io-error'
| 'capture/create-temp-file-error'
| 'capture/invalid-photo-codec'
| 'capture/not-bound-error'
| 'capture/capture-type-not-supported'
| 'capture/unknown';
export type SystemError = 'system/no-camera-manager';
export type UnknownError = 'unknown/unknown';
2021-02-19 08:07:53 -07:00
export interface ErrorWithCause {
/**
* The native error description (Localized on iOS)
*
* * iOS: `NSError.message`
* * Android: `Throwable.message`
*/
message: string;
/**
* Optional additional details
*
* * iOS: `NSError.userInfo`
* * Android: N/A
*/
details?: Record<string, unknown>;
/**
* Optional stacktrace
*
* * iOS: N/A
* * Android: `Throwable.stacktrace.toString()`
*/
stacktrace?: string;
/**
* Optional additional cause for nested errors
*
* * iOS: N/A
* * Android: `Throwable.cause`
*/
cause?: ErrorWithCause;
}
2021-02-20 09:07:10 -07:00
type CameraErrorCode = PermissionError | ParameterError | DeviceError | FormatError | SessionError | CaptureError | SystemError | UnknownError;
2021-02-19 08:07:53 -07:00
/**
* Represents any kind of error that occured in the Camera View Module.
*/
class CameraError<TCode extends CameraErrorCode> extends Error {
private readonly _code: TCode;
private readonly _message: string;
private readonly _cause?: ErrorWithCause;
public get code(): TCode {
return this._code;
}
public get message(): string {
return this._message;
}
public get cause(): ErrorWithCause | undefined {
return this._cause;
}
constructor(code: TCode, message: string, cause?: ErrorWithCause) {
2021-02-20 09:07:10 -07:00
super(`[${code}]: ${message}${cause ? ` (Cause: ${cause.message})` : ''}`);
2021-02-19 08:07:53 -07:00
this._code = code;
this._message = message;
this._cause = cause;
}
}
/**
* Represents any kind of error that occured while trying to capture a video or photo.
*/
export class CameraCaptureError extends CameraError<CaptureError> {}
/**
* Represents any kind of error that occured in the Camera View Module.
*/
export class CameraRuntimeError extends CameraError<
2021-02-20 09:07:10 -07:00
PermissionError | ParameterError | DeviceError | FormatError | SessionError | SystemError | UnknownError
2021-02-19 08:07:53 -07:00
> {}
export const isErrorWithCause = (error: unknown): error is ErrorWithCause =>
2021-02-20 09:07:10 -07:00
typeof error === 'object' &&
2021-02-19 08:07:53 -07:00
error != null &&
// @ts-expect-error error is still unknown
2021-02-20 09:07:10 -07:00
typeof error.message === 'string' &&
2021-02-19 08:07:53 -07:00
// @ts-expect-error error is still unknown
2021-02-20 09:07:10 -07:00
(typeof error.stacktrace === 'string' || error.stacktrace == null) &&
2021-02-19 08:07:53 -07:00
// @ts-expect-error error is still unknown
(isErrorWithCause(error.cause) || error.cause == null);
2021-02-20 09:07:10 -07:00
const isCameraErrorJson = (error: unknown): error is { code: string; message: string; cause?: ErrorWithCause } =>
typeof error === 'object' &&
2021-02-19 08:07:53 -07:00
error != null &&
// @ts-expect-error error is still unknown
2021-02-20 09:07:10 -07:00
typeof error.code === 'string' &&
2021-02-19 08:07:53 -07:00
// @ts-expect-error error is still unknown
2021-02-20 09:07:10 -07:00
typeof error.message === 'string' &&
2021-02-19 08:07:53 -07:00
// @ts-expect-error error is still unknown
2021-02-20 09:07:10 -07:00
(typeof error.cause === 'object' || error.cause == null);
2021-02-19 08:07:53 -07:00
/**
* Tries to parse an error coming from native to a typed JS camera error.
* @param nativeError The native error instance. This is a JSON in the legacy native module architecture.
* @returns A `CameraRuntimeError` or `CameraCaptureError`, or the nativeError if it's not parsable
*/
2021-02-20 09:07:10 -07:00
export const tryParseNativeCameraError = <T>(nativeError: T): (CameraRuntimeError | CameraCaptureError) | T => {
2021-02-19 08:07:53 -07:00
if (isCameraErrorJson(nativeError)) {
2021-02-20 09:07:10 -07:00
if (nativeError.code.startsWith('capture')) {
return new CameraCaptureError(nativeError.code as CaptureError, nativeError.message, nativeError.cause);
2021-02-19 08:07:53 -07:00
} else {
return new CameraRuntimeError(
// @ts-expect-error the code is string, we narrow it down to TS union.
nativeError.code,
nativeError.message,
2021-02-20 09:07:10 -07:00
nativeError.cause,
2021-02-19 08:07:53 -07:00
);
}
} else {
return nativeError;
}
};