@cdklabs/cdk-appmod-catalog-blueprints 1.0.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.
Files changed (105) hide show
  1. package/.jsii +8644 -0
  2. package/LICENSE +202 -0
  3. package/README.md +212 -0
  4. package/lib/document-processing/agentic-document-processing.d.ts +16 -0
  5. package/lib/document-processing/agentic-document-processing.js +90 -0
  6. package/lib/document-processing/base-document-processing.d.ts +189 -0
  7. package/lib/document-processing/base-document-processing.js +509 -0
  8. package/lib/document-processing/bedrock-document-processing.d.ts +167 -0
  9. package/lib/document-processing/bedrock-document-processing.js +297 -0
  10. package/lib/document-processing/index.d.ts +3 -0
  11. package/lib/document-processing/index.js +20 -0
  12. package/lib/document-processing/resources/default-bedrock-invoke/index.py +63 -0
  13. package/lib/document-processing/resources/default-bedrock-invoke/requirements.txt +4 -0
  14. package/lib/document-processing/resources/default-doc-retrieval-lambda/index.mjs +92 -0
  15. package/lib/document-processing/resources/default-doc-retrieval-lambda/package.json +10 -0
  16. package/lib/document-processing/resources/default-error-handler/index.js +46 -0
  17. package/lib/document-processing/resources/default-error-handler/package.json +4 -0
  18. package/lib/document-processing/resources/default-image-processor/classifier.mjs +665 -0
  19. package/lib/document-processing/resources/default-image-processor/extractors.mjs +465 -0
  20. package/lib/document-processing/resources/default-image-processor/index.mjs +143 -0
  21. package/lib/document-processing/resources/default-image-processor/package-lock.json +12 -0
  22. package/lib/document-processing/resources/default-image-processor/package.json +4 -0
  23. package/lib/document-processing/resources/default-image-validator/index.mjs +76 -0
  24. package/lib/document-processing/resources/default-image-validator/package-lock.json +154 -0
  25. package/lib/document-processing/resources/default-image-validator/package.json +7 -0
  26. package/lib/document-processing/resources/default-pdf-processor/index.js +46 -0
  27. package/lib/document-processing/resources/default-pdf-validator/index.js +36 -0
  28. package/lib/document-processing/resources/default-sqs-consumer/index.py +111 -0
  29. package/lib/document-processing/resources/default-sqs-consumer/requirements.txt +4 -0
  30. package/lib/document-processing/resources/default-sqs-consumer/sample_payload.json +20 -0
  31. package/lib/document-processing/resources/default-sqs-consumer/sample_payload_multi.json +24 -0
  32. package/lib/document-processing/resources/default-strands-agent/index.py +111 -0
  33. package/lib/document-processing/resources/default-strands-agent/requirements.txt +6 -0
  34. package/lib/document-processing/tests/agentic-document-processing-nag.test.d.ts +1 -0
  35. package/lib/document-processing/tests/agentic-document-processing-nag.test.js +107 -0
  36. package/lib/document-processing/tests/agentic-document-processing.test.d.ts +1 -0
  37. package/lib/document-processing/tests/agentic-document-processing.test.js +125 -0
  38. package/lib/document-processing/tests/bedrock-document-processing-nag.test.d.ts +1 -0
  39. package/lib/document-processing/tests/bedrock-document-processing-nag.test.js +101 -0
  40. package/lib/document-processing/tests/bedrock-document-processing.test.d.ts +1 -0
  41. package/lib/document-processing/tests/bedrock-document-processing.test.js +79 -0
  42. package/lib/framework/custom-resource/default-runtimes.d.ts +21 -0
  43. package/lib/framework/custom-resource/default-runtimes.js +34 -0
  44. package/lib/framework/custom-resource/index.d.ts +1 -0
  45. package/lib/framework/custom-resource/index.js +18 -0
  46. package/lib/framework/foundation/access-log.d.ts +69 -0
  47. package/lib/framework/foundation/access-log.js +121 -0
  48. package/lib/framework/foundation/eventbridge-broker.d.ts +18 -0
  49. package/lib/framework/foundation/eventbridge-broker.js +42 -0
  50. package/lib/framework/foundation/index.d.ts +3 -0
  51. package/lib/framework/foundation/index.js +20 -0
  52. package/lib/framework/foundation/network.d.ts +19 -0
  53. package/lib/framework/foundation/network.js +83 -0
  54. package/lib/framework/index.d.ts +2 -0
  55. package/lib/framework/index.js +19 -0
  56. package/lib/framework/quickstart/base-quickstart.d.ts +30 -0
  57. package/lib/framework/quickstart/base-quickstart.js +30 -0
  58. package/lib/index.d.ts +4 -0
  59. package/lib/index.js +21 -0
  60. package/lib/tsconfig.tsbuildinfo +1 -0
  61. package/lib/utilities/cdk-nag-config.d.ts +42 -0
  62. package/lib/utilities/cdk-nag-config.js +194 -0
  63. package/lib/utilities/data-loader-lambda/index.py +282 -0
  64. package/lib/utilities/data-loader-lambda/requirements.txt +3 -0
  65. package/lib/utilities/data-loader.d.ts +173 -0
  66. package/lib/utilities/data-loader.js +447 -0
  67. package/lib/utilities/index.d.ts +3 -0
  68. package/lib/utilities/index.js +20 -0
  69. package/lib/utilities/lambda-iam-utils.d.ts +145 -0
  70. package/lib/utilities/lambda-iam-utils.js +235 -0
  71. package/lib/utilities/lambda_layers/data-masking/layer-construct.d.ts +42 -0
  72. package/lib/utilities/lambda_layers/data-masking/layer-construct.js +53 -0
  73. package/lib/utilities/lambda_layers/data-masking/layer-construct.ts +88 -0
  74. package/lib/utilities/observability/bedrock-observability.d.ts +18 -0
  75. package/lib/utilities/observability/bedrock-observability.js +131 -0
  76. package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.d.ts +6 -0
  77. package/lib/utilities/observability/cloudfront-distribution-observability-property-injector.js +22 -0
  78. package/lib/utilities/observability/index.d.ts +6 -0
  79. package/lib/utilities/observability/index.js +25 -0
  80. package/lib/utilities/observability/lambda-observability-property-injector.d.ts +8 -0
  81. package/lib/utilities/observability/lambda-observability-property-injector.js +43 -0
  82. package/lib/utilities/observability/log-group-data-protection-props.d.ts +19 -0
  83. package/lib/utilities/observability/log-group-data-protection-props.js +5 -0
  84. package/lib/utilities/observability/observability.d.ts +83 -0
  85. package/lib/utilities/observability/observability.js +278 -0
  86. package/lib/utilities/observability/observable.d.ts +32 -0
  87. package/lib/utilities/observability/observable.js +3 -0
  88. package/lib/utilities/observability/powertools-config.d.ts +3 -0
  89. package/lib/utilities/observability/powertools-config.js +25 -0
  90. package/lib/utilities/observability/resources/bedrock-manage-logging-configuration/index.py +27 -0
  91. package/lib/utilities/observability/state-machine-observability-property-injector.d.ts +8 -0
  92. package/lib/utilities/observability/state-machine-observability-property-injector.js +49 -0
  93. package/lib/utilities/tests/data-loader-nag.test.d.ts +1 -0
  94. package/lib/utilities/tests/data-loader-nag.test.js +432 -0
  95. package/lib/utilities/tests/data-loader.test.d.ts +1 -0
  96. package/lib/utilities/tests/data-loader.test.js +284 -0
  97. package/lib/webapp/frontend-construct.d.ts +136 -0
  98. package/lib/webapp/frontend-construct.js +253 -0
  99. package/lib/webapp/index.d.ts +1 -0
  100. package/lib/webapp/index.js +18 -0
  101. package/lib/webapp/tests/frontend-construct-nag.test.d.ts +1 -0
  102. package/lib/webapp/tests/frontend-construct-nag.test.js +266 -0
  103. package/lib/webapp/tests/frontend-construct.test.d.ts +1 -0
  104. package/lib/webapp/tests/frontend-construct.test.js +385 -0
  105. package/package.json +183 -0
