index.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import { HttpStatusCode } from "axios";
  2. export interface ApiErrorResponse {
  3. code: string;
  4. message: string;
  5. }
  6. export class ApiError extends Error {
  7. httpStatusCode: number;
  8. errCode: string;
  9. constructor(message: string, errCode: string, httpStatus: number) {
  10. super(message);
  11. this.name = "ApiError";
  12. this.errCode = errCode;
  13. this.httpStatusCode = httpStatus;
  14. }
  15. }
  16. export function isApiErrorResponse(object: any): object is ApiErrorResponse {
  17. return object && "code" in object && "message" in object;
  18. }
  19. export const CustomError = {
  20. THUMBNAIL_GENERATION_FAILED: "thumbnail generation failed",
  21. VIDEO_PLAYBACK_FAILED: "video playback failed",
  22. ETAG_MISSING: "no header/etag present in response body",
  23. KEY_MISSING: "encrypted key missing from localStorage",
  24. FAILED_TO_LOAD_WEB_WORKER: "failed to load web worker",
  25. CHUNK_MORE_THAN_EXPECTED: "chunks more than expected",
  26. CHUNK_LESS_THAN_EXPECTED: "chunks less than expected",
  27. UNSUPPORTED_FILE_FORMAT: "unsupported file format",
  28. FILE_TOO_LARGE: "file too large",
  29. SUBSCRIPTION_EXPIRED: "subscription expired",
  30. STORAGE_QUOTA_EXCEEDED: "storage quota exceeded",
  31. SESSION_EXPIRED: "session expired",
  32. INVALID_MIME_TYPE: (type: string) => `invalid mime type -${type}`,
  33. SIGNUP_FAILED: "signup failed",
  34. FAV_COLLECTION_MISSING: "favorite collection missing",
  35. INVALID_COLLECTION_OPERATION: "invalid collection operation",
  36. TO_MOVE_FILES_FROM_MULTIPLE_COLLECTIONS:
  37. "to move files from multiple collections",
  38. WAIT_TIME_EXCEEDED: "operation wait time exceeded",
  39. REQUEST_CANCELLED: "request canceled",
  40. REQUEST_FAILED: "request failed",
  41. TOKEN_EXPIRED: "token expired",
  42. TOKEN_MISSING: "token missing",
  43. TOO_MANY_REQUESTS: "too many requests",
  44. BAD_REQUEST: "bad request",
  45. SUBSCRIPTION_NEEDED: "subscription not present",
  46. NOT_FOUND: "not found ",
  47. NO_METADATA: "no metadata",
  48. TOO_LARGE_LIVE_PHOTO_ASSETS: "too large live photo assets",
  49. NOT_A_DATE: "not a date",
  50. NOT_A_LOCATION: "not a location",
  51. FILE_ID_NOT_FOUND: "file with id not found",
  52. WEAK_DEVICE: "password decryption failed on the device",
  53. INCORRECT_PASSWORD: "incorrect password",
  54. UPLOAD_CANCELLED: "upload cancelled",
  55. REQUEST_TIMEOUT: "request taking too long",
  56. HIDDEN_COLLECTION_SYNC_FILE_ATTEMPTED:
  57. "hidden collection sync file attempted",
  58. UNKNOWN_ERROR: "Something went wrong, please try again",
  59. TYPE_DETECTION_FAILED: (fileFormat: string) =>
  60. `type detection failed ${fileFormat}`,
  61. WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED:
  62. "Windows native image processing is not supported",
  63. NETWORK_ERROR: "Network Error",
  64. NOT_FILE_OWNER: "not file owner",
  65. UPDATE_EXPORTED_RECORD_FAILED: "update file exported record failed",
  66. EXPORT_STOPPED: "export stopped",
  67. NO_EXPORT_FOLDER_SELECTED: "no export folder selected",
  68. EXPORT_FOLDER_DOES_NOT_EXIST: "export folder does not exist",
  69. NO_INTERNET_CONNECTION: "no internet connection",
  70. AUTH_KEY_NOT_FOUND: "auth key not found",
  71. EXIF_DATA_NOT_FOUND: "exif data not found",
  72. SELECT_FOLDER_ABORTED: "select folder aborted",
  73. NON_MEDIA_FILE: "non media file",
  74. NOT_AVAILABLE_ON_WEB: "not available on web",
  75. UNSUPPORTED_RAW_FORMAT: "unsupported raw format",
  76. NON_PREVIEWABLE_FILE: "non previewable file",
  77. PROCESSING_FAILED: "processing failed",
  78. EXPORT_RECORD_JSON_PARSING_FAILED: "export record json parsing failed",
  79. TWO_FACTOR_ENABLED: "two factor enabled",
  80. PASSKEYS_TWO_FACTOR_ENABLED: "passkeys two factor enabled",
  81. CLIENT_ERROR: "client error",
  82. ServerError: "server error",
  83. FILE_NOT_FOUND: "file not found",
  84. UNSUPPORTED_PLATFORM: "Unsupported platform",
  85. MODEL_DOWNLOAD_PENDING:
  86. "Model download pending, skipping clip search request",
  87. DOWNLOAD_MANAGER_NOT_READY: "Download manager not initialized",
  88. UPDATE_URL_FILE_ID_MISMATCH: "update url file id mismatch",
  89. URL_ALREADY_SET: "url already set",
  90. FILE_CONVERSION_FAILED: "file conversion failed",
  91. };
  92. export function handleUploadError(error: any): Error {
  93. const parsedError = parseUploadErrorCodes(error);
  94. // breaking errors
  95. switch (parsedError.message) {
  96. case CustomError.SUBSCRIPTION_EXPIRED:
  97. case CustomError.STORAGE_QUOTA_EXCEEDED:
  98. case CustomError.SESSION_EXPIRED:
  99. case CustomError.UPLOAD_CANCELLED:
  100. throw parsedError;
  101. }
  102. return parsedError;
  103. }
  104. export function errorWithContext(originalError: Error, context: string) {
  105. const errorWithContext = new Error(context);
  106. errorWithContext.stack =
  107. errorWithContext.stack?.split("\n").slice(2, 4).join("\n") +
  108. "\n" +
  109. originalError.stack;
  110. return errorWithContext;
  111. }
  112. export function parseUploadErrorCodes(error: any) {
  113. let parsedMessage = null;
  114. if (error instanceof ApiError) {
  115. switch (error.httpStatusCode) {
  116. case HttpStatusCode.PaymentRequired:
  117. parsedMessage = CustomError.SUBSCRIPTION_EXPIRED;
  118. break;
  119. case HttpStatusCode.UpgradeRequired:
  120. parsedMessage = CustomError.STORAGE_QUOTA_EXCEEDED;
  121. break;
  122. case HttpStatusCode.Unauthorized:
  123. parsedMessage = CustomError.SESSION_EXPIRED;
  124. break;
  125. case HttpStatusCode.PayloadTooLarge:
  126. parsedMessage = CustomError.FILE_TOO_LARGE;
  127. break;
  128. default:
  129. parsedMessage = `${CustomError.UNKNOWN_ERROR} statusCode:${error.httpStatusCode}`;
  130. }
  131. } else {
  132. parsedMessage = error.message;
  133. }
  134. return new Error(parsedMessage);
  135. }
  136. export const parseSharingErrorCodes = (error: any) => {
  137. let parsedMessage = null;
  138. if (error instanceof ApiError) {
  139. switch (error.httpStatusCode) {
  140. case HttpStatusCode.BadRequest:
  141. parsedMessage = CustomError.BAD_REQUEST;
  142. break;
  143. case HttpStatusCode.PaymentRequired:
  144. parsedMessage = CustomError.SUBSCRIPTION_NEEDED;
  145. break;
  146. case HttpStatusCode.NotFound:
  147. parsedMessage = CustomError.NOT_FOUND;
  148. break;
  149. case HttpStatusCode.Unauthorized:
  150. case HttpStatusCode.Gone:
  151. parsedMessage = CustomError.TOKEN_EXPIRED;
  152. break;
  153. case HttpStatusCode.TooManyRequests:
  154. parsedMessage = CustomError.TOO_MANY_REQUESTS;
  155. break;
  156. default:
  157. parsedMessage = `${CustomError.UNKNOWN_ERROR} statusCode:${error.httpStatusCode}`;
  158. }
  159. } else {
  160. parsedMessage = error.message;
  161. }
  162. return new Error(parsedMessage);
  163. };