@energica-city/shared-amplify-utils
Version:
Shared utilities for AWS Amplify projects
186 lines • 25.3 kB
JavaScript
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