@@ -0,0 +1,385 @@
1
+ "use strict";
2
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
8
+ const assertions_1 = require("aws-cdk-lib/assertions");
9
+ const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
10
+ const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
11
+ const aws_route53_1 = require("aws-cdk-lib/aws-route53");
12
+ const aws_s3_1 = require("aws-cdk-lib/aws-s3");
13
+ const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
14
+ const frontend_construct_1 = require("../frontend-construct");
15
+ // Mock execSync to avoid actual build execution during tests
16
+ jest.mock('child_process', () => ({
17
+ execSync: jest.fn(),
18
+ }));
19
+ describe('@webapp Frontend', () => {
20
+ let app;
21
+ let stack;
22
+ let template;
23
+ let testBuildDir;
24
+ let testSrcDir;
25
+ beforeAll(() => {
26
+ // Create a temporary build directory for tests
27
+ testBuildDir = '/tmp/test-frontend-build';
28
+ if (!fs.existsSync(testBuildDir)) {
29
+ fs.mkdirSync(testBuildDir, { recursive: true });
30
+ }
31
+ fs.writeFileSync(path.join(testBuildDir, 'index.html'), '<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Test App</h1></body></html>');
32
+ // Create a temporary source directory for tests
33
+ testSrcDir = '/tmp/test-frontend-src';
34
+ if (!fs.existsSync(testSrcDir)) {
35
+ fs.mkdirSync(testSrcDir, { recursive: true });
36
+ }
37
+ // Create default build directory inside source directory
38
+ const defaultBuildDir = path.join(testSrcDir, 'build');
39
+ if (!fs.existsSync(defaultBuildDir)) {
40
+ fs.mkdirSync(defaultBuildDir, { recursive: true });
41
+ }
42
+ fs.writeFileSync(path.join(defaultBuildDir, 'index.html'), '<!DOCTYPE html><html><head><title>Default Test</title></head><body><h1>Default Test App</h1></body></html>');
43
+ });
44
+ beforeEach(() => {
45
+ app = new aws_cdk_lib_1.App();
46
+ stack = new aws_cdk_lib_1.Stack(app, 'TestStack');
47
+ });
48
+ describe('@webapp Basic functionality', () => {
49
+ test('@webapp creates frontend construct with minimal configuration', () => {
50
+ const frontend = new frontend_construct_1.Frontend(stack, 'Frontend', {
51
+ sourceDirectory: '/tmp/test-frontend-src',
52
+ buildOutputDirectory: testBuildDir,
53
+ skipBuild: true, // Skip build for testing
54
+ });
55
+ template = assertions_1.Template.fromStack(stack);
56
+ // Verify S3 bucket is created
57
+ template.hasResourceProperties('AWS::S3::Bucket', {
58
+ BucketEncryption: {
59
+ ServerSideEncryptionConfiguration: [
60
+ {
61
+ ServerSideEncryptionByDefault: {
62
+ SSEAlgorithm: 'AES256',
63
+ },
64
+ },
65
+ ],
66
+ },
67
+ PublicAccessBlockConfiguration: {
68
+ BlockPublicAcls: true,
69
+ BlockPublicPolicy: true,
70
+ IgnorePublicAcls: true,
71
+ RestrictPublicBuckets: true,
72
+ },
73
+ });
74
+ // Verify CloudFront distribution is created
75
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
76
+ DistributionConfig: {
77
+ DefaultRootObject: 'index.html',
78
+ CustomErrorResponses: [
79
+ {
80
+ ErrorCode: 403,
81
+ ResponseCode: 200,
82
+ ResponsePagePath: '/index.html',
83
+ },
84
+ {
85
+ ErrorCode: 404,
86
+ ResponseCode: 200,
87
+ ResponsePagePath: '/index.html',
88
+ },
89
+ ],
90
+ },
91
+ });
92
+ // Verify security headers function is created
93
+ template.hasResourceProperties('AWS::CloudFront::Function', {
94
+ FunctionConfig: {
95
+ Runtime: 'cloudfront-js-1.0',
96
+ },
97
+ });
98
+ // Verify bucket deployment is created
99
+ template.hasResource('Custom::CDKBucketDeployment', {});
100
+ // Test public methods
101
+ expect(frontend.bucket).toBeInstanceOf(aws_s3_1.Bucket);
102
+ expect(frontend.distribution).toBeInstanceOf(aws_cloudfront_1.Distribution);
103
+ expect(frontend.bucketDeployment).toBeInstanceOf(aws_s3_deployment_1.BucketDeployment);
104
+ expect(typeof frontend.distributionDomainName()).toBe('string');
105
+ expect(typeof frontend.bucketName()).toBe('string');
106
+ expect(frontend.url()).toContain('https://');
107
+ });
108
+ test('@webapp creates frontend construct with custom build command', () => {
109
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
110
+ sourceDirectory: '/tmp/test-frontend-src',
111
+ buildOutputDirectory: testBuildDir,
112
+ buildCommand: 'yarn build',
113
+ skipBuild: true,
114
+ });
115
+ template = assertions_1.Template.fromStack(stack);
116
+ // Should still create the same resources
117
+ template.resourceCountIs('AWS::S3::Bucket', 1);
118
+ template.resourceCountIs('AWS::CloudFront::Distribution', 1);
119
+ });
120
+ test('@webapp creates frontend construct with custom error responses', () => {
121
+ const customErrorResponses = [
122
+ {
123
+ httpStatus: 500,
124
+ responseHttpStatus: 200,
125
+ responsePagePath: '/error.html',
126
+ },
127
+ ];
128
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
129
+ sourceDirectory: '/tmp/test-frontend-src',
130
+ buildOutputDirectory: testBuildDir,
131
+ errorResponses: customErrorResponses,
132
+ skipBuild: true,
133
+ });
134
+ template = assertions_1.Template.fromStack(stack);
135
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
136
+ DistributionConfig: {
137
+ CustomErrorResponses: [
138
+ {
139
+ ErrorCode: 500,
140
+ ResponseCode: 200,
141
+ ResponsePagePath: '/error.html',
142
+ },
143
+ ],
144
+ },
145
+ });
146
+ });
147
+ });
148
+ describe('@webapp Custom domain functionality', () => {
149
+ test('@webapp creates frontend construct with custom domain', () => {
150
+ const certificate = aws_certificatemanager_1.Certificate.fromCertificateArn(stack, 'Certificate', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');
151
+ const frontend = new frontend_construct_1.Frontend(stack, 'Frontend', {
152
+ sourceDirectory: '/tmp/test-frontend-src',
153
+ buildOutputDirectory: testBuildDir,
154
+ customDomain: {
155
+ domainName: 'app.example.com',
156
+ certificate,
157
+ },
158
+ skipBuild: true,
159
+ });
160
+ template = assertions_1.Template.fromStack(stack);
161
+ // Verify CloudFront distribution has custom domain
162
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
163
+ DistributionConfig: {
164
+ Aliases: ['app.example.com'],
165
+ ViewerCertificate: {
166
+ AcmCertificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
167
+ SslSupportMethod: 'sni-only',
168
+ },
169
+ },
170
+ });
171
+ expect(frontend.domainName).toBe('app.example.com');
172
+ expect(frontend.url()).toBe('https://app.example.com');
173
+ });
174
+ test('@webapp creates frontend construct with custom domain and hosted zone', () => {
175
+ const certificate = aws_certificatemanager_1.Certificate.fromCertificateArn(stack, 'Certificate', 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012');
176
+ const hostedZone = aws_route53_1.HostedZone.fromHostedZoneAttributes(stack, 'HostedZone', {
177
+ hostedZoneId: 'Z123456789',
178
+ zoneName: 'example.com',
179
+ });
180
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
181
+ sourceDirectory: '/tmp/test-frontend-src',
182
+ buildOutputDirectory: testBuildDir,
183
+ customDomain: {
184
+ domainName: 'app.example.com',
185
+ certificate,
186
+ hostedZone,
187
+ },
188
+ skipBuild: true,
189
+ });
190
+ template = assertions_1.Template.fromStack(stack);
191
+ // Verify Route53 A record is created
192
+ template.hasResourceProperties('AWS::Route53::RecordSet', {
193
+ Type: 'A',
194
+ Name: 'app.example.com.',
195
+ HostedZoneId: 'Z123456789',
196
+ });
197
+ });
198
+ });
199
+ describe('@webapp Validation', () => {
200
+ test('@webapp throws error when sourceDirectory is missing', () => {
201
+ expect(() => {
202
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
203
+ sourceDirectory: '',
204
+ buildOutputDirectory: testBuildDir,
205
+ skipBuild: true,
206
+ });
207
+ }).toThrow('sourceDirectory is required');
208
+ });
209
+ test('@webapp uses default buildOutputDirectory when not provided', () => {
210
+ // Use the existing test build directory
211
+ const frontend = new frontend_construct_1.Frontend(stack, 'Frontend', {
212
+ sourceDirectory: testSrcDir,
213
+ // buildOutputDirectory not provided - should use default './build/'
214
+ skipBuild: true,
215
+ });
216
+ expect(frontend).toBeDefined();
217
+ // The construct should be created successfully with default buildOutputDirectory
218
+ });
219
+ test('@webapp applies custom removal policy to resources', () => {
220
+ const retainStack = new aws_cdk_lib_1.Stack(app, 'RetainTestStack');
221
+ const frontend = new frontend_construct_1.Frontend(retainStack, 'Frontend', {
222
+ sourceDirectory: testSrcDir,
223
+ buildOutputDirectory: testBuildDir,
224
+ skipBuild: true,
225
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.RETAIN,
226
+ });
227
+ expect(frontend).toBeDefined();
228
+ // Check that the bucket has the correct removal policy
229
+ const retainTemplate = assertions_1.Template.fromStack(retainStack);
230
+ retainTemplate.hasResource('AWS::S3::Bucket', {
231
+ DeletionPolicy: 'Retain',
232
+ UpdateReplacePolicy: 'Retain',
233
+ });
234
+ });
235
+ test('@webapp uses default DESTROY removal policy when not specified', () => {
236
+ const destroyStack = new aws_cdk_lib_1.Stack(app, 'DestroyTestStack');
237
+ const frontend = new frontend_construct_1.Frontend(destroyStack, 'Frontend', {
238
+ sourceDirectory: testSrcDir,
239
+ buildOutputDirectory: testBuildDir,
240
+ skipBuild: true,
241
+ // removalPolicy not specified - should default to DESTROY
242
+ });
243
+ expect(frontend).toBeDefined();
244
+ // Check that the bucket has the default DESTROY removal policy
245
+ const destroyTemplate = assertions_1.Template.fromStack(destroyStack);
246
+ destroyTemplate.hasResource('AWS::S3::Bucket', {
247
+ DeletionPolicy: 'Delete',
248
+ UpdateReplacePolicy: 'Delete',
249
+ });
250
+ });
251
+ test('@webapp throws error when domainName is provided without certificate', () => {
252
+ expect(() => {
253
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
254
+ sourceDirectory: '/tmp/test-frontend-src',
255
+ buildOutputDirectory: testBuildDir,
256
+ customDomain: {
257
+ domainName: 'app.example.com',
258
+ }, // Type assertion to bypass TypeScript validation for testing
259
+ skipBuild: true,
260
+ });
261
+ }).toThrow('certificate is required when domainName is provided');
262
+ });
263
+ });
264
+ describe('@webapp Security features', () => {
265
+ test('@webapp creates S3 bucket with security best practices', () => {
266
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
267
+ sourceDirectory: '/tmp/test-frontend-src',
268
+ buildOutputDirectory: testBuildDir,
269
+ skipBuild: true,
270
+ });
271
+ template = assertions_1.Template.fromStack(stack);
272
+ // Verify S3 bucket security settings
273
+ template.hasResourceProperties('AWS::S3::Bucket', {
274
+ BucketEncryption: {
275
+ ServerSideEncryptionConfiguration: [
276
+ {
277
+ ServerSideEncryptionByDefault: {
278
+ SSEAlgorithm: 'AES256',
279
+ },
280
+ },
281
+ ],
282
+ },
283
+ PublicAccessBlockConfiguration: {
284
+ BlockPublicAcls: true,
285
+ BlockPublicPolicy: true,
286
+ IgnorePublicAcls: true,
287
+ RestrictPublicBuckets: true,
288
+ },
289
+ });
290
+ });
291
+ test('@webapp creates CloudFront distribution with security headers', () => {
292
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
293
+ sourceDirectory: '/tmp/test-frontend-src',
294
+ buildOutputDirectory: testBuildDir,
295
+ skipBuild: true,
296
+ });
297
+ template = assertions_1.Template.fromStack(stack);
298
+ // Verify security headers function exists
299
+ template.hasResourceProperties('AWS::CloudFront::Function', {
300
+ FunctionConfig: {
301
+ Runtime: 'cloudfront-js-1.0',
302
+ },
303
+ });
304
+ // Verify HTTPS redirect is enabled
305
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
306
+ DistributionConfig: {
307
+ DefaultCacheBehavior: {
308
+ ViewerProtocolPolicy: 'redirect-to-https',
309
+ },
310
+ },
311
+ });
312
+ });
313
+ test('@webapp enables auto delete objects on S3 bucket', () => {
314
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
315
+ sourceDirectory: '/tmp/test-frontend-src',
316
+ buildOutputDirectory: testBuildDir,
317
+ skipBuild: true,
318
+ });
319
+ template = assertions_1.Template.fromStack(stack);
320
+ // Verify auto delete objects custom resource is created
321
+ template.hasResource('Custom::S3AutoDeleteObjects', {});
322
+ });
323
+ });
324
+ describe('@webapp Default values', () => {
325
+ test('@webapp uses default SPA error responses', () => {
326
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
327
+ sourceDirectory: '/tmp/test-frontend-src',
328
+ buildOutputDirectory: testBuildDir,
329
+ skipBuild: true,
330
+ });
331
+ template = assertions_1.Template.fromStack(stack);
332
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
333
+ DistributionConfig: {
334
+ CustomErrorResponses: [
335
+ {
336
+ ErrorCode: 403,
337
+ ResponseCode: 200,
338
+ ResponsePagePath: '/index.html',
339
+ },
340
+ {
341
+ ErrorCode: 404,
342
+ ResponseCode: 200,
343
+ ResponsePagePath: '/index.html',
344
+ },
345
+ ],
346
+ },
347
+ });
348
+ });
349
+ test('@webapp exports default SPA error responses', () => {
350
+ expect(frontend_construct_1.DEFAULT_SPA_ERROR_RESPONSES).toEqual([
351
+ {
352
+ httpStatus: 403,
353
+ responseHttpStatus: 200,
354
+ responsePagePath: '/index.html',
355
+ },
356
+ {
357
+ httpStatus: 404,
358
+ responseHttpStatus: 200,
359
+ responsePagePath: '/index.html',
360
+ },
361
+ ]);
362
+ });
363
+ });
364
+ describe('@webapp Additional distribution properties', () => {
365
+ test('@webapp accepts additional CloudFront distribution properties', () => {
366
+ new frontend_construct_1.Frontend(stack, 'Frontend', {
367
+ sourceDirectory: '/tmp/test-frontend-src',
368
+ buildOutputDirectory: testBuildDir,
369
+ distributionProps: {
370
+ comment: 'Custom frontend distribution',
371
+ enabled: true,
372
+ },
373
+ skipBuild: true,
374
+ });
375
+ template = assertions_1.Template.fromStack(stack);
376
+ template.hasResourceProperties('AWS::CloudFront::Distribution', {
377
+ DistributionConfig: {
378
+ Comment: 'Custom frontend distribution',
379
+ Enabled: true,
380
+ },
381
+ });
382
+ });
383
+ });
384
+ });
385
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJvbnRlbmQtY29uc3RydWN0LnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi91c2UtY2FzZXMvd2ViYXBwL3Rlc3RzL2Zyb250ZW5kLWNvbnN0cnVjdC50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxxRUFBcUU7QUFDckUsc0NBQXNDOztBQUV0Qyx5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLDZDQUF3RDtBQUN4RCx1REFBa0Q7QUFDbEQsK0VBQWlFO0FBQ2pFLCtEQUEwRDtBQUMxRCx5REFBcUQ7QUFDckQsK0NBQTRDO0FBQzVDLHFFQUFpRTtBQUNqRSw4REFBOEU7QUFFOUUsNkRBQTZEO0FBQzdELElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDaEMsUUFBUSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7Q0FDcEIsQ0FBQyxDQUFDLENBQUM7QUFFSixRQUFRLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFO0lBQ2hDLElBQUksR0FBUSxDQUFDO0lBQ2IsSUFBSSxLQUFZLENBQUM7SUFDakIsSUFBSSxRQUFrQixDQUFDO0lBQ3ZCLElBQUksWUFBb0IsQ0FBQztJQUN6QixJQUFJLFVBQWtCLENBQUM7SUFFdkIsU0FBUyxDQUFDLEdBQUcsRUFBRTtRQUNiLCtDQUErQztRQUMvQyxZQUFZLEdBQUcsMEJBQTBCLENBQUM7UUFDMUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUNqQyxFQUFFLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFDRCxFQUFFLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxFQUFFLDRGQUE0RixDQUFDLENBQUM7UUFFdEosZ0RBQWdEO1FBQ2hELFVB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Q0FBQywrQkFBK0IsRUFBRTtnQkFDOUQsa0JBQWtCLEVBQUU7b0JBQ2xCLE9BQU8sRUFBRSw4QkFBOEI7b0JBQ3ZDLE9BQU8sRUFBRSxJQUFJO2lCQUNkO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgQXBwLCBSZW1vdmFsUG9saWN5LCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IFRlbXBsYXRlIH0gZnJvbSAnYXdzLWNkay1saWIvYXNzZXJ0aW9ucyc7XG5pbXBvcnQgeyBDZXJ0aWZpY2F0ZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jZXJ0aWZpY2F0ZW1hbmFnZXInO1xuaW1wb3J0IHsgRGlzdHJpYnV0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQnO1xuaW1wb3J0IHsgSG9zdGVkWm9uZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1yb3V0ZTUzJztcbmltcG9ydCB7IEJ1Y2tldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBCdWNrZXREZXBsb3ltZW50IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWRlcGxveW1lbnQnO1xuaW1wb3J0IHsgRnJvbnRlbmQsIERFRkFVTFRfU1BBX0VSUk9SX1JFU1BPTlNFUyB9IGZyb20gJy4uL2Zyb250ZW5kLWNvbnN0cnVjdCc7XG5cbi8vIE1vY2sgZXhlY1N5bmMgdG8gYXZvaWQgYWN0dWFsIGJ1aWxkIGV4ZWN1dGlvbiBkdXJpbmcgdGVzdHNcbmplc3QubW9jaygnY2hpbGRfcHJvY2VzcycsICgpID0+ICh7XG4gIGV4ZWNTeW5jOiBqZXN0LmZuKCksXG59KSk7XG5cbmRlc2NyaWJlKCdAd2ViYXBwIEZyb250ZW5kJywgKCkgPT4ge1xuICBsZXQgYXBwOiBBcHA7XG4gIGxldCBzdGFjazogU3RhY2s7XG4gIGxldCB0ZW1wbGF0ZTogVGVtcGxhdGU7XG4gIGxldCB0ZXN0QnVpbGREaXI6IHN0cmluZztcbiAgbGV0IHRlc3RTcmNEaXI6IHN0cmluZztcblxuICBiZWZvcmVBbGwoKCkgPT4ge1xuICAgIC8vIENyZWF0ZSBhIHRlbXBvcmFyeSBidWlsZCBkaXJlY3RvcnkgZm9yIHRlc3RzXG4gICAgdGVzdEJ1aWxkRGlyID0gJy90bXAvdGVzdC1mcm9udGVuZC1idWlsZCc7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRlc3RCdWlsZERpcikpIHtcbiAgICAgIGZzLm1rZGlyU3luYyh0ZXN0QnVpbGREaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH1cbiAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGguam9pbih0ZXN0QnVpbGREaXIsICdpbmRleC5odG1sJyksICc8IURPQ1RZUEUgaHRtbD48aHRtbD48aGVhZD48dGl0bGU+VGVzdDwvdGl0bGU+PC9oZWFkPjxib2R5PjxoMT5UZXN0IEFwcDwvaDE+PC9ib2R5PjwvaHRtbD4nKTtcblxuICAgIC8vIENyZWF0ZSBhIHRlbXBvcmFyeSBzb3VyY2UgZGlyZWN0b3J5IGZvciB0ZXN0c1xuICAgIHRlc3RTcmNEaXIgPSAnL3RtcC90ZXN0LWZyb250ZW5kLXNyYyc7XG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRlc3RTcmNEaXIpKSB7XG4gICAgICBmcy5ta2RpclN5bmModGVzdFNyY0RpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGRlZmF1bHQgYnVpbGQgZGlyZWN0b3J5IGluc2lkZSBzb3VyY2UgZGlyZWN0b3J5XG4gICAgY29uc3QgZGVmYXVsdEJ1aWxkRGlyID0gcGF0aC5qb2luKHRlc3RTcmNEaXIsICdidWlsZCcpO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhkZWZhdWx0QnVpbGREaXIpKSB7XG4gICAgICBmcy5ta2RpclN5bmMoZGVmYXVsdEJ1aWxkRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG4gICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4oZGVmYXVsdEJ1aWxkRGlyLCAnaW5kZXguaHRtbCcpLCAnPCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+PHRpdGxlPkRlZmF1bHQgVGVzdDwvdGl0bGU+PC9oZWFkPjxib2R5PjxoMT5EZWZhdWx0IFRlc3QgQXBwPC9oMT48L2JvZHk+PC9odG1sPicpO1xuICB9KTtcblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBhcHAgPSBuZXcgQXBwKCk7XG4gICAgc3RhY2sgPSBuZXcgU3RhY2soYXBwLCAnVGVzdFN0YWNrJyk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdAd2ViYXBwIEJhc2ljIGZ1bmN0aW9uYWxpdHknLCAoKSA9PiB7XG4gICAgdGVzdCgnQHdlYmFwcCBjcmVhdGVzIGZyb250ZW5kIGNvbnN0cnVjdCB3aXRoIG1pbmltYWwgY29uZmlndXJhdGlvbicsICgpID0+IHtcbiAgICAgIGNvbnN0IGZyb250ZW5kID0gbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBza2lwQnVpbGQ6IHRydWUsIC8vIFNraXAgYnVpbGQgZm9yIHRlc3RpbmdcbiAgICAgIH0pO1xuXG4gICAgICB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgICAgIC8vIFZlcmlmeSBTMyBidWNrZXQgaXMgY3JlYXRlZFxuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgICAgIEJ1Y2tldEVuY3J5cHRpb246IHtcbiAgICAgICAgICBTZXJ2ZXJTaWRlRW5jcnlwdGlvbkNvbmZpZ3VyYXRpb246IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25CeURlZmF1bHQ6IHtcbiAgICAgICAgICAgICAgICBTU0VBbGdvcml0aG06ICdBRVMyNTYnLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgICBCbG9ja1B1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgICAgQmxvY2tQdWJsaWNQb2xpY3k6IHRydWUsXG4gICAgICAgICAgSWdub3JlUHVibGljQWNsczogdHJ1ZSxcbiAgICAgICAgICBSZXN0cmljdFB1YmxpY0J1Y2tldHM6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gVmVyaWZ5IENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uIGlzIGNyZWF0ZWRcbiAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpDbG91ZEZyb250OjpEaXN0cmlidXRpb24nLCB7XG4gICAgICAgIERpc3RyaWJ1dGlvbkNvbmZpZzoge1xuICAgICAgICAgIERlZmF1bHRSb290T2JqZWN0OiAnaW5kZXguaHRtbCcsXG4gICAgICAgICAgQ3VzdG9tRXJyb3JSZXNwb25zZXM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRXJyb3JDb2RlOiA0MDMsXG4gICAgICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRXJyb3JDb2RlOiA0MDQsXG4gICAgICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFZlcmlmeSBzZWN1cml0eSBoZWFkZXJzIGZ1bmN0aW9uIGlzIGNyZWF0ZWRcbiAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpDbG91ZEZyb250OjpGdW5jdGlvbicsIHtcbiAgICAgICAgRnVuY3Rpb25Db25maWc6IHtcbiAgICAgICAgICBSdW50aW1lOiAnY2xvdWRmcm9udC1qcy0xLjAnLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFZlcmlmeSBidWNrZXQgZGVwbG95bWVudCBpcyBjcmVhdGVkXG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZSgnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50Jywge30pO1xuXG4gICAgICAvLyBUZXN0IHB1YmxpYyBtZXRob2RzXG4gICAgICBleHBlY3QoZnJvbnRlbmQuYnVja2V0KS50b0JlSW5zdGFuY2VPZihCdWNrZXQpO1xuICAgICAgZXhwZWN0KGZyb250ZW5kLmRpc3RyaWJ1dGlvbikudG9CZUluc3RhbmNlT2YoRGlzdHJpYnV0aW9uKTtcbiAgICAgIGV4cGVjdChmcm9udGVuZC5idWNrZXREZXBsb3ltZW50KS50b0JlSW5zdGFuY2VPZihCdWNrZXREZXBsb3ltZW50KTtcbiAgICAgIGV4cGVjdCh0eXBlb2YgZnJvbnRlbmQuZGlzdHJpYnV0aW9uRG9tYWluTmFtZSgpKS50b0JlKCdzdHJpbmcnKTtcbiAgICAgIGV4cGVjdCh0eXBlb2YgZnJvbnRlbmQuYnVja2V0TmFtZSgpKS50b0JlKCdzdHJpbmcnKTtcbiAgICAgIGV4cGVjdChmcm9udGVuZC51cmwoKSkudG9Db250YWluKCdodHRwczovLycpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnQHdlYmFwcCBjcmVhdGVzIGZyb250ZW5kIGNvbnN0cnVjdCB3aXRoIGN1c3RvbSBidWlsZCBjb21tYW5kJywgKCkgPT4ge1xuICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBidWlsZENvbW1hbmQ6ICd5YXJuIGJ1aWxkJyxcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAgICAgLy8gU2hvdWxkIHN0aWxsIGNyZWF0ZSB0aGUgc2FtZSByZXNvdXJjZXNcbiAgICAgIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcygnQVdTOjpTMzo6QnVja2V0JywgMSk7XG4gICAgICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJywgMSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdAd2ViYXBwIGNyZWF0ZXMgZnJvbnRlbmQgY29uc3RydWN0IHdpdGggY3VzdG9tIGVycm9yIHJlc3BvbnNlcycsICgpID0+IHtcbiAgICAgIGNvbnN0IGN1c3RvbUVycm9yUmVzcG9uc2VzID0gW1xuICAgICAgICB7XG4gICAgICAgICAgaHR0cFN0YXR1czogNTAwLFxuICAgICAgICAgIHJlc3BvbnNlSHR0cFN0YXR1czogMjAwLFxuICAgICAgICAgIHJlc3BvbnNlUGFnZVBhdGg6ICcvZXJyb3IuaHRtbCcsXG4gICAgICAgIH0sXG4gICAgICBdO1xuXG4gICAgICBuZXcgRnJvbnRlbmQoc3RhY2ssICdGcm9udGVuZCcsIHtcbiAgICAgICAgc291cmNlRGlyZWN0b3J5OiAnL3RtcC90ZXN0LWZyb250ZW5kLXNyYycsXG4gICAgICAgIGJ1aWxkT3V0cHV0RGlyZWN0b3J5OiB0ZXN0QnVpbGREaXIsXG4gICAgICAgIGVycm9yUmVzcG9uc2VzOiBjdXN0b21FcnJvclJlc3BvbnNlcyxcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICAgICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICAgICAgQ3VzdG9tRXJyb3JSZXNwb25zZXM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRXJyb3JDb2RlOiA1MDAsXG4gICAgICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2Vycm9yLmh0bWwnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdAd2ViYXBwIEN1c3RvbSBkb21haW4gZnVuY3Rpb25hbGl0eScsICgpID0+IHtcbiAgICB0ZXN0KCdAd2ViYXBwIGNyZWF0ZXMgZnJvbnRlbmQgY29uc3RydWN0IHdpdGggY3VzdG9tIGRvbWFpbicsICgpID0+IHtcbiAgICAgIGNvbnN0IGNlcnRpZmljYXRlID0gQ2VydGlmaWNhdGUuZnJvbUNlcnRpZmljYXRlQXJuKFxuICAgICAgICBzdGFjayxcbiAgICAgICAgJ0NlcnRpZmljYXRlJyxcbiAgICAgICAgJ2Fybjphd3M6YWNtOnVzLWVhc3QtMToxMjM0NTY3ODkwMTI6Y2VydGlmaWNhdGUvMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyJyxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGZyb250ZW5kID0gbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBjdXN0b21Eb21haW46IHtcbiAgICAgICAgICBkb21haW5OYW1lOiAnYXBwLmV4YW1wbGUuY29tJyxcbiAgICAgICAgICBjZXJ0aWZpY2F0ZSxcbiAgICAgICAgfSxcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAgICAgLy8gVmVyaWZ5IENsb3VkRnJvbnQgZGlzdHJpYnV0aW9uIGhhcyBjdXN0b20gZG9tYWluXG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJywge1xuICAgICAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgICAgICBBbGlhc2VzOiBbJ2FwcC5leGFtcGxlLmNvbSddLFxuICAgICAgICAgIFZpZXdlckNlcnRpZmljYXRlOiB7XG4gICAgICAgICAgICBBY21DZXJ0aWZpY2F0ZUFybjogJ2Fybjphd3M6YWNtOnVzLWVhc3QtMToxMjM0NTY3ODkwMTI6Y2VydGlmaWNhdGUvMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyJyxcbiAgICAgICAgICAgIFNzbFN1cHBvcnRNZXRob2Q6ICdzbmktb25seScsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QoZnJvbnRlbmQuZG9tYWluTmFtZSkudG9CZSgnYXBwLmV4YW1wbGUuY29tJyk7XG4gICAgICBleHBlY3QoZnJvbnRlbmQudXJsKCkpLnRvQmUoJ2h0dHBzOi8vYXBwLmV4YW1wbGUuY29tJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdAd2ViYXBwIGNyZWF0ZXMgZnJvbnRlbmQgY29uc3RydWN0IHdpdGggY3VzdG9tIGRvbWFpbiBhbmQgaG9zdGVkIHpvbmUnLCAoKSA9PiB7XG4gICAgICBjb25zdCBjZXJ0aWZpY2F0ZSA9IENlcnRpZmljYXRlLmZyb21DZXJ0aWZpY2F0ZUFybihcbiAgICAgICAgc3RhY2ssXG4gICAgICAgICdDZXJ0aWZpY2F0ZScsXG4gICAgICAgICdhcm46YXdzOmFjbTp1cy1lYXN0LTE6MTIzNDU2Nzg5MDEyOmNlcnRpZmljYXRlLzEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMicsXG4gICAgICApO1xuXG4gICAgICBjb25zdCBob3N0ZWRab25lID0gSG9zdGVkWm9uZS5mcm9tSG9zdGVkWm9uZUF0dHJpYnV0ZXMoc3RhY2ssICdIb3N0ZWRab25lJywge1xuICAgICAgICBob3N0ZWRab25lSWQ6ICdaMTIzNDU2Nzg5JyxcbiAgICAgICAgem9uZU5hbWU6ICdleGFtcGxlLmNvbScsXG4gICAgICB9KTtcblxuICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBjdXN0b21Eb21haW46IHtcbiAgICAgICAgICBkb21haW5OYW1lOiAnYXBwLmV4YW1wbGUuY29tJyxcbiAgICAgICAgICBjZXJ0aWZpY2F0ZSxcbiAgICAgICAgICBob3N0ZWRab25lLFxuICAgICAgICB9LFxuICAgICAgICBza2lwQnVpbGQ6IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gICAgICAvLyBWZXJpZnkgUm91dGU1MyBBIHJlY29yZCBpcyBjcmVhdGVkXG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6Um91dGU1Mzo6UmVjb3JkU2V0Jywge1xuICAgICAgICBUeXBlOiAnQScsXG4gICAgICAgIE5hbWU6ICdhcHAuZXhhbXBsZS5jb20uJyxcbiAgICAgICAgSG9zdGVkWm9uZUlkOiAnWjEyMzQ1Njc4OScsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0B3ZWJhcHAgVmFsaWRhdGlvbicsICgpID0+IHtcbiAgICB0ZXN0KCdAd2ViYXBwIHRocm93cyBlcnJvciB3aGVuIHNvdXJjZURpcmVjdG9yeSBpcyBtaXNzaW5nJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHtcbiAgICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgICAgc291cmNlRGlyZWN0b3J5OiAnJyxcbiAgICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICAgIHNraXBCdWlsZDogdHJ1ZSxcbiAgICAgICAgfSk7XG4gICAgICB9KS50b1Rocm93KCdzb3VyY2VEaXJlY3RvcnkgaXMgcmVxdWlyZWQnKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ0B3ZWJhcHAgdXNlcyBkZWZhdWx0IGJ1aWxkT3V0cHV0RGlyZWN0b3J5IHdoZW4gbm90IHByb3ZpZGVkJywgKCkgPT4ge1xuICAgICAgLy8gVXNlIHRoZSBleGlzdGluZyB0ZXN0IGJ1aWxkIGRpcmVjdG9yeVxuICAgICAgY29uc3QgZnJvbnRlbmQgPSBuZXcgRnJvbnRlbmQoc3RhY2ssICdGcm9udGVuZCcsIHtcbiAgICAgICAgc291cmNlRGlyZWN0b3J5OiB0ZXN0U3JjRGlyLFxuICAgICAgICAvLyBidWlsZE91dHB1dERpcmVjdG9yeSBub3QgcHJvdmlkZWQgLSBzaG91bGQgdXNlIGRlZmF1bHQgJy4vYnVpbGQvJ1xuICAgICAgICBza2lwQnVpbGQ6IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KGZyb250ZW5kKS50b0JlRGVmaW5lZCgpO1xuICAgICAgLy8gVGhlIGNvbnN0cnVjdCBzaG91bGQgYmUgY3JlYXRlZCBzdWNjZXNzZnVsbHkgd2l0aCBkZWZhdWx0IGJ1aWxkT3V0cHV0RGlyZWN0b3J5XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdAd2ViYXBwIGFwcGxpZXMgY3VzdG9tIHJlbW92YWwgcG9saWN5IHRvIHJlc291cmNlcycsICgpID0+IHtcbiAgICAgIGNvbnN0IHJldGFpblN0YWNrID0gbmV3IFN0YWNrKGFwcCwgJ1JldGFpblRlc3RTdGFjaycpO1xuICAgICAgY29uc3QgZnJvbnRlbmQgPSBuZXcgRnJvbnRlbmQocmV0YWluU3RhY2ssICdGcm9udGVuZCcsIHtcbiAgICAgICAgc291cmNlRGlyZWN0b3J5OiB0ZXN0U3JjRGlyLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBza2lwQnVpbGQ6IHRydWUsXG4gICAgICAgIHJlbW92YWxQb2xpY3k6IFJlbW92YWxQb2xpY3kuUkVUQUlOLFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChmcm9udGVuZCkudG9CZURlZmluZWQoKTtcblxuICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgYnVja2V0IGhhcyB0aGUgY29ycmVjdCByZW1vdmFsIHBvbGljeVxuICAgICAgY29uc3QgcmV0YWluVGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2socmV0YWluU3RhY2spO1xuICAgICAgcmV0YWluVGVtcGxhdGUuaGFzUmVzb3VyY2UoJ0FXUzo6UzM6OkJ1Y2tldCcsIHtcbiAgICAgICAgRGVsZXRpb25Qb2xpY3k6ICdSZXRhaW4nLFxuICAgICAgICBVcGRhdGVSZXBsYWNlUG9saWN5OiAnUmV0YWluJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnQHdlYmFwcCB1c2VzIGRlZmF1bHQgREVTVFJPWSByZW1vdmFsIHBvbGljeSB3aGVuIG5vdCBzcGVjaWZpZWQnLCAoKSA9PiB7XG4gICAgICBjb25zdCBkZXN0cm95U3RhY2sgPSBuZXcgU3RhY2soYXBwLCAnRGVzdHJveVRlc3RTdGFjaycpO1xuICAgICAgY29uc3QgZnJvbnRlbmQgPSBuZXcgRnJvbnRlbmQoZGVzdHJveVN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogdGVzdFNyY0RpcixcbiAgICAgICAgYnVpbGRPdXRwdXREaXJlY3Rvcnk6IHRlc3RCdWlsZERpcixcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgICAvLyByZW1vdmFsUG9saWN5IG5vdCBzcGVjaWZpZWQgLSBzaG91bGQgZGVmYXVsdCB0byBERVNUUk9ZXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KGZyb250ZW5kKS50b0JlRGVmaW5lZCgpO1xuXG4gICAgICAvLyBDaGVjayB0aGF0IHRoZSBidWNrZXQgaGFzIHRoZSBkZWZhdWx0IERFU1RST1kgcmVtb3ZhbCBwb2xpY3lcbiAgICAgIGNvbnN0IGRlc3Ryb3lUZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhkZXN0cm95U3RhY2spO1xuICAgICAgZGVzdHJveVRlbXBsYXRlLmhhc1Jlc291cmNlKCdBV1M6OlMzOjpCdWNrZXQnLCB7XG4gICAgICAgIERlbGV0aW9uUG9saWN5OiAnRGVsZXRlJyxcbiAgICAgICAgVXBkYXRlUmVwbGFjZVBvbGljeTogJ0RlbGV0ZScsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ0B3ZWJhcHAgdGhyb3dzIGVycm9yIHdoZW4gZG9tYWluTmFtZSBpcyBwcm92aWRlZCB3aXRob3V0IGNlcnRpZmljYXRlJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHtcbiAgICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgICAgc291cmNlRGlyZWN0b3J5OiAnL3RtcC90ZXN0LWZyb250ZW5kLXNyYycsXG4gICAgICAgICAgYnVpbGRPdXRwdXREaXJlY3Rvcnk6IHRlc3RCdWlsZERpcixcbiAgICAgICAgICBjdXN0b21Eb21haW46IHtcbiAgICAgICAgICAgIGRvbWFpbk5hbWU6ICdhcHAuZXhhbXBsZS5jb20nLFxuICAgICAgICAgIH0gYXMgYW55LCAvLyBUeXBlIGFzc2VydGlvbiB0byBieXBhc3MgVHlwZVNjcmlwdCB2YWxpZGF0aW9uIGZvciB0ZXN0aW5nXG4gICAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgIH0pLnRvVGhyb3coJ2NlcnRpZmljYXRlIGlzIHJlcXVpcmVkIHdoZW4gZG9tYWluTmFtZSBpcyBwcm92aWRlZCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnQHdlYmFwcCBTZWN1cml0eSBmZWF0dXJlcycsICgpID0+IHtcbiAgICB0ZXN0KCdAd2ViYXBwIGNyZWF0ZXMgUzMgYnVja2V0IHdpdGggc2VjdXJpdHkgYmVzdCBwcmFjdGljZXMnLCAoKSA9PiB7XG4gICAgICBuZXcgRnJvbnRlbmQoc3RhY2ssICdGcm9udGVuZCcsIHtcbiAgICAgICAgc291cmNlRGlyZWN0b3J5OiAnL3RtcC90ZXN0LWZyb250ZW5kLXNyYycsXG4gICAgICAgIGJ1aWxkT3V0cHV0RGlyZWN0b3J5OiB0ZXN0QnVpbGREaXIsXG4gICAgICAgIHNraXBCdWlsZDogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG5cbiAgICAgIC8vIFZlcmlmeSBTMyBidWNrZXQgc2VjdXJpdHkgc2V0dGluZ3NcbiAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpTMzo6QnVja2V0Jywge1xuICAgICAgICBCdWNrZXRFbmNyeXB0aW9uOiB7XG4gICAgICAgICAgU2VydmVyU2lkZUVuY3J5cHRpb25Db25maWd1cmF0aW9uOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIFNlcnZlclNpZGVFbmNyeXB0aW9uQnlEZWZhdWx0OiB7XG4gICAgICAgICAgICAgICAgU1NFQWxnb3JpdGhtOiAnQUVTMjU2JyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiB7XG4gICAgICAgICAgQmxvY2tQdWJsaWNBY2xzOiB0cnVlLFxuICAgICAgICAgIEJsb2NrUHVibGljUG9saWN5OiB0cnVlLFxuICAgICAgICAgIElnbm9yZVB1YmxpY0FjbHM6IHRydWUsXG4gICAgICAgICAgUmVzdHJpY3RQdWJsaWNCdWNrZXRzOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdAd2ViYXBwIGNyZWF0ZXMgQ2xvdWRGcm9udCBkaXN0cmlidXRpb24gd2l0aCBzZWN1cml0eSBoZWFkZXJzJywgKCkgPT4ge1xuICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBza2lwQnVpbGQ6IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gICAgICAvLyBWZXJpZnkgc2VjdXJpdHkgaGVhZGVycyBmdW5jdGlvbiBleGlzdHNcbiAgICAgIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpDbG91ZEZyb250OjpGdW5jdGlvbicsIHtcbiAgICAgICAgRnVuY3Rpb25Db25maWc6IHtcbiAgICAgICAgICBSdW50aW1lOiAnY2xvdWRmcm9udC1qcy0xLjAnLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFZlcmlmeSBIVFRQUyByZWRpcmVjdCBpcyBlbmFibGVkXG4gICAgICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6Q2xvdWRGcm9udDo6RGlzdHJpYnV0aW9uJywge1xuICAgICAgICBEaXN0cmlidXRpb25Db25maWc6IHtcbiAgICAgICAgICBEZWZhdWx0Q2FjaGVCZWhhdmlvcjoge1xuICAgICAgICAgICAgVmlld2VyUHJvdG9jb2xQb2xpY3k6ICdyZWRpcmVjdC10by1odHRwcycsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnQHdlYmFwcCBlbmFibGVzIGF1dG8gZGVsZXRlIG9iamVjdHMgb24gUzMgYnVja2V0JywgKCkgPT4ge1xuICAgICAgbmV3IEZyb250ZW5kKHN0YWNrLCAnRnJvbnRlbmQnLCB7XG4gICAgICAgIHNvdXJjZURpcmVjdG9yeTogJy90bXAvdGVzdC1mcm9udGVuZC1zcmMnLFxuICAgICAgICBidWlsZE91dHB1dERpcmVjdG9yeTogdGVzdEJ1aWxkRGlyLFxuICAgICAgICBza2lwQnVpbGQ6IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuXG4gICAgICAvLyBWZXJpZnkgYXV0byBkZWxldGUgb2JqZWN0cyBjdXN0b20gcmVzb3VyY2UgaXMgY3JlYXRlZFxuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2UoJ0N1c3RvbTo6UzNBdXRvRGVsZXRlT2JqZWN0cycsIHt9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0B3ZWJhcHAgRGVmYXVsdCB2YWx1ZXMnLCAoKSA9PiB7XG4gICAgdGVzdCgnQHdlYmFwcCB1c2VzIGRlZmF1bHQgU1BBIGVycm9yIHJlc3BvbnNlcycsICgpID0+IHtcbiAgICAgIG5ldyBGcm9udGVuZChzdGFjaywgJ0Zyb250ZW5kJywge1xuICAgICAgICBzb3VyY2VEaXJlY3Rvcnk6ICcvdG1wL3Rlc3QtZnJvbnRlbmQtc3JjJyxcbiAgICAgICAgYnVpbGRPdXRwdXREaXJlY3Rvcnk6IHRlc3RCdWlsZERpcixcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICAgICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICAgICAgQ3VzdG9tRXJyb3JSZXNwb25zZXM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRXJyb3JDb2RlOiA0MDMsXG4gICAgICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRXJyb3JDb2RlOiA0MDQsXG4gICAgICAgICAgICAgIFJlc3BvbnNlQ29kZTogMjAwLFxuICAgICAgICAgICAgICBSZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdAd2ViYXBwIGV4cG9ydHMgZGVmYXVsdCBTUEEgZXJyb3IgcmVzcG9uc2VzJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KERFRkFVTFRfU1BBX0VSUk9SX1JFU1BPTlNFUykudG9FcXVhbChbXG4gICAgICAgIHtcbiAgICAgICAgICBodHRwU3RhdHVzOiA0MDMsXG4gICAgICAgICAgcmVzcG9uc2VIdHRwU3RhdHVzOiAyMDAsXG4gICAgICAgICAgcmVzcG9uc2VQYWdlUGF0aDogJy9pbmRleC5odG1sJyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGh0dHBTdGF0dXM6IDQwNCxcbiAgICAgICAgICByZXNwb25zZUh0dHBTdGF0dXM6IDIwMCxcbiAgICAgICAgICByZXNwb25zZVBhZ2VQYXRoOiAnL2luZGV4Lmh0bWwnLFxuICAgICAgICB9LFxuICAgICAgXSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdAd2ViYXBwIEFkZGl0aW9uYWwgZGlzdHJpYnV0aW9uIHByb3BlcnRpZXMnLCAoKSA9PiB7XG4gICAgdGVzdCgnQHdlYmFwcCBhY2NlcHRzIGFkZGl0aW9uYWwgQ2xvdWRGcm9udCBkaXN0cmlidXRpb24gcHJvcGVydGllcycsICgpID0+IHtcbiAgICAgIG5ldyBGcm9udGVuZChzdGFjaywgJ0Zyb250ZW5kJywge1xuICAgICAgICBzb3VyY2VEaXJlY3Rvcnk6ICcvdG1wL3Rlc3QtZnJvbnRlbmQtc3JjJyxcbiAgICAgICAgYnVpbGRPdXRwdXREaXJlY3Rvcnk6IHRlc3RCdWlsZERpcixcbiAgICAgICAgZGlzdHJpYnV0aW9uUHJvcHM6IHtcbiAgICAgICAgICBjb21tZW50OiAnQ3VzdG9tIGZyb250ZW5kIGRpc3RyaWJ1dGlvbicsXG4gICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgICAgc2tpcEJ1aWxkOiB0cnVlLFxuICAgICAgfSk7XG5cbiAgICAgIHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcblxuICAgICAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OkNsb3VkRnJvbnQ6OkRpc3RyaWJ1dGlvbicsIHtcbiAgICAgICAgRGlzdHJpYnV0aW9uQ29uZmlnOiB7XG4gICAgICAgICAgQ29tbWVudDogJ0N1c3RvbSBmcm9udGVuZCBkaXN0cmlidXRpb24nLFxuICAgICAgICAgIEVuYWJsZWQ6IHRydWUsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
package/package.json ADDED
@@ -0,0 +1,183 @@
1
+ {
2
+ "name": "@cdklabs/cdk-appmod-catalog-blueprints",
3
+ "description": "Serverless infrastructure components organized by business use cases",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git@github.com:cdklabs/cdk-appmod-catalog-blueprints.git"
7
+ },
8
+ "scripts": {
9
+ "build": "npx projen build",
10
+ "build:fast": "npx projen build:fast",
11
+ "bump": "npx projen bump",
12
+ "clobber": "npx projen clobber",
13
+ "compat": "npx projen compat",
14
+ "compile": "npx projen compile",
15
+ "default": "npx projen default",
16
+ "docgen": "npx projen docgen",
17
+ "eject": "npx projen eject",
18
+ "eslint": "npx projen eslint",
19
+ "integ": "npx projen integ",
20
+ "integ:update": "npx projen integ:update",
21
+ "package": "npx projen package",
22
+ "package-all": "npx projen package-all",
23
+ "package:dotnet": "npx projen package:dotnet",
24
+ "package:go": "npx projen package:go",
25
+ "package:java": "npx projen package:java",
26
+ "package:js": "npx projen package:js",
27
+ "package:python": "npx projen package:python",
28
+ "post-compile": "npx projen post-compile",
29
+ "post-upgrade": "npx projen post-upgrade",
30
+ "pre-compile": "npx projen pre-compile",
31
+ "release": "npx projen release",
32
+ "rosetta:extract": "npx projen rosetta:extract",
33
+ "test": "npx projen test",
34
+ "test:cdk-nag:all": "npx projen test:cdk-nag:all",
35
+ "test:cdk-nag:document-processing": "npx projen test:cdk-nag:document-processing",
36
+ "test:cdk-nag:webapp": "npx projen test:cdk-nag:webapp",
37
+ "test:document-processing": "npx projen test:document-processing",
38
+ "test:document-processing:unit": "npx projen test:document-processing:unit",
39
+ "test:security": "npx projen test:security",
40
+ "test:watch": "npx projen test:watch",
41
+ "test:webapp": "npx projen test:webapp",
42
+ "test:webapp:core": "npx projen test:webapp:core",
43
+ "test:webapp:frontend": "npx projen test:webapp:frontend",
44
+ "test:webapp:quickstart": "npx projen test:webapp:quickstart",
45
+ "test:webapp:unit": "npx projen test:webapp:unit",
46
+ "unbump": "npx projen unbump",
47
+ "upgrade": "npx projen upgrade",
48
+ "upgrade-cdklabs-projen-project-types": "npx projen upgrade-cdklabs-projen-project-types",
49
+ "upgrade-dev-deps": "npx projen upgrade-dev-deps",
50
+ "watch": "npx projen watch",
51
+ "projen": "npx projen"
52
+ },
53
+ "author": {
54
+ "name": "Amazon Web Services",
55
+ "email": "aws-cdk-dev@amazon.com",
56
+ "organization": true
57
+ },
58
+ "devDependencies": {
59
+ "@aws-cdk/aws-lambda-python-alpha": "2.192.0-alpha.0",
60
+ "@aws-cdk/integ-runner": "latest",
61
+ "@aws-cdk/integ-tests-alpha": "latest",
62
+ "@stylistic/eslint-plugin": "^2",
63
+ "@types/jest": "^29.5.14",
64
+ "@types/node": "^18",
65
+ "@typescript-eslint/eslint-plugin": "^8",
66
+ "@typescript-eslint/parser": "^8",
67
+ "aws-cdk-lib": "2.216.0",
68
+ "cdk-nag": "^2.37.35",
69
+ "cdklabs-projen-project-types": "^0.3.1",
70
+ "commit-and-tag-version": "^12",
71
+ "constructs": "10.0.5",
72
+ "eslint": "^9",
73
+ "eslint-import-resolver-typescript": "^4.2.5",
74
+ "eslint-plugin-import": "^2.31.0",
75
+ "jest": "^29.7.0",
76
+ "jest-junit": "^16",
77
+ "jsii": "~5.9.5",
78
+ "jsii-diff": "^1.110.0",
79
+ "jsii-docgen": "^10.5.0",
80
+ "jsii-pacmak": "^1.110.0",
81
+ "jsii-rosetta": "~5.8.0",
82
+ "projen": "^0.95.2",
83
+ "ts-jest": "^29.3.0",
84
+ "ts-node": "^10.9.2",
85
+ "typescript": "^5.8.2"
86
+ },
87
+ "peerDependencies": {
88
+ "@aws-cdk/aws-lambda-python-alpha": "2.192.0-alpha.0",
89
+ "aws-cdk-lib": "^2.216.0",
90
+ "constructs": "^10.0.5"
91
+ },
92
+ "keywords": [
93
+ "cdk"
94
+ ],
95
+ "engines": {
96
+ "node": ">= 18.12.0"
97
+ },
98
+ "main": "lib/index.js",
99
+ "license": "Apache-2.0",
100
+ "publishConfig": {
101
+ "access": "public"
102
+ },
103
+ "version": "1.0.0",
104
+ "jest": {
105
+ "coverageProvider": "v8",
106
+ "testMatch": [
107
+ "<rootDir>/@(use-cases|test)/**/*(*.)@(spec|test).ts?(x)",
108
+ "<rootDir>/@(use-cases|test)/**/__tests__/**/*.ts?(x)",
109
+ "<rootDir>/@(projenrc)/**/*(*.)@(spec|test).ts?(x)",
110
+ "<rootDir>/@(projenrc)/**/__tests__/**/*.ts?(x)"
111
+ ],
112
+ "clearMocks": true,
113
+ "collectCoverage": true,
114
+ "coverageReporters": [
115
+ "json",
116
+ "lcov",
117
+ "clover",
118
+ "cobertura",
119
+ "text"
120
+ ],
121
+ "coverageDirectory": "coverage",
122
+ "coveragePathIgnorePatterns": [
123
+ "/node_modules/"
124
+ ],
125
+ "testPathIgnorePatterns": [
126
+ "/node_modules/"
127
+ ],
128
+ "watchPathIgnorePatterns": [
129
+ "/node_modules/"
130
+ ],
131
+ "reporters": [
132
+ "default",
133
+ [
134
+ "jest-junit",
135
+ {
136
+ "outputDirectory": "test-reports"
137
+ }
138
+ ]
139
+ ],
140
+ "transform": {
141
+ "^.+\\.[t]sx?$": [
142
+ "ts-jest",
143
+ {
144
+ "tsconfig": "tsconfig.dev.json"
145
+ }
146
+ ]
147
+ }
148
+ },
149
+ "types": "lib/index.d.ts",
150
+ "stability": "experimental",
151
+ "jsii": {
152
+ "outdir": "dist",
153
+ "targets": {
154
+ "java": {
155
+ "package": "io.github.cdklabs.appmod.catalog.blueprints",
156
+ "maven": {
157
+ "groupId": "io.github.cdklabs",
158
+ "artifactId": "appmod-catalog-blueprints"
159
+ }
160
+ },
161
+ "python": {
162
+ "distName": "appmod-catalog-blueprints",
163
+ "module": "appmod_catalog_blueprints"
164
+ },
165
+ "dotnet": {
166
+ "namespace": "CdklabsAppmodCatalogBlueprints",
167
+ "packageId": "CdklabsAppmodCatalogBlueprints"
168
+ },
169
+ "go": {
170
+ "moduleName": "github.com/cdklabs/appmod-catalog-blueprints-go"
171
+ }
172
+ },
173
+ "tsc": {
174
+ "outDir": "lib",
175
+ "rootDir": "use-cases"
176
+ }
177
+ },
178
+ "files": [
179
+ "lib/",
180
+ ".jsii"
181
+ ],
182
+ "//": "~~ Generated by projen. To modify, edit .projenrc.ts and run \"npx projen\"."
183
+ }