cdk-nextjs-standalone
Version:
Deploy a NextJS app to AWS using CDK and OpenNext.
109 lines • 17.9 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NextjsServer = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const node_crypto_1 = require("node:crypto");
const node_fs_1 = require("node:fs");
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
const constructs_1 = require("constructs");
const constants_1 = require("./constants");
const NextjsBucketDeployment_1 = require("./NextjsBucketDeployment");
const common_lambda_props_1 = require("./utils/common-lambda-props");
const create_archive_1 = require("./utils/create-archive");
/**
* Build a lambda function from a NextJS application to handle server-side rendering, API routes, and image optimization.
*/
class NextjsServer extends constructs_1.Construct {
get environment() {
return {
...this.props.environment,
...this.props.lambda?.environment,
CACHE_BUCKET_NAME: this.props.staticAssetBucket.bucketName,
CACHE_BUCKET_REGION: aws_cdk_lib_1.Stack.of(this.props.staticAssetBucket).region,
CACHE_BUCKET_KEY_PREFIX: constants_1.CACHE_BUCKET_KEY_PREFIX,
};
}
constructor(scope, id, props) {
super(scope, id);
this.props = props;
// must create code asset separately (typically it is implicitly created in
//`Function` construct) b/c we need to substitute unresolved env vars
const sourceAsset = this.createSourceCodeAsset();
// source and destination assets are defined separately so that source
// assets are immutable (easier debugging). Technically we could overwrite
// source asset
const destinationAsset = this.createDestinationCodeAsset();
const bucketDeployment = this.createBucketDeployment(sourceAsset, destinationAsset);
this.lambdaFunction = this.createFunction(destinationAsset);
// don't update lambda function until bucket deployment is complete
this.lambdaFunction.node.addDependency(bucketDeployment);
}
createSourceCodeAsset() {
const archivePath = (0, create_archive_1.createArchive)({
directory: this.props.nextBuild.nextServerFnDir,
quiet: this.props.quiet,
zipFileName: 'server-fn.zip',
});
const asset = new aws_s3_assets_1.Asset(this, 'SourceCodeAsset', {
path: archivePath,
...this.props.overrides?.sourceCodeAssetProps,
});
// new Asset() creates copy of zip into cdk.out/. This cleans up tmp folder
(0, node_fs_1.rmSync)(archivePath, { recursive: true });
return asset;
}
createDestinationCodeAsset() {
// create dummy directory to upload with random values so it's uploaded each time
// TODO: look into caching?
const assetsTmpDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.resolve)((0, node_os_1.tmpdir)(), 'bucket-deployment-dest-asset-'));
// this code will never run b/c we explicitly declare dependency between
// lambda function and bucket deployment.
(0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(assetsTmpDir, 'index.mjs'), `export function handler() { return '${(0, node_crypto_1.randomUUID)()}' }`);
const destinationAsset = new aws_s3_assets_1.Asset(this, 'DestinationCodeAsset', {
path: assetsTmpDir,
...this.props.overrides?.destinationCodeAssetProps,
});
(0, node_fs_1.rmSync)(assetsTmpDir, { recursive: true });
return destinationAsset;
}
createBucketDeployment(sourceAsset, destinationAsset) {
const bucketDeployment = new NextjsBucketDeployment_1.NextjsBucketDeployment(this, 'BucketDeployment', {
asset: sourceAsset,
debug: true,
destinationBucket: destinationAsset.bucket,
destinationKeyPrefix: destinationAsset.s3ObjectKey,
prune: false, // not applicable b/c zip: true
// this.props.environment is for build time, not this.environment which is for runtime
substitutionConfig: NextjsBucketDeployment_1.NextjsBucketDeployment.getSubstitutionConfig(this.props.environment || {}),
zip: true,
...this.props.overrides?.nextjsBucketDeploymentProps,
});
return bucketDeployment;
}
createFunction(asset) {
// until after the build time env vars in code zip asset are substituted
const fn = new aws_lambda_1.Function(this, 'Fn', {
...(0, common_lambda_props_1.getCommonFunctionProps)(this),
code: aws_lambda_1.Code.fromBucket(asset.bucket, asset.s3ObjectKey),
handler: 'index.handler',
description: 'Next.js Server Handler',
...this.props.lambda,
// `environment` needs to go after `this.props.lambda` b/c if
// `this.props.lambda.environment` is defined, it will override
// CACHE_* environment variables which are required
environment: { ...this.environment, ...this.props.lambda?.environment },
...this.props.overrides?.functionProps,
});
this.props.staticAssetBucket.grantReadWrite(fn);
return fn;
}
}
exports.NextjsServer = NextjsServer;
_a = JSII_RTTI_SYMBOL_1;
NextjsServer[_a] = { fqn: "cdk-nextjs-standalone.NextjsServer", version: "4.2.3" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmV4dGpzU2VydmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL05leHRqc1NlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDZDQUF5QztBQUN6QyxxQ0FBNkQ7QUFDN0QscUNBQWlDO0FBQ2pDLHlDQUFvQztBQUNwQyw2Q0FBb0M7QUFDcEMsdURBQXlFO0FBRXpFLDZEQUFrRDtBQUNsRCwyQ0FBdUM7QUFDdkMsMkNBQXNEO0FBR3RELHFFQUFrRTtBQUVsRSxxRUFBcUU7QUFDckUsMkRBQXVEO0FBc0N2RDs7R0FFRztBQUNILE1BQWEsWUFBYSxTQUFRLHNCQUFTO0lBS3pDLElBQVksV0FBVztRQUNyQixPQUFPO1lBQ0wsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVc7WUFDekIsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxXQUFXO1lBQ2pDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsVUFBVTtZQUMxRCxtQkFBbUIsRUFBRSxtQkFBSyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUMsTUFBTTtZQUNsRSx1QkFBdUIsRUFBdkIsbUNBQXVCO1NBQ3hCLENBQUM7SUFDSixDQUFDO0lBRUQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUF3QjtRQUNoRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLDJFQUEyRTtRQUMzRSxxRUFBcUU7UUFDckUsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDakQsc0VBQXNFO1FBQ3RFLDBFQUEwRTtRQUMxRSxlQUFlO1FBQ2YsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUMzRCxNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxXQUFXLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUNwRixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUM1RCxtRUFBbUU7UUFDbkUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVPLHFCQUFxQjtRQUMzQixNQUFNLFdBQVcsR0FBRyxJQUFBLDhCQUFhLEVBQUM7WUFDaEMsU0FBUyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLGVBQWU7WUFDL0MsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSztZQUN2QixXQUFXLEVBQUUsZUFBZTtTQUM3QixDQUFDLENBQUM7UUFDSCxNQUFNLEtBQUssR0FBRyxJQUFJLHFCQUFLLENBQUMsSUFBSSxFQUFFLGlCQUFpQixFQUFFO1lBQy9DLElBQUksRUFBRSxXQUFXO1lBQ2pCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsb0JBQW9CO1NBQzlDLENBQUMsQ0FBQztRQUNILDJFQUEyRTtRQUMzRSxJQUFBLGdCQUFNLEVBQUMsV0FBVyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDekMsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRU8sMEJBQTBCO1FBQ2hDLGlGQUFpRjtRQUNqRiwyQkFBMkI7UUFDM0IsTUFBTSxZQUFZLEdBQUcsSUFBQSxxQkFBVyxFQUFDLElBQUEsbUJBQU8sRUFBQyxJQUFBLGdCQUFNLEdBQUUsRUFBRSwrQkFBK0IsQ0FBQyxDQUFDLENBQUM7UUFDckYsd0VBQXdFO1FBQ3hFLHlDQUF5QztRQUN6QyxJQUFBLHVCQUFhLEVBQUMsSUFBQSxtQkFBTyxFQUFDLFlBQVksRUFBRSxXQUFXLENBQUMsRUFBRSx1Q0FBdUMsSUFBQSx3QkFBVSxHQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzVHLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxxQkFBSyxDQUFDLElBQUksRUFBRSxzQkFBc0IsRUFBRTtZQUMvRCxJQUFJLEVBQUUsWUFBWTtZQUNsQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLHlCQUF5QjtTQUNuRCxDQUFDLENBQUM7UUFDSCxJQUFBLGdCQUFNLEVBQUMsWUFBWSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUMsT0FBTyxnQkFBZ0IsQ0FBQztJQUMxQixDQUFDO0lBRU8sc0JBQXNCLENBQUMsV0FBa0IsRUFBRSxnQkFBdUI7UUFDeEUsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLCtDQUFzQixDQUFDLElBQUksRUFBRSxrQkFBa0IsRUFBRTtZQUM1RSxLQUFLLEVBQUUsV0FBVztZQUNsQixLQUFLLEVBQUUsSUFBSTtZQUNYLGlCQUFpQixFQUFFLGdCQUFnQixDQUFDLE1BQU07WUFDMUMsb0JBQW9CLEVBQUUsZ0JBQWdCLENBQUMsV0FBVztZQUNsRCxLQUFLLEVBQUUsS0FBSyxFQUFFLCtCQUErQjtZQUM3QyxzRkFBc0Y7WUFDdEYsa0JBQWtCLEVBQUUsK0NBQXNCLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLElBQUksRUFBRSxDQUFDO1lBQzlGLEdBQUcsRUFBRSxJQUFJO1lBQ1QsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSwyQkFBMkI7U0FDckQsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxnQkFBZ0IsQ0FBQztJQUMxQixDQUFDO0lBRU8sY0FBYyxDQUFDLEtBQVk7UUFDakMsd0VBQXdFO1FBQ3hFLE1BQU0sRUFBRSxHQUFHLElBQUkscUJBQVEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFO1lBQ2xDLEdBQUcsSUFBQSw0Q0FBc0IsRUFBQyxJQUFJLENBQUM7WUFDL0IsSUFBSSxFQUFFLGlCQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLFdBQVcsQ0FBQztZQUN0RCxPQUFPLEVBQUUsZUFBZTtZQUN4QixXQUFXLEVBQUUsd0JBQXdCO1lBQ3JDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNO1lBQ3BCLDZEQUE2RDtZQUM3RCwrREFBK0Q7WUFDL0QsbURBQW1EO1lBQ25ELFdBQVcsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFdBQVcsRUFBRTtZQUN2RSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLGFBQWE7U0FDdkMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFaEQsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDOztBQTlGSCxvQ0ErRkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0IHsgbWtkdGVtcFN5bmMsIHJtU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyByZXNvbHZlIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ29kZSwgRnVuY3Rpb24sIEZ1bmN0aW9uT3B0aW9ucyB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgQnVja2V0LCBJQnVja2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCB7IEFzc2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWFzc2V0cyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IENBQ0hFX0JVQ0tFVF9LRVlfUFJFRklYIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgT3B0aW9uYWxBc3NldFByb3BzLCBPcHRpb25hbEZ1bmN0aW9uUHJvcHMsIE9wdGlvbmFsTmV4dGpzQnVja2V0RGVwbG95bWVudFByb3BzIH0gZnJvbSAnLi9nZW5lcmF0ZWQtc3RydWN0cyc7XG5pbXBvcnQgeyBOZXh0anNQcm9wcyB9IGZyb20gJy4vTmV4dGpzJztcbmltcG9ydCB7IE5leHRqc0J1Y2tldERlcGxveW1lbnQgfSBmcm9tICcuL05leHRqc0J1Y2tldERlcGxveW1lbnQnO1xuaW1wb3J0IHsgTmV4dGpzQnVpbGQgfSBmcm9tICcuL05leHRqc0J1aWxkJztcbmltcG9ydCB7IGdldENvbW1vbkZ1bmN0aW9uUHJvcHMgfSBmcm9tICcuL3V0aWxzL2NvbW1vbi1sYW1iZGEtcHJvcHMnO1xuaW1wb3J0IHsgY3JlYXRlQXJjaGl2ZSB9IGZyb20gJy4vdXRpbHMvY3JlYXRlLWFyY2hpdmUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5leHRqc1NlcnZlck92ZXJyaWRlcyB7XG4gIHJlYWRvbmx5IHNvdXJjZUNvZGVBc3NldFByb3BzPzogT3B0aW9uYWxBc3NldFByb3BzO1xuICByZWFkb25seSBkZXN0aW5hdGlvbkNvZGVBc3NldFByb3BzPzogT3B0aW9uYWxBc3NldFByb3BzO1xuICByZWFkb25seSBmdW5jdGlvblByb3BzPzogT3B0aW9uYWxGdW5jdGlvblByb3BzO1xuICByZWFkb25seSBuZXh0anNCdWNrZXREZXBsb3ltZW50UHJvcHM/OiBPcHRpb25hbE5leHRqc0J1Y2tldERlcGxveW1lbnRQcm9wcztcbn1cblxuZXhwb3J0IHR5cGUgRW52aXJvbm1lbnRWYXJzID0gUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcblxuZXhwb3J0IGludGVyZmFjZSBOZXh0anNTZXJ2ZXJQcm9wcyB7XG4gIC8qKlxuICAgKiBAc2VlIHtAbGluayBOZXh0anNQcm9wcy5lbnZpcm9ubWVudH1cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50PzogTmV4dGpzUHJvcHNbJ2Vudmlyb25tZW50J107XG4gIC8qKlxuICAgKiBPdmVycmlkZSBmdW5jdGlvbiBwcm9wZXJ0aWVzLlxuICAgKi9cbiAgcmVhZG9ubHkgbGFtYmRhPzogRnVuY3Rpb25PcHRpb25zO1xuICAvKipcbiAgICogQHNlZSB7QGxpbmsgTmV4dGpzQnVpbGR9XG4gICAqL1xuICByZWFkb25seSBuZXh0QnVpbGQ6IE5leHRqc0J1aWxkO1xuICAvKipcbiAgICogT3ZlcnJpZGUgcHJvcHMgZm9yIGV2ZXJ5IGNvbnN0cnVjdC5cbiAgICovXG4gIHJlYWRvbmx5IG92ZXJyaWRlcz86IE5leHRqc1NlcnZlck92ZXJyaWRlcztcbiAgLyoqXG4gICAqIEBzZWUge0BsaW5rIE5leHRqc1Byb3BzLnF1aWV0fVxuICAgKi9cbiAgcmVhZG9ubHkgcXVpZXQ/OiBOZXh0anNQcm9wc1sncXVpZXQnXTtcbiAgLyoqXG4gICAqIFN0YXRpYyBhc3NldCBidWNrZXQuIEZ1bmN0aW9uIG5lZWRzIGJ1Y2tldCB0byByZWFkIGZyb20gY2FjaGUuXG4gICAqL1xuICByZWFkb25seSBzdGF0aWNBc3NldEJ1Y2tldDogSUJ1Y2tldDtcbn1cblxuLyoqXG4gKiBCdWlsZCBhIGxhbWJkYSBmdW5jdGlvbiBmcm9tIGEgTmV4dEpTIGFwcGxpY2F0aW9uIHRvIGhhbmRsZSBzZXJ2ZXItc2lkZSByZW5kZXJpbmcsIEFQSSByb3V0ZXMsIGFuZCBpbWFnZSBvcHRpbWl6YXRpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBOZXh0anNTZXJ2ZXIgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25maWdCdWNrZXQ/OiBCdWNrZXQ7XG4gIGxhbWJkYUZ1bmN0aW9uOiBGdW5jdGlvbjtcblxuICBwcml2YXRlIHByb3BzOiBOZXh0anNTZXJ2ZXJQcm9wcztcbiAgcHJpdmF0ZSBnZXQgZW52aXJvbm1lbnQoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnRoaXMucHJvcHMuZW52aXJvbm1lbnQsXG4gICAgICAuLi50aGlzLnByb3BzLmxhbWJkYT8uZW52aXJvbm1lbnQsXG4gICAgICBDQUNIRV9CVUNLRVRfTkFNRTogdGhpcy5wcm9wcy5zdGF0aWNBc3NldEJ1Y2tldC5idWNrZXROYW1lLFxuICAgICAgQ0FDSEVfQlVDS0VUX1JFR0lPTjogU3RhY2sub2YodGhpcy5wcm9wcy5zdGF0aWNBc3NldEJ1Y2tldCkucmVnaW9uLFxuICAgICAgQ0FDSEVfQlVDS0VUX0tFWV9QUkVGSVgsXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXh0anNTZXJ2ZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuXG4gICAgLy8gbXVzdCBjcmVhdGUgY29kZSBhc3NldCBzZXBhcmF0ZWx5ICh0eXBpY2FsbHkgaXQgaXMgaW1wbGljaXRseSBjcmVhdGVkIGluXG4gICAgLy9gRnVuY3Rpb25gIGNvbnN0cnVjdCkgYi9jIHdlIG5lZWQgdG8gc3Vic3RpdHV0ZSB1bnJlc29sdmVkIGVudiB2YXJzXG4gICAgY29uc3Qgc291cmNlQXNzZXQgPSB0aGlzLmNyZWF0ZVNvdXJjZUNvZGVBc3NldCgpO1xuICAgIC8vIHNvdXJjZSBhbmQgZGVzdGluYXRpb24gYXNzZXRzIGFyZSBkZWZpbmVkIHNlcGFyYXRlbHkgc28gdGhhdCBzb3VyY2VcbiAgICAvLyBhc3NldHMgYXJlIGltbXV0YWJsZSAoZWFzaWVyIGRlYnVnZ2luZykuIFRlY2huaWNhbGx5IHdlIGNvdWxkIG92ZXJ3cml0ZVxuICAgIC8vIHNvdXJjZSBhc3NldFxuICAgIGNvbnN0IGRlc3RpbmF0aW9uQXNzZXQgPSB0aGlzLmNyZWF0ZURlc3RpbmF0aW9uQ29kZUFzc2V0KCk7XG4gICAgY29uc3QgYnVja2V0RGVwbG95bWVudCA9IHRoaXMuY3JlYXRlQnVja2V0RGVwbG95bWVudChzb3VyY2VBc3NldCwgZGVzdGluYXRpb25Bc3NldCk7XG4gICAgdGhpcy5sYW1iZGFGdW5jdGlvbiA9IHRoaXMuY3JlYXRlRnVuY3Rpb24oZGVzdGluYXRpb25Bc3NldCk7XG4gICAgLy8gZG9uJ3QgdXBkYXRlIGxhbWJkYSBmdW5jdGlvbiB1bnRpbCBidWNrZXQgZGVwbG95bWVudCBpcyBjb21wbGV0ZVxuICAgIHRoaXMubGFtYmRhRnVuY3Rpb24ubm9kZS5hZGREZXBlbmRlbmN5KGJ1Y2tldERlcGxveW1lbnQpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVTb3VyY2VDb2RlQXNzZXQoKSB7XG4gICAgY29uc3QgYXJjaGl2ZVBhdGggPSBjcmVhdGVBcmNoaXZlKHtcbiAgICAgIGRpcmVjdG9yeTogdGhpcy5wcm9wcy5uZXh0QnVpbGQubmV4dFNlcnZlckZuRGlyLFxuICAgICAgcXVpZXQ6IHRoaXMucHJvcHMucXVpZXQsXG4gICAgICB6aXBGaWxlTmFtZTogJ3NlcnZlci1mbi56aXAnLFxuICAgIH0pO1xuICAgIGNvbnN0IGFzc2V0ID0gbmV3IEFzc2V0KHRoaXMsICdTb3VyY2VDb2RlQXNzZXQnLCB7XG4gICAgICBwYXRoOiBhcmNoaXZlUGF0aCxcbiAgICAgIC4uLnRoaXMucHJvcHMub3ZlcnJpZGVzPy5zb3VyY2VDb2RlQXNzZXRQcm9wcyxcbiAgICB9KTtcbiAgICAvLyBuZXcgQXNzZXQoKSBjcmVhdGVzIGNvcHkgb2YgemlwIGludG8gY2RrLm91dC8uIFRoaXMgY2xlYW5zIHVwIHRtcCBmb2xkZXJcbiAgICBybVN5bmMoYXJjaGl2ZVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIHJldHVybiBhc3NldDtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlRGVzdGluYXRpb25Db2RlQXNzZXQoKSB7XG4gICAgLy8gY3JlYXRlIGR1bW15IGRpcmVjdG9yeSB0byB1cGxvYWQgd2l0aCByYW5kb20gdmFsdWVzIHNvIGl0J3MgdXBsb2FkZWQgZWFjaCB0aW1lXG4gICAgLy8gVE9ETzogbG9vayBpbnRvIGNhY2hpbmc/XG4gICAgY29uc3QgYXNzZXRzVG1wRGlyID0gbWtkdGVtcFN5bmMocmVzb2x2ZSh0bXBkaXIoKSwgJ2J1Y2tldC1kZXBsb3ltZW50LWRlc3QtYXNzZXQtJykpO1xuICAgIC8vIHRoaXMgY29kZSB3aWxsIG5ldmVyIHJ1biBiL2Mgd2UgZXhwbGljaXRseSBkZWNsYXJlIGRlcGVuZGVuY3kgYmV0d2VlblxuICAgIC8vIGxhbWJkYSBmdW5jdGlvbiBhbmQgYnVja2V0IGRlcGxveW1lbnQuXG4gICAgd3JpdGVGaWxlU3luYyhyZXNvbHZlKGFzc2V0c1RtcERpciwgJ2luZGV4Lm1qcycpLCBgZXhwb3J0IGZ1bmN0aW9uIGhhbmRsZXIoKSB7IHJldHVybiAnJHtyYW5kb21VVUlEKCl9JyB9YCk7XG4gICAgY29uc3QgZGVzdGluYXRpb25Bc3NldCA9IG5ldyBBc3NldCh0aGlzLCAnRGVzdGluYXRpb25Db2RlQXNzZXQnLCB7XG4gICAgICBwYXRoOiBhc3NldHNUbXBEaXIsXG4gICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8uZGVzdGluYXRpb25Db2RlQXNzZXRQcm9wcyxcbiAgICB9KTtcbiAgICBybVN5bmMoYXNzZXRzVG1wRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICByZXR1cm4gZGVzdGluYXRpb25Bc3NldDtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQnVja2V0RGVwbG95bWVudChzb3VyY2VBc3NldDogQXNzZXQsIGRlc3RpbmF0aW9uQXNzZXQ6IEFzc2V0KSB7XG4gICAgY29uc3QgYnVja2V0RGVwbG95bWVudCA9IG5ldyBOZXh0anNCdWNrZXREZXBsb3ltZW50KHRoaXMsICdCdWNrZXREZXBsb3ltZW50Jywge1xuICAgICAgYXNzZXQ6IHNvdXJjZUFzc2V0LFxuICAgICAgZGVidWc6IHRydWUsXG4gICAgICBkZXN0aW5hdGlvbkJ1Y2tldDogZGVzdGluYXRpb25Bc3NldC5idWNrZXQsXG4gICAgICBkZXN0aW5hdGlvbktleVByZWZpeDogZGVzdGluYXRpb25Bc3NldC5zM09iamVjdEtleSxcbiAgICAgIHBydW5lOiBmYWxzZSwgLy8gbm90IGFwcGxpY2FibGUgYi9jIHppcDogdHJ1ZVxuICAgICAgLy8gdGhpcy5wcm9wcy5lbnZpcm9ubWVudCBpcyBmb3IgYnVpbGQgdGltZSwgbm90IHRoaXMuZW52aXJvbm1lbnQgd2hpY2ggaXMgZm9yIHJ1bnRpbWVcbiAgICAgIHN1YnN0aXR1dGlvbkNvbmZpZzogTmV4dGpzQnVja2V0RGVwbG95bWVudC5nZXRTdWJzdGl0dXRpb25Db25maWcodGhpcy5wcm9wcy5lbnZpcm9ubWVudCB8fCB7fSksXG4gICAgICB6aXA6IHRydWUsXG4gICAgICAuLi50aGlzLnByb3BzLm92ZXJyaWRlcz8ubmV4dGpzQnVja2V0RGVwbG95bWVudFByb3BzLFxuICAgIH0pO1xuICAgIHJldHVybiBidWNrZXREZXBsb3ltZW50O1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVGdW5jdGlvbihhc3NldDogQXNzZXQpIHtcbiAgICAvLyB1bnRpbCBhZnRlciB0aGUgYnVpbGQgdGltZSBlbnYgdmFycyBpbiBjb2RlIHppcCBhc3NldCBhcmUgc3Vic3RpdHV0ZWRcbiAgICBjb25zdCBmbiA9IG5ldyBGdW5jdGlvbih0aGlzLCAnRm4nLCB7XG4gICAgICAuLi5nZXRDb21tb25GdW5jdGlvblByb3BzKHRoaXMpLFxuICAgICAgY29kZTogQ29kZS5mcm9tQnVja2V0KGFzc2V0LmJ1Y2tldCwgYXNzZXQuczNPYmplY3RLZXkpLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdOZXh0LmpzIFNlcnZlciBIYW5kbGVyJyxcbiAgICAgIC4uLnRoaXMucHJvcHMubGFtYmRhLFxuICAgICAgLy8gYGVudmlyb25tZW50YCBuZWVkcyB0byBnbyBhZnRlciBgdGhpcy5wcm9wcy5sYW1iZGFgIGIvYyBpZlxuICAgICAgLy8gYHRoaXMucHJvcHMubGFtYmRhLmVudmlyb25tZW50YCBpcyBkZWZpbmVkLCBpdCB3aWxsIG92ZXJyaWRlXG4gICAgICAvLyBDQUNIRV8qIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aGljaCBhcmUgcmVxdWlyZWRcbiAgICAgIGVudmlyb25tZW50OiB7IC4uLnRoaXMuZW52aXJvbm1lbnQsIC4uLnRoaXMucHJvcHMubGFtYmRhPy5lbnZpcm9ubWVudCB9LFxuICAgICAgLi4udGhpcy5wcm9wcy5vdmVycmlkZXM/LmZ1bmN0aW9uUHJvcHMsXG4gICAgfSk7XG4gICAgdGhpcy5wcm9wcy5zdGF0aWNBc3NldEJ1Y2tldC5ncmFudFJlYWRXcml0ZShmbik7XG5cbiAgICByZXR1cm4gZm47XG4gIH1cbn1cbiJdfQ==