UNPKG

@energica-city/shared-amplify-utils

Version:

Shared utilities for AWS Amplify projects

186 lines 25.3 kB
import { logger } from '../../log'; import * as yup from 'yup'; import { buildRestContext, parseJsonBody, createValidationError, getRequestId, } from './utils'; /** Symbol key for storing validated request body data */ const VALIDATED_BODY_KEY = Symbol('validatedBody'); /** Symbol key for storing validated query parameters */ const VALIDATED_QUERY_KEY = Symbol('validatedQuery'); /** Symbol key for storing validated path parameters */ const VALIDATED_PATH_KEY = Symbol('validatedPath'); /** Symbol key for storing validated headers */ const VALIDATED_HEADERS_KEY = Symbol('validatedHeaders'); export { VALIDATED_BODY_KEY, VALIDATED_QUERY_KEY, VALIDATED_PATH_KEY, VALIDATED_HEADERS_KEY, }; /** * Retrieves validated request body from middleware chain * @param input - REST input with validation data storage * @returns Validated and typed request body * * @example * ```typescript * const userData = getValidatedBody<UserCreateInput>(input); * console.log(userData.name); // Type-safe access * ``` */ export function getValidatedBody(input) { const validatedData = input.event; return validatedData[VALIDATED_BODY_KEY]; } /** * Retrieves validated query parameters from middleware chain * @param input - REST input with validation data storage * @returns Validated and typed query parameters * * @example * ```typescript * const queryParams = getValidatedQuery<{ page: number; limit: number }>(input); * ``` */ export function getValidatedQuery(input) { const validatedData = input.event; return validatedData[VALIDATED_QUERY_KEY]; } /** * Retrieves validated path parameters from middleware chain * @param input - REST input with validation data storage * @returns Validated and typed path parameters */ export function getValidatedPath(input) { const validatedData = input.event; return validatedData[VALIDATED_PATH_KEY]; } /** * Retrieves validated headers from middleware chain * @param input - REST input with validation data storage * @returns Validated and typed headers */ export function getValidatedHeaders(input) { const validatedData = input.event; return validatedData[VALIDATED_HEADERS_KEY]; } /** * Stores validated data in the event object using symbol keys * @param input - REST input with validation data storage * @param key - Symbol key for data storage * @param data - Validated data to store */ function storeValidatedData(input, key, data) { const validatedData = input.event; validatedData[key] = data; } /** * Validates data against a Yup schema with standardized error handling * @param schema - Yup validation schema * @param data - Data to validate * @param fieldName - Name of the field being validated (for error messages) * @param input - REST input for error context * @returns Validated data conforming to schema type * @throws ValidationError with REST context if validation fails */ async function validateSchema(schema, data, fieldName, input) { try { return await schema.validate(data, { abortEarly: false }); } catch (error) { if (error instanceof yup.ValidationError) { throw createValidationError({ message: `Validation failed for ${fieldName}: ${error.errors.join(', ')}`, event: input.event, errorCode: 'VALIDATION_ERROR', statusCode: 400, additionalContext: { field: fieldName, errors: error.errors, }, }); } throw error; } } /** * Creates REST request validator middleware with parallel validation * * Validates request components (body, query, path, headers) in parallel for optimal performance. * Stores validated data using symbol keys for type-safe retrieval in handlers. * * @param validationConfig - Configuration specifying which parts to validate * @returns Middleware function that validates requests and stores results * * @example * ```typescript * const validator = createRestRequestValidator({ * body: yup.object({ * name: yup.string().required(), * email: yup.string().email().required() * }), * headers: yup.object({ * authorization: yup.string().required() * }) * }); * * chain.use('validator', validator); * ``` */ export function createRestRequestValidator(validationConfig) { const { body: bodySchema, query: querySchema, path: pathSchema, headers: headersSchema, } = validationConfig; return async (input, next) => { const typedInput = input; const { event } = typedInput; const requestId = getRequestId(event, input.context); const logContext = buildRestContext(typedInput, { requestId, }); const validationTasks = []; if (bodySchema) { const bodyValidation = (async () => { const body = parseJsonBody(event.body ?? undefined, logContext); const validatedBody = await validateSchema(bodySchema, body, 'body', typedInput); storeValidatedData(typedInput, VALIDATED_BODY_KEY, validatedBody); })(); validationTasks.push(bodyValidation); } if (querySchema) { const queryValidation = (async () => { const validatedQuery = await validateSchema(querySchema, event.queryStringParameters || {}, 'query', typedInput); storeValidatedData(typedInput, VALIDATED_QUERY_KEY, validatedQuery); })(); validationTasks.push(queryValidation); } if (pathSchema) { const pathValidation = (async () => { const validatedPath = await validateSchema(pathSchema, event.pathParameters || {}, 'path', typedInput); storeValidatedData(typedInput, VALIDATED_PATH_KEY, validatedPath); })(); validationTasks.push(pathValidation); } if (headersSchema) { const headersValidation = (async () => { const validatedHeaders = await validateSchema(headersSchema, event.headers || {}, 'headers', typedInput); storeValidatedData(typedInput, VALIDATED_HEADERS_KEY, validatedHeaders); })(); validationTasks.push(headersValidation); } if (validationTasks.length > 0) { try { await Promise.all(validationTasks); logger.debug('Request validation completed', buildRestContext(typedInput, { requestId, validatedFields: [ bodySchema ? 'body' : null, querySchema ? 'query' : null, pathSchema ? 'path' : null, headersSchema ? 'headers' : null, ].filter(Boolean), })); } catch (error) { logger.error('Request validation failed', buildRestContext(typedInput, { requestId, error: error instanceof Error ? error.message : 'Unknown error', })); throw error; } } return next(typedInput); }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVzdFJlcXVlc3RWYWxpZGF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9taWRkbGV3YXJlL3Jlc3QvUmVzdFJlcXVlc3RWYWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNuQyxPQUFPLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQztBQVUzQixPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLGFBQWEsRUFDYixxQkFBcUIsRUFDckIsWUFBWSxHQUNiLE1BQU0sU0FBUyxDQUFDO0FBRWpCLHlEQUF5RDtBQUN6RCxNQUFNLGtCQUFrQixHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztBQUNuRCx3REFBd0Q7QUFDeEQsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUNyRCx1REFBdUQ7QUFDdkQsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7QUFDbkQsK0NBQStDO0FBQy9DLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFFekQsT0FBTyxFQUNMLGtCQUFrQixFQUNsQixtQkFBbUIsRUFDbkIsa0JBQWtCLEVBQ2xCLHFCQUFxQixHQUN0QixDQUFDO0FBRUY7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FNOUIsS0FBc0M7SUFDdEMsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLEtBQTZCLENBQUM7SUFDMUQsT0FBTyxhQUFhLENBQUMsa0JBQWtCLENBQU0sQ0FBQztBQUNoRCxDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQU0vQixLQUFzQztJQUN0QyxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsS0FBNkIsQ0FBQztJQUMxRCxPQUFPLGFBQWEsQ0FBQyxtQkFBbUIsQ0FBTSxDQUFDO0FB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bmltcG9ydCAqIGFzIHl1cCBmcm9tICd5dXAnO1xuaW1wb3J0IHR5cGUgeyBNaWRkbGV3YXJlIH0gZnJvbSAnLi4vbWlkZGxld2FyZUNoYWluJztcbmltcG9ydCB0eXBlIHtcbiAgUmVzdFJlc3BvbnNlLFxuICBSZXN0SW5wdXRXaXRoTW9kZWxzLFxuICBSZXN0SW5wdXRXaXRoVmFsaWRhdGlvbixcbiAgUmVzdFJlcXVlc3RWYWxpZGF0aW9uQ29uZmlnLFxuICBWYWxpZGF0ZWREYXRhU3RvcmFnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgdHlwZSB7IEFtcGxpZnlNb2RlbFR5cGUgfSBmcm9tICcuLi8uLi9xdWVyaWVzL3R5cGVzJztcbmltcG9ydCB7XG4gIGJ1aWxkUmVzdENvbnRleHQsXG4gIHBhcnNlSnNvbkJvZHksXG4gIGNyZWF0ZVZhbGlkYXRpb25FcnJvcixcbiAgZ2V0UmVxdWVzdElkLFxufSBmcm9tICcuL3V0aWxzJztcblxuLyoqIFN5bWJvbCBrZXkgZm9yIHN0b3JpbmcgdmFsaWRhdGVkIHJlcXVlc3QgYm9keSBkYXRhICovXG5jb25zdCBWQUxJREFURURfQk9EWV9LRVkgPSBTeW1ib2woJ3ZhbGlkYXRlZEJvZHknKTtcbi8qKiBTeW1ib2wga2V5IGZvciBzdG9yaW5nIHZhbGlkYXRlZCBxdWVyeSBwYXJhbWV0ZXJzICovXG5jb25zdCBWQUxJREFURURfUVVFUllfS0VZID0gU3ltYm9sKCd2YWxpZGF0ZWRRdWVyeScpO1xuLyoqIFN5bWJvbCBrZXkgZm9yIHN0b3JpbmcgdmFsaWRhdGVkIHBhdGggcGFyYW1ldGVycyAqL1xuY29uc3QgVkFMSURBVEVEX1BBVEhfS0VZID0gU3ltYm9sKCd2YWxpZGF0ZWRQYXRoJyk7XG4vKiogU3ltYm9sIGtleSBmb3Igc3RvcmluZyB2YWxpZGF0ZWQgaGVhZGVycyAqL1xuY29uc3QgVkFMSURBVEVEX0hFQURFUlNfS0VZID0gU3ltYm9sKCd2YWxpZGF0ZWRIZWFkZXJzJyk7XG5cbmV4cG9ydCB7XG4gIFZBTElEQVRFRF9CT0RZX0tFWSxcbiAgVkFMSURBVEVEX1FVRVJZX0tFWSxcbiAgVkFMSURBVEVEX1BBVEhfS0VZLFxuICBWQUxJREFURURfSEVBREVSU19LRVksXG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyB2YWxpZGF0ZWQgcmVxdWVzdCBib2R5IGZyb20gbWlkZGxld2FyZSBjaGFpblxuICogQHBhcmFtIGlucHV0IC0gUkVTVCBpbnB1dCB3aXRoIHZhbGlkYXRpb24gZGF0YSBzdG9yYWdlXG4gKiBAcmV0dXJucyBWYWxpZGF0ZWQgYW5kIHR5cGVkIHJlcXVlc3QgYm9keVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB1c2VyRGF0YSA9IGdldFZhbGlkYXRlZEJvZHk8VXNlckNyZWF0ZUlucHV0PihpbnB1dCk7XG4gKiBjb25zb2xlLmxvZyh1c2VyRGF0YS5uYW1lKTsgLy8gVHlwZS1zYWZlIGFjY2Vzc1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRWYWxpZGF0ZWRCb2R5PFxuICBUID0gdW5rbm93bixcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbj4oaW5wdXQ6IFJlc3RJbnB1dFdpdGhWYWxpZGF0aW9uPFRUeXBlcz4pOiBUIHtcbiAgY29uc3QgdmFsaWRhdGVkRGF0YSA9IGlucHV0LmV2ZW50IGFzIFZhbGlkYXRlZERhdGFTdG9yYWdlO1xuICByZXR1cm4gdmFsaWRhdGVkRGF0YVtWQUxJREFURURfQk9EWV9LRVldIGFzIFQ7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHZhbGlkYXRlZCBxdWVyeSBwYXJhbWV0ZXJzIGZyb20gbWlkZGxld2FyZSBjaGFpblxuICogQHBhcmFtIGlucHV0IC0gUkVTVCBpbnB1dCB3aXRoIHZhbGlkYXRpb24gZGF0YSBzdG9yYWdlXG4gKiBAcmV0dXJucyBWYWxpZGF0ZWQgYW5kIHR5cGVkIHF1ZXJ5IHBhcmFtZXRlcnNcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgcXVlcnlQYXJhbXMgPSBnZXRWYWxpZGF0ZWRRdWVyeTx7IHBhZ2U6IG51bWJlcjsgbGltaXQ6IG51bWJlciB9PihpbnB1dCk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbGlkYXRlZFF1ZXJ5PFxuICBUID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gIFRUeXBlcyBleHRlbmRzIFJlY29yZDxzdHJpbmcsIEFtcGxpZnlNb2RlbFR5cGU+ID0gUmVjb3JkPFxuICAgIHN0cmluZyxcbiAgICBBbXBsaWZ5TW9kZWxUeXBlXG4gID4sXG4+KGlucHV0OiBSZXN0SW5wdXRXaXRoVmFsaWRhdGlvbjxUVHlwZXM+KTogVCB7XG4gIGNvbnN0IHZhbGlkYXRlZERhdGEgPSBpbnB1dC5ldmVudCBhcyBWYWxpZGF0ZWREYXRhU3RvcmFnZTtcbiAgcmV0dXJuIHZhbGlkYXRlZERhdGFbVkFMSURBVEVEX1FVRVJZX0tFWV0gYXMgVDtcbn1cblxuLyoqXG4gKiBSZXRyaWV2ZXMgdmFsaWRhdGVkIHBhdGggcGFyYW1ldGVycyBmcm9tIG1pZGRsZXdhcmUgY2hhaW5cbiAqIEBwYXJhbSBpbnB1dCAtIFJFU1QgaW5wdXQgd2l0aCB2YWxpZGF0aW9uIGRhdGEgc3RvcmFnZVxuICogQHJldHVybnMgVmFsaWRhdGVkIGFuZCB0eXBlZCBwYXRoIHBhcmFtZXRlcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbGlkYXRlZFBhdGg8XG4gIFQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbj4oaW5wdXQ6IFJlc3RJbnB1dFdpdGhWYWxpZGF0aW9uPFRUeXBlcz4pOiBUIHtcbiAgY29uc3QgdmFsaWRhdGVkRGF0YSA9IGlucHV0LmV2ZW50IGFzIFZhbGlkYXRlZERhdGFTdG9yYWdlO1xuICByZXR1cm4gdmFsaWRhdGVkRGF0YVtWQUxJREFURURfUEFUSF9LRVldIGFzIFQ7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHZhbGlkYXRlZCBoZWFkZXJzIGZyb20gbWlkZGxld2FyZSBjaGFpblxuICogQHBhcmFtIGlucHV0IC0gUkVTVCBpbnB1dCB3aXRoIHZhbGlkYXRpb24gZGF0YSBzdG9yYWdlXG4gKiBAcmV0dXJucyBWYWxpZGF0ZWQgYW5kIHR5cGVkIGhlYWRlcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbGlkYXRlZEhlYWRlcnM8XG4gIFQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbj4oaW5wdXQ6IFJlc3RJbnB1dFdpdGhWYWxpZGF0aW9uPFRUeXBlcz4pOiBUIHtcbiAgY29uc3QgdmFsaWRhdGVkRGF0YSA9IGlucHV0LmV2ZW50IGFzIFZhbGlkYXRlZERhdGFTdG9yYWdlO1xuICByZXR1cm4gdmFsaWRhdGVkRGF0YVtWQUxJREFURURfSEVBREVSU19LRVldIGFzIFQ7XG59XG5cbi8qKlxuICogU3RvcmVzIHZhbGlkYXRlZCBkYXRhIGluIHRoZSBldmVudCBvYmplY3QgdXNpbmcgc3ltYm9sIGtleXNcbiAqIEBwYXJhbSBpbnB1dCAtIFJFU1QgaW5wdXQgd2l0aCB2YWxpZGF0aW9uIGRhdGEgc3RvcmFnZVxuICogQHBhcmFtIGtleSAtIFN5bWJvbCBrZXkgZm9yIGRhdGEgc3RvcmFnZVxuICogQHBhcmFtIGRhdGEgLSBWYWxpZGF0ZWQgZGF0YSB0byBzdG9yZVxuICovXG5mdW5jdGlvbiBzdG9yZVZhbGlkYXRlZERhdGE8XG4gIFRUeXBlcyBleHRlbmRzIFJlY29yZDxzdHJpbmcsIEFtcGxpZnlNb2RlbFR5cGU+ID0gUmVjb3JkPFxuICAgIHN0cmluZyxcbiAgICBBbXBsaWZ5TW9kZWxUeXBlXG4gID4sXG4+KGlucHV0OiBSZXN0SW5wdXRXaXRoVmFsaWRhdGlvbjxUVHlwZXM+LCBrZXk6IHN5bWJvbCwgZGF0YTogdW5rbm93bik6IHZvaWQge1xuICBjb25zdCB2YWxpZGF0ZWREYXRhID0gaW5wdXQuZXZlbnQgYXMgVmFsaWRhdGVkRGF0YVN0b3JhZ2U7XG4gIHZhbGlkYXRlZERhdGFba2V5XSA9IGRhdGE7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIGRhdGEgYWdhaW5zdCBhIFl1cCBzY2hlbWEgd2l0aCBzdGFuZGFyZGl6ZWQgZXJyb3IgaGFuZGxpbmdcbiAqIEBwYXJhbSBzY2hlbWEgLSBZdXAgdmFsaWRhdGlvbiBzY2hlbWFcbiAqIEBwYXJhbSBkYXRhIC0gRGF0YSB0byB2YWxpZGF0ZVxuICogQHBhcmFtIGZpZWxkTmFtZSAtIE5hbWUgb2YgdGhlIGZpZWxkIGJlaW5nIHZhbGlkYXRlZCAoZm9yIGVycm9yIG1lc3NhZ2VzKVxuICogQHBhcmFtIGlucHV0IC0gUkVTVCBpbnB1dCBmb3IgZXJyb3IgY29udGV4dFxuICogQHJldHVybnMgVmFsaWRhdGVkIGRhdGEgY29uZm9ybWluZyB0byBzY2hlbWEgdHlwZVxuICogQHRocm93cyBWYWxpZGF0aW9uRXJyb3Igd2l0aCBSRVNUIGNvbnRleHQgaWYgdmFsaWRhdGlvbiBmYWlsc1xuICovXG5hc3luYyBmdW5jdGlvbiB2YWxpZGF0ZVNjaGVtYTxcbiAgVCxcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbj4oXG4gIHNjaGVtYTogeXVwLlNjaGVtYTxUPixcbiAgZGF0YTogdW5rbm93bixcbiAgZmllbGROYW1lOiBzdHJpbmcsXG4gIGlucHV0OiBSZXN0SW5wdXRXaXRoVmFsaWRhdGlvbjxUVHlwZXM+LFxuKTogUHJvbWlzZTxUPiB7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IHNjaGVtYS52YWxpZGF0ZShkYXRhLCB7IGFib3J0RWFybHk6IGZhbHNlIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIHl1cC5WYWxpZGF0aW9uRXJyb3IpIHtcbiAgICAgIHRocm93IGNyZWF0ZVZhbGlkYXRpb25FcnJvcih7XG4gICAgICAgIG1lc3NhZ2U6IGBWYWxpZGF0aW9uIGZhaWxlZCBmb3IgJHtmaWVsZE5hbWV9OiAke2Vycm9yLmVycm9ycy5qb2luKCcsICcpfWAsXG4gICAgICAgIGV2ZW50OiBpbnB1dC5ldmVudCxcbiAgICAgICAgZXJyb3JDb2RlOiAnVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHN0YXR1c0NvZGU6IDQwMCxcbiAgICAgICAgYWRkaXRpb25hbENvbnRleHQ6IHtcbiAgICAgICAgICBmaWVsZDogZmllbGROYW1lLFxuICAgICAgICAgIGVycm9yczogZXJyb3IuZXJyb3JzLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfVxuICAgIHRocm93IGVycm9yO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBSRVNUIHJlcXVlc3QgdmFsaWRhdG9yIG1pZGRsZXdhcmUgd2l0aCBwYXJhbGxlbCB2YWxpZGF0aW9uXG4gKlxuICogVmFsaWRhdGVzIHJlcXVlc3QgY29tcG9uZW50cyAoYm9keSwgcXVlcnksIHBhdGgsIGhlYWRlcnMpIGluIHBhcmFsbGVsIGZvciBvcHRpbWFsIHBlcmZvcm1hbmNlLlxuICogU3RvcmVzIHZhbGlkYXRlZCBkYXRhIHVzaW5nIHN5bWJvbCBrZXlzIGZvciB0eXBlLXNhZmUgcmV0cmlldmFsIGluIGhhbmRsZXJzLlxuICpcbiAqIEBwYXJhbSB2YWxpZGF0aW9uQ29uZmlnIC0gQ29uZmlndXJhdGlvbiBzcGVjaWZ5aW5nIHdoaWNoIHBhcnRzIHRvIHZhbGlkYXRlXG4gKiBAcmV0dXJucyBNaWRkbGV3YXJlIGZ1bmN0aW9uIHRoYXQgdmFsaWRhdGVzIHJlcXVlc3RzIGFuZCBzdG9yZXMgcmVzdWx0c1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCB2YWxpZGF0b3IgPSBjcmVhdGVSZXN0UmVxdWVzdFZhbGlkYXRvcih7XG4gKiAgIGJvZHk6IHl1cC5vYmplY3Qoe1xuICogICAgIG5hbWU6IHl1cC5zdHJpbmcoKS5yZXF1aXJlZCgpLFxuICogICAgIGVtYWlsOiB5dXAuc3RyaW5nKCkuZW1haWwoKS5yZXF1aXJlZCgpXG4gKiAgIH0pLFxuICogICBoZWFkZXJzOiB5dXAub2JqZWN0KHtcbiAqICAgICBhdXRob3JpemF0aW9uOiB5dXAuc3RyaW5nKCkucmVxdWlyZWQoKVxuICogICB9KVxuICogfSk7XG4gKlxuICogY2hhaW4udXNlKCd2YWxpZGF0b3InLCB2YWxpZGF0b3IpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVSZXN0UmVxdWVzdFZhbGlkYXRvcjxcbiAgVFR5cGVzIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgQW1wbGlmeU1vZGVsVHlwZT4gPSBSZWNvcmQ8XG4gICAgc3RyaW5nLFxuICAgIEFtcGxpZnlNb2RlbFR5cGVcbiAgPixcbj4oXG4gIHZhbGlkYXRpb25Db25maWc6IFJlc3RSZXF1ZXN0VmFsaWRhdGlvbkNvbmZpZyxcbik6IE1pZGRsZXdhcmU8UmVzdElucHV0V2l0aE1vZGVsczxUVHlwZXM+LCBSZXN0UmVzcG9uc2U+IHtcbiAgY29uc3Qge1xuICAgIGJvZHk6IGJvZHlTY2hlbWEsXG4gICAgcXVlcnk6IHF1ZXJ5U2NoZW1hLFxuICAgIHBhdGg6IHBhdGhTY2hlbWEsXG4gICAgaGVhZGVyczogaGVhZGVyc1NjaGVtYSxcbiAgfSA9IHZhbGlkYXRpb25Db25maWc7XG5cbiAgcmV0dXJuIGFzeW5jIChpbnB1dDogUmVzdElucHV0V2l0aE1vZGVsczxUVHlwZXM+LCBuZXh0KSA9PiB7XG4gICAgY29uc3QgdHlwZWRJbnB1dCA9IGlucHV0IGFzIFJlc3RJbnB1dFdpdGhWYWxpZGF0aW9uPFRUeXBlcz47XG4gICAgY29uc3QgeyBldmVudCB9ID0gdHlwZWRJbnB1dDtcblxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IGdldFJlcXVlc3RJZChldmVudCwgaW5wdXQuY29udGV4dCk7XG4gICAgY29uc3QgbG9nQ29udGV4dCA9IGJ1aWxkUmVzdENvbnRleHQodHlwZWRJbnB1dCBhcyBSZXN0SW5wdXRXaXRoTW9kZWxzLCB7XG4gICAgICByZXF1ZXN0SWQsXG4gICAgfSk7XG5cbiAgICBjb25zdCB2YWxpZGF0aW9uVGFza3M6IFByb21pc2U8dm9pZD5bXSA9IFtdO1xuXG4gICAgaWYgKGJvZHlTY2hlbWEpIHtcbiAgICAgIGNvbnN0IGJvZHlWYWxpZGF0aW9uID0gKGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgYm9keSA9IHBhcnNlSnNvbkJvZHkoZXZlbnQuYm9keSA/PyB1bmRlZmluZWQsIGxvZ0NvbnRleHQpO1xuICAgICAgICBjb25zdCB2YWxpZGF0ZWRCb2R5ID0gYXdhaXQgdmFsaWRhdGVTY2hlbWEoXG4gICAgICAgICAgYm9keVNjaGVtYSxcbiAgICAgICAgICBib2R5LFxuICAgICAgICAgICdib2R5JyxcbiAgICAgICAgICB0eXBlZElucHV0LFxuICAgICAgICApO1xuICAgICAgICBzdG9yZVZhbGlkYXRlZERhdGEodHlwZWRJbnB1dCwgVkFMSURBVEVEX0JPRFlfS0VZLCB2YWxpZGF0ZWRCb2R5KTtcbiAgICAgIH0pKCk7XG4gICAgICB2YWxpZGF0aW9uVGFza3MucHVzaChib2R5VmFsaWRhdGlvbik7XG4gICAgfVxuXG4gICAgaWYgKHF1ZXJ5U2NoZW1hKSB7XG4gICAgICBjb25zdCBxdWVyeVZhbGlkYXRpb24gPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCB2YWxpZGF0ZWRRdWVyeSA9IGF3YWl0IHZhbGlkYXRlU2NoZW1hKFxuICAgICAgICAgIHF1ZXJ5U2NoZW1hLFxuICAgICAgICAgIGV2ZW50LnF1ZXJ5U3RyaW5nUGFyYW1ldGVycyB8fCB7fSxcbiAgICAgICAgICAncXVlcnknLFxuICAgICAgICAgIHR5cGVkSW5wdXQsXG4gICAgICAgICk7XG4gICAgICAgIHN0b3JlVmFsaWRhdGVkRGF0YSh0eXBlZElucHV0LCBWQUxJREFURURfUVVFUllfS0VZLCB2YWxpZGF0ZWRRdWVyeSk7XG4gICAgICB9KSgpO1xuICAgICAgdmFsaWRhdGlvblRhc2tzLnB1c2gocXVlcnlWYWxpZGF0aW9uKTtcbiAgICB9XG5cbiAgICBpZiAocGF0aFNjaGVtYSkge1xuICAgICAgY29uc3QgcGF0aFZhbGlkYXRpb24gPSAoYXN5bmMgKCkgPT4ge1xuICAgICAgICBjb25zdCB2YWxpZGF0ZWRQYXRoID0gYXdhaXQgdmFsaWRhdGVTY2hlbWEoXG4gICAgICAgICAgcGF0aFNjaGVtYSxcbiAgICAgICAgICBldmVudC5wYXRoUGFyYW1ldGVycyB8fCB7fSxcbiAgICAgICAgICAncGF0aCcsXG4gICAgICAgICAgdHlwZWRJbnB1dCxcbiAgICAgICAgKTtcbiAgICAgICAgc3RvcmVWYWxpZGF0ZWREYXRhKHR5cGVkSW5wdXQsIFZBTElEQVRFRF9QQVRIX0tFWSwgdmFsaWRhdGVkUGF0aCk7XG4gICAgICB9KSgpO1xuICAgICAgdmFsaWRhdGlvblRhc2tzLnB1c2gocGF0aFZhbGlkYXRpb24pO1xuICAgIH1cblxuICAgIGlmIChoZWFkZXJzU2NoZW1hKSB7XG4gICAgICBjb25zdCBoZWFkZXJzVmFsaWRhdGlvbiA9IChhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRlZEhlYWRlcnMgPSBhd2FpdCB2YWxpZGF0ZVNjaGVtYShcbiAgICAgICAgICBoZWFkZXJzU2NoZW1hLFxuICAgICAgICAgIGV2ZW50LmhlYWRlcnMgfHwge30sXG4gICAgICAgICAgJ2hlYWRlcnMnLFxuICAgICAgICAgIHR5cGVkSW5wdXQsXG4gICAgICAgICk7XG4gICAgICAgIHN0b3JlVmFsaWRhdGVkRGF0YSh0eXBlZElucHV0LCBWQUxJREFURURfSEVBREVSU19LRVksIHZhbGlkYXRlZEhlYWRlcnMpO1xuICAgICAgfSkoKTtcbiAgICAgIHZhbGlkYXRpb25UYXNrcy5wdXNoKGhlYWRlcnNWYWxpZGF0aW9uKTtcbiAgICB9XG5cbiAgICBpZiAodmFsaWRhdGlvblRhc2tzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHZhbGlkYXRpb25UYXNrcyk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAnUmVxdWVzdCB2YWxpZGF0aW9uIGNvbXBsZXRlZCcsXG4gICAgICAgICAgYnVpbGRSZXN0Q29udGV4dCh0eXBlZElucHV0IGFzIFJlc3RJbnB1dFdpdGhNb2RlbHMsIHtcbiAgICAgICAgICAgIHJlcXVlc3RJZCxcbiAgICAgICAgICAgIHZhbGlkYXRlZEZpZWxkczogW1xuICAgICAgICAgICAgICBib2R5U2NoZW1hID8gJ2JvZHknIDogbnVsbCxcbiAgICAgICAgICAgICAgcXVlcnlTY2hlbWEgPyAncXVlcnknIDogbnVsbCxcbiAgICAgICAgICAgICAgcGF0aFNjaGVtYSA/ICdwYXRoJyA6IG51bGwsXG4gICAgICAgICAgICAgIGhlYWRlcnNTY2hlbWEgPyAnaGVhZGVycycgOiBudWxsLFxuICAgICAgICAgICAgXS5maWx0ZXIoQm9vbGVhbiksXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgICAgJ1JlcXVlc3QgdmFsaWRhdGlvbiBmYWlsZWQnLFxuICAgICAgICAgIGJ1aWxkUmVzdENvbnRleHQodHlwZWRJbnB1dCBhcyBSZXN0SW5wdXRXaXRoTW9kZWxzLCB7XG4gICAgICAgICAgICByZXF1ZXN0SWQsXG4gICAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcicsXG4gICAgICAgICAgfSksXG4gICAgICAgICk7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBuZXh0KHR5cGVkSW5wdXQpO1xuICB9O1xufVxuIl19