From 60ba60bec3f5c236545d23c44f8e021afb7ded1d Mon Sep 17 00:00:00 2001 From: nd0ut Date: Thu, 21 Dec 2023 18:47:55 +0800 Subject: [PATCH] types(upload-client): add types for the server-side error codes --- .../upload-client/src/api/fromUrlStatus.ts | 5 +- packages/upload-client/src/request/types.ts | 3 +- .../src/tools/ServerErrorCode.ts | 97 +++++++++++++++++++ .../upload-client/src/uploadFile/pusher.ts | 5 +- .../test/tools/UploadError.test.ts | 4 +- 5 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 packages/upload-client/src/tools/ServerErrorCode.ts diff --git a/packages/upload-client/src/api/fromUrlStatus.ts b/packages/upload-client/src/api/fromUrlStatus.ts index 5816f29e1..92ad21493 100644 --- a/packages/upload-client/src/api/fromUrlStatus.ts +++ b/packages/upload-client/src/api/fromUrlStatus.ts @@ -9,6 +9,7 @@ import defaultSettings from '../defaultSettings' import { getUserAgent } from '../tools/getUserAgent' import { UploadError } from '../tools/UploadError' import { retryIfFailed } from '../tools/retryIfFailed' +import { ServerErrorCode } from '../tools/ServerErrorCode' export enum Status { Unknown = 'unknown', @@ -36,7 +37,7 @@ export type StatusProgressResponse = { export type StatusErrorResponse = { status: Status.Error error: string - errorCode: string + errorCode: ServerErrorCode } export type StatusSuccessResponse = { @@ -109,7 +110,7 @@ export default function fromUrlStatus( if ('error' in response && !isErrorResponse(response)) { throw new UploadError( response.error.content, - undefined, + response.error.errorCode, request, response, headers diff --git a/packages/upload-client/src/request/types.ts b/packages/upload-client/src/request/types.ts index 32b129ae8..642c5023b 100644 --- a/packages/upload-client/src/request/types.ts +++ b/packages/upload-client/src/request/types.ts @@ -5,6 +5,7 @@ import { UnknownProgressInfo } from '../api/types' import { SupportedFileInput } from '../types' +import { ServerErrorCode } from '../tools/ServerErrorCode' export type Headers = { [key: string]: string | string[] | undefined @@ -39,6 +40,6 @@ export type FailedResponse = { error: { content: string statusCode: number - errorCode: string + errorCode: ServerErrorCode } } diff --git a/packages/upload-client/src/tools/ServerErrorCode.ts b/packages/upload-client/src/tools/ServerErrorCode.ts new file mode 100644 index 000000000..d72ab2e1e --- /dev/null +++ b/packages/upload-client/src/tools/ServerErrorCode.ts @@ -0,0 +1,97 @@ +/** @see https://uploadcare.com/api-refs/upload-api/#tag/Errors */ +export type ServerErrorCode = + // Base upload errors: + | 'AccountBlockedError' // 403 Account has been blocked. + | 'AccountLimitsExceededError' // 403 Account has reached its limits. + | 'AccountUnpaidError' // 403 Account has been blocked for non payment. + | 'AutostoreDisabledError' // 403 Autostore is disabled. + | 'BaseViewsError' // 400 Request processing failed. + | 'FileMetadataKeyDuplicatedError' // 400 File's metadata key `%s` has a duplicate. + | 'FileMetadataKeyEmptyError' // 400 File's metadata key can not be empty. + | 'FileMetadataKeyForbiddenError' // 400 File's metadata key `%s` contains symbols not allowed by the metadata key format. + | 'FileMetadataKeyLengthTooBigError' // 400 Length of file metadata key `%s` can not be more than %d symbols. + | 'FileMetadataKeysNumberTooBigError' // 400 A file can not have more than %d metadata keys. + | 'FileMetadataValueEmptyError' // 400 Value of the file metadata key `%s` can not be empty. + | 'FileMetadataValueForbiddenError' // 400 Value of file metadata key `%s` contains symbols not allowed by the metadata value format. + | 'FileMetadataValueLengthTooBigError' // 400 Value of file metadata's key `%s` can not be more than %d symbols in length. + | 'FileSizeLimitExceededError' // 400 File is too large. + | 'MethodNotAllowedError' // 405 HTTP method %s is not allowed for %s + | 'NullCharactersForbiddenError' // 400 Null characters are not allowed. + | 'PostRequestParserFailedError' // 400 HTTP POST request parsing failed. + | 'ProjectPublicKeyInvalidError' // 403 %s is invalid. + | 'ProjectPublicKeyRemovedError' // 403 Project %s is marked as removed. + | 'ProjectPublicKeyRequiredError' // 403 %s is required. + | 'RequestFileNumberLimitExceededError' // 400 The request contains too many files. + | 'RequestFiledsNumberLimitExceededError' // 400 The request contains too many HTTP POST fields. + | 'RequestSizeLimitExceededError' // 413 The size of the request is too large. + | 'RequestThrottledError' // 429 Request was throttled. + | 'SignatureExpirationError' // 403 Expired signature. + | 'SignatureExpirationInvalidError' // 400 `expire` must be a UNIX timestamp. + | 'SignatureExpirationRequiredError' // 400 `expire` is required. + | 'SignatureInvalidError' // 403 Invalid signature. + | 'SignatureRequiredError' // 400 `signature` is required. + | 'UploadAPIError' // 500 Internal error. + | 'UploadFailedError' // 403 Upload failed. + // FromURL upload errors: + | 'DownloadFileError' // 500 Failed to download the file. + | 'DownloadFileHTTPClientError' // 500 HTTP client error: %s. + | 'DownloadFileHTTPNetworkError' // 500 HTTP network error: %s. + | 'DownloadFileHTTPServerError' // 500 HTTP server error: %s. + | 'DownloadFileHTTPURLValidationError' // 500 HTTP URL validation error: %s. + | 'DownloadFileInternalServerError' // 500 Internal server error. + | 'DownloadFileNotFoundError' // 500 downloaded file not found. + | 'DownloadFileSizeLimitExceededError' // 500 Downloaded file is too big: %s > %s. + | 'DownloadFileTaskFailedError' // 500 download task failed. + | 'DownloadFileTimeLimitExceededError' // 500 Failed to download the file within the allotted time limit of %s seconds. + | 'DownloadFileValidationFailedError' // 500 File validation error: %s + // File upload errors: + | 'FileIdInvalidError' // 400 file_id is invalid. + | 'FileIdNotUniqueError' // 400 File id must be unique. + | 'FileIdRequiredError' // 400 file_id is required. + | 'FileNotFoundError' // 404 File is not found. + | 'FileRequiredError' // 400 There should be a file. + | 'FilesNumberLimitExceededError' // 400 There are too many files. + | 'FilesRequiredError' // 400 Request does not contain files. + | 'InternalRequestForbiddenError' // 403 Forbidden request. + | 'InternalRequestInvalidError' // 400 Incorrect request. + | 'MultipartFileAlreadyUploadedError' // 400 File is already uploaded. + | 'MultipartFileCompletionFailedError' // 400 Can not complete upload. Wrong parts size? + | 'MultipartFileIdRequiredError' // 400 uuid is required. + | 'MultipartFileNotFoundError' // 404 File is not found. + | 'MultipartFileSizeLimitExceededError' // 400 File size exceeds project limit. + | 'MultipartFileSizeTooSmallError' // 400 File size can not be less than %d bytes. Please use direct upload instead of multipart. + | 'MultipartPartSizeInvalidError' // 400 Multipart Upload Part Size should be an integer. + | 'MultipartPartSizeTooBigError' // 400 Multipart Upload Part Size can not be more than %d bytes. + | 'MultipartPartSizeTooSmallError' // 400 Multipart Upload Part Size can not be less than %d bytes. + | 'MultipartSizeInvalidError' // 400 size should be integer. + | 'MultipartUploadSizeTooLargeError' // 400 Uploaded size is more than expected. + | 'MultipartUploadSizeTooSmallError' // 400 File size mismatch. Not all parts uploaded? + | 'RequestParamRequiredError' // 400 %s is required. + | 'SourceURLRequiredError' // 400 source_url is required. + | 'TokenRequiredError' // 400 token is required. + | 'UUIDInvalidError' // 400 uuid is invalid. + | 'UploadViewsError' // 400 Upload request processing failed. + | 'UploadcareFileIdDuplicatedError' // 400 UPLOADCARE_FILE_ID is duplicated. You are probably a lottery winner. + | 'UploadcareFileIdInvalidError' // 400 UPLOADCARE_FILE_ID should be a valid UUID. + | 'UploadcareFileIdRequiredError' // 400 UPLOADCARE_FILE_ID is required. + // File group errors: + | 'GroupFileURLParsingFailedError' // 400 This is not valid file url: %s. + | 'GroupFilesInvalidError' // 400 No files[N] parameters found. + | 'GroupFilesNotFoundError' // 400 Some files not found. + | 'GroupIdRequiredError' // 400 group_id is required. + | 'GroupNotFoundError' // 404 group_id is invalid. + | 'GroupViewsError' // 400 Request to group processing failed. + // File content validation errors: + | 'FileInfectedError' // 400 The file is infected by %s virus. + | 'FileTypeForbiddenError' // 400 Uploading of these file types is not allowed. + // URL validation errors: + | 'HostnameNotFoundError' // 400 Host does not exist. + | 'URLBlacklistedError' // 400 Source is blacklisted. + | 'URLHostMalformedError' // 400 URL host is malformed. + | 'URLHostPrivateIPForbiddenError' // 400 Only public IPs are allowed. + | 'URLHostRequiredError' // 400 No URL host supplied. + | 'URLParsingFailedError' // 400 Failed to parse URL. + | 'URLRedirectsLimitExceededError' // 400 Too many redirects. + | 'URLSchemeInvalidError' // 400 Invalid URL scheme. + | 'URLSchemeRequiredError' // 400 No URL scheme supplied. + | 'URLValidationError' // 400 Failed to validate URL. diff --git a/packages/upload-client/src/uploadFile/pusher.ts b/packages/upload-client/src/uploadFile/pusher.ts index d39f3d6f6..60944e96c 100644 --- a/packages/upload-client/src/uploadFile/pusher.ts +++ b/packages/upload-client/src/uploadFile/pusher.ts @@ -1,7 +1,8 @@ import WebSocket from '../tools/sockets.node' -import { FileInfo } from '../api/types' import { Status } from '../api/fromUrlStatus' +import { FileInfo } from '../api/types' +import { ServerErrorCode } from '../tools/ServerErrorCode' import { Events } from './events' type AllStatuses = @@ -19,7 +20,7 @@ type StatusErrorResponse = { status: Status.Error msg: string url: string - error_code: string + error_code: ServerErrorCode } type StatusSuccessResponse = { diff --git a/packages/upload-client/test/tools/UploadError.test.ts b/packages/upload-client/test/tools/UploadError.test.ts index 8aeac6a5f..ab51176d9 100644 --- a/packages/upload-client/test/tools/UploadError.test.ts +++ b/packages/upload-client/test/tools/UploadError.test.ts @@ -15,10 +15,10 @@ describe('UploadError', () => { }) it('should have code', () => { - const error = new UploadError('test error', 'error code') + const error = new UploadError('test error', 'AccountBlockedError') expect(error.message).toBe('test error') - expect(error.code).toBe('error code') + expect(error.code).toBe('AccountBlockedError') }) it('should have stack', () => {