trainingpeaks-sdk
Version:
TypeScript SDK for TrainingPeaks API integration
212 lines (211 loc) • 8.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createUserFriendlyMessage = exports.withClientResponseHandling = exports.transformToClientError = exports.withClientErrorHandling = exports.ClientError = void 0;
const http_errors_1 = require("../adapters/errors/http-errors.js");
const domain_errors_1 = require("../domain/errors/domain-errors.js");
const error_codes_1 = require("../domain/errors/error-codes.js");
const sdk_error_1 = require("../domain/errors/sdk-error.js");
class ClientError extends sdk_error_1.SDKError {
constructor(message, code, operation, options = {}) {
super(message, code, {
...options.context,
originalError: options.originalError,
});
this.name = 'ClientError';
this.operation = operation;
this.suggestions = options.suggestions || [];
this.isRetryable = options.isRetryable || false;
this.httpStatus = options.httpStatus;
}
}
exports.ClientError = ClientError;
const withClientErrorHandling = async (operation, operationName, context = {}) => {
try {
return await operation();
}
catch (error) {
throw (0, exports.transformToClientError)(error, operationName, context);
}
};
exports.withClientErrorHandling = withClientErrorHandling;
const transformToClientError = (error, operation, context = {}) => {
if (error instanceof domain_errors_1.AuthenticationError) {
return new ClientError(error.message, error_codes_1.ERROR_CODES.AUTH_FAILED, operation, {
suggestions: getSuggestionsForCode(error_codes_1.ERROR_CODES.AUTH_FAILED),
isRetryable: false,
originalError: error,
context,
});
}
if (error instanceof domain_errors_1.ValidationError) {
return new ClientError(error.message, error_codes_1.ERROR_CODES.VALIDATION_FAILED, operation, {
suggestions: getSuggestionsForCode(error_codes_1.ERROR_CODES.VALIDATION_FAILED),
isRetryable: false,
originalError: error,
context,
});
}
if (error instanceof domain_errors_1.NetworkError) {
return new ClientError(error.message, error_codes_1.ERROR_CODES.NETWORK_REQUEST_FAILED, operation, {
suggestions: getSuggestionsForCode(error_codes_1.ERROR_CODES.NETWORK_TIMEOUT),
isRetryable: true,
originalError: error,
context,
});
}
if (error instanceof domain_errors_1.UserError) {
return new ClientError(error.message, error.code, operation, {
suggestions: getSuggestionsForCode(error.code),
isRetryable: false,
originalError: error,
context,
});
}
if (error instanceof http_errors_1.HttpError) {
return new ClientError(error.message, error.code, operation, {
suggestions: getSuggestionsForHttpError(error),
isRetryable: error.status >= 500 || error.status === 429,
httpStatus: error.status,
originalError: error,
context: { ...context, url: error.url, method: error.method },
});
}
if (error instanceof sdk_error_1.SDKError) {
return new ClientError(error.message, error.code, operation, {
suggestions: getSuggestionsForCode(error.code),
originalError: error,
context,
});
}
return new ClientError(`${operation} failed: ${error.message}`, error_codes_1.ERROR_CODES.UNKNOWN_ERROR, operation, {
suggestions: [
'Check network connection',
'Verify API credentials',
'Try again later',
],
originalError: error,
context,
});
};
exports.transformToClientError = transformToClientError;
const getSuggestionsForHttpError = (error) => {
switch (error.status) {
case 400:
return [
'Check request parameters for valid format',
'Ensure all required fields are included',
'Verify data types match API expectations',
];
case 401:
return [
'Check if your authentication token is valid',
'Try refreshing your authentication token',
'Verify your API credentials are correct',
];
case 403:
return [
'Verify you have permission to access this resource',
'Check if your account has the required subscription plan',
'Contact support if you believe this is an error',
];
case 404:
return [
'Verify the resource ID exists',
'Check if the resource has been deleted',
'Ensure you have access to this resource',
];
case 408:
case 504:
return [
'The request timed out - try again',
'Check your network connection',
'Consider increasing timeout settings',
];
case 429:
return [
'You have exceeded the rate limit',
'Wait before making another request',
'Consider implementing exponential backoff',
'Check your subscription plan for higher limits',
];
case 500:
case 502:
case 503:
return [
'This is a temporary server error',
'Try again in a few moments',
'Check the service status page',
'Contact support if the issue persists',
];
default:
return [
'Check the HTTP status code for specific guidance',
'Verify your request format',
'Try again if this seems like a temporary issue',
];
}
};
const getSuggestionsForCode = (code) => {
switch (code) {
case error_codes_1.ERROR_CODES.AUTH_FAILED:
case error_codes_1.ERROR_CODES.AUTH_TOKEN_INVALID:
return [
'Verify your authentication credentials',
'Check if your token has expired',
'Try re-authenticating',
];
case error_codes_1.ERROR_CODES.NETWORK_TIMEOUT:
return [
'Check your network connection',
'Try again with a longer timeout',
'Verify the service is available',
];
case error_codes_1.ERROR_CODES.NETWORK_RATE_LIMITED:
return [
'Reduce the frequency of your requests',
'Implement exponential backoff',
'Check your rate limit allowance',
];
case error_codes_1.ERROR_CODES.VALIDATION_FAILED:
return [
'Check your input parameters',
'Ensure required fields are provided',
'Verify data formats are correct',
];
default:
return ['Check the error code documentation for specific guidance'];
}
};
const withClientResponseHandling = async (operation, operationName, errorResponseFactory, context = {}) => {
try {
return await (0, exports.withClientErrorHandling)(operation, operationName, context);
}
catch (error) {
const clientError = error;
return errorResponseFactory(clientError.message, clientError.code);
}
};
exports.withClientResponseHandling = withClientResponseHandling;
const createUserFriendlyMessage = (error) => {
const baseMessage = `Operation "${error.operation}" failed`;
if (error.httpStatus) {
switch (error.httpStatus) {
case 401:
return `${baseMessage}: Authentication required. Please check your credentials.`;
case 403:
return `${baseMessage}: Access denied. You may not have permission for this resource.`;
case 404:
return `${baseMessage}: Resource not found. Please verify the ID is correct.`;
case 429:
return `${baseMessage}: Rate limit exceeded. Please wait before trying again.`;
case 500:
case 502:
case 503:
return `${baseMessage}: Server error. This is likely temporary - please try again.`;
default:
return `${baseMessage}: ${error.message}`;
}
}
return `${baseMessage}: ${error.message}`;
};
exports.createUserFriendlyMessage = createUserFriendlyMessage;