cdk-nuxt 0.3.12 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,7 +31,7 @@ class NuxtAppStack extends aws_cdk_lib_1.Stack {
31
31
  this.cdnAccessIdentity = this.createCdnAccessIdentity();
32
32
  this.staticAssetsBucket = this.createStaticAssetsBucket();
33
33
  this.lambdaFunction = this.createLambdaFunction();
34
- this.apiGateway = this.createApiGateway();
34
+ this.apiGateway = this.createApiGateway(props);
35
35
  this.cdn = this.createCloudFrontDistribution(props);
36
36
  this.configureDeployments();
37
37
  this.createDnsRecords(props);
@@ -115,15 +115,25 @@ class NuxtAppStack extends aws_cdk_lib_1.Stack {
115
115
  *
116
116
  * @private
117
117
  */
118
- createApiGateway() {
119
- const lambdaIntegration = new aws_apigatewayv2_integrations_alpha_1.HttpLambdaIntegration(`${this.resourceIdPrefix}-lambda-integration`, this.lambdaFunction);
118
+ createApiGateway(props) {
120
119
  const apiName = `${this.resourceIdPrefix}-api`;
120
+ const lambdaIntegration = new aws_apigatewayv2_integrations_alpha_1.HttpLambdaIntegration(`${this.resourceIdPrefix}-lambda-integration`, this.lambdaFunction);
121
+ // We want the API gateway to be accessible by the custom domain name.
122
+ // Even though we access the gateway via Cloudfront (for auto http to https redirects), this is required
123
+ // to be able to redirect the original 'Host' header to our Nuxt application, if requested.
124
+ const domainName = new aws_apigatewayv2_alpha_1.DomainName(this, `${this.resourceIdPrefix}-api-domain`, {
125
+ domainName: props.domain,
126
+ certificate: this.tlsCertificate
127
+ });
121
128
  const apiGateway = new aws_apigatewayv2_alpha_1.HttpApi(this, apiName, {
122
129
  apiName,
123
130
  description: `Connects the ${this.resourceIdPrefix} cloudfront distribution with the ${this.resourceIdPrefix} lambda function to make it publicly available.`,
124
131
  // The app does not allow any cross-origin access by purpose: the app should not be embeddable anywhere
125
132
  corsPreflight: undefined,
126
133
  defaultIntegration: lambdaIntegration,
134
+ defaultDomainMapping: {
135
+ domainName: domainName
136
+ }
127
137
  });
128
138
  apiGateway.addRoutes({
129
139
  integration: lambdaIntegration,
@@ -179,10 +189,12 @@ class NuxtAppStack extends aws_cdk_lib_1.Stack {
179
189
  * is cached, one would expect, that anything would/could be forwarded, but anyway...
180
190
  */
181
191
  createSsrCachePolicy() {
182
- // The headers to make accessible in our Nuxt app code
192
+ // The headers to make accessible in our Nuxt app code.
193
+ // There is no 'CacheHeaderBehavior.all()' option, so we have to explicitly define them.
183
194
  const headers = [
184
195
  'User-Agent',
185
- 'Authorization', // For authorization
196
+ 'Authorization',
197
+ 'Host' // To access the domain name on SSR requests
186
198
  ];
187
199
  return new aws_cloudfront_1.CachePolicy(this, `${this.resourceIdPrefix}-cache-policy`, {
188
200
  cachePolicyName: `${this.resourceIdPrefix}-cdn-cache-policy`,
@@ -305,4 +317,4 @@ class NuxtAppStack extends aws_cdk_lib_1.Stack {
305
317
  }
306
318
  }
307
319
  exports.NuxtAppStack = NuxtAppStack;
308
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1hcHAtc3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJudXh0LWFwcC1zdGFjay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBMkQ7QUFFM0QsK0VBQTZFO0FBQzdFLCtEQVNvQztBQUNwQyx1REFBMkY7QUFDM0YsK0NBQTJGO0FBQzNGLHlEQUFtRztBQUNuRyxxRUFBbUc7QUFDbkcsK0VBQXdFO0FBQ3hFLHlFQUFpRTtBQUNqRSxpRkFBK0Q7QUFDL0QsbURBQW1EO0FBQ25ELHNHQUFxRjtBQUNyRiw0RUFBd0Q7QUFDeEQscUVBQXlGO0FBRXpGLHlCQUF5QjtBQUN6Qix1REFBc0Q7QUFDdEQsdUVBQThEO0FBaUM5RDs7R0FFRztBQUNILE1BQWEsWUFBYSxTQUFRLG1CQUFLO0lBaUVyQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXdCO1FBQ2hFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXhCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLE9BQU8sSUFBSSxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDakYsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUEscURBQTRCLEVBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUN4RCxJQUFJLENBQUMsa0JBQWtCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDMUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENB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QyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssY0FBYztRQUNwQixJQUFJLGlCQUFJLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixjQUFjLEVBQUU7WUFDckQsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixTQUFTO1lBQzNDLFdBQVcsRUFBRSxvQ0FBb0MsSUFBSSxDQUFDLGdCQUFnQix1Q0FBdUM7WUFDN0csT0FBTyxFQUFFLElBQUk7WUFDYixRQUFRLEVBQUUscUJBQVEsQ0FBQyxJQUFJLENBQUMsc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDNUMsT0FBTyxFQUFFLENBQUMsSUFBSSxtQ0FBYyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztTQUNuRCxDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFyWEQsb0NBcVhDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtEdXJhdGlvbiwgUmVtb3ZhbFBvbGljeSwgU3RhY2t9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHtDZXJ0aWZpY2F0ZSwgSUNlcnRpZmljYXRlfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNlcnRpZmljYXRlbWFuYWdlclwiO1xuaW1wb3J0IHtcbiAgQWxsb3dlZE1ldGhvZHMsXG4gIEJlaGF2aW9yT3B0aW9ucywgQ2FjaGVDb29raWVCZWhhdmlvcixcbiAgQ2FjaGVkTWV0aG9kcywgQ2FjaGVIZWFkZXJCZWhhdmlvcixcbiAgQ2FjaGVQb2xpY3ksIENhY2hlUXVlcnlTdHJpbmdCZWhhdmlvcixcbiAgRGlzdHJpYnV0aW9uLCBJQ2FjaGVQb2xpY3ksXG4gIElPcmlnaW5BY2Nlc3NJZGVudGl0eSwgT3JpZ2luQWNjZXNzSWRlbnRpdHksIE9yaWdpblByb3RvY29sUG9saWN5LCBQcmljZUNsYXNzLFxuICBTZWN1cml0eVBvbGljeVByb3RvY29sLFxuICBWaWV3ZXJQcm90b2NvbFBvbGljeVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnRcIjtcbmltcG9ydCB7QXJjaGl0ZWN0dXJlLCBDb2RlLCBMYXllclZlcnNpb24sIFJ1bnRpbWUsIEZ1bmN0aW9ufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHtCbG9ja1B1YmxpY0FjY2VzcywgQnVja2V0LCBCdWNrZXRBY2Nlc3NDb250cm9sLCBJQnVja2V0fSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzXCI7XG5pbXBvcnQge0FSZWNvcmQsIEFhYWFSZWNvcmQsIEhvc3RlZFpvbmUsIElIb3N0ZWRab25lLCBSZWNvcmRUYXJnZXR9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1M1wiO1xuaW1wb3J0IHtCdWNrZXREZXBsb3ltZW50LCBDYWNoZUNvbnRyb2wsIFNvdXJjZSwgU3RvcmFnZUNsYXNzfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzLWRlcGxveW1lbnRcIjtcbmltcG9ydCB7SHR0cE9yaWdpbiwgUzNPcmlnaW59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udC1vcmlnaW5zXCI7XG5pbXBvcnQge0Nsb3VkRnJvbnRUYXJnZXR9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzXCI7XG5pbXBvcnQge0h0dHBNZXRob2R9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc3RlcGZ1bmN0aW9ucy10YXNrc1wiO1xuaW1wb3J0IHtSZXRlbnRpb25EYXlzfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxvZ3NcIjtcbmltcG9ydCB7IEh0dHBMYW1iZGFJbnRlZ3JhdGlvbiB9IGZyb20gJ0Bhd3MtY2RrL2F3cy1hcGlnYXRld2F5djItaW50ZWdyYXRpb25zLWFscGhhJztcbmltcG9ydCB7SHR0cEFwaX0gZnJvbSBcIkBhd3MtY2RrL2F3cy1hcGlnYXRld2F5djItYWxwaGFcIjtcbmltcG9ydCB7Z2V0TnV4dEFwcFN0YXRpY0Fzc2V0Q29uZmlncywgU3RhdGljQXNzZXRDb25maWd9IGZyb20gXCIuL251eHQtYXBwLXN0YXRpYy1hc3NldHNcIjtcbmltcG9ydCB7QXBwU3RhY2tQcm9wc30gZnJvbSBcIi4vYXBwLXN0YWNrLXByb3BzXCI7XG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7UnVsZSwgU2NoZWR1bGV9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZXZlbnRzXCI7XG5pbXBvcnQge0xhbWJkYUZ1bmN0aW9ufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWV2ZW50cy10YXJnZXRzXCI7XG5pbXBvcnQge051eHRDb25maWd9IGZyb20gXCIuL251eHQtY29uZmlnXCI7XG5cbi8qKlxuICogRGVmaW5lcyB0aGUgcHJvcHMgcmVxdWlyZWQgZm9yIHRoZSB7QHNlZSBOdXh0QXBwU3RhY2t9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE51eHRBcHBTdGFja1Byb3BzIGV4dGVuZHMgQXBwU3RhY2tQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgZG9tYWluICh3aXRob3V0IHRoZSBwcm90b2NvbCkgYXQgd2hpY2ggdGhlIE51eHQgYXBwIHNoYWxsIGJlIHB1YmxpY2x5IGF2YWlsYWJsZS5cbiAgICogQSBETlMgcmVjb3JkIHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGluIFJvdXRlNTMgZm9yIHRoZSBkb21haW4uXG4gICAqIFRoaXMgYWxzbyBzdXBwb3J0cyBzdWJkb21haW5zLlxuICAgKiBFeGFtcGxlczogXCJleGFtcGxlLmNvbVwiLCBcInN1Yi5leGFtcGxlLmNvbVwiXG4gICAqL1xuICByZWFkb25seSBkb21haW46IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGlkIG9mIHRoZSBob3N0ZWQgem9uZSB0byBjcmVhdGUgYSBETlMgcmVjb3JkIGZvciB0aGUgc3BlY2lmaWVkIGRvbWFpbi5cbiAgICovXG4gIHJlYWRvbmx5IGhvc3RlZFpvbmVJZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSBjZXJ0aWZpY2F0ZSB0byB1c2UgZm9yIHRoZSBOdXh0IGFwcCB0byBtYWtlIGl0IGFjY2Vzc2libGUgdmlhIEhUVFBTLlxuICAgKiBUaGUgY2VydGlmaWNhdGUgbXVzdCBiZSBpc3N1ZWQgZm9yIHRoZSBzcGVjaWZpZWQgZG9tYWluIGluIHVzLWVhc3QtMSAoZ2xvYmFsKSByZWdhcmRsZXNzIG9mIHRoZVxuICAgKiByZWdpb24gdXNlZCBmb3IgdGhlIE51eHQgYXBwIGl0c2VsZi5cbiAgICovXG4gIHJlYWRvbmx5IGdsb2JhbFRsc0NlcnRpZmljYXRlQXJuOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBudXh0LmNvbmZpZy5qcyBvZiB0aGUgTnV4dCBhcHAuXG4gICAqL1xuICByZWFkb25seSBudXh0Q29uZmlnOiBOdXh0Q29uZmlnO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBsYW1iZGEgZnVuY3Rpb24gdGhhdCByZW5kZXJzIHRoZSBOdXh0IGFwcCBhbmQgaXMgcHVibGljbHkgcmVhY2hhYmxlIHZpYSBhIHNwZWNpZmllZCBkb21haW4uXG4gKi9cbmV4cG9ydCBjbGFzcyBOdXh0QXBwU3RhY2sgZXh0ZW5kcyBTdGFjayB7XG5cbiAgLyoqXG4gICAqIFRoZSBpZGVudGlmaWVyIHByZWZpeCBvZiB0aGUgcmVzb3VyY2VzIGNyZWF0ZWQgYnkgdGhlIHN0YWNrLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSByZXNvdXJjZUlkUHJlZml4OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBpZGVudGlmaWVyIGZvciB0aGUgY3VycmVudCBkZXBsb3ltZW50IHRoYXQgaXMgdXNlZCBhcyBTMyBmb2xkZXIgbmFtZVxuICAgKiB0byBzdG9yZSB0aGUgc3RhdGljIGFzc2V0cyBvZiB0aGUgTnV4dCBhcHAuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGRlcGxveW1lbnRSZXZpc2lvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgY2VydGlmaWNhdGUgdG8gdXNlIGZvciB0aGUgTnV4dCBhcHAgdG8gbWFrZSBpdCBhY2Nlc3NpYmxlIHZpYSBIVFRQUy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgdGxzQ2VydGlmaWNhdGU6IElDZXJ0aWZpY2F0ZTtcblxuICAvKipcbiAgICogVGhlIGlkZW50aXR5IHRvIHVzZSBmb3IgYWNjZXNzaW5nIHRoZSBkZXBsb3ltZW50IGFzc2V0cyBvbiBTMy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY2RuQWNjZXNzSWRlbnRpdHk6IElPcmlnaW5BY2Nlc3NJZGVudGl0eTtcblxuICAvKipcbiAgICogVGhlIFMzIGJ1Y2tldCB3aGVyZSB0aGUgZGVwbG95bWVudCBhc3NldHMgZ2V0cyBzdG9yZWQuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljQXNzZXRzQnVja2V0OiBJQnVja2V0O1xuXG4gIC8qKlxuICAgKiBUaGUgbGFtYmRhIGZ1bmN0aW9uIHRvIHJlbmRlciB0aGUgTnV4dCBhcHAgb24gdGhlIHNlcnZlciBzaWRlLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsYW1iZGFGdW5jdGlvbjogRnVuY3Rpb247XG5cbiAgLyoqXG4gICAqIFRoZSBBUEkgZ2F0ZXdheSB0byBtYWtlIHRoZSBsYW1iZGEgZnVuY3Rpb24gdG8gcmVuZGVyIHRoZSBOdXh0IGFwcCBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGFwaUdhdGV3YXk6IEh0dHBBcGk7XG5cbiAgLyoqXG4gICAqIFRoZSBjb25maWdzIGZvciB0aGUgc3RhdGljIGFzc2V0cyBvZiB0aGUgTnV4dCBhcHAgdGhhdCBzaGFsbCBiZSBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHN0YXRpY0Fzc2V0Q29uZmlnczogU3RhdGljQXNzZXRDb25maWdbXTtcblxuICAvKipcbiAgICogVGhlIGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uIHRvIHJvdXRlIGluY29taW5nIHJlcXVlc3RzIHRvIHRoZSBOdXh0IGxhbWJkYSBmdW5jdGlvbiAodmlhIHRoZSBBUEkgZ2F0ZXdheSlcbiAgICogb3IgdGhlIFMzIGFzc2V0cyBmb2xkZXIgKHdpdGggY2FjaGluZykuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGNkbjogRGlzdHJpYnV0aW9uO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOdXh0QXBwU3RhY2tQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuXG4gICAgdGhpcy5yZXNvdXJjZUlkUHJlZml4ID0gYCR7cHJvcHMucHJvamVjdH0tJHtwcm9wcy5zZXJ2aWNlfS0ke3Byb3BzLmVudmlyb25tZW50fWA7XG4gICAgdGhpcy5kZXBsb3ltZW50UmV2aXNpb24gPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4gICAgdGhpcy5zdGF0aWNBc3NldENvbmZpZ3MgPSBnZXROdXh0QXBwU3RhdGljQXNzZXRDb25maWdzKHByb3BzLm51eHRDb25maWcpO1xuICAgIHRoaXMudGxzQ2VydGlmaWNhdGUgPSB0aGlzLmZpbmRUbHNDZXJ0aWZpY2F0ZShwcm9wcyk7XG4gICAgdGhpcy5jZG5BY2Nlc3NJZGVudGl0eSA9IHRoaXMuY3JlYXRlQ2RuQWNjZXNzSWRlbnRpdHkoKTtcbiAgICB0aGlzLnN0YXRpY0Fzc2V0c0J1Y2tldCA9IHRoaXMuY3JlYXRlU3RhdGljQXNzZXRzQnVja2V0KCk7XG4gICAgdGhpcy5sYW1iZGFGdW5jdGlvbiA9IHRoaXMuY3JlYXRlTGFtYmRhRnVuY3Rpb24oKTtcbiAgICB0aGlzLmFwaUdhdGV3YXkgPSB0aGlzLmNyZWF0ZUFwaUdhdGV3YXkoKTtcbiAgICB0aGlzLmNkbiA9IHRoaXMuY3JlYXRlQ2xvdWRGcm9udERpc3RyaWJ1dGlvbihwcm9wcyk7XG4gICAgdGhpcy5jb25maWd1cmVEZXBsb3ltZW50cygpO1xuICAgIHRoaXMuY3JlYXRlRG5zUmVjb3Jkcyhwcm9wcyk7XG4gICAgdGhpcy5jcmVhdGVQaW5nUnVsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmRzIHRoZSBjZXJ0aWZpY2F0ZSB0byB1c2UgZm9yIHByb3ZpZGluZyBIVFRQUyByZXF1ZXN0cyB0byBvdXIgTnV4dCBhcHAuXG4gICAqXG4gICAqIEBwYXJhbSBwcm9wc1xuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBmaW5kVGxzQ2VydGlmaWNhdGUocHJvcHM6IE51eHRBcHBTdGFja1Byb3BzKTogSUNlcnRpZmljYXRlIHtcbiAgICByZXR1cm4gQ2VydGlmaWNhdGUuZnJvbUNlcnRpZmljYXRlQXJuKHRoaXMsIGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tdGxzLWNlcnRpZmljYXRlYCwgcHJvcHMuZ2xvYmFsVGxzQ2VydGlmaWNhdGVBcm4pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgdGhlIGlkZW50aXR5IHRvIGFjY2VzcyBvdXIgUzMgZGVwbG95bWVudCBhc3NldCBmaWxlcyB2aWEgdGhlIGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVDZG5BY2Nlc3NJZGVudGl0eSgpOiBJT3JpZ2luQWNjZXNzSWRlbnRpdHkge1xuICAgIGNvbnN0IG9yaWdpbkFjY2Vzc0lkZW50aXR5TmFtZSA9IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tY2RuLXMzLWFjY2Vzc2A7XG4gICAgcmV0dXJuIG5ldyBPcmlnaW5BY2Nlc3NJZGVudGl0eSh0aGlzLCBvcmlnaW5BY2Nlc3NJZGVudGl0eU5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgdGhlIGJ1Y2tldCB0byBzdG9yZSB0aGUgc3RhdGljIGRlcGxveW1lbnQgYXNzZXQgZmlsZXMgb2YgdGhlIE51eHQgYXBwLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVTdGF0aWNBc3NldHNCdWNrZXQoKTogSUJ1Y2tldCB7XG4gICAgY29uc3QgYnVja2V0TmFtZSA9IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tYXNzZXRzYDtcbiAgICBjb25zdCBidWNrZXQgPSBuZXcgQnVja2V0KHRoaXMsIGJ1Y2tldE5hbWUsIHtcbiAgICAgIGFjY2Vzc0NvbnRyb2w6IEJ1Y2tldEFjY2Vzc0NvbnRyb2wuQVVUSEVOVElDQVRFRF9SRUFELFxuICAgICAgYmxvY2tQdWJsaWNBY2Nlc3M6IEJsb2NrUHVibGljQWNjZXNzLkJMT0NLX0FMTCxcbiAgICAgIGJ1Y2tldE5hbWUsXG4gICAgICAvLyBUaGUgYnVja2V0IGFuZCBhbGwgb2YgaXRzIG9iamVjdHMgY2FuIGJlIGRlbGV0ZWQsIGJlY2F1c2UgYWxsIHRoZSBjb250ZW50IGlzIG1hbmFnZWQgaW4gdGhpcyBwcm9qZWN0XG4gICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICB9KTtcblxuICAgIGJ1Y2tldC5ncmFudFJlYWRXcml0ZSh0aGlzLmNkbkFjY2Vzc0lkZW50aXR5KTtcblxuICAgIHJldHVybiBidWNrZXQ7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGxhbWJkYSBsYXllciB3aXRoIHRoZSBub2RlX21vZHVsZXMgcmVxdWlyZWQgdG8gcmVuZGVyIHRoZSBOdXh0IGFwcCBvbiB0aGUgc2VydmVyIHNpZGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZVNzckxhbWJkYUxheWVyKCk6IExheWVyVmVyc2lvbiB7XG4gICAgY29uc3QgbGF5ZXJOYW1lID0gYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1zc3ItbGF5ZXJgO1xuICAgIHJldHVybiBuZXcgTGF5ZXJWZXJzaW9uKHRoaXMsIGxheWVyTmFtZSwge1xuICAgICAgbGF5ZXJWZXJzaW9uTmFtZTogbGF5ZXJOYW1lLFxuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQoJy5udXh0L2Nkay1kZXBsb3ltZW50L2xheWVyJyksXG4gICAgICBjb21wYXRpYmxlUnVudGltZXM6IFtSdW50aW1lLk5PREVKU18xMl9YXSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgUHJvdmlkZXMgdGhlIG5vZGVfbW9kdWxlcyByZXF1aXJlZCBmb3IgU1NSIG9mICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS5gLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgdGhlIGxhbWJkYSBmdW5jdGlvbiB0byByZW5kZXIgdGhlIE51eHQgYXBwLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVMYW1iZGFGdW5jdGlvbigpOiBGdW5jdGlvbiB7XG4gICAgY29uc3QgZnVuY05hbWUgPSBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWZ1bmN0aW9uYDtcblxuICAgIHJldHVybiBuZXcgRnVuY3Rpb24odGhpcywgZnVuY05hbWUsIHtcbiAgICAgIGZ1bmN0aW9uTmFtZTogZnVuY05hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogYFJlbmRlcnMgdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBOdXh0IGFwcC5gLFxuICAgICAgcnVudGltZTogUnVudGltZS5OT0RFSlNfMTJfWCxcbiAgICAgIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlLkFSTV82NCxcbiAgICAgIGxheWVyczogW3RoaXMuY3JlYXRlU3NyTGFtYmRhTGF5ZXIoKV0sXG4gICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcicsXG4gICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldCgnLm51eHQvY2RrLWRlcGxveW1lbnQvc3JjJywge1xuICAgICAgICBleGNsdWRlOiBbJyoqLnN2ZycsICcqKi5pY28nLCAnKioucG5nJywgJyoqLmpwZycsICcqKi5qcy5tYXAnXSxcbiAgICAgIH0pLFxuICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygxMCksXG4gICAgICBtZW1vcnlTaXplOiA1MTIsXG4gICAgICBsb2dSZXRlbnRpb246IFJldGVudGlvbkRheXMuT05FX01PTlRILFxuICAgICAgYWxsb3dQdWJsaWNTdWJuZXQ6IGZhbHNlXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgQVBJIGdhdGV3YXkgdG8gbWFrZSB0aGUgTnV4dCBhcHAgcmVuZGVyIGxhbWJkYSBmdW5jdGlvbiBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUFwaUdhdGV3YXkoKTogSHR0cEFwaSB7XG4gICAgY29uc3QgbGFtYmRhSW50ZWdyYXRpb24gPSBuZXcgSHR0cExhbWJkYUludGVncmF0aW9uKGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tbGFtYmRhLWludGVncmF0aW9uYCwgdGhpcy5sYW1iZGFGdW5jdGlvbik7XG4gICAgY29uc3QgYXBpTmFtZSA9IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tYXBpYDtcbiAgICBjb25zdCBhcGlHYXRld2F5ID0gbmV3IEh0dHBBcGkodGhpcywgYXBpTmFtZSwge1xuICAgICAgYXBpTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgQ29ubmVjdHMgdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBjbG91ZGZyb250IGRpc3RyaWJ1dGlvbiB3aXRoIHRoZSAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0gbGFtYmRhIGZ1bmN0aW9uIHRvIG1ha2UgaXQgcHVibGljbHkgYXZhaWxhYmxlLmAsXG4gICAgICAvLyBUaGUgYXBwIGRvZXMgbm90IGFsbG93IGFueSBjcm9zcy1vcmlnaW4gYWNjZXNzIGJ5IHB1cnBvc2U6IHRoZSBhcHAgc2hvdWxkIG5vdCBiZSBlbWJlZGRhYmxlIGFueXdoZXJlXG4gICAgICBjb3JzUHJlZmxpZ2h0OiB1bmRlZmluZWQsXG4gICAgICBkZWZhdWx0SW50ZWdyYXRpb246IGxhbWJkYUludGVncmF0aW9uLFxuICAgIH0pO1xuXG4gICAgYXBpR2F0ZXdheS5hZGRSb3V0ZXMoe1xuICAgICAgaW50ZWdyYXRpb246IGxhbWJkYUludGVncmF0aW9uLFxuICAgICAgcGF0aDogJy97cHJveHkrfScsXG4gICAgICBtZXRob2RzOiBbSHR0cE1ldGhvZC5HRVQsIEh0dHBNZXRob2QuSEVBRF0sXG4gICAgfSk7XG4gICAgcmV0dXJuIGFwaUdhdGV3YXk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgY2xvdWRmcm9udCBkaXN0cmlidXRpb24gdGhhdCByb3V0ZXMgaW5jb21pbmcgcmVxdWVzdHMgdG8gdGhlIE51eHQgbGFtYmRhIGZ1bmN0aW9uICh2aWEgdGhlIEFQSSBnYXRld2F5KVxuICAgKiBvciB0aGUgUzMgYXNzZXRzIGZvbGRlciAod2l0aCBjYWNoaW5nKS5cbiAgICpcbiAgICogQHBhcmFtIHByb3BzXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZUNsb3VkRnJvbnREaXN0cmlidXRpb24ocHJvcHM6IE51eHRBcHBTdGFja1Byb3BzKTogRGlzdHJpYnV0aW9uIHtcbiAgICBjb25zdCBjZG5OYW1lID0gYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1jZG5gO1xuXG4gICAgcmV0dXJuIG5ldyBEaXN0cmlidXRpb24odGhpcywgY2RuTmFtZSwge1xuICAgICAgZG9tYWluTmFtZXM6IFtwcm9wcy5kb21haW5dLFxuICAgICAgY29tbWVudDogYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1yZWRpcmVjdGAsXG4gICAgICBtaW5pbXVtUHJvdG9jb2xWZXJzaW9uOiBTZWN1cml0eVBvbGljeVByb3RvY29sLlRMU19WMV8yXzIwMTgsXG4gICAgICBjZXJ0aWZpY2F0ZTogdGhpcy50bHNDZXJ0aWZpY2F0ZSxcbiAgICAgIGRlZmF1bHRCZWhhdmlvcjogdGhpcy5jcmVhdGVOdXh0QXBwUm91dGVCZWhhdmlvcigpLFxuICAgICAgYWRkaXRpb25hbEJlaGF2aW9yczogdGhpcy5jcmVhdGVTdGF0aWNBc3NldHNSb3V0ZUJlaGF2aW9yKCksXG4gICAgICBwcmljZUNsYXNzOiBQcmljZUNsYXNzLlBSSUNFX0NMQVNTXzEwMCwgLy8gVXNlIG9ubHkgTm9ydGggQW1lcmljYSBhbmQgRXVyb3BlXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGJlaGF2aW9yIGZvciB0aGUgY2xvdWRmcm9udCBkaXN0cmlidXRpb24gdG8gcm91dGUgaW5jb21pbmcgcmVxdWVzdHMgdG8gdGhlIE51eHQgcmVuZGVyIGxhbWJkYSBmdW5jdGlvbiAodmlhIEFQSSBnYXRld2F5KS5cbiAgICogQWRkaXRpb25hbGx5LCB0aGlzIGF1dG9tYXRpY2FsbHkgcmVkaXJlY3RzIEhUVFAgcmVxdWVzdHMgdG8gSFRUUFMuXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGNyZWF0ZU51eHRBcHBSb3V0ZUJlaGF2aW9yKCk6IEJlaGF2aW9yT3B0aW9ucyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG9yaWdpbjogbmV3IEh0dHBPcmlnaW4oYCR7dGhpcy5hcGlHYXRld2F5Lmh0dHBBcGlJZH0uZXhlY3V0ZS1hcGkuJHt0aGlzLnJlZ2lvbn0uYW1hem9uYXdzLmNvbWAsIHtcbiAgICAgICAgY29ubmVjdGlvbkF0dGVtcHRzOiAyLFxuICAgICAgICBjb25uZWN0aW9uVGltZW91dDogRHVyYXRpb24uc2Vjb25kcygyKSxcbiAgICAgICAgcmVhZFRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTApLFxuICAgICAgICBwcm90b2NvbFBvbGljeTogT3JpZ2luUHJvdG9jb2xQb2xpY3kuSFRUUFNfT05MWSxcbiAgICAgIH0pLFxuICAgICAgYWxsb3dlZE1ldGhvZHM6IEFsbG93ZWRNZXRob2RzLkFMTE9XX0dFVF9IRUFELFxuICAgICAgY29tcHJlc3M6IHRydWUsXG4gICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICBvcmlnaW5SZXF1ZXN0UG9saWN5OiB1bmRlZmluZWQsXG4gICAgICBjYWNoZVBvbGljeTogdGhpcy5jcmVhdGVTc3JDYWNoZVBvbGljeSgpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGNhY2hlIHBvbGljeSBmb3IgdGhlIE51eHQgYXBwIHJvdXRlIGJlaGF2aW9yIG9mIG91ciBjbG91ZGZyb250IGRpc3RyaWJ1dGlvbi5cbiAgICogRXZlbnRob3VnaCB3ZSBkb24ndCB3YW50IHRvIGNhY2hlIFNTUiByZXF1ZXN0cywgd2Ugc3RpbGwgaGF2ZSB0byBjcmVhdGUgdGhpcyBjYWNoZSBwb2xpY3kgaW4gb3JkZXIgdG9cbiAgICogZm9yd2FyZCByZXF1aXJlZCBjb29raWVzLCBxdWVyeSBwYXJhbXMgYW5kIGhlYWRlcnMuIFRoaXMgZG9lc24ndCBtYWtlIGFueSBzZW5zZSwgYmVjYXVzZSBpZiBub3RoaW5nXG4gICAqIGlzIGNhY2hlZCwgb25lIHdvdWxkIGV4cGVjdCwgdGhhdCBhbnl0aGluZyB3b3VsZC9jb3VsZCBiZSBmb3J3YXJkZWQsIGJ1dCBhbnl3YXkuLi5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlU3NyQ2FjaGVQb2xpY3koKTogSUNhY2hlUG9saWN5IHtcblxuICAgIC8vIFRoZSBoZWFkZXJzIHRvIG1ha2UgYWNjZXNzaWJsZSBpbiBvdXIgTnV4dCBhcHAgY29kZVxuICAgIGNvbnN0IGhlYWRlcnMgPSBbXG4gICAgICAnVXNlci1BZ2VudCcsIC8vIFJlcXVpcmVkIHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gbW9iaWxlIGFuZCBkZXNrdG9wIHRlbXBsYXRlXG4gICAgICAnQXV0aG9yaXphdGlvbicsIC8vIEZvciBhdXRob3JpemF0aW9uXG4gICAgXTtcblxuICAgIHJldHVybiBuZXcgQ2FjaGVQb2xpY3kodGhpcywgYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1jYWNoZS1wb2xpY3lgLCB7XG4gICAgICBjYWNoZVBvbGljeU5hbWU6IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tY2RuLWNhY2hlLXBvbGljeWAsXG4gICAgICBjb21tZW50OiBgUGFzc2VzIGFsbCByZXF1aXJlZCByZXF1ZXN0IGRhdGEgdG8gdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBvcmlnaW4uYCxcbiAgICAgIGRlZmF1bHRUdGw6IER1cmF0aW9uLnNlY29uZHMoMCksXG4gICAgICBtaW5UdGw6IER1cmF0aW9uLnNlY29uZHMoMCksXG4gICAgICBtYXhUdGw6IER1cmF0aW9uLnNlY29uZHMoMSksIC8vIFRoZSBtYXggVFRMIG11c3Qgbm90IGJlIDAgZm9yIGEgY2FjaGUgcG9saWN5XG4gICAgICBxdWVyeVN0cmluZ0JlaGF2aW9yOiBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IuYWxsKCksXG4gICAgICBoZWFkZXJCZWhhdmlvcjogQ2FjaGVIZWFkZXJCZWhhdmlvci5hbGxvd0xpc3QoLi4uaGVhZGVycyksXG4gICAgICBjb29raWVCZWhhdmlvcjogQ2FjaGVDb29raWVCZWhhdmlvci5hbGwoKSxcbiAgICAgIGVuYWJsZUFjY2VwdEVuY29kaW5nQnJvdGxpOiB0cnVlLFxuICAgICAgZW5hYmxlQWNjZXB0RW5jb2RpbmdHemlwOiB0cnVlLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBiZWhhdmlvciBmb3IgdGhlIGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uIHRvIHJvdXRlIG1hdGNoaW5nIGluY29taW5nIHJlcXVlc3RzIGZvciBvdXIgc3RhdGljIGFzc2V0c1xuICAgKiB0byB0aGUgUzMgYnVja2V0IHRoYXQgaG9sZHMgdGhlc2Ugc3RhdGljIGFzc2V0cy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlU3RhdGljQXNzZXRzUm91dGVCZWhhdmlvcigpOiBSZWNvcmQ8c3RyaW5nLCBCZWhhdmlvck9wdGlvbnM+IHtcbiAgICBjb25zdCBzdGF0aWNBc3NldHNDYWNoZUNvbmZpZzogQmVoYXZpb3JPcHRpb25zID0ge1xuICAgICAgb3JpZ2luOiBuZXcgUzNPcmlnaW4odGhpcy5zdGF0aWNBc3NldHNCdWNrZXQsIHtcbiAgICAgICAgY29ubmVjdGlvbkF0dGVtcHRzOiAyLFxuICAgICAgICBjb25uZWN0aW9uVGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzKSxcbiAgICAgICAgb3JpZ2luQWNjZXNzSWRlbnRpdHk6IHRoaXMuY2RuQWNjZXNzSWRlbnRpdHksXG4gICAgICAgIG9yaWdpblBhdGg6IHRoaXMuZGVwbG95bWVudFJldmlzaW9uLFxuICAgICAgfSksXG4gICAgICBjb21wcmVzczogdHJ1ZSxcbiAgICAgIGFsbG93ZWRNZXRob2RzOiBBbGxvd2VkTWV0aG9kcy5BTExPV19HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgY2FjaGVkTWV0aG9kczogQ2FjaGVkTWV0aG9kcy5DQUNIRV9HRVRfSEVBRF9PUFRJT05TLFxuICAgICAgY2FjaGVQb2xpY3k6IENhY2hlUG9saWN5LkNBQ0hJTkdfT1BUSU1JWkVELFxuICAgICAgdmlld2VyUHJvdG9jb2xQb2xpY3k6IFZpZXdlclByb3RvY29sUG9saWN5LlJFRElSRUNUX1RPX0hUVFBTLFxuICAgIH07XG5cbiAgICBjb25zdCBydWxlczogUmVjb3JkPHN0cmluZywgQmVoYXZpb3JPcHRpb25zPiA9IHt9O1xuICAgIHRoaXMuc3RhdGljQXNzZXRDb25maWdzLmZvckVhY2goYXNzZXQgPT4ge1xuICAgICAgcnVsZXNbYCR7YXNzZXQudGFyZ2V0fSR7YXNzZXQucGF0dGVybn1gXSA9IHN0YXRpY0Fzc2V0c0NhY2hlQ29uZmlnXG4gICAgfSlcblxuICAgIHJldHVybiBydWxlc1xuICB9XG5cbiAgLyoqXG4gICAqIFVwbG9hZHMgdGhlIHN0YXRpYyBhc3NldHMgb2YgdGhlIE51eHQgYXBwIGFzIGRlZmluZWQgaW4ge0BzZWUgZ2V0TnV4dEFwcFN0YXRpY0Fzc2V0Q29uZmlnc30gdG8gdGhlIHN0YXRpYyBhc3NldHMgUzMgYnVja2V0LlxuICAgKiBJbiBvcmRlciB0byBlbmFibGUgYSB6ZXJvLWRvd250aW1lIGRlcGxveW1lbnQsIHdlIHVzZSBhIG5ldyBzdWJkaXJlY3RvcnkgKHJldmlzaW9uKSBmb3IgZXZlcnkgZGVwbG95bWVudC5cbiAgICogVGhlIHByZXZpb3VzIHZlcnNpb25zIGFyZSByZXRhaW5lZCB0byBhbGxvdyBjbGllbnRzIHRvIGNvbnRpbnVlIHRvIHdvcmsgd2l0aCBhbiBvbGRlciByZXZpc2lvbiBidXQgZ2V0cyBjbGVhbmVkIHVwXG4gICAqIGFmdGVyIGEgc3BlY2lmaWVkIHBlcmlvZCBvZiB0aW1lIHZpYSB0aGUgbGFtYmRhIGZ1bmN0aW9uIGluIHRoZSB7QHNlZSBOdXh0QXBwQXNzZXRzQ2xlYW51cFN0YWNrfS5cbiAgICovXG4gIHByaXZhdGUgY29uZmlndXJlRGVwbG95bWVudHMoKTogQnVja2V0RGVwbG95bWVudFtdIHtcbiAgICBjb25zdCBkZWZhdWx0Q2FjaGVDb25maWcgPSBbXG4gICAgICBDYWNoZUNvbnRyb2wuc2V0UHVibGljKCksXG4gICAgICBDYWNoZUNvbnRyb2wubWF4QWdlKER1cmF0aW9uLmRheXMoMzY1KSksXG4gICAgICBDYWNoZUNvbnRyb2wuZnJvbVN0cmluZygnaW1tdXRhYmxlJyksXG4gICAgXTtcblxuICAgIC8vIFJldHVybnMgYSBkZXBsb3ltZW50IGZvciBldmVyeSBjb25maWd1cmVkIHN0YXRpYyBhc3NldCB0eXBlIHRvIHJlc3BlY3QgdGhlIGRpZmZlcmVudCBjYWNoZSBzZXR0aW5nc1xuICAgIHJldHVybiB0aGlzLnN0YXRpY0Fzc2V0Q29uZmlncy5maWx0ZXIoYXNzZXQgPT4gZnMuZXhpc3RzU3luYyhhc3NldC5zb3VyY2UpKS5tYXAoKGFzc2V0LCBhc3NldEluZGV4KSA9PiB7XG4gICAgICByZXR1cm4gbmV3IEJ1Y2tldERlcGxveW1lbnQodGhpcywgYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1hc3NldHMtZGVwbG95bWVudC0ke2Fzc2V0SW5kZXh9YCwge1xuICAgICAgICBzb3VyY2VzOiBbU291cmNlLmFzc2V0KGFzc2V0LnNvdXJjZSldLFxuICAgICAgICBkZXN0aW5hdGlvbkJ1Y2tldDogdGhpcy5zdGF0aWNBc3NldHNCdWNrZXQsXG4gICAgICAgIGRlc3RpbmF0aW9uS2V5UHJlZml4OiB0aGlzLmRlcGxveW1lbnRSZXZpc2lvbiArIGFzc2V0LnRhcmdldCxcbiAgICAgICAgcHJ1bmU6IGZhbHNlLFxuICAgICAgICBzdG9yYWdlQ2xhc3M6IFN0b3JhZ2VDbGFzcy5TVEFOREFSRCxcbiAgICAgICAgZXhjbHVkZTogWycqJ10sXG4gICAgICAgIGluY2x1ZGU6IFthc3NldC5wYXR0ZXJuXSxcbiAgICAgICAgY2FjaGVDb250cm9sOiBhc3NldC5jYWNoZUNvbnRyb2wgPz8gZGVmYXVsdENhY2hlQ29uZmlnLFxuICAgICAgICBjb250ZW50VHlwZTogYXNzZXQuY29udGVudFR5cGUsXG4gICAgICAgIGxvZ1JldGVudGlvbjogUmV0ZW50aW9uRGF5cy5PTkVfREFZLFxuICAgICAgICBtZW1vcnlMaW1pdDogMjU2IC8vIFNvbWUgTnV4dCBhcHBsaWNhdGlvbnMgaGF2ZSBhIGxvdCBvZiBhc3NldHMgdG8gZGVwbG95IHdoZXJlYnkgdGhlIGZ1bmN0aW9uIG1pZ2h0IHJ1biBvdXQgb2YgbWVtb3J5XG4gICAgICB9KVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHRoZSBob3N0ZWQgem9uZSBhdCB3aGljaCB0aGUgRE5TIHJlY29yZHMgc2hhbGwgYmUgY3JlYXRlZCB0byBhY2Nlc3Mgb3VyIE51eHQgYXBwIG9uIHRoZSBpbnRlcm5ldC5cbiAgICpcbiAgICogQHBhcmFtIHByb3BzXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIGZpbmRIb3N0ZWRab25lKHByb3BzOiBOdXh0QXBwU3RhY2tQcm9wcyk6IElIb3N0ZWRab25lIHtcbiAgICBjb25zdCBkb21haW5QYXJ0cyA9IHByb3BzLmRvbWFpbi5zcGxpdCgnLicpO1xuXG4gICAgcmV0dXJuIEhvc3RlZFpvbmUuZnJvbUhvc3RlZFpvbmVBdHRyaWJ1dGVzKHRoaXMsIGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0taG9zdGVkLXpvbmVgLCB7XG4gICAgICBob3N0ZWRab25lSWQ6IHByb3BzLmhvc3RlZFpvbmVJZCxcbiAgICAgIHpvbmVOYW1lOiBkb21haW5QYXJ0c1tkb21haW5QYXJ0cy5sZW5ndGggLSAxXSwgLy8gU3VwcG9ydCBzdWJkb21haW5zXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgRE5TIHJlY29yZHMgdG8gYWNjZXNzIG91ciBOdXh0IGFwcCBvbiB0aGUgaW50ZXJuZXQgdmlhIG91ciBjdXN0b20gZG9tYWluLlxuICAgKlxuICAgKiBAcGFyYW0gcHJvcHNcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlRG5zUmVjb3Jkcyhwcm9wczogTnV4dEFwcFN0YWNrUHJvcHMpOiB2b2lkIHtcbiAgICBjb25zdCBob3N0ZWRab25lID0gdGhpcy5maW5kSG9zdGVkWm9uZShwcm9wcyk7XG4gICAgY29uc3QgZG5zVGFyZ2V0ID0gUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhuZXcgQ2xvdWRGcm9udFRhcmdldCh0aGlzLmNkbikpO1xuXG4gICAgLy8gQ3JlYXRlIGEgcmVjb3JkIGZvciBJUHY0XG4gICAgbmV3IEFSZWNvcmQodGhpcywgYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1pcHY0LXJlY29yZGAsIHtcbiAgICAgIHJlY29yZE5hbWU6IHByb3BzLmRvbWFpbixcbiAgICAgIHpvbmU6IGhvc3RlZFpvbmUsXG4gICAgICB0YXJnZXQ6IGRuc1RhcmdldCxcbiAgICB9KTtcblxuICAgIC8vIENyZWF0ZSBhIHJlY29yZCBmb3IgSVB2NlxuICAgIG5ldyBBYWFhUmVjb3JkKHRoaXMsIGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0taXB2Ni1yZWNvcmRgLCB7XG4gICAgICByZWNvcmROYW1lOiBwcm9wcy5kb21haW4sXG4gICAgICB6b25lOiBob3N0ZWRab25lLFxuICAgICAgdGFyZ2V0OiBkbnNUYXJnZXQsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHNjaGVkdWxlZCBydWxlIHRvIHBpbmcgb3VyIE51eHQgYXBwIGxhbWJkYSBmdW5jdGlvbiBldmVyeSA1IG1pbnV0ZXMgaW4gb3JkZXIgdG8ga2VlcCBpdCB3YXJtXG4gICAqIGFuZCBzcGVlZCB1cCBpbml0aWFsIFNTUiByZXF1ZXN0cy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlUGluZ1J1bGUoKTogdm9pZCB7XG4gICAgbmV3IFJ1bGUodGhpcywgYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1waW5nZXItcnVsZWAsIHtcbiAgICAgIHJ1bGVOYW1lOiBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LXBpbmdlcmAsXG4gICAgICBkZXNjcmlwdGlvbjogYFBpbmdzIHRoZSBsYW1iZGEgZnVuY3Rpb24gb2YgdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBhcHAgZXZlcnkgNSBtaW51dGVzIHRvIGtlZXAgaXQgd2FybS5gLFxuICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgIHNjaGVkdWxlOiBTY2hlZHVsZS5yYXRlKER1cmF0aW9uLm1pbnV0ZXMoNSkpLFxuICAgICAgdGFyZ2V0czogW25ldyBMYW1iZGFGdW5jdGlvbih0aGlzLmxhbWJkYUZ1bmN0aW9uKV0sXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
320
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnV4dC1hcHAtc3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJudXh0LWFwcC1zdGFjay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBMkQ7QUFFM0QsK0VBQTZFO0FBQzdFLCtEQWdCb0M7QUFDcEMsdURBQTJGO0FBQzNGLCtDQUEyRjtBQUMzRix5REFBbUc7QUFDbkcscUVBQW1HO0FBQ25HLCtFQUF3RTtBQUN4RSx5RUFBaUU7QUFDakUsaUZBQStEO0FBQy9ELG1EQUFtRDtBQUNuRCxzR0FBbUY7QUFDbkYsNEVBQW9FO0FBQ3BFLHFFQUF5RjtBQUV6Rix5QkFBeUI7QUFDekIsdURBQXNEO0FBQ3RELHVFQUE4RDtBQWlDOUQ7O0dBRUc7QUFDSCxNQUFhLFlBQWEsU0FBUSxtQkFBSztJQWlFbkMsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUF3QjtRQUM5RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4QixJQUFJLENBQUMsZ0JBQWdCLEdBQUcsR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLEtBQUssQ0FBQyxPQUFPLElBQUksS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ2pGLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25ELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFBLHFEQUE0QixFQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN6RSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7UUFDeEQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1FBQzFELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxD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SSxFQUFFLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixjQUFjLEVBQUU7WUFDdEQsVUFBVSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3hCLElBQUksRUFBRSxVQUFVO1lBQ2hCLE1BQU0sRUFBRSxTQUFTO1NBQ3BCLENBQUMsQ0FBQztRQUVILDJCQUEyQjtRQUMzQixJQUFJLHdCQUFVLENBQUMsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixjQUFjLEVBQUU7WUFDekQsVUFBVSxFQUFFLEtBQUssQ0FBQyxNQUFNO1lBQ3hCLElBQUksRUFBRSxVQUFVO1lBQ2hCLE1BQU0sRUFBRSxTQUFTO1NBQ3BCLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNLLGNBQWM7UUFDbEIsSUFBSSxpQkFBSSxDQUFDLElBQUksRUFBRSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsY0FBYyxFQUFFO1lBQ25ELFFBQVEsRUFBRSxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsU0FBUztZQUMzQyxXQUFXLEVBQUUsb0NBQW9DLElBQUksQ0FBQyxnQkFBZ0IsdUNBQXVDO1lBQzdHLE9BQU8sRUFBRSxJQUFJO1lBQ2IsUUFBUSxFQUFFLHFCQUFRLENBQUMsSUFBSSxDQUFDLHNCQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVDLE9BQU8sRUFBRSxDQUFDLElBQUksbUNBQWMsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7U0FDckQsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztDQUNKO0FBbllELG9DQW1ZQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7RHVyYXRpb24sIFJlbW92YWxQb2xpY3ksIFN0YWNrfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQge0NvbnN0cnVjdH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQge0NlcnRpZmljYXRlLCBJQ2VydGlmaWNhdGV9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICAgIEFsbG93ZWRNZXRob2RzLFxuICAgIEJlaGF2aW9yT3B0aW9ucyxcbiAgICBDYWNoZUNvb2tpZUJlaGF2aW9yLFxuICAgIENhY2hlZE1ldGhvZHMsXG4gICAgQ2FjaGVIZWFkZXJCZWhhdmlvcixcbiAgICBDYWNoZVBvbGljeSxcbiAgICBDYWNoZVF1ZXJ5U3RyaW5nQmVoYXZpb3IsXG4gICAgRGlzdHJpYnV0aW9uLFxuICAgIElDYWNoZVBvbGljeSxcbiAgICBJT3JpZ2luQWNjZXNzSWRlbnRpdHksXG4gICAgT3JpZ2luQWNjZXNzSWRlbnRpdHksXG4gICAgT3JpZ2luUHJvdG9jb2xQb2xpY3ksXG4gICAgUHJpY2VDbGFzcyxcbiAgICBTZWN1cml0eVBvbGljeVByb3RvY29sLFxuICAgIFZpZXdlclByb3RvY29sUG9saWN5XG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udFwiO1xuaW1wb3J0IHtBcmNoaXRlY3R1cmUsIENvZGUsIEZ1bmN0aW9uLCBMYXllclZlcnNpb24sIFJ1bnRpbWV9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbGFtYmRhXCI7XG5pbXBvcnQge0Jsb2NrUHVibGljQWNjZXNzLCBCdWNrZXQsIEJ1Y2tldEFjY2Vzc0NvbnRyb2wsIElCdWNrZXR9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczNcIjtcbmltcG9ydCB7QWFhYVJlY29yZCwgQVJlY29yZCwgSG9zdGVkWm9uZSwgSUhvc3RlZFpvbmUsIFJlY29yZFRhcmdldH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzXCI7XG5pbXBvcnQge0J1Y2tldERlcGxveW1lbnQsIENhY2hlQ29udHJvbCwgU291cmNlLCBTdG9yYWdlQ2xhc3N9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtczMtZGVwbG95bWVudFwiO1xuaW1wb3J0IHtIdHRwT3JpZ2luLCBTM09yaWdpbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jbG91ZGZyb250LW9yaWdpbnNcIjtcbmltcG9ydCB7Q2xvdWRGcm9udFRhcmdldH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzLXRhcmdldHNcIjtcbmltcG9ydCB7SHR0cE1ldGhvZH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zdGVwZnVuY3Rpb25zLXRhc2tzXCI7XG5pbXBvcnQge1JldGVudGlvbkRheXN9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbG9nc1wiO1xuaW1wb3J0IHtIdHRwTGFtYmRhSW50ZWdyYXRpb259IGZyb20gJ0Bhd3MtY2RrL2F3cy1hcGlnYXRld2F5djItaW50ZWdyYXRpb25zLWFscGhhJztcbmltcG9ydCB7RG9tYWluTmFtZSwgSHR0cEFwaX0gZnJvbSBcIkBhd3MtY2RrL2F3cy1hcGlnYXRld2F5djItYWxwaGFcIjtcbmltcG9ydCB7Z2V0TnV4dEFwcFN0YXRpY0Fzc2V0Q29uZmlncywgU3RhdGljQXNzZXRDb25maWd9IGZyb20gXCIuL251eHQtYXBwLXN0YXRpYy1hc3NldHNcIjtcbmltcG9ydCB7QXBwU3RhY2tQcm9wc30gZnJvbSBcIi4vYXBwLXN0YWNrLXByb3BzXCI7XG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCB7UnVsZSwgU2NoZWR1bGV9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZXZlbnRzXCI7XG5pbXBvcnQge0xhbWJkYUZ1bmN0aW9ufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWV2ZW50cy10YXJnZXRzXCI7XG5pbXBvcnQge051eHRDb25maWd9IGZyb20gXCIuL251eHQtY29uZmlnXCI7XG5cbi8qKlxuICogRGVmaW5lcyB0aGUgcHJvcHMgcmVxdWlyZWQgZm9yIHRoZSB7QHNlZSBOdXh0QXBwU3RhY2t9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE51eHRBcHBTdGFja1Byb3BzIGV4dGVuZHMgQXBwU3RhY2tQcm9wcyB7XG4gICAgLyoqXG4gICAgICogVGhlIGRvbWFpbiAod2l0aG91dCB0aGUgcHJvdG9jb2wpIGF0IHdoaWNoIHRoZSBOdXh0IGFwcCBzaGFsbCBiZSBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAgICogQSBETlMgcmVjb3JkIHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGluIFJvdXRlNTMgZm9yIHRoZSBkb21haW4uXG4gICAgICogVGhpcyBhbHNvIHN1cHBvcnRzIHN1YmRvbWFpbnMuXG4gICAgICogRXhhbXBsZXM6IFwiZXhhbXBsZS5jb21cIiwgXCJzdWIuZXhhbXBsZS5jb21cIlxuICAgICAqL1xuICAgIHJlYWRvbmx5IGRvbWFpbjogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGlkIG9mIHRoZSBob3N0ZWQgem9uZSB0byBjcmVhdGUgYSBETlMgcmVjb3JkIGZvciB0aGUgc3BlY2lmaWVkIGRvbWFpbi5cbiAgICAgKi9cbiAgICByZWFkb25seSBob3N0ZWRab25lSWQ6IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIFRoZSBBUk4gb2YgdGhlIGNlcnRpZmljYXRlIHRvIHVzZSBmb3IgdGhlIE51eHQgYXBwIHRvIG1ha2UgaXQgYWNjZXNzaWJsZSB2aWEgSFRUUFMuXG4gICAgICogVGhlIGNlcnRpZmljYXRlIG11c3QgYmUgaXNzdWVkIGZvciB0aGUgc3BlY2lmaWVkIGRvbWFpbiBpbiB1cy1lYXN0LTEgKGdsb2JhbCkgcmVnYXJkbGVzcyBvZiB0aGVcbiAgICAgKiByZWdpb24gdXNlZCBmb3IgdGhlIE51eHQgYXBwIGl0c2VsZi5cbiAgICAgKi9cbiAgICByZWFkb25seSBnbG9iYWxUbHNDZXJ0aWZpY2F0ZUFybjogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG51eHQuY29uZmlnLmpzIG9mIHRoZSBOdXh0IGFwcC5cbiAgICAgKi9cbiAgICByZWFkb25seSBudXh0Q29uZmlnOiBOdXh0Q29uZmlnO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBsYW1iZGEgZnVuY3Rpb24gdGhhdCByZW5kZXJzIHRoZSBOdXh0IGFwcCBhbmQgaXMgcHVibGljbHkgcmVhY2hhYmxlIHZpYSBhIHNwZWNpZmllZCBkb21haW4uXG4gKi9cbmV4cG9ydCBjbGFzcyBOdXh0QXBwU3RhY2sgZXh0ZW5kcyBTdGFjayB7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaWRlbnRpZmllciBwcmVmaXggb2YgdGhlIHJlc291cmNlcyBjcmVhdGVkIGJ5IHRoZSBzdGFjay5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSByZXNvdXJjZUlkUHJlZml4OiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaWRlbnRpZmllciBmb3IgdGhlIGN1cnJlbnQgZGVwbG95bWVudCB0aGF0IGlzIHVzZWQgYXMgUzMgZm9sZGVyIG5hbWVcbiAgICAgKiB0byBzdG9yZSB0aGUgc3RhdGljIGFzc2V0cyBvZiB0aGUgTnV4dCBhcHAuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVwbG95bWVudFJldmlzaW9uOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2VydGlmaWNhdGUgdG8gdXNlIGZvciB0aGUgTnV4dCBhcHAgdG8gbWFrZSBpdCBhY2Nlc3NpYmxlIHZpYSBIVFRQUy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSB0bHNDZXJ0aWZpY2F0ZTogSUNlcnRpZmljYXRlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGlkZW50aXR5IHRvIHVzZSBmb3IgYWNjZXNzaW5nIHRoZSBkZXBsb3ltZW50IGFzc2V0cyBvbiBTMy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSByZWFkb25seSBjZG5BY2Nlc3NJZGVudGl0eTogSU9yaWdpbkFjY2Vzc0lkZW50aXR5O1xuXG4gICAgLyoqXG4gICAgICogVGhlIFMzIGJ1Y2tldCB3aGVyZSB0aGUgZGVwbG95bWVudCBhc3NldHMgZ2V0cyBzdG9yZWQuXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpY0Fzc2V0c0J1Y2tldDogSUJ1Y2tldDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBsYW1iZGEgZnVuY3Rpb24gdG8gcmVuZGVyIHRoZSBOdXh0IGFwcCBvbiB0aGUgc2VydmVyIHNpZGUuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgcmVhZG9ubHkgbGFtYmRhRnVuY3Rpb246IEZ1bmN0aW9uO1xuXG4gICAgLyoqXG4gICAgICogVGhlIEFQSSBnYXRld2F5IHRvIG1ha2UgdGhlIGxhbWJkYSBmdW5jdGlvbiB0byByZW5kZXIgdGhlIE51eHQgYXBwIHB1YmxpY2x5IGF2YWlsYWJsZS5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBhcGlHYXRld2F5OiBIdHRwQXBpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGNvbmZpZ3MgZm9yIHRoZSBzdGF0aWMgYXNzZXRzIG9mIHRoZSBOdXh0IGFwcCB0aGF0IHNoYWxsIGJlIHB1YmxpY2x5IGF2YWlsYWJsZS5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBzdGF0aWNBc3NldENvbmZpZ3M6IFN0YXRpY0Fzc2V0Q29uZmlnW107XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2xvdWRmcm9udCBkaXN0cmlidXRpb24gdG8gcm91dGUgaW5jb21pbmcgcmVxdWVzdHMgdG8gdGhlIE51eHQgbGFtYmRhIGZ1bmN0aW9uICh2aWEgdGhlIEFQSSBnYXRld2F5KVxuICAgICAqIG9yIHRoZSBTMyBhc3NldHMgZm9sZGVyICh3aXRoIGNhY2hpbmcpLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IGNkbjogRGlzdHJpYnV0aW9uO1xuXG4gICAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE51eHRBcHBTdGFja1Byb3BzKSB7XG4gICAgICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuXG4gICAgICAgIHRoaXMucmVzb3VyY2VJZFByZWZpeCA9IGAke3Byb3BzLnByb2plY3R9LSR7cHJvcHMuc2VydmljZX0tJHtwcm9wcy5lbnZpcm9ubWVudH1gO1xuICAgICAgICB0aGlzLmRlcGxveW1lbnRSZXZpc2lvbiA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKTtcbiAgICAgICAgdGhpcy5zdGF0aWNBc3NldENvbmZpZ3MgPSBnZXROdXh0QXBwU3RhdGljQXNzZXRDb25maWdzKHByb3BzLm51eHRDb25maWcpO1xuICAgICAgICB0aGlzLnRsc0NlcnRpZmljYXRlID0gdGhpcy5maW5kVGxzQ2VydGlmaWNhdGUocHJvcHMpO1xuICAgICAgICB0aGlzLmNkbkFjY2Vzc0lkZW50aXR5ID0gdGhpcy5jcmVhdGVDZG5BY2Nlc3NJZGVudGl0eSgpO1xuICAgICAgICB0aGlzLnN0YXRpY0Fzc2V0c0J1Y2tldCA9IHRoaXMuY3JlYXRlU3RhdGljQXNzZXRzQnVja2V0KCk7XG4gICAgICAgIHRoaXMubGFtYmRhRnVuY3Rpb24gPSB0aGlzLmNyZWF0ZUxhbWJkYUZ1bmN0aW9uKCk7XG4gICAgICAgIHRoaXMuYXBpR2F0ZXdheSA9IHRoaXMuY3JlYXRlQXBpR2F0ZXdheShwcm9wcyk7XG4gICAgICAgIHRoaXMuY2RuID0gdGhpcy5jcmVhdGVDbG91ZEZyb250RGlzdHJpYnV0aW9uKHByb3BzKTtcbiAgICAgICAgdGhpcy5jb25maWd1cmVEZXBsb3ltZW50cygpO1xuICAgICAgICB0aGlzLmNyZWF0ZURuc1JlY29yZHMocHJvcHMpO1xuICAgICAgICB0aGlzLmNyZWF0ZVBpbmdSdWxlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmluZHMgdGhlIGNlcnRpZmljYXRlIHRvIHVzZSBmb3IgcHJvdmlkaW5nIEhUVFBTIHJlcXVlc3RzIHRvIG91ciBOdXh0IGFwcC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwcm9wc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBmaW5kVGxzQ2VydGlmaWNhdGUocHJvcHM6IE51eHRBcHBTdGFja1Byb3BzKTogSUNlcnRpZmljYXRlIHtcbiAgICAgICAgcmV0dXJuIENlcnRpZmljYXRlLmZyb21DZXJ0aWZpY2F0ZUFybih0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LXRscy1jZXJ0aWZpY2F0ZWAsIHByb3BzLmdsb2JhbFRsc0NlcnRpZmljYXRlQXJuKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIHRoZSBpZGVudGl0eSB0byBhY2Nlc3Mgb3VyIFMzIGRlcGxveW1lbnQgYXNzZXQgZmlsZXMgdmlhIHRoZSBjbG91ZGZyb250IGRpc3RyaWJ1dGlvbi5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgcHJpdmF0ZSBjcmVhdGVDZG5BY2Nlc3NJZGVudGl0eSgpOiBJT3JpZ2luQWNjZXNzSWRlbnRpdHkge1xuICAgICAgICBjb25zdCBvcmlnaW5BY2Nlc3NJZGVudGl0eU5hbWUgPSBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWNkbi1zMy1hY2Nlc3NgO1xuICAgICAgICByZXR1cm4gbmV3IE9yaWdpbkFjY2Vzc0lkZW50aXR5KHRoaXMsIG9yaWdpbkFjY2Vzc0lkZW50aXR5TmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB0aGUgYnVja2V0IHRvIHN0b3JlIHRoZSBzdGF0aWMgZGVwbG95bWVudCBhc3NldCBmaWxlcyBvZiB0aGUgTnV4dCBhcHAuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlU3RhdGljQXNzZXRzQnVja2V0KCk6IElCdWNrZXQge1xuICAgICAgICBjb25zdCBidWNrZXROYW1lID0gYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1hc3NldHNgO1xuICAgICAgICBjb25zdCBidWNrZXQgPSBuZXcgQnVja2V0KHRoaXMsIGJ1Y2tldE5hbWUsIHtcbiAgICAgICAgICAgIGFjY2Vzc0NvbnRyb2w6IEJ1Y2tldEFjY2Vzc0NvbnRyb2wuQVVUSEVOVElDQVRFRF9SRUFELFxuICAgICAgICAgICAgYmxvY2tQdWJsaWNBY2Nlc3M6IEJsb2NrUHVibGljQWNjZXNzLkJMT0NLX0FMTCxcbiAgICAgICAgICAgIGJ1Y2tldE5hbWUsXG4gICAgICAgICAgICAvLyBUaGUgYnVja2V0IGFuZCBhbGwgb2YgaXRzIG9iamVjdHMgY2FuIGJlIGRlbGV0ZWQsIGJlY2F1c2UgYWxsIHRoZSBjb250ZW50IGlzIG1hbmFnZWQgaW4gdGhpcyBwcm9qZWN0XG4gICAgICAgICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICAgICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYnVja2V0LmdyYW50UmVhZFdyaXRlKHRoaXMuY2RuQWNjZXNzSWRlbnRpdHkpO1xuXG4gICAgICAgIHJldHVybiBidWNrZXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIGxhbWJkYSBsYXllciB3aXRoIHRoZSBub2RlX21vZHVsZXMgcmVxdWlyZWQgdG8gcmVuZGVyIHRoZSBOdXh0IGFwcCBvbiB0aGUgc2VydmVyIHNpZGUuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlU3NyTGFtYmRhTGF5ZXIoKTogTGF5ZXJWZXJzaW9uIHtcbiAgICAgICAgY29uc3QgbGF5ZXJOYW1lID0gYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1zc3ItbGF5ZXJgO1xuICAgICAgICByZXR1cm4gbmV3IExheWVyVmVyc2lvbih0aGlzLCBsYXllck5hbWUsIHtcbiAgICAgICAgICAgIGxheWVyVmVyc2lvbk5hbWU6IGxheWVyTmFtZSxcbiAgICAgICAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KCcubnV4dC9jZGstZGVwbG95bWVudC9sYXllcicpLFxuICAgICAgICAgICAgY29tcGF0aWJsZVJ1bnRpbWVzOiBbUnVudGltZS5OT0RFSlNfMTJfWF0sXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogYFByb3ZpZGVzIHRoZSBub2RlX21vZHVsZXMgcmVxdWlyZWQgZm9yIFNTUiBvZiAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0uYCxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB0aGUgbGFtYmRhIGZ1bmN0aW9uIHRvIHJlbmRlciB0aGUgTnV4dCBhcHAuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlTGFtYmRhRnVuY3Rpb24oKTogRnVuY3Rpb24ge1xuICAgICAgICBjb25zdCBmdW5jTmFtZSA9IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tZnVuY3Rpb25gO1xuXG4gICAgICAgIHJldHVybiBuZXcgRnVuY3Rpb24odGhpcywgZnVuY05hbWUsIHtcbiAgICAgICAgICAgIGZ1bmN0aW9uTmFtZTogZnVuY05hbWUsXG4gICAgICAgICAgICBkZXNjcmlwdGlvbjogYFJlbmRlcnMgdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBOdXh0IGFwcC5gLFxuICAgICAgICAgICAgcnVudGltZTogUnVudGltZS5OT0RFSlNfMTJfWCxcbiAgICAgICAgICAgIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlLkFSTV82NCxcbiAgICAgICAgICAgIGxheWVyczogW3RoaXMuY3JlYXRlU3NyTGFtYmRhTGF5ZXIoKV0sXG4gICAgICAgICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcicsXG4gICAgICAgICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldCgnLm51eHQvY2RrLWRlcGxveW1lbnQvc3JjJywge1xuICAgICAgICAgICAgICAgIGV4Y2x1ZGU6IFsnKiouc3ZnJywgJyoqLmljbycsICcqKi5wbmcnLCAnKiouanBnJywgJyoqLmpzLm1hcCddLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDEwKSxcbiAgICAgICAgICAgIG1lbW9yeVNpemU6IDUxMixcbiAgICAgICAgICAgIGxvZ1JldGVudGlvbjogUmV0ZW50aW9uRGF5cy5PTkVfTU9OVEgsXG4gICAgICAgICAgICBhbGxvd1B1YmxpY1N1Ym5ldDogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB0aGUgQVBJIGdhdGV3YXkgdG8gbWFrZSB0aGUgTnV4dCBhcHAgcmVuZGVyIGxhbWJkYSBmdW5jdGlvbiBwdWJsaWNseSBhdmFpbGFibGUuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlQXBpR2F0ZXdheShwcm9wczogTnV4dEFwcFN0YWNrUHJvcHMpOiBIdHRwQXBpIHtcbiAgICAgICAgY29uc3QgYXBpTmFtZSA9IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tYXBpYDtcbiAgICAgICAgY29uc3QgbGFtYmRhSW50ZWdyYXRpb24gPSBuZXcgSHR0cExhbWJkYUludGVncmF0aW9uKGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tbGFtYmRhLWludGVncmF0aW9uYCwgdGhpcy5sYW1iZGFGdW5jdGlvbik7XG5cbiAgICAgICAgLy8gV2Ugd2FudCB0aGUgQVBJIGdhdGV3YXkgdG8gYmUgYWNjZXNzaWJsZSBieSB0aGUgY3VzdG9tIGRvbWFpbiBuYW1lLlxuICAgICAgICAvLyBFdmVuIHRob3VnaCB3ZSBhY2Nlc3MgdGhlIGdhdGV3YXkgdmlhIENsb3VkZnJvbnQgKGZvciBhdXRvIGh0dHAgdG8gaHR0cHMgcmVkaXJlY3RzKSwgdGhpcyBpcyByZXF1aXJlZFxuICAgICAgICAvLyB0byBiZSBhYmxlIHRvIHJlZGlyZWN0IHRoZSBvcmlnaW5hbCAnSG9zdCcgaGVhZGVyIHRvIG91ciBOdXh0IGFwcGxpY2F0aW9uLCBpZiByZXF1ZXN0ZWQuXG4gICAgICAgIGNvbnN0IGRvbWFpbk5hbWUgPSBuZXcgRG9tYWluTmFtZSh0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWFwaS1kb21haW5gLCB7XG4gICAgICAgICAgICBkb21haW5OYW1lOiBwcm9wcy5kb21haW4sXG4gICAgICAgICAgICBjZXJ0aWZpY2F0ZTogdGhpcy50bHNDZXJ0aWZpY2F0ZVxuICAgICAgICB9KVxuXG4gICAgICAgIGNvbnN0IGFwaUdhdGV3YXkgPSBuZXcgSHR0cEFwaSh0aGlzLCBhcGlOYW1lLCB7XG4gICAgICAgICAgICBhcGlOYW1lLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IGBDb25uZWN0cyB0aGUgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9IGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uIHdpdGggdGhlICR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fSBsYW1iZGEgZnVuY3Rpb24gdG8gbWFrZSBpdCBwdWJsaWNseSBhdmFpbGFibGUuYCxcbiAgICAgICAgICAgIC8vIFRoZSBhcHAgZG9lcyBub3QgYWxsb3cgYW55IGNyb3NzLW9yaWdpbiBhY2Nlc3MgYnkgcHVycG9zZTogdGhlIGFwcCBzaG91bGQgbm90IGJlIGVtYmVkZGFibGUgYW55d2hlcmVcbiAgICAgICAgICAgIGNvcnNQcmVmbGlnaHQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGRlZmF1bHRJbnRlZ3JhdGlvbjogbGFtYmRhSW50ZWdyYXRpb24sXG4gICAgICAgICAgICBkZWZhdWx0RG9tYWluTWFwcGluZzoge1xuICAgICAgICAgICAgICAgIGRvbWFpbk5hbWU6IGRvbWFpbk5hbWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXBpR2F0ZXdheS5hZGRSb3V0ZXMoe1xuICAgICAgICAgICAgaW50ZWdyYXRpb246IGxhbWJkYUludGVncmF0aW9uLFxuICAgICAgICAgICAgcGF0aDogJy97cHJveHkrfScsXG4gICAgICAgICAgICBtZXRob2RzOiBbSHR0cE1ldGhvZC5HRVQsIEh0dHBNZXRob2QuSEVBRF0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gYXBpR2F0ZXdheTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIHRoZSBjbG91ZGZyb250IGRpc3RyaWJ1dGlvbiB0aGF0IHJvdXRlcyBpbmNvbWluZyByZXF1ZXN0cyB0byB0aGUgTnV4dCBsYW1iZGEgZnVuY3Rpb24gKHZpYSB0aGUgQVBJIGdhdGV3YXkpXG4gICAgICogb3IgdGhlIFMzIGFzc2V0cyBmb2xkZXIgKHdpdGggY2FjaGluZykuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcHJvcHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlQ2xvdWRGcm9udERpc3RyaWJ1dGlvbihwcm9wczogTnV4dEFwcFN0YWNrUHJvcHMpOiBEaXN0cmlidXRpb24ge1xuICAgICAgICBjb25zdCBjZG5OYW1lID0gYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1jZG5gO1xuXG4gICAgICAgIHJldHVybiBuZXcgRGlzdHJpYnV0aW9uKHRoaXMsIGNkbk5hbWUsIHtcbiAgICAgICAgICAgIGRvbWFpbk5hbWVzOiBbcHJvcHMuZG9tYWluXSxcbiAgICAgICAgICAgIGNvbW1lbnQ6IGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tcmVkaXJlY3RgLFxuICAgICAgICAgICAgbWluaW11bVByb3RvY29sVmVyc2lvbjogU2VjdXJpdHlQb2xpY3lQcm90b2NvbC5UTFNfVjFfMl8yMDE4LFxuICAgICAgICAgICAgY2VydGlmaWNhdGU6IHRoaXMudGxzQ2VydGlmaWNhdGUsXG4gICAgICAgICAgICBkZWZhdWx0QmVoYXZpb3I6IHRoaXMuY3JlYXRlTnV4dEFwcFJvdXRlQmVoYXZpb3IoKSxcbiAgICAgICAgICAgIGFkZGl0aW9uYWxCZWhhdmlvcnM6IHRoaXMuY3JlYXRlU3RhdGljQXNzZXRzUm91dGVCZWhhdmlvcigpLFxuICAgICAgICAgICAgcHJpY2VDbGFzczogUHJpY2VDbGFzcy5QUklDRV9DTEFTU18xMDAsIC8vIFVzZSBvbmx5IE5vcnRoIEFtZXJpY2EgYW5kIEV1cm9wZVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgYmVoYXZpb3IgZm9yIHRoZSBjbG91ZGZyb250IGRpc3RyaWJ1dGlvbiB0byByb3V0ZSBpbmNvbWluZyByZXF1ZXN0cyB0byB0aGUgTnV4dCByZW5kZXIgbGFtYmRhIGZ1bmN0aW9uICh2aWEgQVBJIGdhdGV3YXkpLlxuICAgICAqIEFkZGl0aW9uYWxseSwgdGhpcyBhdXRvbWF0aWNhbGx5IHJlZGlyZWN0cyBIVFRQIHJlcXVlc3RzIHRvIEhUVFBTLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIGNyZWF0ZU51eHRBcHBSb3V0ZUJlaGF2aW9yKCk6IEJlaGF2aW9yT3B0aW9ucyB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBvcmlnaW46IG5ldyBIdHRwT3JpZ2luKGAke3RoaXMuYXBpR2F0ZXdheS5odHRwQXBpSWR9LmV4ZWN1dGUtYXBpLiR7dGhpcy5yZWdpb259LmFtYXpvbmF3cy5jb21gLCB7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbkF0dGVtcHRzOiAyLFxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25UaW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDIpLFxuICAgICAgICAgICAgICAgIHJlYWRUaW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDEwKSxcbiAgICAgICAgICAgICAgICBwcm90b2NvbFBvbGljeTogT3JpZ2luUHJvdG9jb2xQb2xpY3kuSFRUUFNfT05MWSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgYWxsb3dlZE1ldGhvZHM6IEFsbG93ZWRNZXRob2RzLkFMTE9XX0dFVF9IRUFELFxuICAgICAgICAgICAgY29tcHJlc3M6IHRydWUsXG4gICAgICAgICAgICB2aWV3ZXJQcm90b2NvbFBvbGljeTogVmlld2VyUHJvdG9jb2xQb2xpY3kuUkVESVJFQ1RfVE9fSFRUUFMsXG4gICAgICAgICAgICBvcmlnaW5SZXF1ZXN0UG9saWN5OiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjYWNoZVBvbGljeTogdGhpcy5jcmVhdGVTc3JDYWNoZVBvbGljeSgpLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBjYWNoZSBwb2xpY3kgZm9yIHRoZSBOdXh0IGFwcCByb3V0ZSBiZWhhdmlvciBvZiBvdXIgY2xvdWRmcm9udCBkaXN0cmlidXRpb24uXG4gICAgICogRXZlbnRob3VnaCB3ZSBkb24ndCB3YW50IHRvIGNhY2hlIFNTUiByZXF1ZXN0cywgd2Ugc3RpbGwgaGF2ZSB0byBjcmVhdGUgdGhpcyBjYWNoZSBwb2xpY3kgaW4gb3JkZXIgdG9cbiAgICAgKiBmb3J3YXJkIHJlcXVpcmVkIGNvb2tpZXMsIHF1ZXJ5IHBhcmFtcyBhbmQgaGVhZGVycy4gVGhpcyBkb2Vzbid0IG1ha2UgYW55IHNlbnNlLCBiZWNhdXNlIGlmIG5vdGhpbmdcbiAgICAgKiBpcyBjYWNoZWQsIG9uZSB3b3VsZCBleHBlY3QsIHRoYXQgYW55dGhpbmcgd291bGQvY291bGQgYmUgZm9yd2FyZGVkLCBidXQgYW55d2F5Li4uXG4gICAgICovXG4gICAgcHJpdmF0ZSBjcmVhdGVTc3JDYWNoZVBvbGljeSgpOiBJQ2FjaGVQb2xpY3kge1xuXG4gICAgICAgIC8vIFRoZSBoZWFkZXJzIHRvIG1ha2UgYWNjZXNzaWJsZSBpbiBvdXIgTnV4dCBhcHAgY29kZS5cbiAgICAgICAgLy8gVGhlcmUgaXMgbm8gJ0NhY2hlSGVhZGVyQmVoYXZpb3IuYWxsKCknIG9wdGlvbiwgc28gd2UgaGF2ZSB0byBleHBsaWNpdGx5IGRlZmluZSB0aGVtLlxuICAgICAgICBjb25zdCBoZWFkZXJzID0gW1xuICAgICAgICAgICAgJ1VzZXItQWdlbnQnLCAvLyBSZXF1aXJlZCB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIG1vYmlsZSBhbmQgZGVza3RvcCB0ZW1wbGF0ZVxuICAgICAgICAgICAgJ0F1dGhvcml6YXRpb24nLCAvLyBGb3IgYXV0aG9yaXphdGlvblxuICAgICAgICAgICAgJ0hvc3QnIC8vIFRvIGFjY2VzcyB0aGUgZG9tYWluIG5hbWUgb24gU1NSIHJlcXVlc3RzXG4gICAgICAgIF07XG5cbiAgICAgICAgcmV0dXJuIG5ldyBDYWNoZVBvbGljeSh0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWNhY2hlLXBvbGljeWAsIHtcbiAgICAgICAgICAgIGNhY2hlUG9saWN5TmFtZTogYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1jZG4tY2FjaGUtcG9saWN5YCxcbiAgICAgICAgICAgIGNvbW1lbnQ6IGBQYXNzZXMgYWxsIHJlcXVpcmVkIHJlcXVlc3QgZGF0YSB0byB0aGUgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9IG9yaWdpbi5gLFxuICAgICAgICAgICAgZGVmYXVsdFR0bDogRHVyYXRpb24uc2Vjb25kcygwKSxcbiAgICAgICAgICAgIG1pblR0bDogRHVyYXRpb24uc2Vjb25kcygwKSxcbiAgICAgICAgICAgIG1heFR0bDogRHVyYXRpb24uc2Vjb25kcygxKSwgLy8gVGhlIG1heCBUVEwgbXVzdCBub3QgYmUgMCBmb3IgYSBjYWNoZSBwb2xpY3lcbiAgICAgICAgICAgIHF1ZXJ5U3RyaW5nQmVoYXZpb3I6IENhY2hlUXVlcnlTdHJpbmdCZWhhdmlvci5hbGwoKSxcbiAgICAgICAgICAgIGhlYWRlckJlaGF2aW9yOiBDYWNoZUhlYWRlckJlaGF2aW9yLmFsbG93TGlzdCguLi5oZWFkZXJzKSxcbiAgICAgICAgICAgIGNvb2tpZUJlaGF2aW9yOiBDYWNoZUNvb2tpZUJlaGF2aW9yLmFsbCgpLFxuICAgICAgICAgICAgZW5hYmxlQWNjZXB0RW5jb2RpbmdCcm90bGk6IHRydWUsXG4gICAgICAgICAgICBlbmFibGVBY2NlcHRFbmNvZGluZ0d6aXA6IHRydWUsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBiZWhhdmlvciBmb3IgdGhlIGNsb3VkZnJvbnQgZGlzdHJpYnV0aW9uIHRvIHJvdXRlIG1hdGNoaW5nIGluY29taW5nIHJlcXVlc3RzIGZvciBvdXIgc3RhdGljIGFzc2V0c1xuICAgICAqIHRvIHRoZSBTMyBidWNrZXQgdGhhdCBob2xkcyB0aGVzZSBzdGF0aWMgYXNzZXRzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIGNyZWF0ZVN0YXRpY0Fzc2V0c1JvdXRlQmVoYXZpb3IoKTogUmVjb3JkPHN0cmluZywgQmVoYXZpb3JPcHRpb25zPiB7XG4gICAgICAgIGNvbnN0IHN0YXRpY0Fzc2V0c0NhY2hlQ29uZmlnOiBCZWhhdmlvck9wdGlvbnMgPSB7XG4gICAgICAgICAgICBvcmlnaW46IG5ldyBTM09yaWdpbih0aGlzLnN0YXRpY0Fzc2V0c0J1Y2tldCwge1xuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25BdHRlbXB0czogMixcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uVGltZW91dDogRHVyYXRpb24uc2Vjb25kcygzKSxcbiAgICAgICAgICAgICAgICBvcmlnaW5BY2Nlc3NJZGVudGl0eTogdGhpcy5jZG5BY2Nlc3NJZGVudGl0eSxcbiAgICAgICAgICAgICAgICBvcmlnaW5QYXRoOiB0aGlzLmRlcGxveW1lbnRSZXZpc2lvbixcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgY29tcHJlc3M6IHRydWUsXG4gICAgICAgICAgICBhbGxvd2VkTWV0aG9kczogQWxsb3dlZE1ldGhvZHMuQUxMT1dfR0VUX0hFQURfT1BUSU9OUyxcbiAgICAgICAgICAgIGNhY2hlZE1ldGhvZHM6IENhY2hlZE1ldGhvZHMuQ0FDSEVfR0VUX0hFQURfT1BUSU9OUyxcbiAgICAgICAgICAgIGNhY2hlUG9saWN5OiBDYWNoZVBvbGljeS5DQUNISU5HX09QVElNSVpFRCxcbiAgICAgICAgICAgIHZpZXdlclByb3RvY29sUG9saWN5OiBWaWV3ZXJQcm90b2NvbFBvbGljeS5SRURJUkVDVF9UT19IVFRQUyxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBydWxlczogUmVjb3JkPHN0cmluZywgQmVoYXZpb3JPcHRpb25zPiA9IHt9O1xuICAgICAgICB0aGlzLnN0YXRpY0Fzc2V0Q29uZmlncy5mb3JFYWNoKGFzc2V0ID0+IHtcbiAgICAgICAgICAgIHJ1bGVzW2Ake2Fzc2V0LnRhcmdldH0ke2Fzc2V0LnBhdHRlcm59YF0gPSBzdGF0aWNBc3NldHNDYWNoZUNvbmZpZ1xuICAgICAgICB9KVxuXG4gICAgICAgIHJldHVybiBydWxlc1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwbG9hZHMgdGhlIHN0YXRpYyBhc3NldHMgb2YgdGhlIE51eHQgYXBwIGFzIGRlZmluZWQgaW4ge0BzZWUgZ2V0TnV4dEFwcFN0YXRpY0Fzc2V0Q29uZmlnc30gdG8gdGhlIHN0YXRpYyBhc3NldHMgUzMgYnVja2V0LlxuICAgICAqIEluIG9yZGVyIHRvIGVuYWJsZSBhIHplcm8tZG93bnRpbWUgZGVwbG95bWVudCwgd2UgdXNlIGEgbmV3IHN1YmRpcmVjdG9yeSAocmV2aXNpb24pIGZvciBldmVyeSBkZXBsb3ltZW50LlxuICAgICAqIFRoZSBwcmV2aW91cyB2ZXJzaW9ucyBhcmUgcmV0YWluZWQgdG8gYWxsb3cgY2xpZW50cyB0byBjb250aW51ZSB0byB3b3JrIHdpdGggYW4gb2xkZXIgcmV2aXNpb24gYnV0IGdldHMgY2xlYW5lZCB1cFxuICAgICAqIGFmdGVyIGEgc3BlY2lmaWVkIHBlcmlvZCBvZiB0aW1lIHZpYSB0aGUgbGFtYmRhIGZ1bmN0aW9uIGluIHRoZSB7QHNlZSBOdXh0QXBwQXNzZXRzQ2xlYW51cFN0YWNrfS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGNvbmZpZ3VyZURlcGxveW1lbnRzKCk6IEJ1Y2tldERlcGxveW1lbnRbXSB7XG4gICAgICAgIGNvbnN0IGRlZmF1bHRDYWNoZUNvbmZpZyA9IFtcbiAgICAgICAgICAgIENhY2hlQ29udHJvbC5zZXRQdWJsaWMoKSxcbiAgICAgICAgICAgIENhY2hlQ29udHJvbC5tYXhBZ2UoRHVyYXRpb24uZGF5cygzNjUpKSxcbiAgICAgICAgICAgIENhY2hlQ29udHJvbC5mcm9tU3RyaW5nKCdpbW11dGFibGUnKSxcbiAgICAgICAgXTtcblxuICAgICAgICAvLyBSZXR1cm5zIGEgZGVwbG95bWVudCBmb3IgZXZlcnkgY29uZmlndXJlZCBzdGF0aWMgYXNzZXQgdHlwZSB0byByZXNwZWN0IHRoZSBkaWZmZXJlbnQgY2FjaGUgc2V0dGluZ3NcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RhdGljQXNzZXRDb25maWdzLmZpbHRlcihhc3NldCA9PiBmcy5leGlzdHNTeW5jKGFzc2V0LnNvdXJjZSkpLm1hcCgoYXNzZXQsIGFzc2V0SW5kZXgpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgQnVja2V0RGVwbG95bWVudCh0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWFzc2V0cy1kZXBsb3ltZW50LSR7YXNzZXRJbmRleH1gLCB7XG4gICAgICAgICAgICAgICAgc291cmNlczogW1NvdXJjZS5hc3NldChhc3NldC5zb3VyY2UpXSxcbiAgICAgICAgICAgICAgICBkZXN0aW5hdGlvbkJ1Y2tldDogdGhpcy5zdGF0aWNBc3NldHNCdWNrZXQsXG4gICAgICAgICAgICAgICAgZGVzdGluYXRpb25LZXlQcmVmaXg6IHRoaXMuZGVwbG95bWVudFJldmlzaW9uICsgYXNzZXQudGFyZ2V0LFxuICAgICAgICAgICAgICAgIHBydW5lOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBzdG9yYWdlQ2xhc3M6IFN0b3JhZ2VDbGFzcy5TVEFOREFSRCxcbiAgICAgICAgICAgICAgICBleGNsdWRlOiBbJyonXSxcbiAgICAgICAgICAgICAgICBpbmNsdWRlOiBbYXNzZXQucGF0dGVybl0sXG4gICAgICAgICAgICAgICAgY2FjaGVDb250cm9sOiBhc3NldC5jYWNoZUNvbnRyb2wgPz8gZGVmYXVsdENhY2hlQ29uZmlnLFxuICAgICAgICAgICAgICAgIGNvbnRlbnRUeXBlOiBhc3NldC5jb250ZW50VHlwZSxcbiAgICAgICAgICAgICAgICBsb2dSZXRlbnRpb246IFJldGVudGlvbkRheXMuT05FX0RBWSxcbiAgICAgICAgICAgICAgICBtZW1vcnlMaW1pdDogMjU2IC8vIFNvbWUgTnV4dCBhcHBsaWNhdGlvbnMgaGF2ZSBhIGxvdCBvZiBhc3NldHMgdG8gZGVwbG95IHdoZXJlYnkgdGhlIGZ1bmN0aW9uIG1pZ2h0IHJ1biBvdXQgb2YgbWVtb3J5XG4gICAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXNvbHZlcyB0aGUgaG9zdGVkIHpvbmUgYXQgd2hpY2ggdGhlIEROUyByZWNvcmRzIHNoYWxsIGJlIGNyZWF0ZWQgdG8gYWNjZXNzIG91ciBOdXh0IGFwcCBvbiB0aGUgaW50ZXJuZXQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcHJvcHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgZmluZEhvc3RlZFpvbmUocHJvcHM6IE51eHRBcHBTdGFja1Byb3BzKTogSUhvc3RlZFpvbmUge1xuICAgICAgICBjb25zdCBkb21haW5QYXJ0cyA9IHByb3BzLmRvbWFpbi5zcGxpdCgnLicpO1xuXG4gICAgICAgIHJldHVybiBIb3N0ZWRab25lLmZyb21Ib3N0ZWRab25lQXR0cmlidXRlcyh0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWhvc3RlZC16b25lYCwge1xuICAgICAgICAgICAgaG9zdGVkWm9uZUlkOiBwcm9wcy5ob3N0ZWRab25lSWQsXG4gICAgICAgICAgICB6b25lTmFtZTogZG9tYWluUGFydHNbZG9tYWluUGFydHMubGVuZ3RoIC0gMV0sIC8vIFN1cHBvcnQgc3ViZG9tYWluc1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIHRoZSBETlMgcmVjb3JkcyB0byBhY2Nlc3Mgb3VyIE51eHQgYXBwIG9uIHRoZSBpbnRlcm5ldCB2aWEgb3VyIGN1c3RvbSBkb21haW4uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcHJvcHNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlRG5zUmVjb3Jkcyhwcm9wczogTnV4dEFwcFN0YWNrUHJvcHMpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgaG9zdGVkWm9uZSA9IHRoaXMuZmluZEhvc3RlZFpvbmUocHJvcHMpO1xuICAgICAgICBjb25zdCBkbnNUYXJnZXQgPSBSZWNvcmRUYXJnZXQuZnJvbUFsaWFzKG5ldyBDbG91ZEZyb250VGFyZ2V0KHRoaXMuY2RuKSk7XG5cbiAgICAgICAgLy8gQ3JlYXRlIGEgcmVjb3JkIGZvciBJUHY0XG4gICAgICAgIG5ldyBBUmVjb3JkKHRoaXMsIGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0taXB2NC1yZWNvcmRgLCB7XG4gICAgICAgICAgICByZWNvcmROYW1lOiBwcm9wcy5kb21haW4sXG4gICAgICAgICAgICB6b25lOiBob3N0ZWRab25lLFxuICAgICAgICAgICAgdGFyZ2V0OiBkbnNUYXJnZXQsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIENyZWF0ZSBhIHJlY29yZCBmb3IgSVB2NlxuICAgICAgICBuZXcgQWFhYVJlY29yZCh0aGlzLCBgJHt0aGlzLnJlc291cmNlSWRQcmVmaXh9LWlwdjYtcmVjb3JkYCwge1xuICAgICAgICAgICAgcmVjb3JkTmFtZTogcHJvcHMuZG9tYWluLFxuICAgICAgICAgICAgem9uZTogaG9zdGVkWm9uZSxcbiAgICAgICAgICAgIHRhcmdldDogZG5zVGFyZ2V0LFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgc2NoZWR1bGVkIHJ1bGUgdG8gcGluZyBvdXIgTnV4dCBhcHAgbGFtYmRhIGZ1bmN0aW9uIGV2ZXJ5IDUgbWludXRlcyBpbiBvcmRlciB0byBrZWVwIGl0IHdhcm1cbiAgICAgKiBhbmQgc3BlZWQgdXAgaW5pdGlhbCBTU1IgcmVxdWVzdHMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlUGluZ1J1bGUoKTogdm9pZCB7XG4gICAgICAgIG5ldyBSdWxlKHRoaXMsIGAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0tcGluZ2VyLXJ1bGVgLCB7XG4gICAgICAgICAgICBydWxlTmFtZTogYCR7dGhpcy5yZXNvdXJjZUlkUHJlZml4fS1waW5nZXJgLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IGBQaW5ncyB0aGUgbGFtYmRhIGZ1bmN0aW9uIG9mIHRoZSAke3RoaXMucmVzb3VyY2VJZFByZWZpeH0gYXBwIGV2ZXJ5IDUgbWludXRlcyB0byBrZWVwIGl0IHdhcm0uYCxcbiAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgICAgICAgICBzY2hlZHVsZTogU2NoZWR1bGUucmF0ZShEdXJhdGlvbi5taW51dGVzKDUpKSxcbiAgICAgICAgICAgIHRhcmdldHM6IFtuZXcgTGFtYmRhRnVuY3Rpb24odGhpcy5sYW1iZGFGdW5jdGlvbildLFxuICAgICAgICB9KTtcbiAgICB9XG59XG4iXX0=
@@ -1,26 +1,33 @@
1
1
  import {Duration, RemovalPolicy, Stack} from 'aws-cdk-lib';
2
- import { Construct } from 'constructs';
2
+ import {Construct} from 'constructs';
3
3
  import {Certificate, ICertificate} from "aws-cdk-lib/aws-certificatemanager";
4
4
  import {
5
- AllowedMethods,
6
- BehaviorOptions, CacheCookieBehavior,
7
- CachedMethods, CacheHeaderBehavior,
8
- CachePolicy, CacheQueryStringBehavior,
9
- Distribution, ICachePolicy,
10
- IOriginAccessIdentity, OriginAccessIdentity, OriginProtocolPolicy, PriceClass,
11
- SecurityPolicyProtocol,
12
- ViewerProtocolPolicy
5
+ AllowedMethods,
6
+ BehaviorOptions,
7
+ CacheCookieBehavior,
8
+ CachedMethods,
9
+ CacheHeaderBehavior,
10
+ CachePolicy,
11
+ CacheQueryStringBehavior,
12
+ Distribution,
13
+ ICachePolicy,
14
+ IOriginAccessIdentity,
15
+ OriginAccessIdentity,
16
+ OriginProtocolPolicy,
17
+ PriceClass,
18
+ SecurityPolicyProtocol,
19
+ ViewerProtocolPolicy
13
20
  } from "aws-cdk-lib/aws-cloudfront";
14
- import {Architecture, Code, LayerVersion, Runtime, Function} from "aws-cdk-lib/aws-lambda";
21
+ import {Architecture, Code, Function, LayerVersion, Runtime} from "aws-cdk-lib/aws-lambda";
15
22
  import {BlockPublicAccess, Bucket, BucketAccessControl, IBucket} from "aws-cdk-lib/aws-s3";
16
- import {ARecord, AaaaRecord, HostedZone, IHostedZone, RecordTarget} from "aws-cdk-lib/aws-route53";
23
+ import {AaaaRecord, ARecord, HostedZone, IHostedZone, RecordTarget} from "aws-cdk-lib/aws-route53";
17
24
  import {BucketDeployment, CacheControl, Source, StorageClass} from "aws-cdk-lib/aws-s3-deployment";
18
25
  import {HttpOrigin, S3Origin} from "aws-cdk-lib/aws-cloudfront-origins";
19
26
  import {CloudFrontTarget} from "aws-cdk-lib/aws-route53-targets";
20
27
  import {HttpMethod} from "aws-cdk-lib/aws-stepfunctions-tasks";
21
28
  import {RetentionDays} from "aws-cdk-lib/aws-logs";
22
- import { HttpLambdaIntegration } from '@aws-cdk/aws-apigatewayv2-integrations-alpha';
23
- import {HttpApi} from "@aws-cdk/aws-apigatewayv2-alpha";
29
+ import {HttpLambdaIntegration} from '@aws-cdk/aws-apigatewayv2-integrations-alpha';
30
+ import {DomainName, HttpApi} from "@aws-cdk/aws-apigatewayv2-alpha";
24
31
  import {getNuxtAppStaticAssetConfigs, StaticAssetConfig} from "./nuxt-app-static-assets";
25
32
  import {AppStackProps} from "./app-stack-props";
26
33
  import * as fs from "fs";
@@ -32,30 +39,30 @@ import {NuxtConfig} from "./nuxt-config";
32
39
  * Defines the props required for the {@see NuxtAppStack}.
33
40
  */
34
41
  export interface NuxtAppStackProps extends AppStackProps {
35
- /**
36
- * The domain (without the protocol) at which the Nuxt app shall be publicly available.
37
- * A DNS record will be automatically created in Route53 for the domain.
38
- * This also supports subdomains.
39
- * Examples: "example.com", "sub.example.com"
40
- */
41
- readonly domain: string;
42
-
43
- /**
44
- * The id of the hosted zone to create a DNS record for the specified domain.
45
- */
46
- readonly hostedZoneId: string;
47
-
48
- /**
49
- * The ARN of the certificate to use for the Nuxt app to make it accessible via HTTPS.
50
- * The certificate must be issued for the specified domain in us-east-1 (global) regardless of the
51
- * region used for the Nuxt app itself.
52
- */
53
- readonly globalTlsCertificateArn: string;
54
-
55
- /**
56
- * The nuxt.config.js of the Nuxt app.
57
- */
58
- readonly nuxtConfig: NuxtConfig;
42
+ /**
43
+ * The domain (without the protocol) at which the Nuxt app shall be publicly available.
44
+ * A DNS record will be automatically created in Route53 for the domain.
45
+ * This also supports subdomains.
46
+ * Examples: "example.com", "sub.example.com"
47
+ */
48
+ readonly domain: string;
49
+
50
+ /**
51
+ * The id of the hosted zone to create a DNS record for the specified domain.
52
+ */
53
+ readonly hostedZoneId: string;
54
+
55
+ /**
56
+ * The ARN of the certificate to use for the Nuxt app to make it accessible via HTTPS.
57
+ * The certificate must be issued for the specified domain in us-east-1 (global) regardless of the
58
+ * region used for the Nuxt app itself.
59
+ */
60
+ readonly globalTlsCertificateArn: string;
61
+
62
+ /**
63
+ * The nuxt.config.js of the Nuxt app.
64
+ */
65
+ readonly nuxtConfig: NuxtConfig;
59
66
  }
60
67
 
61
68
  /**
@@ -63,375 +70,389 @@ export interface NuxtAppStackProps extends AppStackProps {
63
70
  */
64
71
  export class NuxtAppStack extends Stack {
65
72
 
66
- /**
67
- * The identifier prefix of the resources created by the stack.
68
- *
69
- * @private
70
- */
71
- private readonly resourceIdPrefix: string;
72
-
73
- /**
74
- * The identifier for the current deployment that is used as S3 folder name
75
- * to store the static assets of the Nuxt app.
76
- *
77
- * @private
78
- */
79
- private readonly deploymentRevision: string;
80
-
81
- /**
82
- * The certificate to use for the Nuxt app to make it accessible via HTTPS.
83
- *
84
- * @private
85
- */
86
- private readonly tlsCertificate: ICertificate;
87
-
88
- /**
89
- * The identity to use for accessing the deployment assets on S3.
90
- *
91
- * @private
92
- */
93
- private readonly cdnAccessIdentity: IOriginAccessIdentity;
94
-
95
- /**
96
- * The S3 bucket where the deployment assets gets stored.
97
- */
98
- public staticAssetsBucket: IBucket;
99
-
100
- /**
101
- * The lambda function to render the Nuxt app on the server side.
102
- *
103
- * @private
104
- */
105
- private readonly lambdaFunction: Function;
106
-
107
- /**
108
- * The API gateway to make the lambda function to render the Nuxt app publicly available.
109
- *
110
- * @private
111
- */
112
- private apiGateway: HttpApi;
113
-
114
- /**
115
- * The configs for the static assets of the Nuxt app that shall be publicly available.
116
- *
117
- * @private
118
- */
119
- private staticAssetConfigs: StaticAssetConfig[];
120
-
121
- /**
122
- * The cloudfront distribution to route incoming requests to the Nuxt lambda function (via the API gateway)
123
- * or the S3 assets folder (with caching).
124
- *
125
- * @private
126
- */
127
- private readonly cdn: Distribution;
128
-
129
- constructor(scope: Construct, id: string, props: NuxtAppStackProps) {
130
- super(scope, id, props);
131
-
132
- this.resourceIdPrefix = `${props.project}-${props.service}-${props.environment}`;
133
- this.deploymentRevision = new Date().toISOString();
134
- this.staticAssetConfigs = getNuxtAppStaticAssetConfigs(props.nuxtConfig);
135
- this.tlsCertificate = this.findTlsCertificate(props);
136
- this.cdnAccessIdentity = this.createCdnAccessIdentity();
137
- this.staticAssetsBucket = this.createStaticAssetsBucket();
138
- this.lambdaFunction = this.createLambdaFunction();
139
- this.apiGateway = this.createApiGateway();
140
- this.cdn = this.createCloudFrontDistribution(props);
141
- this.configureDeployments();
142
- this.createDnsRecords(props);
143
- this.createPingRule();
144
- }
145
-
146
- /**
147
- * Finds the certificate to use for providing HTTPS requests to our Nuxt app.
148
- *
149
- * @param props
150
- * @private
151
- */
152
- private findTlsCertificate(props: NuxtAppStackProps): ICertificate {
153
- return Certificate.fromCertificateArn(this, `${this.resourceIdPrefix}-tls-certificate`, props.globalTlsCertificateArn);
154
- }
155
-
156
- /**
157
- * Creates the identity to access our S3 deployment asset files via the cloudfront distribution.
158
- *
159
- * @private
160
- */
161
- private createCdnAccessIdentity(): IOriginAccessIdentity {
162
- const originAccessIdentityName = `${this.resourceIdPrefix}-cdn-s3-access`;
163
- return new OriginAccessIdentity(this, originAccessIdentityName);
164
- }
165
-
166
- /**
167
- * Creates the bucket to store the static deployment asset files of the Nuxt app.
168
- *
169
- * @private
170
- */
171
- private createStaticAssetsBucket(): IBucket {
172
- const bucketName = `${this.resourceIdPrefix}-assets`;
173
- const bucket = new Bucket(this, bucketName, {
174
- accessControl: BucketAccessControl.AUTHENTICATED_READ,
175
- blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
176
- bucketName,
177
- // The bucket and all of its objects can be deleted, because all the content is managed in this project
178
- removalPolicy: RemovalPolicy.DESTROY,
179
- autoDeleteObjects: true,
180
- });
181
-
182
- bucket.grantReadWrite(this.cdnAccessIdentity);
183
-
184
- return bucket;
185
- }
186
-
187
- /**
188
- * Creates a lambda layer with the node_modules required to render the Nuxt app on the server side.
189
- *
190
- * @private
191
- */
192
- private createSsrLambdaLayer(): LayerVersion {
193
- const layerName = `${this.resourceIdPrefix}-ssr-layer`;
194
- return new LayerVersion(this, layerName, {
195
- layerVersionName: layerName,
196
- code: Code.fromAsset('.nuxt/cdk-deployment/layer'),
197
- compatibleRuntimes: [Runtime.NODEJS_12_X],
198
- description: `Provides the node_modules required for SSR of ${this.resourceIdPrefix}.`,
199
- });
200
- }
201
-
202
- /**
203
- * Creates the lambda function to render the Nuxt app.
204
- *
205
- * @private
206
- */
207
- private createLambdaFunction(): Function {
208
- const funcName = `${this.resourceIdPrefix}-function`;
209
-
210
- return new Function(this, funcName, {
211
- functionName: funcName,
212
- description: `Renders the ${this.resourceIdPrefix} Nuxt app.`,
213
- runtime: Runtime.NODEJS_12_X,
214
- architecture: Architecture.ARM_64,
215
- layers: [this.createSsrLambdaLayer()],
216
- handler: 'index.handler',
217
- code: Code.fromAsset('.nuxt/cdk-deployment/src', {
218
- exclude: ['**.svg', '**.ico', '**.png', '**.jpg', '**.js.map'],
219
- }),
220
- timeout: Duration.seconds(10),
221
- memorySize: 512,
222
- logRetention: RetentionDays.ONE_MONTH,
223
- allowPublicSubnet: false
224
- });
225
- }
226
-
227
- /**
228
- * Creates the API gateway to make the Nuxt app render lambda function publicly available.
229
- *
230
- * @private
231
- */
232
- private createApiGateway(): HttpApi {
233
- const lambdaIntegration = new HttpLambdaIntegration(`${this.resourceIdPrefix}-lambda-integration`, this.lambdaFunction);
234
- const apiName = `${this.resourceIdPrefix}-api`;
235
- const apiGateway = new HttpApi(this, apiName, {
236
- apiName,
237
- description: `Connects the ${this.resourceIdPrefix} cloudfront distribution with the ${this.resourceIdPrefix} lambda function to make it publicly available.`,
238
- // The app does not allow any cross-origin access by purpose: the app should not be embeddable anywhere
239
- corsPreflight: undefined,
240
- defaultIntegration: lambdaIntegration,
241
- });
242
-
243
- apiGateway.addRoutes({
244
- integration: lambdaIntegration,
245
- path: '/{proxy+}',
246
- methods: [HttpMethod.GET, HttpMethod.HEAD],
247
- });
248
- return apiGateway;
249
- }
250
-
251
- /**
252
- * Creates the cloudfront distribution that routes incoming requests to the Nuxt lambda function (via the API gateway)
253
- * or the S3 assets folder (with caching).
254
- *
255
- * @param props
256
- * @private
257
- */
258
- private createCloudFrontDistribution(props: NuxtAppStackProps): Distribution {
259
- const cdnName = `${this.resourceIdPrefix}-cdn`;
260
-
261
- return new Distribution(this, cdnName, {
262
- domainNames: [props.domain],
263
- comment: `${this.resourceIdPrefix}-redirect`,
264
- minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2018,
265
- certificate: this.tlsCertificate,
266
- defaultBehavior: this.createNuxtAppRouteBehavior(),
267
- additionalBehaviors: this.createStaticAssetsRouteBehavior(),
268
- priceClass: PriceClass.PRICE_CLASS_100, // Use only North America and Europe
269
- });
270
- }
271
-
272
- /**
273
- * Creates a behavior for the cloudfront distribution to route incoming requests to the Nuxt render lambda function (via API gateway).
274
- * Additionally, this automatically redirects HTTP requests to HTTPS.
275
- *
276
- * @private
277
- */
278
- private createNuxtAppRouteBehavior(): BehaviorOptions {
279
- return {
280
- origin: new HttpOrigin(`${this.apiGateway.httpApiId}.execute-api.${this.region}.amazonaws.com`, {
281
- connectionAttempts: 2,
282
- connectionTimeout: Duration.seconds(2),
283
- readTimeout: Duration.seconds(10),
284
- protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
285
- }),
286
- allowedMethods: AllowedMethods.ALLOW_GET_HEAD,
287
- compress: true,
288
- viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
289
- originRequestPolicy: undefined,
290
- cachePolicy: this.createSsrCachePolicy(),
291
- };
292
- }
293
-
294
- /**
295
- * Creates a cache policy for the Nuxt app route behavior of our cloudfront distribution.
296
- * Eventhough we don't want to cache SSR requests, we still have to create this cache policy in order to
297
- * forward required cookies, query params and headers. This doesn't make any sense, because if nothing
298
- * is cached, one would expect, that anything would/could be forwarded, but anyway...
299
- */
300
- private createSsrCachePolicy(): ICachePolicy {
301
-
302
- // The headers to make accessible in our Nuxt app code
303
- const headers = [
304
- 'User-Agent', // Required to distinguish between mobile and desktop template
305
- 'Authorization', // For authorization
306
- ];
307
-
308
- return new CachePolicy(this, `${this.resourceIdPrefix}-cache-policy`, {
309
- cachePolicyName: `${this.resourceIdPrefix}-cdn-cache-policy`,
310
- comment: `Passes all required request data to the ${this.resourceIdPrefix} origin.`,
311
- defaultTtl: Duration.seconds(0),
312
- minTtl: Duration.seconds(0),
313
- maxTtl: Duration.seconds(1), // The max TTL must not be 0 for a cache policy
314
- queryStringBehavior: CacheQueryStringBehavior.all(),
315
- headerBehavior: CacheHeaderBehavior.allowList(...headers),
316
- cookieBehavior: CacheCookieBehavior.all(),
317
- enableAcceptEncodingBrotli: true,
318
- enableAcceptEncodingGzip: true,
319
- });
320
- }
321
-
322
- /**
323
- * Creates a behavior for the cloudfront distribution to route matching incoming requests for our static assets
324
- * to the S3 bucket that holds these static assets.
325
- *
326
- * @private
327
- */
328
- private createStaticAssetsRouteBehavior(): Record<string, BehaviorOptions> {
329
- const staticAssetsCacheConfig: BehaviorOptions = {
330
- origin: new S3Origin(this.staticAssetsBucket, {
331
- connectionAttempts: 2,
332
- connectionTimeout: Duration.seconds(3),
333
- originAccessIdentity: this.cdnAccessIdentity,
334
- originPath: this.deploymentRevision,
335
- }),
336
- compress: true,
337
- allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
338
- cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
339
- cachePolicy: CachePolicy.CACHING_OPTIMIZED,
340
- viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
341
- };
342
-
343
- const rules: Record<string, BehaviorOptions> = {};
344
- this.staticAssetConfigs.forEach(asset => {
345
- rules[`${asset.target}${asset.pattern}`] = staticAssetsCacheConfig
346
- })
347
-
348
- return rules
349
- }
350
-
351
- /**
352
- * Uploads the static assets of the Nuxt app as defined in {@see getNuxtAppStaticAssetConfigs} to the static assets S3 bucket.
353
- * In order to enable a zero-downtime deployment, we use a new subdirectory (revision) for every deployment.
354
- * The previous versions are retained to allow clients to continue to work with an older revision but gets cleaned up
355
- * after a specified period of time via the lambda function in the {@see NuxtAppAssetsCleanupStack}.
356
- */
357
- private configureDeployments(): BucketDeployment[] {
358
- const defaultCacheConfig = [
359
- CacheControl.setPublic(),
360
- CacheControl.maxAge(Duration.days(365)),
361
- CacheControl.fromString('immutable'),
362
- ];
363
-
364
- // Returns a deployment for every configured static asset type to respect the different cache settings
365
- return this.staticAssetConfigs.filter(asset => fs.existsSync(asset.source)).map((asset, assetIndex) => {
366
- return new BucketDeployment(this, `${this.resourceIdPrefix}-assets-deployment-${assetIndex}`, {
367
- sources: [Source.asset(asset.source)],
368
- destinationBucket: this.staticAssetsBucket,
369
- destinationKeyPrefix: this.deploymentRevision + asset.target,
370
- prune: false,
371
- storageClass: StorageClass.STANDARD,
372
- exclude: ['*'],
373
- include: [asset.pattern],
374
- cacheControl: asset.cacheControl ?? defaultCacheConfig,
375
- contentType: asset.contentType,
376
- logRetention: RetentionDays.ONE_DAY,
377
- memoryLimit: 256 // Some Nuxt applications have a lot of assets to deploy whereby the function might run out of memory
378
- })
379
- });
380
- }
381
-
382
- /**
383
- * Resolves the hosted zone at which the DNS records shall be created to access our Nuxt app on the internet.
384
- *
385
- * @param props
386
- * @private
387
- */
388
- private findHostedZone(props: NuxtAppStackProps): IHostedZone {
389
- const domainParts = props.domain.split('.');
390
-
391
- return HostedZone.fromHostedZoneAttributes(this, `${this.resourceIdPrefix}-hosted-zone`, {
392
- hostedZoneId: props.hostedZoneId,
393
- zoneName: domainParts[domainParts.length - 1], // Support subdomains
394
- });
395
- }
396
-
397
- /**
398
- * Creates the DNS records to access our Nuxt app on the internet via our custom domain.
399
- *
400
- * @param props
401
- * @private
402
- */
403
- private createDnsRecords(props: NuxtAppStackProps): void {
404
- const hostedZone = this.findHostedZone(props);
405
- const dnsTarget = RecordTarget.fromAlias(new CloudFrontTarget(this.cdn));
406
-
407
- // Create a record for IPv4
408
- new ARecord(this, `${this.resourceIdPrefix}-ipv4-record`, {
409
- recordName: props.domain,
410
- zone: hostedZone,
411
- target: dnsTarget,
412
- });
413
-
414
- // Create a record for IPv6
415
- new AaaaRecord(this, `${this.resourceIdPrefix}-ipv6-record`, {
416
- recordName: props.domain,
417
- zone: hostedZone,
418
- target: dnsTarget,
419
- });
420
- }
421
-
422
- /**
423
- * Creates a scheduled rule to ping our Nuxt app lambda function every 5 minutes in order to keep it warm
424
- * and speed up initial SSR requests.
425
- *
426
- * @private
427
- */
428
- private createPingRule(): void {
429
- new Rule(this, `${this.resourceIdPrefix}-pinger-rule`, {
430
- ruleName: `${this.resourceIdPrefix}-pinger`,
431
- description: `Pings the lambda function of the ${this.resourceIdPrefix} app every 5 minutes to keep it warm.`,
432
- enabled: true,
433
- schedule: Schedule.rate(Duration.minutes(5)),
434
- targets: [new LambdaFunction(this.lambdaFunction)],
435
- });
436
- }
73
+ /**
74
+ * The identifier prefix of the resources created by the stack.
75
+ *
76
+ * @private
77
+ */
78
+ private readonly resourceIdPrefix: string;
79
+
80
+ /**
81
+ * The identifier for the current deployment that is used as S3 folder name
82
+ * to store the static assets of the Nuxt app.
83
+ *
84
+ * @private
85
+ */
86
+ private readonly deploymentRevision: string;
87
+
88
+ /**
89
+ * The certificate to use for the Nuxt app to make it accessible via HTTPS.
90
+ *
91
+ * @private
92
+ */
93
+ private readonly tlsCertificate: ICertificate;
94
+
95
+ /**
96
+ * The identity to use for accessing the deployment assets on S3.
97
+ *
98
+ * @private
99
+ */
100
+ private readonly cdnAccessIdentity: IOriginAccessIdentity;
101
+
102
+ /**
103
+ * The S3 bucket where the deployment assets gets stored.
104
+ */
105
+ public staticAssetsBucket: IBucket;
106
+
107
+ /**
108
+ * The lambda function to render the Nuxt app on the server side.
109
+ *
110
+ * @private
111
+ */
112
+ private readonly lambdaFunction: Function;
113
+
114
+ /**
115
+ * The API gateway to make the lambda function to render the Nuxt app publicly available.
116
+ *
117
+ * @private
118
+ */
119
+ private apiGateway: HttpApi;
120
+
121
+ /**
122
+ * The configs for the static assets of the Nuxt app that shall be publicly available.
123
+ *
124
+ * @private
125
+ */
126
+ private staticAssetConfigs: StaticAssetConfig[];
127
+
128
+ /**
129
+ * The cloudfront distribution to route incoming requests to the Nuxt lambda function (via the API gateway)
130
+ * or the S3 assets folder (with caching).
131
+ *
132
+ * @private
133
+ */
134
+ private readonly cdn: Distribution;
135
+
136
+ constructor(scope: Construct, id: string, props: NuxtAppStackProps) {
137
+ super(scope, id, props);
138
+
139
+ this.resourceIdPrefix = `${props.project}-${props.service}-${props.environment}`;
140
+ this.deploymentRevision = new Date().toISOString();
141
+ this.staticAssetConfigs = getNuxtAppStaticAssetConfigs(props.nuxtConfig);
142
+ this.tlsCertificate = this.findTlsCertificate(props);
143
+ this.cdnAccessIdentity = this.createCdnAccessIdentity();
144
+ this.staticAssetsBucket = this.createStaticAssetsBucket();
145
+ this.lambdaFunction = this.createLambdaFunction();
146
+ this.apiGateway = this.createApiGateway(props);
147
+ this.cdn = this.createCloudFrontDistribution(props);
148
+ this.configureDeployments();
149
+ this.createDnsRecords(props);
150
+ this.createPingRule();
151
+ }
152
+
153
+ /**
154
+ * Finds the certificate to use for providing HTTPS requests to our Nuxt app.
155
+ *
156
+ * @param props
157
+ * @private
158
+ */
159
+ private findTlsCertificate(props: NuxtAppStackProps): ICertificate {
160
+ return Certificate.fromCertificateArn(this, `${this.resourceIdPrefix}-tls-certificate`, props.globalTlsCertificateArn);
161
+ }
162
+
163
+ /**
164
+ * Creates the identity to access our S3 deployment asset files via the cloudfront distribution.
165
+ *
166
+ * @private
167
+ */
168
+ private createCdnAccessIdentity(): IOriginAccessIdentity {
169
+ const originAccessIdentityName = `${this.resourceIdPrefix}-cdn-s3-access`;
170
+ return new OriginAccessIdentity(this, originAccessIdentityName);
171
+ }
172
+
173
+ /**
174
+ * Creates the bucket to store the static deployment asset files of the Nuxt app.
175
+ *
176
+ * @private
177
+ */
178
+ private createStaticAssetsBucket(): IBucket {
179
+ const bucketName = `${this.resourceIdPrefix}-assets`;
180
+ const bucket = new Bucket(this, bucketName, {
181
+ accessControl: BucketAccessControl.AUTHENTICATED_READ,
182
+ blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
183
+ bucketName,
184
+ // The bucket and all of its objects can be deleted, because all the content is managed in this project
185
+ removalPolicy: RemovalPolicy.DESTROY,
186
+ autoDeleteObjects: true,
187
+ });
188
+
189
+ bucket.grantReadWrite(this.cdnAccessIdentity);
190
+
191
+ return bucket;
192
+ }
193
+
194
+ /**
195
+ * Creates a lambda layer with the node_modules required to render the Nuxt app on the server side.
196
+ *
197
+ * @private
198
+ */
199
+ private createSsrLambdaLayer(): LayerVersion {
200
+ const layerName = `${this.resourceIdPrefix}-ssr-layer`;
201
+ return new LayerVersion(this, layerName, {
202
+ layerVersionName: layerName,
203
+ code: Code.fromAsset('.nuxt/cdk-deployment/layer'),
204
+ compatibleRuntimes: [Runtime.NODEJS_12_X],
205
+ description: `Provides the node_modules required for SSR of ${this.resourceIdPrefix}.`,
206
+ });
207
+ }
208
+
209
+ /**
210
+ * Creates the lambda function to render the Nuxt app.
211
+ *
212
+ * @private
213
+ */
214
+ private createLambdaFunction(): Function {
215
+ const funcName = `${this.resourceIdPrefix}-function`;
216
+
217
+ return new Function(this, funcName, {
218
+ functionName: funcName,
219
+ description: `Renders the ${this.resourceIdPrefix} Nuxt app.`,
220
+ runtime: Runtime.NODEJS_12_X,
221
+ architecture: Architecture.ARM_64,
222
+ layers: [this.createSsrLambdaLayer()],
223
+ handler: 'index.handler',
224
+ code: Code.fromAsset('.nuxt/cdk-deployment/src', {
225
+ exclude: ['**.svg', '**.ico', '**.png', '**.jpg', '**.js.map'],
226
+ }),
227
+ timeout: Duration.seconds(10),
228
+ memorySize: 512,
229
+ logRetention: RetentionDays.ONE_MONTH,
230
+ allowPublicSubnet: false
231
+ });
232
+ }
233
+
234
+ /**
235
+ * Creates the API gateway to make the Nuxt app render lambda function publicly available.
236
+ *
237
+ * @private
238
+ */
239
+ private createApiGateway(props: NuxtAppStackProps): HttpApi {
240
+ const apiName = `${this.resourceIdPrefix}-api`;
241
+ const lambdaIntegration = new HttpLambdaIntegration(`${this.resourceIdPrefix}-lambda-integration`, this.lambdaFunction);
242
+
243
+ // We want the API gateway to be accessible by the custom domain name.
244
+ // Even though we access the gateway via Cloudfront (for auto http to https redirects), this is required
245
+ // to be able to redirect the original 'Host' header to our Nuxt application, if requested.
246
+ const domainName = new DomainName(this, `${this.resourceIdPrefix}-api-domain`, {
247
+ domainName: props.domain,
248
+ certificate: this.tlsCertificate
249
+ })
250
+
251
+ const apiGateway = new HttpApi(this, apiName, {
252
+ apiName,
253
+ description: `Connects the ${this.resourceIdPrefix} cloudfront distribution with the ${this.resourceIdPrefix} lambda function to make it publicly available.`,
254
+ // The app does not allow any cross-origin access by purpose: the app should not be embeddable anywhere
255
+ corsPreflight: undefined,
256
+ defaultIntegration: lambdaIntegration,
257
+ defaultDomainMapping: {
258
+ domainName: domainName
259
+ }
260
+ });
261
+
262
+ apiGateway.addRoutes({
263
+ integration: lambdaIntegration,
264
+ path: '/{proxy+}',
265
+ methods: [HttpMethod.GET, HttpMethod.HEAD],
266
+ });
267
+ return apiGateway;
268
+ }
269
+
270
+ /**
271
+ * Creates the cloudfront distribution that routes incoming requests to the Nuxt lambda function (via the API gateway)
272
+ * or the S3 assets folder (with caching).
273
+ *
274
+ * @param props
275
+ * @private
276
+ */
277
+ private createCloudFrontDistribution(props: NuxtAppStackProps): Distribution {
278
+ const cdnName = `${this.resourceIdPrefix}-cdn`;
279
+
280
+ return new Distribution(this, cdnName, {
281
+ domainNames: [props.domain],
282
+ comment: `${this.resourceIdPrefix}-redirect`,
283
+ minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2018,
284
+ certificate: this.tlsCertificate,
285
+ defaultBehavior: this.createNuxtAppRouteBehavior(),
286
+ additionalBehaviors: this.createStaticAssetsRouteBehavior(),
287
+ priceClass: PriceClass.PRICE_CLASS_100, // Use only North America and Europe
288
+ });
289
+ }
290
+
291
+ /**
292
+ * Creates a behavior for the cloudfront distribution to route incoming requests to the Nuxt render lambda function (via API gateway).
293
+ * Additionally, this automatically redirects HTTP requests to HTTPS.
294
+ *
295
+ * @private
296
+ */
297
+ private createNuxtAppRouteBehavior(): BehaviorOptions {
298
+ return {
299
+ origin: new HttpOrigin(`${this.apiGateway.httpApiId}.execute-api.${this.region}.amazonaws.com`, {
300
+ connectionAttempts: 2,
301
+ connectionTimeout: Duration.seconds(2),
302
+ readTimeout: Duration.seconds(10),
303
+ protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
304
+ }),
305
+ allowedMethods: AllowedMethods.ALLOW_GET_HEAD,
306
+ compress: true,
307
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
308
+ originRequestPolicy: undefined,
309
+ cachePolicy: this.createSsrCachePolicy(),
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Creates a cache policy for the Nuxt app route behavior of our cloudfront distribution.
315
+ * Eventhough we don't want to cache SSR requests, we still have to create this cache policy in order to
316
+ * forward required cookies, query params and headers. This doesn't make any sense, because if nothing
317
+ * is cached, one would expect, that anything would/could be forwarded, but anyway...
318
+ */
319
+ private createSsrCachePolicy(): ICachePolicy {
320
+
321
+ // The headers to make accessible in our Nuxt app code.
322
+ // There is no 'CacheHeaderBehavior.all()' option, so we have to explicitly define them.
323
+ const headers = [
324
+ 'User-Agent', // Required to distinguish between mobile and desktop template
325
+ 'Authorization', // For authorization
326
+ 'Host' // To access the domain name on SSR requests
327
+ ];
328
+
329
+ return new CachePolicy(this, `${this.resourceIdPrefix}-cache-policy`, {
330
+ cachePolicyName: `${this.resourceIdPrefix}-cdn-cache-policy`,
331
+ comment: `Passes all required request data to the ${this.resourceIdPrefix} origin.`,
332
+ defaultTtl: Duration.seconds(0),
333
+ minTtl: Duration.seconds(0),
334
+ maxTtl: Duration.seconds(1), // The max TTL must not be 0 for a cache policy
335
+ queryStringBehavior: CacheQueryStringBehavior.all(),
336
+ headerBehavior: CacheHeaderBehavior.allowList(...headers),
337
+ cookieBehavior: CacheCookieBehavior.all(),
338
+ enableAcceptEncodingBrotli: true,
339
+ enableAcceptEncodingGzip: true,
340
+ });
341
+ }
342
+
343
+ /**
344
+ * Creates a behavior for the cloudfront distribution to route matching incoming requests for our static assets
345
+ * to the S3 bucket that holds these static assets.
346
+ *
347
+ * @private
348
+ */
349
+ private createStaticAssetsRouteBehavior(): Record<string, BehaviorOptions> {
350
+ const staticAssetsCacheConfig: BehaviorOptions = {
351
+ origin: new S3Origin(this.staticAssetsBucket, {
352
+ connectionAttempts: 2,
353
+ connectionTimeout: Duration.seconds(3),
354
+ originAccessIdentity: this.cdnAccessIdentity,
355
+ originPath: this.deploymentRevision,
356
+ }),
357
+ compress: true,
358
+ allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
359
+ cachedMethods: CachedMethods.CACHE_GET_HEAD_OPTIONS,
360
+ cachePolicy: CachePolicy.CACHING_OPTIMIZED,
361
+ viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
362
+ };
363
+
364
+ const rules: Record<string, BehaviorOptions> = {};
365
+ this.staticAssetConfigs.forEach(asset => {
366
+ rules[`${asset.target}${asset.pattern}`] = staticAssetsCacheConfig
367
+ })
368
+
369
+ return rules
370
+ }
371
+
372
+ /**
373
+ * Uploads the static assets of the Nuxt app as defined in {@see getNuxtAppStaticAssetConfigs} to the static assets S3 bucket.
374
+ * In order to enable a zero-downtime deployment, we use a new subdirectory (revision) for every deployment.
375
+ * The previous versions are retained to allow clients to continue to work with an older revision but gets cleaned up
376
+ * after a specified period of time via the lambda function in the {@see NuxtAppAssetsCleanupStack}.
377
+ */
378
+ private configureDeployments(): BucketDeployment[] {
379
+ const defaultCacheConfig = [
380
+ CacheControl.setPublic(),
381
+ CacheControl.maxAge(Duration.days(365)),
382
+ CacheControl.fromString('immutable'),
383
+ ];
384
+
385
+ // Returns a deployment for every configured static asset type to respect the different cache settings
386
+ return this.staticAssetConfigs.filter(asset => fs.existsSync(asset.source)).map((asset, assetIndex) => {
387
+ return new BucketDeployment(this, `${this.resourceIdPrefix}-assets-deployment-${assetIndex}`, {
388
+ sources: [Source.asset(asset.source)],
389
+ destinationBucket: this.staticAssetsBucket,
390
+ destinationKeyPrefix: this.deploymentRevision + asset.target,
391
+ prune: false,
392
+ storageClass: StorageClass.STANDARD,
393
+ exclude: ['*'],
394
+ include: [asset.pattern],
395
+ cacheControl: asset.cacheControl ?? defaultCacheConfig,
396
+ contentType: asset.contentType,
397
+ logRetention: RetentionDays.ONE_DAY,
398
+ memoryLimit: 256 // Some Nuxt applications have a lot of assets to deploy whereby the function might run out of memory
399
+ })
400
+ });
401
+ }
402
+
403
+ /**
404
+ * Resolves the hosted zone at which the DNS records shall be created to access our Nuxt app on the internet.
405
+ *
406
+ * @param props
407
+ * @private
408
+ */
409
+ private findHostedZone(props: NuxtAppStackProps): IHostedZone {
410
+ const domainParts = props.domain.split('.');
411
+
412
+ return HostedZone.fromHostedZoneAttributes(this, `${this.resourceIdPrefix}-hosted-zone`, {
413
+ hostedZoneId: props.hostedZoneId,
414
+ zoneName: domainParts[domainParts.length - 1], // Support subdomains
415
+ });
416
+ }
417
+
418
+ /**
419
+ * Creates the DNS records to access our Nuxt app on the internet via our custom domain.
420
+ *
421
+ * @param props
422
+ * @private
423
+ */
424
+ private createDnsRecords(props: NuxtAppStackProps): void {
425
+ const hostedZone = this.findHostedZone(props);
426
+ const dnsTarget = RecordTarget.fromAlias(new CloudFrontTarget(this.cdn));
427
+
428
+ // Create a record for IPv4
429
+ new ARecord(this, `${this.resourceIdPrefix}-ipv4-record`, {
430
+ recordName: props.domain,
431
+ zone: hostedZone,
432
+ target: dnsTarget,
433
+ });
434
+
435
+ // Create a record for IPv6
436
+ new AaaaRecord(this, `${this.resourceIdPrefix}-ipv6-record`, {
437
+ recordName: props.domain,
438
+ zone: hostedZone,
439
+ target: dnsTarget,
440
+ });
441
+ }
442
+
443
+ /**
444
+ * Creates a scheduled rule to ping our Nuxt app lambda function every 5 minutes in order to keep it warm
445
+ * and speed up initial SSR requests.
446
+ *
447
+ * @private
448
+ */
449
+ private createPingRule(): void {
450
+ new Rule(this, `${this.resourceIdPrefix}-pinger-rule`, {
451
+ ruleName: `${this.resourceIdPrefix}-pinger`,
452
+ description: `Pings the lambda function of the ${this.resourceIdPrefix} app every 5 minutes to keep it warm.`,
453
+ enabled: true,
454
+ schedule: Schedule.rate(Duration.minutes(5)),
455
+ targets: [new LambdaFunction(this.lambdaFunction)],
456
+ });
457
+ }
437
458
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cdk-nuxt",
3
- "version": "0.3.12",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "lib",