UNPKG

open-next-cdk

Version:

Deploy a NextJS app using OpenNext packaging to serverless AWS using CDK

135 lines 20.4 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.NextJsLambda = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const os = require("os"); const path = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const lambda = require("aws-cdk-lib/aws-lambda"); const aws_lambda_1 = require("aws-cdk-lib/aws-lambda"); const aws_s3_1 = require("aws-cdk-lib/aws-s3"); const s3Assets = require("aws-cdk-lib/aws-s3-assets"); const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment"); const aws_ssm_1 = require("aws-cdk-lib/aws-ssm"); const constructs_1 = require("constructs"); const fs = require("fs-extra"); const constants_1 = require("./constants"); const Nextjs_1 = require("./Nextjs"); const NextjsBuild_1 = require("./NextjsBuild"); const NextjsS3EnvRewriter_1 = require("./NextjsS3EnvRewriter"); function getEnvironment(props) { const environmentVariables = { ...props.environment, ...props.lambda?.environment, ...(props.nodeEnv ? { NODE_ENV: props.nodeEnv } : {}), }; return environmentVariables; } /** * Build a lambda function from a NextJS application to handle server-side rendering, API routes, and image optimization. */ class NextJsLambda extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); const { nextBuild, lambda: functionOptions, isPlaceholder } = props; // zip up build.nextServerFnDir const zipOutDir = path.resolve(props.tempBuildDir ? path.resolve(path.join(props.tempBuildDir, `standalone`)) : fs.mkdtempSync(path.join(os.tmpdir(), 'standalone-'))); const zipFilePath = NextjsBuild_1.createArchive({ directory: nextBuild.nextServerFnDir, zipFileName: 'serverFn.zip', zipOutDir, quiet: props.quiet, }); if (!zipFilePath) throw new Error('Failed to create archive for lambda function code'); // upload the lambda package to S3 const s3asset = new s3Assets.Asset(scope, 'MainFnAsset', { path: zipFilePath }); const code = isPlaceholder ? lambda.Code.fromInline("module.exports.handler = async () => { return { statusCode: 200, body: 'SST placeholder site' } }") : lambda.Code.fromBucket(s3asset.bucket, s3asset.s3ObjectKey); // build the lambda function const environment = getEnvironment(props); const fn = new aws_lambda_1.Function(scope, 'ServerHandler', { memorySize: functionOptions?.memorySize || 1024, timeout: functionOptions?.timeout ?? aws_cdk_lib_1.Duration.seconds(10), runtime: constants_1.LAMBDA_RUNTIME, handler: path.join('index.handler'), code, environment, // prevents "Resolution error: Cannot use resource in a cross-environment // fashion, the resource's physical name must be explicit set or use // PhysicalName.GENERATE_IF_NEEDED." functionName: aws_cdk_lib_1.Stack.of(this).region !== 'us-east-1' ? aws_cdk_lib_1.PhysicalName.GENERATE_IF_NEEDED : undefined, ...functionOptions, }); this.lambdaFunction = fn; // rewrite env var placeholders in server code const replacementParams = this._getReplacementParams(environment); if (!isPlaceholder && Object.keys(replacementParams).length) { // put JSON file with env var replacements in S3 const [configBucket, configDeployment] = this.createConfigBucket(replacementParams); this.configBucket = configBucket; // replace env var placeholders in the lambda package with resolved values const rewriter = new NextjsS3EnvRewriter_1.NextjsS3EnvRewriter(this, 'LambdaCodeRewriter', { ...props, s3Bucket: s3asset.bucket, s3keys: [s3asset.s3ObjectKey], replacementConfig: { // use json file in S3 for replacement values // this can contain backend secrets so better to not have them in custom resource logs jsonS3Bucket: configDeployment.deployedBucket, jsonS3Key: Nextjs_1.CONFIG_ENV_JSON_PATH, }, debug: true, }); rewriter.node.addDependency(s3asset); // in order to create this dependency, the lambda function needs to be a child of the current construct // meaning we can't inherit from Function fn.node.addDependency(rewriter); // don't deploy lambda until rewriter is done - we are sort of 'intercepting' the deployment package } } _getReplacementParams(env) { const replacements = NextjsS3EnvRewriter_1.getS3ReplaceValues(env, false); // get placeholder => replacement values const replacementParams = {}; // JSON file with replacements to be uploaded to S3 Object.entries(replacements).forEach(([key, value]) => { // is it a token? if (typeof value === 'undefined') return; if (!value || !aws_cdk_lib_1.Token.isUnresolved(value)) { replacementParams[key] = value; return; } // create param const param = new aws_ssm_1.StringParameter(this, `Config('${key}')`, { stringValue: value, }); // add to env JSON replacementParams[key] = param.stringValue; }); return replacementParams; } // this can hold our resolved environment vars for the server createConfigBucket(replacementParams) { // won't work until this is fixed: https://github.com/aws/aws-cdk/issues/19257 const bucket = new aws_s3_1.Bucket(this, 'NextjsConfigBucket', { removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY, autoDeleteObjects: true, }); // upload environment config to s3 const deployment = new aws_s3_deployment_1.BucketDeployment(this, 'EnvJsonDeployment', { sources: [ // serialize as JSON to S3 object aws_s3_deployment_1.Source.jsonData(Nextjs_1.CONFIG_ENV_JSON_PATH, replacementParams), ], destinationBucket: bucket, }); return [bucket, deployment]; } } exports.NextJsLambda = NextJsLambda; _a = JSII_RTTI_SYMBOL_1; NextJsLambda[_a] = { fqn: "open-next-cdk.NextJsLambda", version: "0.0.10" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmV4dGpzTGFtYmRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL05leHRqc0xhbWJkYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsNkNBQWtGO0FBQ2xGLGlEQUFpRDtBQUNqRCx1REFBbUU7QUFDbkUsK0NBQTRDO0FBQzVDLHNEQUFzRDtBQUN0RCxxRUFBeUU7QUFDekUsaURBQXNEO0FBQ3RELDJDQUF1QztBQUN2QywrQkFBK0I7QUFDL0IsMkNBQTZDO0FBQzdDLHFDQUFnRDtBQUVoRCwrQ0FBMkQ7QUFDM0QsK0RBQWdGO0FBSWhGLFNBQVMsY0FBYyxDQUFDLEtBQXdCO0lBQzlDLE1BQU0sb0JBQW9CLEdBQStCO1FBQ3ZELEdBQUcsS0FBSyxDQUFDLFdBQVc7UUFDcEIsR0FBRyxLQUFLLENBQUMsTUFBTSxFQUFFLFdBQVc7UUFDNUIsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3RELENBQUM7SUFFRixPQUFPLG9CQUFvQixDQUFDO0FBQzlCLENBQUM7QUFjRDs7R0FFRztBQUNILE1BQWEsWUFBYSxTQUFRLHNCQUFTO0lBSXpDLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBd0I7UUFDaEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNqQixNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLEdBQUcsS0FBSyxDQUFDO1FBRXBFLCtCQUErQjtRQUMvQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUM1QixLQUFLLENBQUMsWUFBWTtZQUNoQixDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxZ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aUIsRUFBRSxJQUFJO1NBQ3hCLENBQUMsQ0FBQztRQUVILGtDQUFrQztRQUNsQyxNQUFNLFVBQVUsR0FBRyxJQUFJLG9DQUFnQixDQUFDLElBQUksRUFBRSxtQkFBbUIsRUFBRTtZQUNqRSxPQUFPLEVBQUU7Z0JBQ1AsaUNBQWlDO2dCQUNqQywwQkFBTSxDQUFDLFFBQVEsQ0FBQyw2QkFBb0IsRUFBRSxpQkFBaUIsQ0FBQzthQUN6RDtZQUNELGlCQUFpQixFQUFFLE1BQU07U0FDMUIsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQVUsQ0FBQztJQUN2QyxDQUFDOztBQW5ISCxvQ0FvSEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgRHVyYXRpb24sIFBoeXNpY2FsTmFtZSwgUmVtb3ZhbFBvbGljeSwgU3RhY2ssIFRva2VuIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgRnVuY3Rpb24sIEZ1bmN0aW9uT3B0aW9ucyB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgQnVja2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCAqIGFzIHMzQXNzZXRzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMy1hc3NldHMnO1xuaW1wb3J0IHsgQnVja2V0RGVwbG95bWVudCwgU291cmNlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWRlcGxveW1lbnQnO1xuaW1wb3J0IHsgU3RyaW5nUGFyYW1ldGVyIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNzbSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCB7IExBTUJEQV9SVU5USU1FIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgQ09ORklHX0VOVl9KU09OX1BBVEggfSBmcm9tICcuL05leHRqcyc7XG5pbXBvcnQgeyBOZXh0anNCYXNlUHJvcHMgfSBmcm9tICcuL05leHRqc0Jhc2UnO1xuaW1wb3J0IHsgY3JlYXRlQXJjaGl2ZSwgTmV4dGpzQnVpbGQgfSBmcm9tICcuL05leHRqc0J1aWxkJztcbmltcG9ydCB7IGdldFMzUmVwbGFjZVZhbHVlcywgTmV4dGpzUzNFbnZSZXdyaXRlciB9IGZyb20gJy4vTmV4dGpzUzNFbnZSZXdyaXRlcic7XG5cbmV4cG9ydCB0eXBlIEVudmlyb25tZW50VmFycyA9IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cbmZ1bmN0aW9uIGdldEVudmlyb25tZW50KHByb3BzOiBOZXh0anNMYW1iZGFQcm9wcyk6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9IHtcbiAgY29uc3QgZW52aXJvbm1lbnRWYXJpYWJsZXM6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICAgIC4uLnByb3BzLmVudmlyb25tZW50LFxuICAgIC4uLnByb3BzLmxhbWJkYT8uZW52aXJvbm1lbnQsXG4gICAgLi4uKHByb3BzLm5vZGVFbnYgPyB7IE5PREVfRU5WOiBwcm9wcy5ub2RlRW52IH0gOiB7fSksXG4gIH07XG5cbiAgcmV0dXJuIGVudmlyb25tZW50VmFyaWFibGVzO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc0xhbWJkYVByb3BzIGV4dGVuZHMgTmV4dGpzQmFzZVByb3BzIHtcbiAgLyoqXG4gICAqIEJ1aWx0IG5leHRKUyBhcHBsaWNhdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IG5leHRCdWlsZDogTmV4dGpzQnVpbGQ7XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIGZ1bmN0aW9uIHByb3BlcnRpZXMuXG4gICAqL1xuICByZWFkb25seSBsYW1iZGE/OiBGdW5jdGlvbk9wdGlvbnM7XG59XG5cbi8qKlxuICogQnVpbGQgYSBsYW1iZGEgZnVuY3Rpb24gZnJvbSBhIE5leHRKUyBhcHBsaWNhdGlvbiB0byBoYW5kbGUgc2VydmVyLXNpZGUgcmVuZGVyaW5nLCBBUEkgcm91dGVzLCBhbmQgaW1hZ2Ugb3B0aW1pemF0aW9uLlxuICovXG5leHBvcnQgY2xhc3MgTmV4dEpzTGFtYmRhIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY29uZmlnQnVja2V0PzogQnVja2V0O1xuICBsYW1iZGFGdW5jdGlvbjogRnVuY3Rpb247XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE5leHRqc0xhbWJkYVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcbiAgICBjb25zdCB7IG5leHRCdWlsZCwgbGFtYmRhOiBmdW5jdGlvbk9wdGlvbnMsIGlzUGxhY2Vob2xkZXIgfSA9IHByb3BzO1xuXG4gICAgLy8gemlwIHVwIGJ1aWxkLm5leHRTZXJ2ZXJGbkRpclxuICAgIGNvbnN0IHppcE91dERpciA9IHBhdGgucmVzb2x2ZShcbiAgICAgIHByb3BzLnRlbXBCdWlsZERpclxuICAgICAgICA/IHBhdGgucmVzb2x2ZShwYXRoLmpvaW4ocHJvcHMudGVtcEJ1aWxkRGlyLCBgc3RhbmRhbG9uZWApKVxuICAgICAgICA6IGZzLm1rZHRlbXBTeW5jKHBhdGguam9pbihvcy50bXBkaXIoKSwgJ3N0YW5kYWxvbmUtJykpXG4gICAgKTtcblxuICAgIGNvbnN0IHppcEZpbGVQYXRoID0gY3JlYXRlQXJjaGl2ZSh7XG4gICAgICBkaXJlY3Rvcnk6IG5leHRCdWlsZC5uZXh0U2VydmVyRm5EaXIsXG4gICAgICB6aXBGaWxlTmFtZTogJ3NlcnZlckZuLnppcCcsXG4gICAgICB6aXBPdXREaXIsXG4gICAgICBxdWlldDogcHJvcHMucXVpZXQsXG4gICAgfSk7XG4gICAgaWYgKCF6aXBGaWxlUGF0aCkgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGFyY2hpdmUgZm9yIGxhbWJkYSBmdW5jdGlvbiBjb2RlJyk7XG5cbiAgICAvLyB1cGxvYWQgdGhlIGxhbWJkYSBwYWNrYWdlIHRvIFMzXG4gICAgY29uc3QgczNhc3NldCA9IG5ldyBzM0Fzc2V0cy5Bc3NldChzY29wZSwgJ01haW5GbkFzc2V0JywgeyBwYXRoOiB6aXBGaWxlUGF0aCB9KTtcbiAgICBjb25zdCBjb2RlID0gaXNQbGFjZWhvbGRlclxuICAgICAgPyBsYW1iZGEuQ29kZS5mcm9tSW5saW5lKFxuICAgICAgICAgIFwibW9kdWxlLmV4cG9ydHMuaGFuZGxlciA9IGFzeW5jICgpID0+IHsgcmV0dXJuIHsgc3RhdHVzQ29kZTogMjAwLCBib2R5OiAnU1NUIHBsYWNlaG9sZGVyIHNpdGUnIH0gfVwiXG4gICAgICAgIClcbiAgICAgIDogbGFtYmRhLkNvZGUuZnJvbUJ1Y2tldChzM2Fzc2V0LmJ1Y2tldCwgczNhc3NldC5zM09iamVjdEtleSk7XG5cbiAgICAvLyBidWlsZCB0aGUgbGFtYmRhIGZ1bmN0aW9uXG4gICAgY29uc3QgZW52aXJvbm1lbnQgPSBnZXRFbnZpcm9ubWVudChwcm9wcyk7XG4gICAgY29uc3QgZm4gPSBuZXcgRnVuY3Rpb24oc2NvcGUsICdTZXJ2ZXJIYW5kbGVyJywge1xuICAgICAgbWVtb3J5U2l6ZTogZnVuY3Rpb25PcHRpb25zPy5tZW1vcnlTaXplIHx8IDEwMjQsXG4gICAgICB0aW1lb3V0OiBmdW5jdGlvbk9wdGlvbnM/LnRpbWVvdXQgPz8gRHVyYXRpb24uc2Vjb25kcygxMCksXG4gICAgICBydW50aW1lOiBMQU1CREFfUlVOVElNRSxcbiAgICAgIGhhbmRsZXI6IHBhdGguam9pbignaW5kZXguaGFuZGxlcicpLFxuICAgICAgY29kZSxcbiAgICAgIGVudmlyb25tZW50LFxuICAgICAgLy8gcHJldmVudHMgXCJSZXNvbHV0aW9uIGVycm9yOiBDYW5ub3QgdXNlIHJlc291cmNlIGluIGEgY3Jvc3MtZW52aXJvbm1lbnRcbiAgICAgIC8vIGZhc2hpb24sIHRoZSByZXNvdXJjZSdzIHBoeXNpY2FsIG5hbWUgbXVzdCBiZSBleHBsaWNpdCBzZXQgb3IgdXNlXG4gICAgICAvLyBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVELlwiXG4gICAgICBmdW5jdGlvbk5hbWU6IFN0YWNrLm9mKHRoaXMpLnJlZ2lvbiAhPT0gJ3VzLWVhc3QtMScgPyBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVEIDogdW5kZWZpbmVkLFxuICAgICAgLi4uZnVuY3Rpb25PcHRpb25zLFxuICAgIH0pO1xuICAgIHRoaXMubGFtYmRhRnVuY3Rpb24gPSBmbjtcblxuICAgIC8vIHJld3JpdGUgZW52IHZhciBwbGFjZWhvbGRlcnMgaW4gc2VydmVyIGNvZGVcbiAgICBjb25zdCByZXBsYWNlbWVudFBhcmFtcyA9IHRoaXMuX2dldFJlcGxhY2VtZW50UGFyYW1zKGVudmlyb25tZW50KTtcbiAgICBpZiAoIWlzUGxhY2Vob2xkZXIgJiYgT2JqZWN0LmtleXMocmVwbGFjZW1lbnRQYXJhbXMpLmxlbmd0aCkge1xuICAgICAgLy8gcHV0IEpTT04gZmlsZSB3aXRoIGVudiB2YXIgcmVwbGFjZW1lbnRzIGluIFMzXG4gICAgICBjb25zdCBbY29uZmlnQnVja2V0LCBjb25maWdEZXBsb3ltZW50XSA9IHRoaXMuY3JlYXRlQ29uZmlnQnVja2V0KHJlcGxhY2VtZW50UGFyYW1zKTtcbiAgICAgIHRoaXMuY29uZmlnQnVja2V0ID0gY29uZmlnQnVja2V0O1xuXG4gICAgICAvLyByZXBsYWNlIGVudiB2YXIgcGxhY2Vob2xkZXJzIGluIHRoZSBsYW1iZGEgcGFja2FnZSB3aXRoIHJlc29sdmVkIHZhbHVlc1xuICAgICAgY29uc3QgcmV3cml0ZXIgPSBuZXcgTmV4dGpzUzNFbnZSZXdyaXRlcih0aGlzLCAnTGFtYmRhQ29kZVJld3JpdGVyJywge1xuICAgICAgICAuLi5wcm9wcyxcbiAgICAgICAgczNCdWNrZXQ6IHMzYXNzZXQuYnVja2V0LFxuICAgICAgICBzM2tleXM6IFtzM2Fzc2V0LnMzT2JqZWN0S2V5XSxcbiAgICAgICAgcmVwbGFjZW1lbnRDb25maWc6IHtcbiAgICAgICAgICAvLyB1c2UganNvbiBmaWxlIGluIFMzIGZvciByZXBsYWNlbWVudCB2YWx1ZXNcbiAgICAgICAgICAvLyB0aGlzIGNhbiBjb250YWluIGJhY2tlbmQgc2VjcmV0cyBzbyBiZXR0ZXIgdG8gbm90IGhhdmUgdGhlbSBpbiBjdXN0b20gcmVzb3VyY2UgbG9nc1xuICAgICAgICAgIGpzb25TM0J1Y2tldDogY29uZmlnRGVwbG95bWVudC5kZXBsb3llZEJ1Y2tldCxcbiAgICAgICAgICBqc29uUzNLZXk6IENPTkZJR19FTlZfSlNPTl9QQVRILFxuICAgICAgICB9LFxuICAgICAgICBkZWJ1ZzogdHJ1ZSwgLy8gZW5hYmxlIGZvciBtb3JlIHZlcmJvc2Ugb3V0cHV0IGZyb20gdGhlIHJld3JpdGVyIGZ1bmN0aW9uXG4gICAgICB9KTtcbiAgICAgIHJld3JpdGVyLm5vZGUuYWRkRGVwZW5kZW5jeShzM2Fzc2V0KTtcblxuICAgICAgLy8gaW4gb3JkZXIgdG8gY3JlYXRlIHRoaXMgZGVwZW5kZW5jeSwgdGhlIGxhbWJkYSBmdW5jdGlvbiBuZWVkcyB0byBiZSBhIGNoaWxkIG9mIHRoZSBjdXJyZW50IGNvbnN0cnVjdFxuICAgICAgLy8gbWVhbmluZyB3ZSBjYW4ndCBpbmhlcml0IGZyb20gRnVuY3Rpb25cbiAgICAgIGZuLm5vZGUuYWRkRGVwZW5kZW5jeShyZXdyaXRlcik7IC8vIGRvbid0IGRlcGxveSBsYW1iZGEgdW50aWwgcmV3cml0ZXIgaXMgZG9uZSAtIHdlIGFyZSBzb3J0IG9mICdpbnRlcmNlcHRpbmcnIHRoZSBkZXBsb3ltZW50IHBhY2thZ2VcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9nZXRSZXBsYWNlbWVudFBhcmFtcyhlbnY6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4pIHtcbiAgICBjb25zdCByZXBsYWNlbWVudHMgPSBnZXRTM1JlcGxhY2VWYWx1ZXMoZW52LCBmYWxzZSk7IC8vIGdldCBwbGFjZWhvbGRlciA9PiByZXBsYWNlbWVudCB2YWx1ZXNcbiAgICBjb25zdCByZXBsYWNlbWVudFBhcmFtczogRW52aXJvbm1lbnRWYXJzID0ge307IC8vIEpTT04gZmlsZSB3aXRoIHJlcGxhY2VtZW50cyB0byBiZSB1cGxvYWRlZCB0byBTM1xuICAgIE9iamVjdC5lbnRyaWVzKHJlcGxhY2VtZW50cykuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICAvLyBpcyBpdCBhIHRva2VuP1xuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybjtcbiAgICAgIGlmICghdmFsdWUgfHwgIVRva2VuLmlzVW5yZXNvbHZlZCh2YWx1ZSkpIHtcbiAgICAgICAgcmVwbGFjZW1lbnRQYXJhbXNba2V5XSA9IHZhbHVlO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIGNyZWF0ZSBwYXJhbVxuICAgICAgY29uc3QgcGFyYW0gPSBuZXcgU3RyaW5nUGFyYW1ldGVyKHRoaXMsIGBDb25maWcoJyR7a2V5fScpYCwge1xuICAgICAgICBzdHJpbmdWYWx1ZTogdmFsdWUsXG4gICAgICB9KTtcblxuICAgICAgLy8gYWRkIHRvIGVudiBKU09OXG4gICAgICByZXBsYWNlbWVudFBhcmFtc1trZXldID0gcGFyYW0uc3RyaW5nVmFsdWU7XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlcGxhY2VtZW50UGFyYW1zO1xuICB9XG5cbiAgLy8gdGhpcyBjYW4gaG9sZCBvdXIgcmVzb2x2ZWQgZW52aXJvbm1lbnQgdmFycyBmb3IgdGhlIHNlcnZlclxuICBwcm90ZWN0ZWQgY3JlYXRlQ29uZmlnQnVja2V0KHJlcGxhY2VtZW50UGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KSB7XG4gICAgLy8gd29uJ3Qgd29yayB1bnRpbCB0aGlzIGlzIGZpeGVkOiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzE5MjU3XG4gICAgY29uc3QgYnVja2V0ID0gbmV3IEJ1Y2tldCh0aGlzLCAnTmV4dGpzQ29uZmlnQnVja2V0Jywge1xuICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyB1cGxvYWQgZW52aXJvbm1lbnQgY29uZmlnIHRvIHMzXG4gICAgY29uc3QgZGVwbG95bWVudCA9IG5ldyBCdWNrZXREZXBsb3ltZW50KHRoaXMsICdFbnZKc29uRGVwbG95bWVudCcsIHtcbiAgICAgIHNvdXJjZXM6IFtcbiAgICAgICAgLy8gc2VyaWFsaXplIGFzIEpTT04gdG8gUzMgb2JqZWN0XG4gICAgICAgIFNvdXJjZS5qc29uRGF0YShDT05GSUdfRU5WX0pTT05fUEFUSCwgcmVwbGFjZW1lbnRQYXJhbXMpLFxuICAgICAgXSxcbiAgICAgIGRlc3RpbmF0aW9uQnVja2V0OiBidWNrZXQsXG4gICAgfSk7XG4gICAgcmV0dXJuIFtidWNrZXQsIGRlcGxveW1lbnRdIGFzIGNvbnN0O1xuICB9XG59XG4iXX0=