@energica-city/shared-amplify-utils
Version:
Shared utilities for AWS Amplify projects
209 lines • 25.8 kB
JavaScript
import { logger } from '../../log';
import { throwError } from '../../error';
import { ERROR_CODES, initializeRestMiddleware, isDevelopment, getErrorMessage, getErrorStack, } from './utils';
/**
* Type guard to check if an error is a middleware error
* @param error - Error of unknown type
* @returns True if error is a MiddlewareError with middlewareName property
*/
function isMiddlewareError(error) {
return (error instanceof Error &&
typeof error.middlewareName === 'string');
}
/**
* Extracts middleware information from a MiddlewareError
* @param error - Middleware error object
* @returns Object containing middleware name, index, total count, and chain
*/
function getMiddlewareInfo(error) {
return {
name: error.middlewareName || 'unknown',
index: error.middlewareIndex ?? -1,
total: error.totalMiddlewares ?? 0,
chain: error.middlewareChain || [],
};
}
/**
* Type guard to check if an error has our custom context structure
* @param error - Error of unknown type
* @returns True if error has a context property of object type
*/
function isOurError(error) {
return (error instanceof Error &&
'context' in error &&
typeof error.context === 'object');
}
/**
* Creates a standardized error response for middleware errors
* @param error - Error object with optional statusCode and context
* @param options - Configuration for error response formatting
* @param options.includeStackTrace - Whether to include stack trace in response
* @param options.includeDetails - Whether to include detailed error information
* @param options.productionErrorMessage - Generic message for production environments
* @returns REST API response object with error details
*/
function createMiddlewareErrorResponse(error, options) {
const { includeStackTrace, includeDetails, productionErrorMessage } = options;
return {
statusCode: error.statusCode || 500,
headers: {
'Content-Type': 'application/json',
'X-Request-ID': error.context?.requestId || 'unknown',
},
body: JSON.stringify({
error: {
code: error.context?.code || 'INTERNAL_SERVER_ERROR',
message: includeDetails ? error.message : productionErrorMessage,
timestamp: error.context?.timestamp || new Date().toISOString(),
requestId: error.context?.requestId || 'unknown',
...(includeStackTrace && { stack: error.stack }),
...(includeDetails && error.context && { context: error.context }),
},
}),
};
}
/**
* Creates REST error handler middleware for standardized error processing
* @param config - Configuration options for error handling behavior
* @returns Middleware function that catches and processes errors
*
* @example
* ```typescript
* chain.use('errorHandler', createRestErrorHandler({
* includeStackTrace: true,
* defaultContext: { service: 'my-api' }
* }));
* ```
*/
export function createRestErrorHandler(config = {}) {
const { includeStackTrace = isDevelopment, defaultContext = {}, forceStructuredLogging = true, } = config;
const includeDetails = isDevelopment;
const productionErrorMessage = 'Internal Server Error';
return async (input, next) => {
const { context: baseContext } = initializeRestMiddleware(input, {
defaultContext,
forceStructuredLogging,
operation: 'errorHandler',
});
try {
return await next(input);
}
catch (error) {
const errorMessage = getErrorMessage(error);
const stack = includeStackTrace ? getErrorStack(error) : undefined;
let enhancedError;
if (!isOurError(error)) {
logger.warn('Non-standard error thrown, wrapping with throwError', {
error: typeof error === 'object' ? error : { message: String(error) },
});
enhancedError = throwError(`Non-standard error thrown to error handler: ${errorMessage}`, error);
const lambdaContext = input.context;
if (lambdaContext && enhancedError.context) {
enhancedError.context.requestId = lambdaContext.awsRequestId;
}
}
else {
enhancedError = error;
}
const errorContext = {};
if (enhancedError && typeof enhancedError === 'object') {
if ('code' in enhancedError && typeof enhancedError.code === 'string') {
errorContext.errorCode = enhancedError.code;
}
if ('statusCode' in enhancedError &&
typeof enhancedError.statusCode === 'number') {
errorContext.statusCode = enhancedError.statusCode;
}
}
const logContext = {
...baseContext,
...errorContext,
};
if (isMiddlewareError(error)) {
const middlewareInfo = getMiddlewareInfo(error);
logger.error(`Middleware error in ${middlewareInfo.name}`, {
...logContext,
middlewareError: middlewareInfo,
stack,
});
}
else {
logger.error(`REST error: ${errorMessage}`, {
...logContext,
stack,
});
}
const errorWithStatusCode = enhancedError;
const errorResponse = createMiddlewareErrorResponse(errorWithStatusCode, {
includeStackTrace,
includeDetails,
productionErrorMessage,
});
return errorResponse;
}
};
}
/**
* HTTP error helper functions for creating standardized error objects
*/
export const HttpErrors = {
badRequest: (message) => ({
statusCode: 400,
code: ERROR_CODES.BAD_REQUEST,
message,
}),
unauthorized: (message) => ({
statusCode: 401,
code: ERROR_CODES.UNAUTHORIZED,
message,
}),
forbidden: (message) => ({
statusCode: 403,
code: ERROR_CODES.FORBIDDEN,
message,
}),
notFound: (message) => ({
statusCode: 404,
code: ERROR_CODES.NOT_FOUND,
message,
}),
methodNotAllowed: (message) => ({
statusCode: 405,
code: ERROR_CODES.METHOD_NOT_ALLOWED,
message,
}),
conflict: (message) => ({
statusCode: 409,
code: ERROR_CODES.CONFLICT,
message,
}),
unprocessableEntity: (message) => ({
statusCode: 422,
code: ERROR_CODES.UNPROCESSABLE_ENTITY,
message,
}),
internalServerError: (message) => ({
statusCode: 500,
code: ERROR_CODES.INTERNAL_SERVER_ERROR,
message,
}),
serviceUnavailable: (message) => ({
statusCode: 503,
code: ERROR_CODES.SERVICE_UNAVAILABLE,
message,
}),
};
/**
* Creates an HTTP error object with status code and error code
* @param statusCode - HTTP status code
* @param code - Error code identifier
* @param message - Error message
* @returns Error object with statusCode and code properties
*/
export function createHttpError(statusCode, code, message) {
const error = new Error(message);
error.statusCode = statusCode;
error.code = code;
return error;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVzdEVycm9ySGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL21pZGRsZXdhcmUvcmVzdC9SZXN0RXJyb3JIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbkMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUN6QyxPQUFPLEVBQ0wsV0FBVyxFQUNYLHdCQUF3QixFQUN4QixhQUFhLEVBQ2IsZUFBZSxFQUNmLGFBQWEsR0FDZCxNQUFNLFNBQVMsQ0FBQztBQVNqQjs7OztHQUlHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxLQUFjO0lBQ3ZDLE9BQU8sQ0FDTCxLQUFLLFlBQVksS0FBSztRQUN0QixPQUFRLEtBQXlCLENBQUMsY0FBYyxLQUFLLFFBQVEsQ0FDOUQsQ0FBQztBQUNKLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxpQkFBaUIsQ0FBQyxLQUFzQjtJQUMvQyxPQUFPO1FBQ0wsSUFBSSxFQUFFLEtBQUssQ0FBQyxjQUFjLElBQUksU0FBUztRQUN2QyxLQUFLLEVBQUUsS0FBSyxDQUFDLGVBQWUsSUFBSSxDQUFDLENBQUM7UUFDbEMsS0FBSyxFQUFFLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSxDQUFDO1FBQ2xDLEtBQUssRUFBRSxLQUFLLENBQUMsZUFBZSxJQUFJLEVBQUU7S0FDbkMsQ0FBQztBQUNKLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxVQUFVLENBQ2pCLEtBQWM7SUFFZCxPQUFPLENBQ0wsS0FBSyxZQUFZLEtBQUs7UUFDdEIsU0FBUyxJQUFJLEtBQUs7UUFDbEIsT0FBUSxLQUErQixDQUFDLE9BQU8sS0FBSyxRQUFRLENBQzdELENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFTLDZCQUE2QixDQUNwQyxLQUF5RSxFQUN6RSxPQUlDO0lBRUQsTUFBTSxFQUFFLGlC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LElBQUksRUFBRSxXQUFXLENBQUMsb0JBQW9CO1FBQ3RDLE9BQU87S0FDUixDQUFDO0lBQ0YsbUJBQW1CLEVBQUUsQ0FBQyxPQUFlLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDekMsVUFBVSxFQUFFLEdBQUc7UUFDZixJQUFJLEVBQUUsV0FBVyxDQUFDLHFCQUFxQjtRQUN2QyxPQUFPO0tBQ1IsQ0FBQztJQUNGLGtCQUFrQixFQUFFLENBQUMsT0FBZSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3hDLFVBQVUsRUFBRSxHQUFHO1FBQ2YsSUFBSSxFQUFFLFdBQVcsQ0FBQyxtQkFBbUI7UUFDckMsT0FBTztLQUNSLENBQUM7Q0FDTSxDQUFDO0FBRVg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FDN0IsVUFBa0IsRUFDbEIsSUFBWSxFQUNaLE9BQWU7SUFFZixNQUFNLEtBQUssR0FBRyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBRzlCLENBQUM7SUFDRixLQUFLLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztJQUM5QixLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNsQixPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi8uLi9sb2cnO1xuaW1wb3J0IHsgdGhyb3dFcnJvciB9IGZyb20gJy4uLy4uL2Vycm9yJztcbmltcG9ydCB7XG4gIEVSUk9SX0NPREVTLFxuICBpbml0aWFsaXplUmVzdE1pZGRsZXdhcmUsXG4gIGlzRGV2ZWxvcG1lbnQsXG4gIGdldEVycm9yTWVzc2FnZSxcbiAgZ2V0RXJyb3JTdGFjayxcbn0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgdHlwZSB7IE1pZGRsZXdhcmUsIE1pZGRsZXdhcmVFcnJvciB9IGZyb20gJy4uL21pZGRsZXdhcmVDaGFpbic7XG5pbXBvcnQgdHlwZSB7XG4gIFJlc3RSZXNwb25zZSxcbiAgUmVzdElucHV0V2l0aE1vZGVscyxcbiAgUmVzdEVycm9ySGFuZGxlckNvbmZpZyxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgdHlwZSB7IEFtcGxpZnlNb2RlbFR5cGUgfSBmcm9tICcuLi8uLi9xdWVyaWVzL3R5cGVzJztcblxuLyoqXG4gKiBUeXBlIGd1YXJkIHRvIGNoZWNrIGlmIGFuIGVycm9yIGlzIGEgbWlkZGxld2FyZSBlcnJvclxuICogQHBhcmFtIGVycm9yIC0gRXJyb3Igb2YgdW5rbm93biB0eXBlXG4gKiBAcmV0dXJucyBUcnVlIGlmIGVycm9yIGlzIGEgTWlkZGxld2FyZUVycm9yIHdpdGggbWlkZGxld2FyZU5hbWUgcHJvcGVydHlcbiAqL1xuZnVuY3Rpb24gaXNNaWRkbGV3YXJlRXJyb3IoZXJyb3I6IHVua25vd24pOiBlcnJvciBpcyBNaWRkbGV3YXJlRXJyb3Ige1xuICByZXR1cm4gKFxuICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiZcbiAgICB0eXBlb2YgKGVycm9yIGFzIE1pZGRsZXdhcmVFcnJvcikubWlkZGxld2FyZU5hbWUgPT09ICdzdHJpbmcnXG4gICk7XG59XG5cbi8qKlxuICogRXh0cmFjdHMgbWlkZGxld2FyZSBpbmZvcm1hdGlvbiBmcm9tIGEgTWlkZGxld2FyZUVycm9yXG4gKiBAcGFyYW0gZXJyb3IgLSBNaWRkbGV3YXJlIGVycm9yIG9iamVjdFxuICogQHJldHVybnMgT2JqZWN0IGNvbnRhaW5pbmcgbWlkZGxld2FyZSBuYW1lLCBpbmRleCwgdG90YWwgY291bnQsIGFuZCBjaGFpblxuICovXG5mdW5jdGlvbiBnZXRNaWRkbGV3YXJlSW5mbyhlcnJvcjogTWlkZGxld2FyZUVycm9yKSB7XG4gIHJldHVybiB7XG4gICAgbmFtZTogZXJyb3IubWlkZGxld2FyZU5hbWUgfHwgJ3Vua25vd24nLFxuICAgIGluZGV4OiBlcnJvci5taWRkbGV3YXJlSW5kZXggPz8gLTEsXG4gICAgdG90YWw6IGVycm9yLnRvdGFsTWlkZGxld2FyZXMgPz8gMCxcbiAgICBjaGFpbjogZXJyb3IubWlkZGxld2FyZUNoYWluIHx8IFtdLFxuICB9O1xufVxuXG4vKipcbiAqIFR5cGUgZ3VhcmQgdG8gY2hlY2sgaWYgYW4gZXJyb3IgaGFzIG91ciBjdXN0b20gY29udGV4dCBzdHJ1Y3R1cmVcbiAqIEBwYXJhbSBlcnJvciAtIEVycm9yIG9mIHVua25vd24gdHlwZVxuICogQHJldHVybnMgVHJ1ZSBpZiBlcnJvciBoYXMgYSBjb250ZXh0IHByb3BlcnR5IG9mIG9iamVjdCB0eXBlXG4gKi9cbmZ1bmN0aW9uIGlzT3VyRXJyb3IoXG4gIGVycm9yOiB1bmtub3duLFxuKTogZXJyb3IgaXMgRXJyb3IgJiB7IGNvbnRleHQ/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9IHtcbiAgcmV0dXJuIChcbiAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmXG4gICAgJ2NvbnRleHQnIGluIGVycm9yICYmXG4gICAgdHlwZW9mIChlcnJvciBhcyB7IGNvbnRleHQ/OiB1bmtub3duIH0pLmNvbnRleHQgPT09ICdvYmplY3QnXG4gICk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHN0YW5kYXJkaXplZCBlcnJvciByZXNwb25zZSBmb3IgbWlkZGxld2FyZSBlcnJvcnNcbiAqIEBwYXJhbSBlcnJvciAtIEVycm9yIG9iamVjdCB3aXRoIG9wdGlvbmFsIHN0YXR1c0NvZGUgYW5kIGNvbnRleHRcbiAqIEBwYXJhbSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBmb3IgZXJyb3IgcmVzcG9uc2UgZm9ybWF0dGluZ1xuICogQHBhcmFtIG9wdGlvbnMuaW5jbHVkZVN0YWNrVHJhY2UgLSBXaGV0aGVyIHRvIGluY2x1ZGUgc3RhY2sgdHJhY2UgaW4gcmVzcG9uc2VcbiAqIEBwYXJhbSBvcHRpb25zLmluY2x1ZGVEZXRhaWxzIC0gV2hldGhlciB0byBpbmNsdWRlIGRldGFpbGVkIGVycm9yIGluZm9ybWF0aW9uXG4gKiBAcGFyYW0gb3B0aW9ucy5wcm9kdWN0aW9uRXJyb3JNZXNzYWdlIC0gR2VuZXJpYyBtZXNzYWdlIGZvciBwcm9kdWN0aW9uIGVudmlyb25tZW50c1xuICogQHJldHVybnMgUkVTVCBBUEkgcmVzcG9uc2Ugb2JqZWN0IHdpdGggZXJyb3IgZGV0YWlsc1xuICovXG5mdW5jdGlvbiBjcmVhdGVNaWRkbGV3YXJlRXJyb3JSZXNwb25zZShcbiAgZXJyb3I6IEVycm9yICYgeyBzdGF0dXNDb2RlPzogbnVtYmVyOyBjb250ZXh0PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfSxcbiAgb3B0aW9uczoge1xuICAgIGluY2x1ZGVTdGFja1RyYWNlOiBib29sZWFuO1xuICAgIGluY2x1ZGVEZXRhaWxzOiBib29sZWFuO1xuICAgIHByb2R1Y3Rpb25FcnJvck1lc3NhZ2U6IHN0cmluZztcbiAgfSxcbik6IFJlc3RSZXNwb25zZSB7XG4gIGNvbnN0IHsgaW5jbHVkZVN0YWNrVHJhY2UsIGluY2x1ZGVEZXRhaWxzLCBwcm9kdWN0aW9uRXJyb3JNZXNzYWdlIH0gPSBvcHRpb25zO1xuXG4gIHJldHVybiB7XG4gICAgc3RhdHVzQ29kZTogZXJyb3Iuc3RhdHVzQ29kZSB8fCA1MDAsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICdYLVJlcXVlc3QtSUQnOiAoZXJyb3IuY29udGV4dD8ucmVxdWVzdElkIGFzIHN0cmluZykgfHwgJ3Vua25vd24nLFxuICAgIH0sXG4gICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgZXJyb3I6IHtcbiAgICAgICAgY29kZTogKGVycm9yLmNvbnRleHQ/LmNvZGUgYXMgc3RyaW5nKSB8fCAnSU5URVJOQUxfU0VSVkVSX0VSUk9SJyxcbiAgICAgICAgbWVzc2FnZTogaW5jbHVkZURldGFpbHMgPyBlcnJvci5tZXNzYWdlIDogcHJvZHVjdGlvbkVycm9yTWVzc2FnZSxcbiAgICAgICAgdGltZXN0YW1wOlxuICAgICAgICAgIChlcnJvci5jb250ZXh0Py50aW1lc3RhbXAgYXMgc3RyaW5nKSB8fCBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIHJlcXVlc3RJZDogKGVycm9yLmNvbnRleHQ/LnJlcXVlc3RJZCBhcyBzdHJpbmcpIHx8ICd1bmtub3duJyxcbiAgICAgICAgLi4uKGluY2x1ZGVTdGFja1RyYWNlICYmIHsgc3RhY2s6IGVycm9yLnN0YWNrIH0pLFxuICAgICAgICAuLi4oaW5jbHVkZURldGFpbHMgJiYgZXJyb3IuY29udGV4dCAmJiB7IGNvbnRleHQ6IGVycm9yLmNvbnRleHQgfSksXG4gICAgICB9LFxuICAgIH0pLFxuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgUkVTVCBlcnJvciBoYW5kbGVyIG1pZGRsZXdhcmUgZm9yIHN0YW5kYXJkaXplZCBlcnJvciBwcm9jZXNzaW5nXG4gKiBAcGFyYW0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBlcnJvciBoYW5kbGluZyBiZWhhdmlvclxuICogQHJldHVybnMgTWlkZGxld2FyZSBmdW5jdGlvbiB0aGF0IGNhdGNoZXMgYW5kIHByb2Nlc3NlcyBlcnJvcnNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY2hhaW4udXNlKCdlcnJvckhhbmRsZXInLCBjcmVhdGVSZXN0RXJyb3JIYW5kbGVyKHtcbiAqICAgaW5jbHVkZVN0YWNrVHJhY2U6IHRydWUsXG4gKiAgIGRlZmF1bHRDb250ZXh0OiB7IHNlcnZpY2U6ICdteS1hcGknIH1cbiAqIH0pKTtcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUmVzdEVycm9ySGFuZGxlcjxcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbiAgVE91dHB1dCA9IFJlc3RSZXNwb25zZSxcbj4oXG4gIGNvbmZpZzogUmVzdEVycm9ySGFuZGxlckNvbmZpZyA9IHt9LFxuKTogTWlkZGxld2FyZTxSZXN0SW5wdXRXaXRoTW9kZWxzPFRUeXBlcz4sIFRPdXRwdXQ+IHtcbiAgY29uc3Qge1xuICAgIGluY2x1ZGVTdGFja1RyYWNlID0gaXNEZXZlbG9wbWVudCxcbiAgICBkZWZhdWx0Q29udGV4dCA9IHt9LFxuICAgIGZvcmNlU3RydWN0dXJlZExvZ2dpbmcgPSB0cnVlLFxuICB9ID0gY29uZmlnO1xuXG4gIGNvbnN0IGluY2x1ZGVEZXRhaWxzID0gaXNEZXZlbG9wbWVudDtcbiAgY29uc3QgcHJvZHVjdGlvbkVycm9yTWVzc2FnZSA9ICdJbnRlcm5hbCBTZXJ2ZXIgRXJyb3InO1xuXG4gIHJldHVybiBhc3luYyAoXG4gICAgaW5wdXQ6IFJlc3RJbnB1dFdpdGhNb2RlbHM8VFR5cGVzPixcbiAgICBuZXh0OiAoaW5wdXQ/OiBSZXN0SW5wdXRXaXRoTW9kZWxzPFRUeXBlcz4pID0+IFByb21pc2U8VE91dHB1dD4sXG4gICk6IFByb21pc2U8VE91dHB1dD4gPT4ge1xuICAgIGNvbnN0IHsgY29udGV4dDogYmFzZUNvbnRleHQgfSA9IGluaXRpYWxpemVSZXN0TWlkZGxld2FyZShcbiAgICAgIGlucHV0IGFzIFJlc3RJbnB1dFdpdGhNb2RlbHMsXG4gICAgICB7XG4gICAgICAgIGRlZmF1bHRDb250ZXh0LFxuICAgICAgICBmb3JjZVN0cnVjdHVyZWRMb2dnaW5nLFxuICAgICAgICBvcGVyYXRpb246ICdlcnJvckhhbmRsZXInLFxuICAgICAgfSxcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBuZXh0KGlucHV0KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gZ2V0RXJyb3JNZXNzYWdlKGVycm9yKTtcbiAgICAgIGNvbnN0IHN0YWNrID0gaW5jbHVkZVN0YWNrVHJhY2UgPyBnZXRFcnJvclN0YWNrKGVycm9yKSA6IHVuZGVmaW5lZDtcblxuICAgICAgbGV0IGVuaGFuY2VkRXJyb3I6IEVycm9yICYgeyBjb250ZXh0PzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfTtcblxuICAgICAgaWYgKCFpc091ckVycm9yKGVycm9yKSkge1xuICAgICAgICBsb2dnZXIud2FybignTm9uLXN0YW5kYXJkIGVycm9yIHRocm93biwgd3JhcHBpbmcgd2l0aCB0aHJvd0Vycm9yJywge1xuICAgICAgICAgIGVycm9yOiB0eXBlb2YgZXJyb3IgPT09ICdvYmplY3QnID8gZXJyb3IgOiB7IG1lc3NhZ2U6IFN0cmluZyhlcnJvcikgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZW5oYW5jZWRFcnJvciA9IHRocm93RXJyb3IoXG4gICAgICAgICAgYE5vbi1zdGFuZGFyZCBlcnJvciB0aHJvd24gdG8gZXJyb3IgaGFuZGxlcjogJHtlcnJvck1lc3NhZ2V9YCxcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgKSBhcyBFcnJvciAmIHsgY29udGV4dD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+IH07XG5cbiAgICAgICAgY29uc3QgbGFtYmRhQ29udGV4dCA9IGlucHV0LmNvbnRleHQ7XG4gICAgICAgIGlmIChsYW1iZGFDb250ZXh0ICYmIGVuaGFuY2VkRXJyb3IuY29udGV4dCkge1xuICAgICAgICAgIGVuaGFuY2VkRXJyb3IuY29udGV4dC5yZXF1ZXN0SWQgPSBsYW1iZGFDb250ZXh0LmF3c1JlcXVlc3RJZDtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZW5oYW5jZWRFcnJvciA9IGVycm9yO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlcnJvckNvbnRleHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgICBpZiAoZW5oYW5jZWRFcnJvciAmJiB0eXBlb2YgZW5oYW5jZWRFcnJvciA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgaWYgKCdjb2RlJyBpbiBlbmhhbmNlZEVycm9yICYmIHR5cGVvZiBlbmhhbmNlZEVycm9yLmNvZGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgZXJyb3JDb250ZXh0LmVycm9yQ29kZSA9IGVuaGFuY2VkRXJyb3IuY29kZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoXG4gICAgICAgICAgJ3N0YXR1c0NvZGUnIGluIGVuaGFuY2VkRXJyb3IgJiZcbiAgICAgICAgICB0eXBlb2YgZW5oYW5jZWRFcnJvci5zdGF0dXNDb2RlID09PSAnbnVtYmVyJ1xuICAgICAgICApIHtcbiAgICAgICAgICBlcnJvckNvbnRleHQuc3RhdHVzQ29kZSA9IGVuaGFuY2VkRXJyb3Iuc3RhdHVzQ29kZTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBjb25zdCBsb2dDb250ZXh0ID0ge1xuICAgICAgICAuLi5iYXNlQ29udGV4dCxcbiAgICAgICAgLi4uZXJyb3JDb250ZXh0LFxuICAgICAgfTtcblxuICAgICAgaWYgKGlzTWlkZGxld2FyZUVycm9yKGVycm9yKSkge1xuICAgICAgICBjb25zdCBtaWRkbGV3YXJlSW5mbyA9IGdldE1pZGRsZXdhcmVJbmZvKGVycm9yKTtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBNaWRkbGV3YXJlIGVycm9yIGluICR7bWlkZGxld2FyZUluZm8ubmFtZX1gLCB7XG4gICAgICAgICAgLi4ubG9nQ29udGV4dCxcbiAgICAgICAgICBtaWRkbGV3YXJlRXJyb3I6IG1pZGRsZXdhcmVJbmZvLFxuICAgICAgICAgIHN0YWNrLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgUkVTVCBlcnJvcjogJHtlcnJvck1lc3NhZ2V9YCwge1xuICAgICAgICAgIC4uLmxvZ0NvbnRleHQsXG4gICAgICAgICAgc3RhY2ssXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBlcnJvcldpdGhTdGF0dXNDb2RlID0gZW5oYW5jZWRFcnJvciBhcyBFcnJvciAmIHtcbiAgICAgICAgc3RhdHVzQ29kZT86IG51bWJlcjtcbiAgICAgICAgY29udGV4dD86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgfTtcblxuICAgICAgY29uc3QgZXJyb3JSZXNwb25zZSA9IGNyZWF0ZU1pZGRsZXdhcmVFcnJvclJlc3BvbnNlKGVycm9yV2l0aFN0YXR1c0NvZGUsIHtcbiAgICAgICAgaW5jbHVkZVN0YWNrVHJhY2UsXG4gICAgICAgIGluY2x1ZGVEZXRhaWxzLFxuICAgICAgICBwcm9kdWN0aW9uRXJyb3JNZXNzYWdlLFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBlcnJvclJlc3BvbnNlIGFzIFRPdXRwdXQ7XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIEhUVFAgZXJyb3IgaGVscGVyIGZ1bmN0aW9ucyBmb3IgY3JlYXRpbmcgc3RhbmRhcmRpemVkIGVycm9yIG9iamVjdHNcbiAqL1xuZXhwb3J0IGNvbnN0IEh0dHBFcnJvcnMgPSB7XG4gIGJhZFJlcXVlc3Q6IChtZXNzYWdlOiBzdHJpbmcpID0+ICh7XG4gICAgc3RhdHVzQ29kZTogNDAwLFxuICAgIGNvZGU6IEVSUk9SX0NPREVTLkJBRF9SRVFVRVNULFxuICAgIG1lc3NhZ2UsXG4gIH0pLFxuICB1bmF1dGhvcml6ZWQ6IChtZXNzYWdlOiBzdHJpbmcpID0+ICh7XG4gICAgc3RhdHVzQ29kZTogNDAxLFxuICAgIGNvZGU6IEVSUk9SX0NPREVTLlVOQVVUSE9SSVpFRCxcbiAgICBtZXNzYWdlLFxuICB9KSxcbiAgZm9yYmlkZGVuOiAobWVzc2FnZTogc3RyaW5nKSA9PiAoe1xuICAgIHN0YXR1c0NvZGU6IDQwMyxcbiAgICBjb2RlOiBFUlJPUl9DT0RFUy5GT1JCSURERU4sXG4gICAgbWVzc2FnZSxcbiAgfSksXG4gIG5vdEZvdW5kOiAobWVzc2FnZTogc3RyaW5nKSA9PiAoe1xuICAgIHN0YXR1c0NvZGU6IDQwNCxcbiAgICBjb2RlOiBFUlJPUl9DT0RFUy5OT1RfRk9VTkQsXG4gICAgbWVzc2FnZSxcbiAgfSksXG4gIG1ldGhvZE5vdEFsbG93ZWQ6IChtZXNzYWdlOiBzdHJpbmcpID0+ICh7XG4gICAgc3RhdHVzQ29kZTogNDA1LFxuICAgIGNvZGU6IEVSUk9SX0NPREVTLk1FVEhPRF9OT1RfQUxMT1dFRCxcbiAgICBtZXNzYWdlLFxuICB9KSxcbiAgY29uZmxpY3Q6IChtZXNzYWdlOiBzdHJpbmcpID0+ICh7XG4gICAgc3RhdHVzQ29kZTogNDA5LFxuICAgIGNvZGU6IEVSUk9SX0NPREVTLkNPTkZMSUNULFxuICAgIG1lc3NhZ2UsXG4gIH0pLFxuICB1bnByb2Nlc3NhYmxlRW50aXR5OiAobWVzc2FnZTogc3RyaW5nKSA9PiAoe1xuICAgIHN0YXR1c0NvZGU6IDQyMixcbiAgICBjb2RlOiBFUlJPUl9DT0RFUy5VTlBST0NFU1NBQkxFX0VOVElUWSxcbiAgICBtZXNzYWdlLFxuICB9KSxcbiAgaW50ZXJuYWxTZXJ2ZXJFcnJvcjogKG1lc3NhZ2U6IHN0cmluZykgPT4gKHtcbiAgICBzdGF0dXNDb2RlOiA1MDAsXG4gICAgY29kZTogRVJST1JfQ09ERVMuSU5URVJOQUxfU0VSVkVSX0VSUk9SLFxuICAgIG1lc3NhZ2UsXG4gIH0pLFxuICBzZXJ2aWNlVW5hdmFpbGFibGU6IChtZXNzYWdlOiBzdHJpbmcpID0+ICh7XG4gICAgc3RhdHVzQ29kZTogNTAzLFxuICAgIGNvZGU6IEVSUk9SX0NPREVTLlNFUlZJQ0VfVU5BVkFJTEFCTEUsXG4gICAgbWVzc2FnZSxcbiAgfSksXG59IGFzIGNvbnN0O1xuXG4vKipcbiAqIENyZWF0ZXMgYW4gSFRUUCBlcnJvciBvYmplY3Qgd2l0aCBzdGF0dXMgY29kZSBhbmQgZXJyb3IgY29kZVxuICogQHBhcmFtIHN0YXR1c0NvZGUgLSBIVFRQIHN0YXR1cyBjb2RlXG4gKiBAcGFyYW0gY29kZSAtIEVycm9yIGNvZGUgaWRlbnRpZmllclxuICogQHBhcmFtIG1lc3NhZ2UgLSBFcnJvciBtZXNzYWdlXG4gKiBAcmV0dXJucyBFcnJvciBvYmplY3Qgd2l0aCBzdGF0dXNDb2RlIGFuZCBjb2RlIHByb3BlcnRpZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUh0dHBFcnJvcihcbiAgc3RhdHVzQ29kZTogbnVtYmVyLFxuICBjb2RlOiBzdHJpbmcsXG4gIG1lc3NhZ2U6IHN0cmluZyxcbikge1xuICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlKSBhcyBFcnJvciAmIHtcbiAgICBzdGF0dXNDb2RlOiBudW1iZXI7XG4gICAgY29kZTogc3RyaW5nO1xuICB9O1xuICBlcnJvci5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcbiAgZXJyb3IuY29kZSA9IGNvZGU7XG4gIHJldHVybiBlcnJvcjtcbn1cbiJdfQ==