@aws-amplify/graphql-api-construct
Version:
AppSync GraphQL Api Construct using Amplify GraphQL Transformer.
204 lines • 33.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateDataSourceStrategy = exports.schemaByMergingDefinitions = exports.getDataSourceStrategiesProvider = exports.constructCustomSqlDataSourceStrategies = void 0;
const graphql_1 = require("graphql");
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const graphql_transformer_interfaces_1 = require("@aws-amplify/graphql-transformer-interfaces");
const aws_cdk_lib_1 = require("aws-cdk-lib");
/**
* Creates an interface flavor of customSqlDataSourceStrategies from a factory method's schema and data source. Internally, this function
* scans the fields of `Query` and `Mutation` looking for fields annotated with the `@sql` directive and designates the specified
* dataSourceStrategy to fulfill those custom queries.
*
* Note that we do not scan for `Subscription` fields: `@sql` directives are not allowed on those, and it wouldn't make sense to do so
* anyway, since subscriptions are processed from an incoming Mutation, not as the result of a direct datasource access.
*/
const constructCustomSqlDataSourceStrategies = (schema, dataSourceStrategy) => {
if (!(0, graphql_transformer_core_1.isSqlStrategy)(dataSourceStrategy)) {
return [];
}
const parsedSchema = (0, graphql_1.parse)(schema);
const queryNode = parsedSchema.definitions.find(graphql_transformer_core_1.isQueryNode);
const mutationNode = parsedSchema.definitions.find(graphql_transformer_core_1.isMutationNode);
if (!queryNode && !mutationNode) {
return [];
}
const customSqlDataSourceStrategies = [];
if (queryNode) {
const fields = (0, graphql_transformer_core_1.fieldsWithSqlDirective)(queryNode);
for (const field of fields) {
customSqlDataSourceStrategies.push({
typeName: 'Query',
fieldName: field.name.value,
strategy: dataSourceStrategy,
});
}
}
if (mutationNode) {
const fields = (0, graphql_transformer_core_1.fieldsWithSqlDirective)(mutationNode);
for (const field of fields) {
customSqlDataSourceStrategies.push({
typeName: 'Mutation',
fieldName: field.name.value,
strategy: dataSourceStrategy,
});
}
}
return customSqlDataSourceStrategies;
};
exports.constructCustomSqlDataSourceStrategies = constructCustomSqlDataSourceStrategies;
/**
* Extracts the data source provider from the definition. This jumps through some hoops to avoid changing the public interface. If we decide
* to change the public interface to simplify the structure, then this process gets a lot simpler.
*/
const getDataSourceStrategiesProvider = (definition) => {
const provider = {
// We can directly use the interface strategies, even though the SQL strategies have the customSqlStatements field that is unused by the
// transformer flavor of this type
dataSourceStrategies: definition.dataSourceStrategies,
sqlDirectiveDataSourceStrategies: [],
};
// We'll collect all the custom SQL statements from the definition into a single map, and use that to make our
// SqlDirectiveDataSourceStrategies
const customSqlStatements = {};
const constructSqlStrategies = definition.customSqlDataSourceStrategies ?? [];
// Note that we're relying on the `customSqlStatements` object reference to stay the same throughout this loop. Don't reassign it, or the
// collected sqlDirectiveStrategies will break
constructSqlStrategies.forEach((sqlStrategy) => {
if (sqlStrategy.strategy.customSqlStatements) {
Object.assign(customSqlStatements, sqlStrategy.strategy.customSqlStatements);
}
provider.sqlDirectiveDataSourceStrategies.push({
typeName: sqlStrategy.typeName,
fieldName: sqlStrategy.fieldName,
strategy: sqlStrategy.strategy,
customSqlStatements,
});
});
return provider;
};
exports.getDataSourceStrategiesProvider = getDataSourceStrategiesProvider;
/**
* Creates a new schema by merging the individual schemas contained in the definitions, combining fields of the Query and Mutation types in
* individual definitions into a single combined definition. Adding directives to `Query` and `Mutation` types participating in a
* combination is not supported (the behavior is undefined whether those directives are migrated).
*/
const schemaByMergingDefinitions = (definitions) => {
const schema = definitions.map((def) => def.schema).join('\n');
const parsedSchema = (0, graphql_1.parse)(schema);
// We store the Query & Mutation definitions separately. Since the interfaces are readonly, we'll have to re-compose the types after we've
// collected all the fields
const queryAndMutationDefinitions = {};
// Throws if the field has already been encountered
const validateField = (typeName, fieldName) => {
const fields = queryAndMutationDefinitions[typeName]?.fields;
if (!fields) {
return;
}
if (fields.find((field) => field.name.value === fieldName)) {
throw new Error(`The custom ${typeName} field '${fieldName}' was found in multiple definitions, but a field name cannot be shared between definitions.`);
}
};
// Transform the schema by reducing Mutation & Query types:
// - Collect Mutation and Query definitions
// - Alter the parsed schema by filtering out Mutation & Query types
// - Add the combined Mutation & Query definitions to the filtered schema
parsedSchema.definitions.filter(graphql_transformer_core_1.isBuiltInGraphqlNode).forEach((def) => {
const typeName = def.name.value;
if (!queryAndMutationDefinitions[typeName]) {
queryAndMutationDefinitions[typeName] = {
node: def,
// `ObjectTypeDefinitionNode.fields` is a ReadonlyArray; so we have to create a new mutable array to collect all the fields
fields: [...(def.fields ?? [])],
};
return;
}
(def.fields ?? []).forEach((field) => {
validateField(typeName, field.name.value);
});
queryAndMutationDefinitions[typeName].fields = [...queryAndMutationDefinitions[typeName].fields, ...(def.fields ?? [])];
});
// Gather the collected Query & Mutation fields into <=2 new definitions
const combinedDefinitions = Object.values(queryAndMutationDefinitions)
.sort((a, b) => a.node.name.value.localeCompare(b.node.name.value))
.reduce((acc, cur) => {
const definitionNode = {
...cur.node,
fields: cur.fields,
};
return [...acc, definitionNode];
}, []);
// Filter out the old Query & Mutation definitions
const filteredDefinitions = parsedSchema.definitions.filter((def) => !(0, graphql_transformer_core_1.isBuiltInGraphqlNode)(def));
// Compose the new schema by appending the collected definitions to the filtered definitions. This means that every query will be
// rewritten such that the Mutation and Query types appear at the end of the schema.
const newSchema = {
...parsedSchema,
definitions: [...filteredDefinitions, ...combinedDefinitions],
};
const combinedSchemaString = (0, graphql_1.print)(newSchema);
return combinedSchemaString;
};
exports.schemaByMergingDefinitions = schemaByMergingDefinitions;
/*
* Validates the user input for the dataSourceStrategy. This is a no-op for DynamoDB strategies for now.
* @param strategy user provided model data source strategy
* @returns validates and throws an error if the strategy is invalid
*/
const validateDataSourceStrategy = (strategy) => {
if (!(0, graphql_transformer_core_1.isSqlStrategy)(strategy)) {
return;
}
const dbConnectionConfig = strategy.dbConnectionConfig;
if ((0, graphql_transformer_interfaces_1.isSqlModelDataSourceSsmDbConnectionConfig)(dbConnectionConfig) ||
(0, graphql_transformer_interfaces_1.isSqlModelDataSourceSsmDbConnectionStringConfig)(dbConnectionConfig)) {
const ssmPaths = Object.values(dbConnectionConfig).filter((value) => typeof value === 'string');
if ((0, graphql_transformer_interfaces_1.isSqlModelDataSourceSsmDbConnectionStringConfig)(dbConnectionConfig)) {
const hasMultipleSSMPaths = Array.isArray(dbConnectionConfig?.connectionUriSsmPath);
if (hasMultipleSSMPaths) {
if (dbConnectionConfig?.connectionUriSsmPath?.length < 1) {
throw new Error(`Invalid data source strategy "${strategy.name}". connectionUriSsmPath must be a string or non-empty array.`);
}
ssmPaths.push(...dbConnectionConfig.connectionUriSsmPath);
}
}
const invalidSSMPaths = ssmPaths.filter((value) => !isValidSSMPath(value));
if (invalidSSMPaths.length > 0) {
throw new Error(`Invalid data source strategy "${strategy.name}". Following SSM paths must start with '/' in dbConnectionConfig: ${invalidSSMPaths.join(', ')}.`);
}
}
else if ((0, graphql_transformer_interfaces_1.isSqlModelDataSourceSecretsManagerDbConnectionConfig)(dbConnectionConfig)) {
if (!aws_cdk_lib_1.Token.isUnresolved(dbConnectionConfig.secretArn)) {
try {
const arnComponents = aws_cdk_lib_1.Arn.split(dbConnectionConfig.secretArn, aws_cdk_lib_1.ArnFormat.COLON_RESOURCE_NAME);
if (arnComponents.service !== 'secretsmanager' || arnComponents.resource !== 'secret') {
// error message does not matter because it inside try/catch
throw new Error();
}
}
catch {
throw new Error(`Invalid data source strategy "${strategy.name}". The value of secretArn is not a valid Secrets Manager ARN.`);
}
}
if (dbConnectionConfig.keyArn && !aws_cdk_lib_1.Token.isUnresolved(dbConnectionConfig.keyArn)) {
try {
const arnComponents = aws_cdk_lib_1.Arn.split(dbConnectionConfig.keyArn, aws_cdk_lib_1.ArnFormat.SLASH_RESOURCE_NAME);
if (arnComponents.service !== 'kms' || arnComponents.resource !== 'key') {
// error message does not matter because it inside try/catch
throw new Error();
}
}
catch {
throw new Error(`Invalid data source strategy "${strategy.name}". The value of keyArn is not a valid KMS ARN.`);
}
}
}
else {
throw new Error(`Invalid data source strategy "${strategy.name}". dbConnectionConfig does not include SSM paths or Secret ARN.`);
}
};
exports.validateDataSourceStrategy = validateDataSourceStrategy;
const isValidSSMPath = (path) => {
return path.startsWith('/');
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1zb3VyY2UtY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2ludGVybmFsL2RhdGEtc291cmNlLWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxQ0FBbUk7QUFDbkksb0ZBTStDO0FBQy9DLGdHQUtxRDtBQUNyRCw2Q0FBb0Q7QUFPcEQ7Ozs7Ozs7R0FPRztBQUNJLE1BQU0sc0NBQXNDLEdBQUcsQ0FDcEQsTUFBYyxFQUNkLGtCQUFvRCxFQUNaLEVBQUU7SUFDMUMsSUFBSSxDQUFDLElBQUEsd0NBQWEsRUFBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7UUFDdkMsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQsTUFBTSxZQUFZLEdBQUcsSUFBQSxlQUFLLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFFbkMsTUFBTSxTQUFTLEdBQUcsWUFBWSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsc0NBQVcsQ0FBQyxDQUFDO0lBQzdELE1BQU0sWUFBWSxHQUFHLFlBQVksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLHlDQUFjLENBQUMsQ0FBQztJQUNuRSxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDaEMsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQsTUFBTSw2QkFBNkIsR0FBMkMsRUFBRSxDQUFDO0lBRWpGLElBQUksU0FBUyxFQUFFLENBQUM7UUFDZCxNQUFNLE1BQU0sR0FBRyxJQUFBLGlEQUFzQixFQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ2pELEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxFQUFFLENBQUM7WUFDM0IsNkJBQTZCLENBQUMsSUFBSSxDQUFDO2dCQUNqQyxRQUFRLEVBQUUsT0FBTztnQkFDakIsU0FBUyxFQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSztnQkFDM0IsUUFBUSxFQUFFLGtCQUFrQjthQUM3QixDQUFDLENBQUM7UUFDTCxD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LENBQUMsQ0FBQztBQUM5QixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEZWZpbml0aW9uTm9kZSwgRmllbGREZWZpbml0aW9uTm9kZSwgSW50ZXJmYWNlVHlwZURlZmluaXRpb25Ob2RlLCBPYmplY3RUeXBlRGVmaW5pdGlvbk5vZGUsIHBhcnNlLCBwcmludCB9IGZyb20gJ2dyYXBocWwnO1xuaW1wb3J0IHtcbiAgaXNCdWlsdEluR3JhcGhxbE5vZGUsXG4gIGlzU3FsU3RyYXRlZ3ksXG4gIGlzUXVlcnlOb2RlLFxuICBpc011dGF0aW9uTm9kZSxcbiAgZmllbGRzV2l0aFNxbERpcmVjdGl2ZSxcbn0gZnJvbSAnQGF3cy1hbXBsaWZ5L2dyYXBocWwtdHJhbnNmb3JtZXItY29yZSc7XG5pbXBvcnQge1xuICBEYXRhU291cmNlU3RyYXRlZ2llc1Byb3ZpZGVyLFxuICBpc1NxbE1vZGVsRGF0YVNvdXJjZVNzbURiQ29ubmVjdGlvbkNvbmZpZyxcbiAgaXNTcWxNb2RlbERhdGFTb3VyY2VTZWNyZXRzTWFuYWdlckRiQ29ubmVjdGlvbkNvbmZpZyxcbiAgaXNTcWxNb2RlbERhdGFTb3VyY2VTc21EYkNvbm5lY3Rpb25TdHJpbmdDb25maWcsXG59IGZyb20gJ0Bhd3MtYW1wbGlmeS9ncmFwaHFsLXRyYW5zZm9ybWVyLWludGVyZmFjZXMnO1xuaW1wb3J0IHsgVG9rZW4sIEFybiwgQXJuRm9ybWF0IH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHtcbiAgQ3VzdG9tU3FsRGF0YVNvdXJjZVN0cmF0ZWd5IGFzIENvbnN0cnVjdEN1c3RvbVNxbERhdGFTb3VyY2VTdHJhdGVneSxcbiAgTW9kZWxEYXRhU291cmNlU3RyYXRlZ3kgYXMgQ29uc3RydWN0TW9kZWxEYXRhU291cmNlU3RyYXRlZ3ksXG59IGZyb20gJy4uL21vZGVsLWRhdGFzb3VyY2Utc3RyYXRlZ3ktdHlwZXMnO1xuaW1wb3J0IHsgSUFtcGxpZnlHcmFwaHFsRGVmaW5pdGlvbiB9IGZyb20gJy4uL3R5cGVzJztcblxuLyoqXG4gKiBDcmVhdGVzIGFuIGludGVyZmFjZSBmbGF2b3Igb2YgY3VzdG9tU3FsRGF0YVNvdXJjZVN0cmF0ZWdpZXMgZnJvbSBhIGZhY3RvcnkgbWV0aG9kJ3Mgc2NoZW1hIGFuZCBkYXRhIHNvdXJjZS4gSW50ZXJuYWxseSwgdGhpcyBmdW5jdGlvblxuICogc2NhbnMgdGhlIGZpZWxkcyBvZiBgUXVlcnlgIGFuZCBgTXV0YXRpb25gIGxvb2tpbmcgZm9yIGZpZWxkcyBhbm5vdGF0ZWQgd2l0aCB0aGUgYEBzcWxgIGRpcmVjdGl2ZSBhbmQgZGVzaWduYXRlcyB0aGUgc3BlY2lmaWVkXG4gKiBkYXRhU291cmNlU3RyYXRlZ3kgdG8gZnVsZmlsbCB0aG9zZSBjdXN0b20gcXVlcmllcy5cbiAqXG4gKiBOb3RlIHRoYXQgd2UgZG8gbm90IHNjYW4gZm9yIGBTdWJzY3JpcHRpb25gIGZpZWxkczogYEBzcWxgIGRpcmVjdGl2ZXMgYXJlIG5vdCBhbGxvd2VkIG9uIHRob3NlLCBhbmQgaXQgd291bGRuJ3QgbWFrZSBzZW5zZSB0byBkbyBzb1xuICogYW55d2F5LCBzaW5jZSBzdWJzY3JpcHRpb25zIGFyZSBwcm9jZXNzZWQgZnJvbSBhbiBpbmNvbWluZyBNdXRhdGlvbiwgbm90IGFzIHRoZSByZXN1bHQgb2YgYSBkaXJlY3QgZGF0YXNvdXJjZSBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBjb25zdHJ1Y3RDdXN0b21TcWxEYXRhU291cmNlU3RyYXRlZ2llcyA9IChcbiAgc2NoZW1hOiBzdHJpbmcsXG4gIGRhdGFTb3VyY2VTdHJhdGVneTogQ29uc3RydWN0TW9kZWxEYXRhU291cmNlU3RyYXRlZ3ksXG4pOiBDb25zdHJ1Y3RDdXN0b21TcWxEYXRhU291cmNlU3RyYXRlZ3lbXSA9PiB7XG4gIGlmICghaXNTcWxTdHJhdGVneShkYXRhU291cmNlU3RyYXRlZ3kpKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcGFyc2VkU2NoZW1hID0gcGFyc2Uoc2NoZW1hKTtcblxuICBjb25zdCBxdWVyeU5vZGUgPSBwYXJzZWRTY2hlbWEuZGVmaW5pdGlvbnMuZmluZChpc1F1ZXJ5Tm9kZSk7XG4gIGNvbnN0IG11dGF0aW9uTm9kZSA9IHBhcnNlZFNjaGVtYS5kZWZpbml0aW9ucy5maW5kKGlzTXV0YXRpb25Ob2RlKTtcbiAgaWYgKCFxdWVyeU5vZGUgJiYgIW11dGF0aW9uTm9kZSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IGN1c3RvbVNxbERhdGFTb3VyY2VTdHJhdGVnaWVzOiBDb25zdHJ1Y3RDdXN0b21TcWxEYXRhU291cmNlU3RyYXRlZ3lbXSA9IFtdO1xuXG4gIGlmIChxdWVyeU5vZGUpIHtcbiAgICBjb25zdCBmaWVsZHMgPSBmaWVsZHNXaXRoU3FsRGlyZWN0aXZlKHF1ZXJ5Tm9kZSk7XG4gICAgZm9yIChjb25zdCBmaWVsZCBvZiBmaWVsZHMpIHtcbiAgICAgIGN1c3RvbVNxbERhdGFTb3VyY2VTdHJhdGVnaWVzLnB1c2goe1xuICAgICAgICB0eXBlTmFtZTogJ1F1ZXJ5JyxcbiAgICAgICAgZmllbGROYW1lOiBmaWVsZC5uYW1lLnZhbHVlLFxuICAgICAgICBzdHJhdGVneTogZGF0YVNvdXJjZVN0cmF0ZWd5LFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaWYgKG11dGF0aW9uTm9kZSkge1xuICAgIGNvbnN0IGZpZWxkcyA9IGZpZWxkc1dpdGhTcWxEaXJlY3RpdmUobXV0YXRpb25Ob2RlKTtcbiAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIGZpZWxkcykge1xuICAgICAgY3VzdG9tU3FsRGF0YVNvdXJjZVN0cmF0ZWdpZXMucHVzaCh7XG4gICAgICAgIHR5cGVOYW1lOiAnTXV0YXRpb24nLFxuICAgICAgICBmaWVsZE5hbWU6IGZpZWxkLm5hbWUudmFsdWUsXG4gICAgICAgIHN0cmF0ZWd5OiBkYXRhU291cmNlU3RyYXRlZ3ksXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY3VzdG9tU3FsRGF0YVNvdXJjZVN0cmF0ZWdpZXM7XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBkYXRhIHNvdXJjZSBwcm92aWRlciBmcm9tIHRoZSBkZWZpbml0aW9uLiBUaGlzIGp1bXBzIHRocm91Z2ggc29tZSBob29wcyB0byBhdm9pZCBjaGFuZ2luZyB0aGUgcHVibGljIGludGVyZmFjZS4gSWYgd2UgZGVjaWRlXG4gKiB0byBjaGFuZ2UgdGhlIHB1YmxpYyBpbnRlcmZhY2UgdG8gc2ltcGxpZnkgdGhlIHN0cnVjdHVyZSwgdGhlbiB0aGlzIHByb2Nlc3MgZ2V0cyBhIGxvdCBzaW1wbGVyLlxuICovXG5leHBvcnQgY29uc3QgZ2V0RGF0YVNvdXJjZVN0cmF0ZWdpZXNQcm92aWRlciA9IChkZWZpbml0aW9uOiBJQW1wbGlmeUdyYXBocWxEZWZpbml0aW9uKTogRGF0YVNvdXJjZVN0cmF0ZWdpZXNQcm92aWRlciA9PiB7XG4gIGNvbnN0IHByb3ZpZGVyOiBEYXRhU291cmNlU3RyYXRlZ2llc1Byb3ZpZGVyID0ge1xuICAgIC8vIFdlIGNhbiBkaXJlY3RseSB1c2UgdGhlIGludGVyZmFjZSBzdHJhdGVnaWVzLCBldmVuIHRob3VnaCB0aGUgU1FMIHN0cmF0ZWdpZXMgaGF2ZSB0aGUgY3VzdG9tU3FsU3RhdGVtZW50cyBmaWVsZCB0aGF0IGlzIHVudXNlZCBieSB0aGVcbiAgICAvLyB0cmFuc2Zvcm1lciBmbGF2b3Igb2YgdGhpcyB0eXBlXG4gICAgZGF0YVNvdXJjZVN0cmF0ZWdpZXM6IGRlZmluaXRpb24uZGF0YVNvdXJjZVN0cmF0ZWdpZXMsXG4gICAgc3FsRGlyZWN0aXZlRGF0YVNvdXJjZVN0cmF0ZWdpZXM6IFtdLFxuICB9O1xuXG4gIC8vIFdlJ2xsIGNvbGxlY3QgYWxsIHRoZSBjdXN0b20gU1FMIHN0YXRlbWVudHMgZnJvbSB0aGUgZGVmaW5pdGlvbiBpbnRvIGEgc2luZ2xlIG1hcCwgYW5kIHVzZSB0aGF0IHRvIG1ha2Ugb3VyXG4gIC8vIFNxbERpcmVjdGl2ZURhdGFTb3VyY2VTdHJhdGVnaWVzXG4gIGNvbnN0IGN1c3RvbVNxbFN0YXRlbWVudHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICBjb25zdCBjb25zdHJ1Y3RTcWxTdHJhdGVnaWVzID0gZGVmaW5pdGlvbi5jdXN0b21TcWxEYXRhU291cmNlU3RyYXRlZ2llcyA/PyBbXTtcblxuICAvLyBOb3RlIHRoYXQgd2UncmUgcmVseWluZyBvbiB0aGUgYGN1c3RvbVNxbFN0YXRlbWVudHNgIG9iamVjdCByZWZlcmVuY2UgdG8gc3RheSB0aGUgc2FtZSB0aHJvdWdob3V0IHRoaXMgbG9vcC4gRG9uJ3QgcmVhc3NpZ24gaXQsIG9yIHRoZVxuICAvLyBjb2xsZWN0ZWQgc3FsRGlyZWN0aXZlU3RyYXRlZ2llcyB3aWxsIGJyZWFrXG4gIGNvbnN0cnVjdFNxbFN0cmF0ZWdpZXMuZm9yRWFjaCgoc3FsU3RyYXRlZ3kpID0+IHtcbiAgICBpZiAoc3FsU3RyYXRlZ3kuc3RyYXRlZ3kuY3VzdG9tU3FsU3RhdGVtZW50cykge1xuICAgICAgT2JqZWN0LmFzc2lnbihjdXN0b21TcWxTdGF0ZW1lbnRzLCBzcWxTdHJhdGVneS5zdHJhdGVneS5jdXN0b21TcWxTdGF0ZW1lbnRzKTtcbiAgICB9XG5cbiAgICBwcm92aWRlci5zcWxEaXJlY3RpdmVEYXRhU291cmNlU3RyYXRlZ2llcyEucHVzaCh7XG4gICAgICB0eXBlTmFtZTogc3FsU3RyYXRlZ3kudHlwZU5hbWUsXG4gICAgICBmaWVsZE5hbWU6IHNxbFN0cmF0ZWd5LmZpZWxkTmFtZSxcbiAgICAgIHN0cmF0ZWd5OiBzcWxTdHJhdGVneS5zdHJhdGVneSxcbiAgICAgIGN1c3RvbVNxbFN0YXRlbWVudHMsXG4gICAgfSk7XG4gIH0pO1xuXG4gIHJldHVybiBwcm92aWRlcjtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBzY2hlbWEgYnkgbWVyZ2luZyB0aGUgaW5kaXZpZHVhbCBzY2hlbWFzIGNvbnRhaW5lZCBpbiB0aGUgZGVmaW5pdGlvbnMsIGNvbWJpbmluZyBmaWVsZHMgb2YgdGhlIFF1ZXJ5IGFuZCBNdXRhdGlvbiB0eXBlcyBpblxuICogaW5kaXZpZHVhbCBkZWZpbml0aW9ucyBpbnRvIGEgc2luZ2xlIGNvbWJpbmVkIGRlZmluaXRpb24uIEFkZGluZyBkaXJlY3RpdmVzIHRvIGBRdWVyeWAgYW5kIGBNdXRhdGlvbmAgdHlwZXMgcGFydGljaXBhdGluZyBpbiBhXG4gKiBjb21iaW5hdGlvbiBpcyBub3Qgc3VwcG9ydGVkICh0aGUgYmVoYXZpb3IgaXMgdW5kZWZpbmVkIHdoZXRoZXIgdGhvc2UgZGlyZWN0aXZlcyBhcmUgbWlncmF0ZWQpLlxuICovXG5leHBvcnQgY29uc3Qgc2NoZW1hQnlNZXJnaW5nRGVmaW5pdGlvbnMgPSAoZGVmaW5pdGlvbnM6IElBbXBsaWZ5R3JhcGhxbERlZmluaXRpb25bXSk6IHN0cmluZyA9PiB7XG4gIGNvbnN0IHNjaGVtYSA9IGRlZmluaXRpb25zLm1hcCgoZGVmKSA9PiBkZWYuc2NoZW1hKS5qb2luKCdcXG4nKTtcbiAgY29uc3QgcGFyc2VkU2NoZW1hID0gcGFyc2Uoc2NoZW1hKTtcblxuICAvLyBXZSBzdG9yZSB0aGUgUXVlcnkgJiBNdXRhdGlvbiBkZWZpbml0aW9ucyBzZXBhcmF0ZWx5LiBTaW5jZSB0aGUgaW50ZXJmYWNlcyBhcmUgcmVhZG9ubHksIHdlJ2xsIGhhdmUgdG8gcmUtY29tcG9zZSB0aGUgdHlwZXMgYWZ0ZXIgd2UndmVcbiAgLy8gY29sbGVjdGVkIGFsbCB0aGUgZmllbGRzXG4gIGNvbnN0IHF1ZXJ5QW5kTXV0YXRpb25EZWZpbml0aW9uczogUmVjb3JkPFxuICAgIHN0cmluZyxcbiAgICB7XG4gICAgICBub2RlOiBPYmplY3RUeXBlRGVmaW5pdGlvbk5vZGUgfCBJbnRlcmZhY2VUeXBlRGVmaW5pdGlvbk5vZGU7XG4gICAgICBmaWVsZHM6IEZpZWxkRGVmaW5pdGlvbk5vZGVbXTtcbiAgICB9XG4gID4gPSB7fTtcblxuICAvLyBUaHJvd3MgaWYgdGhlIGZpZWxkIGhhcyBhbHJlYWR5IGJlZW4gZW5jb3VudGVyZWRcbiAgY29uc3QgdmFsaWRhdGVGaWVsZCA9ICh0eXBlTmFtZTogc3RyaW5nLCBmaWVsZE5hbWU6IHN0cmluZyk6IHZvaWQgPT4ge1xuICAgIGNvbnN0IGZpZWxkcyA9IHF1ZXJ5QW5kTXV0YXRpb25EZWZpbml0aW9uc1t0eXBlTmFtZV0/LmZpZWxkcztcbiAgICBpZiAoIWZpZWxkcykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoZmllbGRzLmZpbmQoKGZpZWxkKSA9PiBmaWVsZC5uYW1lLnZhbHVlID09PSBmaWVsZE5hbWUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBUaGUgY3VzdG9tICR7dHlwZU5hbWV9IGZpZWxkICcke2ZpZWxkTmFtZX0nIHdhcyBmb3VuZCBpbiBtdWx0aXBsZSBkZWZpbml0aW9ucywgYnV0IGEgZmllbGQgbmFtZSBjYW5ub3QgYmUgc2hhcmVkIGJldHdlZW4gZGVmaW5pdGlvbnMuYCxcbiAgICAgICk7XG4gICAgfVxuICB9O1xuXG4gIC8vIFRyYW5zZm9ybSB0aGUgc2NoZW1hIGJ5IHJlZHVjaW5nIE11dGF0aW9uICYgUXVlcnkgdHlwZXM6XG4gIC8vIC0gQ29sbGVjdCBNdXRhdGlvbiBhbmQgUXVlcnkgZGVmaW5pdGlvbnNcbiAgLy8gLSBBbHRlciB0aGUgcGFyc2VkIHNjaGVtYSBieSBmaWx0ZXJpbmcgb3V0IE11dGF0aW9uICYgUXVlcnkgdHlwZXNcbiAgLy8gLSBBZGQgdGhlIGNvbWJpbmVkIE11dGF0aW9uICYgUXVlcnkgZGVmaW5pdGlvbnMgdG8gdGhlIGZpbHRlcmVkIHNjaGVtYVxuICBwYXJzZWRTY2hlbWEuZGVmaW5pdGlvbnMuZmlsdGVyKGlzQnVpbHRJbkdyYXBocWxOb2RlKS5mb3JFYWNoKChkZWYpID0+IHtcbiAgICBjb25zdCB0eXBlTmFtZSA9IGRlZi5uYW1lLnZhbHVlO1xuICAgIGlmICghcXVlcnlBbmRNdXRhdGlvbkRlZmluaXRpb25zW3R5cGVOYW1lXSkge1xuICAgICAgcXVlcnlBbmRNdXRhdGlvbkRlZmluaXRpb25zW3R5cGVOYW1lXSA9IHtcbiAgICAgICAgbm9kZTogZGVmLFxuICAgICAgICAvLyBgT2JqZWN0VHlwZURlZmluaXRpb25Ob2RlLmZpZWxkc2AgaXMgYSBSZWFkb25seUFycmF5OyBzbyB3ZSBoYXZlIHRvIGNyZWF0ZSBhIG5ldyBtdXRhYmxlIGFycmF5IHRvIGNvbGxlY3QgYWxsIHRoZSBmaWVsZHNcbiAgICAgICAgZmllbGRzOiBbLi4uKGRlZi5maWVsZHMgPz8gW10pXSxcbiAgICAgIH07XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgKGRlZi5maWVsZHMgPz8gW10pLmZvckVhY2goKGZpZWxkKSA9PiB7XG4gICAgICB2YWxpZGF0ZUZpZWxkKHR5cGVOYW1lLCBmaWVsZC5uYW1lLnZhbHVlKTtcbiAgICB9KTtcblxuICAgIHF1ZXJ5QW5kTXV0YXRpb25EZWZpbml0aW9uc1t0eXBlTmFtZV0uZmllbGRzID0gWy4uLnF1ZXJ5QW5kTXV0YXRpb25EZWZpbml0aW9uc1t0eXBlTmFtZV0uZmllbGRzLCAuLi4oZGVmLmZpZWxkcyA/PyBbXSldO1xuICB9KTtcblxuICAvLyBHYXRoZXIgdGhlIGNvbGxlY3RlZCBRdWVyeSAmIE11dGF0aW9uIGZpZWxkcyBpbnRvIDw9MiBuZXcgZGVmaW5pdGlvbnNcbiAgY29uc3QgY29tYmluZWREZWZpbml0aW9ucyA9IE9iamVjdC52YWx1ZXMocXVlcnlBbmRNdXRhdGlvbkRlZmluaXRpb25zKVxuICAgIC5zb3J0KChhLCBiKSA9PiBhLm5vZGUubmFtZS52YWx1ZS5sb2NhbGVDb21wYXJlKGIubm9kZS5uYW1lLnZhbHVlKSlcbiAgICAucmVkdWNlKChhY2MsIGN1cikgPT4ge1xuICAgICAgY29uc3QgZGVmaW5pdGlvbk5vZGUgPSB7XG4gICAgICAgIC4uLmN1ci5ub2RlLFxuICAgICAgICBmaWVsZHM6IGN1ci5maWVsZHMsXG4gICAgICB9O1xuICAgICAgcmV0dXJuIFsuLi5hY2MsIGRlZmluaXRpb25Ob2RlXTtcbiAgICB9LCBbXSBhcyBEZWZpbml0aW9uTm9kZVtdKTtcblxuICAvLyBGaWx0ZXIgb3V0IHRoZSBvbGQgUXVlcnkgJiBNdXRhdGlvbiBkZWZpbml0aW9uc1xuICBjb25zdCBmaWx0ZXJlZERlZmluaXRpb25zID0gcGFyc2VkU2NoZW1hLmRlZmluaXRpb25zLmZpbHRlcigoZGVmKSA9PiAhaXNCdWlsdEluR3JhcGhxbE5vZGUoZGVmKSk7XG5cbiAgLy8gQ29tcG9zZSB0aGUgbmV3IHNjaGVtYSBieSBhcHBlbmRpbmcgdGhlIGNvbGxlY3RlZCBkZWZpbml0aW9ucyB0byB0aGUgZmlsdGVyZWQgZGVmaW5pdGlvbnMuIFRoaXMgbWVhbnMgdGhhdCBldmVyeSBxdWVyeSB3aWxsIGJlXG4gIC8vIHJld3JpdHRlbiBzdWNoIHRoYXQgdGhlIE11dGF0aW9uIGFuZCBRdWVyeSB0eXBlcyBhcHBlYXIgYXQgdGhlIGVuZCBvZiB0aGUgc2NoZW1hLlxuICBjb25zdCBuZXdTY2hlbWEgPSB7XG4gICAgLi4ucGFyc2VkU2NoZW1hLFxuICAgIGRlZmluaXRpb25zOiBbLi4uZmlsdGVyZWREZWZpbml0aW9ucywgLi4uY29tYmluZWREZWZpbml0aW9uc10sXG4gIH07XG5cbiAgY29uc3QgY29tYmluZWRTY2hlbWFTdHJpbmcgPSBwcmludChuZXdTY2hlbWEpO1xuICByZXR1cm4gY29tYmluZWRTY2hlbWFTdHJpbmc7XG59O1xuXG4vKlxuICogVmFsaWRhdGVzIHRoZSB1c2VyIGlucHV0IGZvciB0aGUgZGF0YVNvdXJjZVN0cmF0ZWd5LiBUaGlzIGlzIGEgbm8tb3AgZm9yIER5bmFtb0RCIHN0cmF0ZWdpZXMgZm9yIG5vdy5cbiAqIEBwYXJhbSBzdHJhdGVneSB1c2VyIHByb3ZpZGVkIG1vZGVsIGRhdGEgc291cmNlIHN0cmF0ZWd5XG4gKiBAcmV0dXJucyB2YWxpZGF0ZXMgYW5kIHRocm93cyBhbiBlcnJvciBpZiB0aGUgc3RyYXRlZ3kgaXMgaW52YWxpZFxuICovXG5leHBvcnQgY29uc3QgdmFsaWRhdGVEYXRhU291cmNlU3RyYXRlZ3kgPSAoc3RyYXRlZ3k6IENvbnN0cnVjdE1vZGVsRGF0YVNvdXJjZVN0cmF0ZWd5KTogdm9pZCA9PiB7XG4gIGlmICghaXNTcWxTdHJhdGVneShzdHJhdGVneSkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBkYkNvbm5lY3Rpb25Db25maWcgPSBzdHJhdGVneS5kYkNvbm5lY3Rpb25Db25maWc7XG4gIGlmIChcbiAgICBpc1NxbE1vZGVsRGF0YVNvdXJjZVNzbURiQ29ubmVjdGlvbkNvbmZpZyhkYkNvbm5lY3Rpb25Db25maWcpIHx8XG4gICAgaXNTcWxNb2RlbERhdGFTb3VyY2VTc21EYkNvbm5lY3Rpb25TdHJpbmdDb25maWcoZGJDb25uZWN0aW9uQ29uZmlnKVxuICApIHtcbiAgICBjb25zdCBzc21QYXRocyA9IE9iamVjdC52YWx1ZXMoZGJDb25uZWN0aW9uQ29uZmlnKS5maWx0ZXIoKHZhbHVlKSA9PiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKTtcbiAgICBpZiAoaXNTcWxNb2RlbERhdGFTb3VyY2VTc21EYkNvbm5lY3Rpb25TdHJpbmdDb25maWcoZGJDb25uZWN0aW9uQ29uZmlnKSkge1xuICAgICAgY29uc3QgaGFzTXVsdGlwbGVTU01QYXRocyA9IEFycmF5LmlzQXJyYXkoZGJDb25uZWN0aW9uQ29uZmlnPy5jb25uZWN0aW9uVXJpU3NtUGF0aCk7XG4gICAgICBpZiAoaGFzTXVsdGlwbGVTU01QYXRocykge1xuICAgICAgICBpZiAoZGJDb25uZWN0aW9uQ29uZmlnPy5jb25uZWN0aW9uVXJpU3NtUGF0aD8ubGVuZ3RoIDwgMSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBkYXRhIHNvdXJjZSBzdHJhdGVneSBcIiR7c3RyYXRlZ3kubmFtZX1cIi4gY29ubmVjdGlvblVyaVNzbVBhdGggbXVzdCBiZSBhIHN0cmluZyBvciBub24tZW1wdHkgYXJyYXkuYCk7XG4gICAgICAgIH1cbiAgICAgICAgc3NtUGF0aHMucHVzaCguLi5kYkNvbm5lY3Rpb25Db25maWcuY29ubmVjdGlvblVyaVNzbVBhdGgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGludmFsaWRTU01QYXRocyA9IHNzbVBhdGhzLmZpbHRlcigodmFsdWUpID0+ICFpc1ZhbGlkU1NNUGF0aCh2YWx1ZSkpO1xuICAgIGlmIChpbnZhbGlkU1NNUGF0aHMubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgSW52YWxpZCBkYXRhIHNvdXJjZSBzdHJhdGVneSBcIiR7XG4gICAgICAgICAgc3RyYXRlZ3kubmFtZVxuICAgICAgICB9XCIuIEZvbGxvd2luZyBTU00gcGF0aHMgbXVzdCBzdGFydCB3aXRoICcvJyBpbiBkYkNvbm5lY3Rpb25Db25maWc6ICR7aW52YWxpZFNTTVBhdGhzLmpvaW4oJywgJyl9LmAsXG4gICAgICApO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc1NxbE1vZGVsRGF0YVNvdXJjZVNlY3JldHNNYW5hZ2VyRGJDb25uZWN0aW9uQ29uZmlnKGRiQ29ubmVjdGlvbkNvbmZpZykpIHtcbiAgICBpZiAoIVRva2VuLmlzVW5yZXNvbHZlZChkYkNvbm5lY3Rpb25Db25maWcuc2VjcmV0QXJuKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgYXJuQ29tcG9uZW50cyA9IEFybi5zcGxpdChkYkNvbm5lY3Rpb25Db25maWcuc2VjcmV0QXJuLCBBcm5Gb3JtYXQuQ09MT05fUkVTT1VSQ0VfTkFNRSk7XG4gICAgICAgIGlmIChhcm5Db21wb25lbnRzLnNlcnZpY2UgIT09ICdzZWNyZXRzbWFuYWdlcicgfHwgYXJuQ29tcG9uZW50cy5yZXNvdXJjZSAhPT0gJ3NlY3JldCcpIHtcbiAgICAgICAgICAvLyBlcnJvciBtZXNzYWdlIGRvZXMgbm90IG1hdHRlciBiZWNhdXNlIGl0IGluc2lkZSB0cnkvY2F0Y2hcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBkYXRhIHNvdXJjZSBzdHJhdGVneSBcIiR7c3RyYXRlZ3kubmFtZX1cIi4gVGhlIHZhbHVlIG9mIHNlY3JldEFybiBpcyBub3QgYSB2YWxpZCBTZWNyZXRzIE1hbmFnZXIgQVJOLmApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChkYkNvbm5lY3Rpb25Db25maWcua2V5QXJuICYmICFUb2tlbi5pc1VucmVzb2x2ZWQoZGJDb25uZWN0aW9uQ29uZmlnLmtleUFybikpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGFybkNvbXBvbmVudHMgPSBBcm4uc3BsaXQoZGJDb25uZWN0aW9uQ29uZmlnLmtleUFybiwgQXJuRm9ybWF0LlNMQVNIX1JFU09VUkNFX05BTUUpO1xuICAgICAgICBpZiAoYXJuQ29tcG9uZW50cy5zZXJ2aWNlICE9PSAna21zJyB8fCBhcm5Db21wb25lbnRzLnJlc291cmNlICE9PSAna2V5Jykge1xuICAgICAgICAgIC8vIGVycm9yIG1lc3NhZ2UgZG9lcyBub3QgbWF0dGVyIGJlY2F1c2UgaXQgaW5zaWRlIHRyeS9jYXRjaFxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGRhdGEgc291cmNlIHN0cmF0ZWd5IFwiJHtzdHJhdGVneS5uYW1lfVwiLiBUaGUgdmFsdWUgb2Yga2V5QXJuIGlzIG5vdCBhIHZhbGlkIEtNUyBBUk4uYCk7XG4gICAgICB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBkYXRhIHNvdXJjZSBzdHJhdGVneSBcIiR7c3RyYXRlZ3kubmFtZX1cIi4gZGJDb25uZWN0aW9uQ29uZmlnIGRvZXMgbm90IGluY2x1ZGUgU1NNIHBhdGhzIG9yIFNlY3JldCBBUk4uYCk7XG4gIH1cbn07XG5cbmNvbnN0IGlzVmFsaWRTU01QYXRoID0gKHBhdGg6IHN0cmluZyk6IGJvb2xlYW4gPT4ge1xuICByZXR1cm4gcGF0aC5zdGFydHNXaXRoKCcvJyk7XG59O1xuIl19