UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

291 lines 32.5 kB
import { logger } from '../log'; /** * Helper to process string messages with optional context. */ function processStringMessage(message, originalErrorOrContext) { if (originalErrorOrContext === undefined) { return { finalMessage: message, originalError: undefined, errorContext: {}, }; } if (originalErrorOrContext instanceof Error) { return { finalMessage: `${message}: ${originalErrorOrContext.message}`, originalError: originalErrorOrContext, errorContext: { originalError: { name: originalErrorOrContext.name, message: originalErrorOrContext.message, stack: originalErrorOrContext.stack, }, }, }; } if (typeof originalErrorOrContext === 'object' && originalErrorOrContext !== null) { return { finalMessage: message, originalError: originalErrorOrContext, errorContext: originalErrorOrContext, }; } return { finalMessage: `${message}: ${String(originalErrorOrContext)}`, originalError: originalErrorOrContext, errorContext: { originalError: originalErrorOrContext }, }; } /** * Helper to process Error objects. */ function processErrorObject(error) { return { finalMessage: error.message, originalError: error, errorContext: { originalError: { name: error.name, message: error.message, stack: error.stack, }, }, }; } /** * Helper to process arrays of errors. */ function processErrorArray(errors) { const errorMessages = errors.map(err => { if (err instanceof Error) return err.message; if (typeof err === 'object' && err !== null && 'message' in err) { return String(err.message); } return String(err); }); const finalMessage = errorMessages.length > 1 ? `Multiple errors occurred: ${errorMessages.join('; ')}` : errorMessages[0] || 'Unknown error occurred'; return { finalMessage, originalError: errors, errorContext: { errors }, }; } /** * Helper to process unknown values. */ function processUnknownValue(unknownError) { const errorObj = unknownError; if (typeof errorObj === 'object' && errorObj !== null && 'message' in errorObj) { return { finalMessage: String(errorObj.message), originalError: unknownError, errorContext: { originalError: unknownError }, }; } return { finalMessage: `Unexpected error: ${String(unknownError)}`, originalError: unknownError, errorContext: { originalError: unknownError }, }; } /** * Helper to create and configure the error object using ES2022 standards. */ function createErrorObject(finalMessage, originalError, errorContext) { let error; // Use modern Error constructor with cause (ES2022 standard) when originalError exists if (originalError !== undefined) { try { // Modern approach - supported in Node.js 16.9+ and modern browsers error = new Error(finalMessage, { cause: originalError }); } catch { // Fallback for older environments that don't support cause parameter error = new Error(finalMessage); Object.defineProperty(error, 'cause', { value: originalError, writable: true, enumerable: false, configurable: true, }); } // Backward compatibility: also set originalError property if (!('originalError' in error)) { Object.defineProperty(error, 'originalError', { value: originalError, writable: true, enumerable: false, configurable: true, }); } } else { error = new Error(finalMessage); } // Enhanced stack trace chaining for better debugging if (originalError instanceof Error && originalError.stack) { error.stack = `${error.stack}\n\nCaused by: ${originalError.stack}`; } // Always add a marker to identify errors from our library Object.defineProperty(error, '__fromErrorLibrary', { value: true, writable: false, enumerable: false, configurable: false, }); // Assign context properties as non-enumerable properties if (errorContext && typeof errorContext === 'object') { for (const [key, value] of Object.entries(errorContext)) { // Skip system properties that are already handled if (!['originalError', 'cause', 'stack', '__fromErrorLibrary'].includes(key)) { Object.defineProperty(error, key, { value, writable: true, enumerable: false, configurable: true, }); } } } return error; } /** * Enhanced error throwing function that ensures consistent error handling and logging * across the application. It automatically logs errors with structured data and creates * properly formatted Error objects with additional context. * * @param messageOrError - The primary error message (string) or Error object to throw * @param originalErrorOrContext - Optional: original error object or additional context * @throws {Error} Always throws a properly formatted Error with enhanced context * * @example * ```typescript * // Simple message * throwError('Database connection failed'); * * // Message with context * throwError('User not found', { userId: '123', operation: 'getUser' }); * * // Message with original error * throwError('Failed to process request', originalError); * * // Error object (will extract message) * throwError(new Error('Something went wrong')); * * // Array of errors (will combine messages) * throwError([error1, error2, 'Additional info']); * ``` */ export function throwError(messageOrError, originalErrorOrContext) { let result; if (typeof messageOrError === 'string') { result = processStringMessage(messageOrError, originalErrorOrContext); } else if (messageOrError instanceof Error) { result = processErrorObject(messageOrError); } else if (Array.isArray(messageOrError)) { result = processErrorArray(messageOrError); } else { result = processUnknownValue(messageOrError); } const { finalMessage, originalError, errorContext } = result; // Enhanced logging with structured data (CloudWatch handles timestamps) logger.error(finalMessage, { ...errorContext, errorType: typeof originalError, stack: new Error().stack, // Capture current stack trace for debugging }); // Create and throw the error const error = createErrorObject(finalMessage, originalError, errorContext); throw error; } /** * Utility function to safely extract an error message from an unknown error type. * It handles various types of error objects, strings, and other values to produce a consistent * string representation of the error, which is useful for displaying error messages to users. * * @param error - The error from which to extract the message. It can be of any type. * @returns A string representing the error message. * @example * try { * // some operation * } catch (error) { * const message = extractErrorMessage(error); * console.log('Error occurred:', message); * } */ export function extractErrorMessage(error) { if (error instanceof Error) { return error.message; } if (typeof error === 'string') { return error; } if (Array.isArray(error)) { if (error.length === 0) { return ''; } // Recursively flatten and extract messages from arrays const messages = []; function flattenAndExtract(item) { if (Array.isArray(item)) { item.forEach(flattenAndExtract); } else { const message = extractErrorMessage(item); if (message) { messages.push(message); } } } error.forEach(flattenAndExtract); return messages.join('; '); } if (typeof error === 'object' && error !== null) { if ('message' in error && typeof error.message === 'string') { return error.message; } if ('error' in error && typeof error.error === 'string') { return error.error; } if ('details' in error && typeof error.details === 'string') { return error.details; } if ('description' in error && typeof error.description === 'string') { return error.description; } } return String(error); } /** * Utility function to create error context objects with proper filtering. * This ensures consistent context structure while removing undefined values * that could clutter logs or cause serialization issues. * * @param context - Raw context object that may contain undefined values * @returns Filtered context object with undefined values removed * @example * const context = createErrorContext({ * userId: user?.id, // might be undefined * operation: 'deleteUser', // always defined * requestId: req.id // always defined * }); * // Result: { operation: 'deleteUser', requestId: 'abc123' } * // (userId omitted because it was undefined) */ export function createErrorContext(context) { return Object.fromEntries(Object.entries(context).filter(([, value]) => value !== undefined)); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9lcnJvci9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBUWhDOztHQUVHO0FBQ0gsU0FBUyxvQkFBb0IsQ0FDM0IsT0FBZSxFQUNmLHNCQUFnQztJQU1oQyxJQUFJLHNCQUFzQixLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3pDLE9BQU87WUFDTCxZQUFZLEVBQUUsT0FBTztZQUNyQixhQUFhLEVBQUUsU0FBUztZQUN4QixZQUFZLEVBQUUsRUFBRTtTQUNqQixDQUFDO0lBQ0osQ0FBQztJQUVELElBQUksc0JBQXNCLFlBQVksS0FBSyxFQUFFLENBQUM7UUFDNUMsT0FBTztZQUNMLFlBQVksRUFBRSxHQUFHLE9BQU8sS0FBSyxzQkFBc0IsQ0FBQyxPQUFPLEVBQUU7WUFDN0QsYUFBYSxFQUFFLHNCQUFzQjtZQUNyQyxZQUFZLEVBQUU7Z0JBQ1osYUFBYSxFQUFFO29CQUNiLElBQUksRUFBRSxzQkFBc0IsQ0FBQyxJQUFJO29CQUNqQyxPQUFPLEVBQUUsc0JBQXNCLENBQUMsT0FBTztvQkFDdkMsS0FBSyxFQUFFLHNCQUFzQixDQUFDLEtBQUs7aUJBQ3BDO2FBQ0Y7U0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELElBQ0UsT0FBTyxzQkFBc0IsS0FBSyxRQUFRO1FBQzFDLHNCQUFzQixLQUFLLElBQUksRUFDL0IsQ0FBQztRQUNELE9BQU87WUFDTCxZQUFZLEVBQUUsT0FBTztZQUNyQixhQUFhLEVBQUUsc0JBQXNCO1lBQ3JDLFlBQVksRUFBRSxzQkFBc0M7U0FDckQsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPO1FBQ0wsWUFBWSxFQUFFLEdBQUcsT0FBTyxLQUFLLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxFQUFFO1FBQzdELGFBQWEsRUFBRSxzQkFBc0I7UUFDckMsWUFBWSxFQUFFLEVBQUUsYUFBYSxFQUFF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SUFDRSxTQUFTLElBQUksS0FBSztZQUNsQixPQUFRLEtBQThCLENBQUMsT0FBTyxLQUFLLFFBQVEsRUFDM0QsQ0FBQztZQUNELE9BQVEsS0FBNkIsQ0FBQyxPQUFPLENBQUM7UUFDaEQsQ0FBQztRQUVELElBQ0UsT0FBTyxJQUFJLEtBQUs7WUFDaEIsT0FBUSxLQUE0QixDQUFDLEtBQUssS0FBSyxRQUFRLEVBQ3ZELENBQUM7WUFDRCxPQUFRLEtBQTJCLENBQUMsS0FBSyxDQUFDO1FBQzVDLENBQUM7UUFFRCxJQUNFLFNBQVMsSUFBSSxLQUFLO1lBQ2xCLE9BQVEsS0FBOEIsQ0FBQyxPQUFPLEtBQUssUUFBUSxFQUMzRCxDQUFDO1lBQ0QsT0FBUSxLQUE2QixDQUFDLE9BQU8sQ0FBQztRQUNoRCxDQUFDO1FBRUQsSUFDRSxhQUFhLElBQUksS0FBSztZQUN0QixPQUFRLEtBQWtDLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFDbkUsQ0FBQztZQUNELE9BQVEsS0FBaUMsQ0FBQyxXQUFXLENBQUM7UUFDeEQsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN2QixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxVQUFVLGtCQUFrQixDQUNoQyxPQUFnQztJQUVoQyxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQ25FLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vbG9nJztcblxuLyoqXG4gKiBUeXBlIGRlZmluaXRpb24gZm9yIGVycm9yIGNvbnRleHQgb2JqZWN0cyB0aGF0IGNhbiBiZSBwYXNzZWQgdG8gdGhyb3dFcnJvci5cbiAqIFRoaXMgYWxsb3dzIGZvciBzdHJ1Y3R1cmVkIGVycm9yIGluZm9ybWF0aW9uIHdoaWxlIG1haW50YWluaW5nIHR5cGUgc2FmZXR5LlxuICovXG5leHBvcnQgdHlwZSBFcnJvckNvbnRleHQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcblxuLyoqXG4gKiBIZWxwZXIgdG8gcHJvY2VzcyBzdHJpbmcgbWVzc2FnZXMgd2l0aCBvcHRpb25hbCBjb250ZXh0LlxuICovXG5mdW5jdGlvbiBwcm9jZXNzU3RyaW5nTWVzc2FnZShcbiAgbWVzc2FnZTogc3RyaW5nLFxuICBvcmlnaW5hbEVycm9yT3JDb250ZXh0PzogdW5rbm93bixcbik6IHtcbiAgZmluYWxNZXNzYWdlOiBzdHJpbmc7XG4gIG9yaWdpbmFsRXJyb3I6IHVua25vd247XG4gIGVycm9yQ29udGV4dDogRXJyb3JDb250ZXh0O1xufSB7XG4gIGlmIChvcmlnaW5hbEVycm9yT3JDb250ZXh0ID09PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgZmluYWxNZXNzYWdlOiBtZXNzYWdlLFxuICAgICAgb3JpZ2luYWxFcnJvcjogdW5kZWZpbmVkLFxuICAgICAgZXJyb3JDb250ZXh0OiB7fSxcbiAgICB9O1xuICB9XG5cbiAgaWYgKG9yaWdpbmFsRXJyb3JPckNvbnRleHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHJldHVybiB7XG4gICAgICBmaW5hbE1lc3NhZ2U6IGAke21lc3NhZ2V9OiAke29yaWdpbmFsRXJyb3JPckNvbnRleHQubWVzc2FnZX1gLFxuICAgICAgb3JpZ2luYWxFcnJvcjogb3JpZ2luYWxFcnJvck9yQ29udGV4dCxcbiAgICAgIGVycm9yQ29udGV4dDoge1xuICAgICAgICBvcmlnaW5hbEVycm9yOiB7XG4gICAgICAgICAgbmFtZTogb3JpZ2luYWxFcnJvck9yQ29udGV4dC5uYW1lLFxuICAgICAgICAgIG1lc3NhZ2U6IG9yaWdpbmFsRXJyb3JPckNvbnRleHQubWVzc2FnZSxcbiAgICAgICAgICBzdGFjazogb3JpZ2luYWxFcnJvck9yQ29udGV4dC5zdGFjayxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIGlmIChcbiAgICB0eXBlb2Ygb3JpZ2luYWxFcnJvck9yQ29udGV4dCA9PT0gJ29iamVjdCcgJiZcbiAgICBvcmlnaW5hbEVycm9yT3JDb250ZXh0ICE9PSBudWxsXG4gICkge1xuICAgIHJldHVybiB7XG4gICAgICBmaW5hbE1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICBvcmlnaW5hbEVycm9yOiBvcmlnaW5hbEVycm9yT3JDb250ZXh0LFxuICAgICAgZXJyb3JDb250ZXh0OiBvcmlnaW5hbEVycm9yT3JDb250ZXh0IGFzIEVycm9yQ29udGV4dCxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBmaW5hbE1lc3NhZ2U6IGAke21lc3NhZ2V9OiAke1N0cmluZyhvcmlnaW5hbEVycm9yT3JDb250ZXh0KX1gLFxuICAgIG9yaWdpbmFsRXJyb3I6IG9yaWdpbmFsRXJyb3JPckNvbnRleHQsXG4gICAgZXJyb3JDb250ZXh0OiB7IG9yaWdpbmFsRXJyb3I6IG9yaWdpbmFsRXJyb3JPckNvbnRleHQgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBIZWxwZXIgdG8gcHJvY2VzcyBFcnJvciBvYmplY3RzLlxuICovXG5mdW5jdGlvbiBwcm9jZXNzRXJyb3JPYmplY3QoZXJyb3I6IEVycm9yKToge1xuICBmaW5hbE1lc3NhZ2U6IHN0cmluZztcbiAgb3JpZ2luYWxFcnJvcjogRXJyb3I7XG4gIGVycm9yQ29udGV4dDogRXJyb3JDb250ZXh0O1xufSB7XG4gIHJldHVybiB7XG4gICAgZmluYWxNZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgIG9yaWdpbmFsRXJyb3I6IGVycm9yLFxuICAgIGVycm9yQ29udGV4dDoge1xuICAgICAgb3JpZ2luYWxFcnJvcjoge1xuICAgICAgICBuYW1lOiBlcnJvci5uYW1lLFxuICAgICAgICBtZXNzYWdlOiBlcnJvci5tZXNzYWdlLFxuICAgICAgICBzdGFjazogZXJyb3Iuc3RhY2ssXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG59XG5cbi8qKlxuICogSGVscGVyIHRvIHByb2Nlc3MgYXJyYXlzIG9mIGVycm9ycy5cbiAqL1xuZnVuY3Rpb24gcHJvY2Vzc0Vycm9yQXJyYXkoZXJyb3JzOiB1bmtub3duW10pOiB7XG4gIGZpbmFsTWVzc2FnZTogc3RyaW5nO1xuICBvcmlnaW5hbEVycm9yOiB1bmtub3duW107XG4gIGVycm9yQ29udGV4dDogRXJyb3JDb250ZXh0O1xufSB7XG4gIGNvbnN0IGVycm9yTWVzc2FnZXMgPSBlcnJvcnMubWFwKGVyciA9PiB7XG4gICAgaWYgKGVyciBpbnN0YW5jZW9mIEVycm9yKSByZXR1cm4gZXJyLm1lc3NhZ2U7XG4gICAgaWYgKHR5cGVvZiBlcnIgPT09ICdvYmplY3QnICYmIGVyciAhPT0gbnVsbCAmJiAnbWVzc2FnZScgaW4gZXJyKSB7XG4gICAgICByZXR1cm4gU3RyaW5nKChlcnIgYXMgeyBtZXNzYWdlOiB1bmtub3duIH0pLm1lc3NhZ2UpO1xuICAgIH1cbiAgICByZXR1cm4gU3RyaW5nKGVycik7XG4gIH0pO1xuXG4gIGNvbnN0IGZpbmFsTWVzc2FnZSA9XG4gICAgZXJyb3JNZXNzYWdlcy5sZW5ndGggPiAxXG4gICAgICA/IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQ6ICR7ZXJyb3JNZXNzYWdlcy5qb2luKCc7ICcpfWBcbiAgICAgIDogZXJyb3JNZXNzYWdlc1swXSB8fCAnVW5rbm93biBlcnJvciBvY2N1cnJlZCc7XG5cbiAgcmV0dXJuIHtcbiAgICBmaW5hbE1lc3NhZ2UsXG4gICAgb3JpZ2luYWxFcnJvcjogZXJyb3JzLFxuICAgIGVycm9yQ29udGV4dDogeyBlcnJvcnMgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBIZWxwZXIgdG8gcHJvY2VzcyB1bmtub3duIHZhbHVlcy5cbiAqL1xuZnVuY3Rpb24gcHJvY2Vzc1Vua25vd25WYWx1ZSh1bmtub3duRXJyb3I6IHVua25vd24pOiB7XG4gIGZpbmFsTWVzc2FnZTogc3RyaW5nO1xuICBvcmlnaW5hbEVycm9yOiB1bmtub3duO1xuICBlcnJvckNvbnRleHQ6IEVycm9yQ29udGV4dDtcbn0ge1xuICBjb25zdCBlcnJvck9iaiA9IHVua25vd25FcnJvciBhcyB7IG1lc3NhZ2U/OiB1bmtub3duIH07XG5cbiAgaWYgKFxuICAgIHR5cGVvZiBlcnJvck9iaiA9PT0gJ29iamVjdCcgJiZcbiAgICBlcnJvck9iaiAhPT0gbnVsbCAmJlxuICAgICdtZXNzYWdlJyBpbiBlcnJvck9ialxuICApIHtcbiAgICByZXR1cm4ge1xuICAgICAgZmluYWxNZXNzYWdlOiBTdHJpbmcoZXJyb3JPYmoubWVzc2FnZSksXG4gICAgICBvcmlnaW5hbEVycm9yOiB1bmtub3duRXJyb3IsXG4gICAgICBlcnJvckNvbnRleHQ6IHsgb3JpZ2luYWxFcnJvcjogdW5rbm93bkVycm9yIH0sXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgZmluYWxNZXNzYWdlOiBgVW5leHBlY3RlZCBlcnJvcjogJHtTdHJpbmcodW5rbm93bkVycm9yKX1gLFxuICAgIG9yaWdpbmFsRXJyb3I6IHVua25vd25FcnJvcixcbiAgICBlcnJvckNvbnRleHQ6IHsgb3JpZ2luYWxFcnJvcjogdW5rbm93bkVycm9yIH0sXG4gIH07XG59XG5cbi8qKlxuICogSGVscGVyIHRvIGNyZWF0ZSBhbmQgY29uZmlndXJlIHRoZSBlcnJvciBvYmplY3QgdXNpbmcgRVMyMDIyIHN0YW5kYXJkcy5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlRXJyb3JPYmplY3QoXG4gIGZpbmFsTWVzc2FnZTogc3RyaW5nLFxuICBvcmlnaW5hbEVycm9yOiB1bmtub3duLFxuICBlcnJvckNvbnRleHQ6IEVycm9yQ29udGV4dCxcbik6IEVycm9yIHtcbiAgbGV0IGVycm9yOiBFcnJvcjtcblxuICAvLyBVc2UgbW9kZXJuIEVycm9yIGNvbnN0cnVjdG9yIHdpdGggY2F1c2UgKEVTMjAyMiBzdGFuZGFyZCkgd2hlbiBvcmlnaW5hbEVycm9yIGV4aXN0c1xuICBpZiAob3JpZ2luYWxFcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIE1vZGVybiBhcHByb2FjaCAtIHN1cHBvcnRlZCBpbiBOb2RlLmpzIDE2LjkrIGFuZCBtb2Rlcm4gYnJvd3NlcnNcbiAgICAgIGVycm9yID0gbmV3IEVycm9yKGZpbmFsTWVzc2FnZSwgeyBjYXVzZTogb3JpZ2luYWxFcnJvciB9KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIEZhbGxiYWNrIGZvciBvbGRlciBlbnZpcm9ubWVudHMgdGhhdCBkb24ndCBzdXBwb3J0IGNhdXNlIHBhcmFtZXRlclxuICAgICAgZXJyb3IgPSBuZXcgRXJyb3IoZmluYWxNZXNzYWdlKTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlcnJvciwgJ2NhdXNlJywge1xuICAgICAgICB2YWx1ZTogb3JpZ2luYWxFcnJvcixcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBCYWNrd2FyZCBjb21wYXRpYmlsaXR5OiBhbHNvIHNldCBvcmlnaW5hbEVycm9yIHByb3BlcnR5XG4gICAgaWYgKCEoJ29yaWdpbmFsRXJyb3InIGluIGVycm9yKSkge1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGVycm9yLCAnb3JpZ2luYWxFcnJvcicsIHtcbiAgICAgICAgdmFsdWU6IG9yaWdpbmFsRXJyb3IsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGVycm9yID0gbmV3IEVycm9yKGZpbmFsTWVzc2FnZSk7XG4gIH1cblxuICAvLyBFbmhhbmNlZCBzdGFjayB0cmFjZSBjaGFpbmluZyBmb3IgYmV0dGVyIGRlYnVnZ2luZ1xuICBpZiAob3JpZ2luYWxFcnJvciBpbnN0YW5jZW9mIEVycm9yICYmIG9yaWdpbmFsRXJyb3Iuc3RhY2spIHtcbiAgICBlcnJvci5zdGFjayA9IGAke2Vycm9yLnN0YWNrfVxcblxcbkNhdXNlZCBieTogJHtvcmlnaW5hbEVycm9yLnN0YWNrfWA7XG4gIH1cblxuICAvLyBBbHdheXMgYWRkIGEgbWFya2VyIHRvIGlkZW50aWZ5IGVycm9ycyBmcm9tIG91ciBsaWJyYXJ5XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShlcnJvciwgJ19fZnJvbUVycm9yTGlicmFyeScsIHtcbiAgICB2YWx1ZTogdHJ1ZSxcbiAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgfSk7XG5cbiAgLy8gQXNzaWduIGNvbnRleHQgcHJvcGVydGllcyBhcyBub24tZW51bWVyYWJsZSBwcm9wZXJ0aWVzXG4gIGlmIChlcnJvckNvbnRleHQgJiYgdHlwZW9mIGVycm9yQ29udGV4dCA9PT0gJ29iamVjdCcpIHtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhlcnJvckNvbnRleHQpKSB7XG4gICAgICAvLyBTa2lwIHN5c3RlbSBwcm9wZXJ0aWVzIHRoYXQgYXJlIGFscmVhZHkgaGFuZGxlZFxuICAgICAgaWYgKFxuICAgICAgICAhWydvcmlnaW5hbEVycm9yJywgJ2NhdXNlJywgJ3N0YWNrJywgJ19fZnJvbUVycm9yTGlicmFyeSddLmluY2x1ZGVzKGtleSlcbiAgICAgICkge1xuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZXJyb3IsIGtleSwge1xuICAgICAgICAgIHZhbHVlLFxuICAgICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGVycm9yO1xufVxuXG4vKipcbiAqIEVuaGFuY2VkIGVycm9yIHRocm93aW5nIGZ1bmN0aW9uIHRoYXQgZW5zdXJlcyBjb25zaXN0ZW50IGVycm9yIGhhbmRsaW5nIGFuZCBsb2dnaW5nXG4gKiBhY3Jvc3MgdGhlIGFwcGxpY2F0aW9uLiBJdCBhdXRvbWF0aWNhbGx5IGxvZ3MgZXJyb3JzIHdpdGggc3RydWN0dXJlZCBkYXRhIGFuZCBjcmVhdGVzXG4gKiBwcm9wZXJseSBmb3JtYXR0ZWQgRXJyb3Igb2JqZWN0cyB3aXRoIGFkZGl0aW9uYWwgY29udGV4dC5cbiAqXG4gKiBAcGFyYW0gbWVzc2FnZU9yRXJyb3IgLSBUaGUgcHJpbWFyeSBlcnJvciBtZXNzYWdlIChzdHJpbmcpIG9yIEVycm9yIG9iamVjdCB0byB0aHJvd1xuICogQHBhcmFtIG9yaWdpbmFsRXJyb3JPckNvbnRleHQgLSBPcHRpb25hbDogb3JpZ2luYWwgZXJyb3Igb2JqZWN0IG9yIGFkZGl0aW9uYWwgY29udGV4dFxuICogQHRocm93cyB7RXJyb3J9IEFsd2F5cyB0aHJvd3MgYSBwcm9wZXJseSBmb3JtYXR0ZWQgRXJyb3Igd2l0aCBlbmhhbmNlZCBjb250ZXh0XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFNpbXBsZSBtZXNzYWdlXG4gKiB0aHJvd0Vycm9yKCdEYXRhYmFzZSBjb25uZWN0aW9uIGZhaWxlZCcpO1xuICpcbiAqIC8vIE1lc3NhZ2Ugd2l0aCBjb250ZXh0XG4gKiB0aHJvd0Vycm9yKCdVc2VyIG5vdCBmb3VuZCcsIHsgdXNlcklkOiAnMTIzJywgb3BlcmF0aW9uOiAnZ2V0VXNlcicgfSk7XG4gKlxuICogLy8gTWVzc2FnZSB3aXRoIG9yaWdpbmFsIGVycm9yXG4gKiB0aHJvd0Vycm9yKCdGYWlsZWQgdG8gcHJvY2VzcyByZXF1ZXN0Jywgb3JpZ2luYWxFcnJvcik7XG4gKlxuICogLy8gRXJyb3Igb2JqZWN0ICh3aWxsIGV4dHJhY3QgbWVzc2FnZSlcbiAqIHRocm93RXJyb3IobmV3IEVycm9yKCdTb21ldGhpbmcgd2VudCB3cm9uZycpKTtcbiAqXG4gKiAvLyBBcnJheSBvZiBlcnJvcnMgKHdpbGwgY29tYmluZSBtZXNzYWdlcylcbiAqIHRocm93RXJyb3IoW2Vycm9yMSwgZXJyb3IyLCAnQWRkaXRpb25hbCBpbmZvJ10pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB0aHJvd0Vycm9yKFxuICBtZXNzYWdlT3JFcnJvcjogc3RyaW5nIHwgRXJyb3IgfCB1bmtub3duW10sXG4gIG9yaWdpbmFsRXJyb3JPckNvbnRleHQ/OiB1bmtub3duLFxuKTogbmV2ZXIge1xuICBsZXQgcmVzdWx0OiB7XG4gICAgZmluYWxNZXNzYWdlOiBzdHJpbmc7XG4gICAgb3JpZ2luYWxFcnJvcjogdW5rbm93bjtcbiAgICBlcnJvckNvbnRleHQ6IEVycm9yQ29udGV4dDtcbiAgfTtcblxuICBpZiAodHlwZW9mIG1lc3NhZ2VPckVycm9yID09PSAnc3RyaW5nJykge1xuICAgIHJlc3VsdCA9IHByb2Nlc3NTdHJpbmdNZXNzYWdlKG1lc3NhZ2VPckVycm9yLCBvcmlnaW5hbEVycm9yT3JDb250ZXh0KTtcbiAgfSBlbHNlIGlmIChtZXNzYWdlT3JFcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgcmVzdWx0ID0gcHJvY2Vzc0Vycm9yT2JqZWN0KG1lc3NhZ2VPckVycm9yKTtcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG1lc3NhZ2VPckVycm9yKSkge1xuICAgIHJlc3VsdCA9IHByb2Nlc3NFcnJvckFycmF5KG1lc3NhZ2VPckVycm9yKTtcbiAgfSBlbHNlIHtcbiAgICByZXN1bHQgPSBwcm9jZXNzVW5rbm93blZhbHVlKG1lc3NhZ2VPckVycm9yKTtcbiAgfVxuXG4gIGNvbnN0IHsgZmluYWxNZXNzYWdlLCBvcmlnaW5hbEVycm9yLCBlcnJvckNvbnRleHQgfSA9IHJlc3VsdDtcblxuICAvLyBFbmhhbmNlZCBsb2dnaW5nIHdpdGggc3RydWN0dXJlZCBkYXRhIChDbG91ZFdhdGNoIGhhbmRsZXMgdGltZXN0YW1wcylcbiAgbG9nZ2VyLmVycm9yKGZpbmFsTWVzc2FnZSwge1xuICAgIC4uLmVycm9yQ29udGV4dCxcbiAgICBlcnJvclR5cGU6IHR5cGVvZiBvcmlnaW5hbEVycm9yLFxuICAgIHN0YWNrOiBuZXcgRXJyb3IoKS5zdGFjaywgLy8gQ2FwdHVyZSBjdXJyZW50IHN0YWNrIHRyYWNlIGZvciBkZWJ1Z2dpbmdcbiAgfSk7XG5cbiAgLy8gQ3JlYXRlIGFuZCB0aHJvdyB0aGUgZXJyb3JcbiAgY29uc3QgZXJyb3IgPSBjcmVhdGVFcnJvck9iamVjdChmaW5hbE1lc3NhZ2UsIG9yaWdpbmFsRXJyb3IsIGVycm9yQ29udGV4dCk7XG4gIHRocm93IGVycm9yO1xufVxuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gc2FmZWx5IGV4dHJhY3QgYW4gZXJyb3IgbWVzc2FnZSBmcm9tIGFuIHVua25vd24gZXJyb3IgdHlwZS5cbiAqIEl0IGhhbmRsZXMgdmFyaW91cyB0eXBlcyBvZiBlcnJvciBvYmplY3RzLCBzdHJpbmdzLCBhbmQgb3RoZXIgdmFsdWVzIHRvIHByb2R1Y2UgYSBjb25zaXN0ZW50XG4gKiBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGVycm9yLCB3aGljaCBpcyB1c2VmdWwgZm9yIGRpc3BsYXlpbmcgZXJyb3IgbWVzc2FnZXMgdG8gdXNlcnMuXG4gKlxuICogQHBhcmFtIGVycm9yIC0gVGhlIGVycm9yIGZyb20gd2hpY2ggdG8gZXh0cmFjdCB0aGUgbWVzc2FnZS4gSXQgY2FuIGJlIG9mIGFueSB0eXBlLlxuICogQHJldHVybnMgQSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBlcnJvciBtZXNzYWdlLlxuICogQGV4YW1wbGVcbiAqIHRyeSB7XG4gKiAgIC8vIHNvbWUgb3BlcmF0aW9uXG4gKiB9IGNhdGNoIChlcnJvcikge1xuICogICBjb25zdCBtZXNzYWdlID0gZXh0cmFjdEVycm9yTWVzc2FnZShlcnJvcik7XG4gKiAgIGNvbnNvbGUubG9nKCdFcnJvciBvY2N1cnJlZDonLCBtZXNzYWdlKTtcbiAqIH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RFcnJvck1lc3NhZ2UoZXJyb3I6IHVua25vd24pOiBzdHJpbmcge1xuICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgIHJldHVybiBlcnJvci5tZXNzYWdlO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBlcnJvciA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZXJyb3I7XG4gIH1cblxuICBpZiAoQXJyYXkuaXNBcnJheShlcnJvcikpIHtcbiAgICBpZiAoZXJyb3IubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgLy8gUmVjdXJzaXZlbHkgZmxhdHRlbiBhbmQgZXh0cmFjdCBtZXNzYWdlcyBmcm9tIGFycmF5c1xuICAgIGNvbnN0IG1lc3NhZ2VzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgZnVuY3Rpb24gZmxhdHRlbkFuZEV4dHJhY3QoaXRlbTogdW5rbm93bik6IHZvaWQge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoaXRlbSkpIHtcbiAgICAgICAgaXRlbS5mb3JFYWNoKGZsYXR0ZW5BbmRFeHRyYWN0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBleHRyYWN0RXJyb3JNZXNzYWdlKGl0ZW0pO1xuICAgICAgICBpZiAobWVzc2FnZSkge1xuICAgICAgICAgIG1lc3NhZ2VzLnB1c2gobWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBlcnJvci5mb3JFYWNoKGZsYXR0ZW5BbmRFeHRyYWN0KTtcbiAgICByZXR1cm4gbWVzc2FnZXMuam9pbignOyAnKTtcbiAgfVxuXG4gIGlmICh0eXBlb2YgZXJyb3IgPT09ICdvYmplY3QnICYmIGVycm9yICE9PSBudWxsKSB7XG4gICAgaWYgKFxuICAgICAgJ21lc3NhZ2UnIGluIGVycm9yICYmXG4gICAgICB0eXBlb2YgKGVycm9yIGFzIHsgbWVzc2FnZTogdW5rbm93biB9KS5tZXNzYWdlID09PSAnc3RyaW5nJ1xuICAgICkge1xuICAgICAgcmV0dXJuIChlcnJvciBhcyB7IG1lc3NhZ2U6IHN0cmluZyB9KS5tZXNzYWdlO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgICdlcnJvcicgaW4gZXJyb3IgJiZcbiAgICAgIHR5cGVvZiAoZXJyb3IgYXMgeyBlcnJvcjogdW5rbm93biB9KS5lcnJvciA9PT0gJ3N0cmluZydcbiAgICApIHtcbiAgICAgIHJldHVybiAoZXJyb3IgYXMgeyBlcnJvcjogc3RyaW5nIH0pLmVycm9yO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgICdkZXRhaWxzJyBpbiBlcnJvciAmJlxuICAgICAgdHlwZW9mIChlcnJvciBhcyB7IGRldGFpbHM6IHVua25vd24gfSkuZGV0YWlscyA9PT0gJ3N0cmluZydcbiAgICApIHtcbiAgICAgIHJldHVybiAoZXJyb3IgYXMgeyBkZXRhaWxzOiBzdHJpbmcgfSkuZGV0YWlscztcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICAnZGVzY3JpcHRpb24nIGluIGVycm9yICYmXG4gICAgICB0eXBlb2YgKGVycm9yIGFzIHsgZGVzY3JpcHRpb246IHVua25vd24gfSkuZGVzY3JpcHRpb24gPT09ICdzdHJpbmcnXG4gICAgKSB7XG4gICAgICByZXR1cm4gKGVycm9yIGFzIHsgZGVzY3JpcHRpb246IHN0cmluZyB9KS5kZXNjcmlwdGlvbjtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gU3RyaW5nKGVycm9yKTtcbn1cblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIGNyZWF0ZSBlcnJvciBjb250ZXh0IG9iamVjdHMgd2l0aCBwcm9wZXIgZmlsdGVyaW5nLlxuICogVGhpcyBlbnN1cmVzIGNvbnNpc3RlbnQgY29udGV4dCBzdHJ1Y3R1cmUgd2hpbGUgcmVtb3ZpbmcgdW5kZWZpbmVkIHZhbHVlc1xuICogdGhhdCBjb3VsZCBjbHV0dGVyIGxvZ3Mgb3IgY2F1c2Ugc2VyaWFsaXphdGlvbiBpc3N1ZXMuXG4gKlxuICogQHBhcmFtIGNvbnRleHQgLSBSYXcgY29udGV4dCBvYmplY3QgdGhhdCBtYXkgY29udGFpbiB1bmRlZmluZWQgdmFsdWVzXG4gKiBAcmV0dXJucyBGaWx0ZXJlZCBjb250ZXh0IG9iamVjdCB3aXRoIHVuZGVmaW5lZCB2YWx1ZXMgcmVtb3ZlZFxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGNvbnRleHQgPSBjcmVhdGVFcnJvckNvbnRleHQoe1xuICogICB1c2VySWQ6IHVzZXI/LmlkLCAgICAgICAgLy8gbWlnaHQgYmUgdW5kZWZpbmVkXG4gKiAgIG9wZXJhdGlvbjogJ2RlbGV0ZVVzZXInLCAvLyBhbHdheXMgZGVmaW5lZFxuICogICByZXF1ZXN0SWQ6IHJlcS5pZCAgICAgICAgLy8gYWx3YXlzIGRlZmluZWRcbiAqIH0pO1xuICogLy8gUmVzdWx0OiB7IG9wZXJhdGlvbjogJ2RlbGV0ZVVzZXInLCByZXF1ZXN0SWQ6ICdhYmMxMjMnIH1cbiAqIC8vICh1c2VySWQgb21pdHRlZCBiZWNhdXNlIGl0IHdhcyB1bmRlZmluZWQpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFcnJvckNvbnRleHQoXG4gIGNvbnRleHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgIE9iamVjdC5lbnRyaWVzKGNvbnRleHQpLmZpbHRlcigoWywgdmFsdWVdKSA9PiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSxcbiAgKTtcbn1cbiJdfQ==