trainingpeaks-sdk
Version:
TypeScript SDK for TrainingPeaks API integration
177 lines (176 loc) • 8.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleRepositoryError = exports.throwTokenExpiredError = exports.throwCookieNotFoundError = exports.throwAuthError = exports.throwServerError = exports.throwMissingDataError = exports.throwValidationError = exports.throwHttpErrorFromResponse = exports.isRetryableError = exports.isServerError = exports.isClientError = exports.isHttpError = exports.createHttpError = exports.HttpError = void 0;
const error_codes_1 = require("../../domain/errors/error-codes.js");
const sdk_error_1 = require("../../domain/errors/sdk-error.js");
class HttpError extends sdk_error_1.SDKError {
constructor(message, code, context, options) {
super(message, code, context, options);
this.name = 'HttpError';
this.code = code;
this.status = context.status;
this.statusText = context.statusText;
this.url = context.url;
this.method = context.method;
this.requestId = context.requestId;
}
}
exports.HttpError = HttpError;
const createHttpError = (response, context = {}, cause) => {
const { status, statusText, data } = response;
const { url, method, requestData, requestId } = context;
const errorContext = {
status,
statusText,
url,
method,
requestData,
responseData: data,
headers: response.headers,
requestId,
};
switch (status) {
case 400:
return new HttpError(`Bad Request: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.VALIDATION_FAILED, errorContext, cause ? { cause } : undefined);
case 401:
return new HttpError(`Authentication failed: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.AUTH_TOKEN_INVALID, errorContext, cause ? { cause } : undefined);
case 403:
return new HttpError(`Access forbidden: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.AUTH_FAILED, errorContext, cause ? { cause } : undefined);
case 404:
return new HttpError(`Resource not found: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.WORKOUT_NOT_FOUND, errorContext, cause ? { cause } : undefined);
case 408:
case 504:
return new HttpError(`Request timeout: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_TIMEOUT, errorContext, cause ? { cause } : undefined);
case 409:
return new HttpError(`Conflict: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.VALIDATION_FAILED, errorContext, cause ? { cause } : undefined);
case 422:
return new HttpError(`Validation error: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.VALIDATION_FAILED, errorContext, cause ? { cause } : undefined);
case 429:
return new HttpError(`Rate limit exceeded: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_RATE_LIMITED, errorContext, cause ? { cause } : undefined);
case 500:
return new HttpError(`Server error: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_SERVER_ERROR, errorContext, cause ? { cause } : undefined);
case 502:
return new HttpError(`Bad gateway: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_RESPONSE_INVALID, errorContext, cause ? { cause } : undefined);
case 503:
return new HttpError(`Service unavailable: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_SERVICE_UNAVAILABLE, errorContext, cause ? { cause } : undefined);
default:
return new HttpError(`HTTP Error ${status}: ${getErrorMessage(data) || statusText}`, error_codes_1.ERROR_CODES.NETWORK_REQUEST_FAILED, errorContext, cause ? { cause } : undefined);
}
};
exports.createHttpError = createHttpError;
const getErrorMessage = (data) => {
if (!data || typeof data !== 'object')
return null;
const errorData = data;
return (errorData.message ||
errorData.error ||
errorData.detail ||
errorData.description ||
null);
};
const isHttpError = (error) => {
return error instanceof HttpError;
};
exports.isHttpError = isHttpError;
const isClientError = (error) => {
return (0, exports.isHttpError)(error) && error.status >= 400 && error.status < 500;
};
exports.isClientError = isClientError;
const isServerError = (error) => {
return (0, exports.isHttpError)(error) && error.status >= 500;
};
exports.isServerError = isServerError;
const isRetryableError = (error) => {
if (!(0, exports.isHttpError)(error))
return false;
return (error.status >= 500 ||
error.status === 408 ||
error.status === 429 ||
error.status === 502 ||
error.status === 503 ||
error.status === 504);
};
exports.isRetryableError = isRetryableError;
const throwHttpErrorFromResponse = (response, operation, context) => {
if (response.error && (0, exports.isHttpError)(response.error)) {
throw response.error;
}
const errorMessage = response.error
? response.error instanceof Error
? response.error.message
: String(response.error)
: `${operation} failed`;
const httpErrorResponse = {
status: 500,
statusText: 'Unknown Error',
data: { message: errorMessage },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwHttpErrorFromResponse = throwHttpErrorFromResponse;
const throwValidationError = (message, context) => {
const httpErrorResponse = {
status: 400,
statusText: 'Bad Request',
data: { message },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwValidationError = throwValidationError;
const throwMissingDataError = (message, context) => {
const httpErrorResponse = {
status: 502,
statusText: 'Bad Gateway',
data: { message },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwMissingDataError = throwMissingDataError;
const throwServerError = (error, fallbackMessage, context) => {
if ((0, exports.isHttpError)(error)) {
throw error;
}
const httpErrorResponse = {
status: 500,
statusText: 'Internal Server Error',
data: {
message: error instanceof Error ? error.message : fallbackMessage,
},
};
throw (0, exports.createHttpError)(httpErrorResponse, context, error);
};
exports.throwServerError = throwServerError;
const throwAuthError = (message, context) => {
const httpErrorResponse = {
status: 401,
statusText: 'Unauthorized',
data: { message },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwAuthError = throwAuthError;
const throwCookieNotFoundError = (cookieName, context) => {
const httpErrorResponse = {
status: 401,
statusText: 'Unauthorized',
data: { message: `${cookieName} cookie not found` },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwCookieNotFoundError = throwCookieNotFoundError;
const throwTokenExpiredError = (context) => {
const httpErrorResponse = {
status: 401,
statusText: 'Unauthorized',
data: { message: 'Received expired token from TrainingPeaks API' },
};
throw (0, exports.createHttpError)(httpErrorResponse, context);
};
exports.throwTokenExpiredError = throwTokenExpiredError;
const handleRepositoryError = (error, operation, context, logger, params) => {
logger.error(`Failed to ${operation}`, { error, params });
if ((0, exports.isHttpError)(error))
throw error;
(0, exports.throwServerError)(error, `Failed to ${operation}`, context);
};
exports.handleRepositoryError = handleRepositoryError;