├── .eslintignore
├── .eslintrc.json
├── .github
├── dependabot.yml
└── workflows
│ └── main.yml
├── .gitignore
├── .jsii
├── .npmignore
├── LICENSE
├── README.md
├── cdk.context.json
├── cdk.json
├── jest.config.js
├── lib
├── index.ts
└── spa-deploy
│ └── spa-deploy-construct.ts
├── package-lock.json
├── package.json
├── test
└── cdk-spa-deploy.test.ts
├── tsconfig.json
└── website
└── index.html
/.eslintignore:
--------------------------------------------------------------------------------
1 | cdk.out/*
2 | **/*.d.ts
3 | **/*.d.tsx
4 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "extends": [
4 | "airbnb-base",
5 | "eslint:recommended",
6 | "plugin:jest/recommended"
7 | ],
8 | "plugins": [
9 | "jest"
10 | ],
11 | "rules": {
12 | "import/no-unresolved": 0,
13 | "import/extensions":0,
14 | "class-methods-use-this": 0,
15 | "no-new": 0,
16 | "max-len": 0,
17 | "jest/no-disabled-tests": 2,
18 | "jest/no-focused-tests": 2,
19 | "jest/no-identical-title": 2,
20 | "jest/prefer-to-have-length": 1,
21 | "jest/valid-expect": 2,
22 | "jest/expect-expect": 0,
23 | "jest/consistent-test-it": [
24 | 2,
25 | {
26 | "fn": "test",
27 | "withinDescribe": "it"
28 | }
29 | ]
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Enable version updates for npm
4 | - package-ecosystem: "npm"
5 | # Look for `package.json` and `lock` files in the `root` directory
6 | directory: "/"
7 | # Check the npm registry for updates every day (weekdays)
8 | schedule:
9 | interval: "daily"
10 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: CI
4 |
5 | # Controls when the action will run.
6 | on:
7 | push:
8 | tags:
9 | - '*'
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
15 | jobs:
16 | # This workflow contains a single job called "build"
17 | build:
18 | # The type of runner that the job will run on
19 | runs-on: ubuntu-latest
20 | container:
21 | image: jsii/superchain
22 |
23 | # Steps represent a sequence of tasks that will be executed as part of the job
24 | steps:
25 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26 | - uses: actions/checkout@v2
27 |
28 | # Run the tests
29 | - name: Run the tests
30 | run: npm i && npm run build && npm run test
31 |
32 | # Runs a single command using the runners shell
33 | - name: Build and Package JSII modules
34 | run: npm i && npm run build && npm run package
35 |
36 | # Release to NPM
37 | - name: Release NPM
38 | run: npx -p jsii-release jsii-release-npm
39 | env:
40 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
41 |
42 | # Release to Pypi
43 | - name: Release Pypi
44 | run: npx -p jsii-release jsii-release-pypi
45 | env:
46 | TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
47 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
48 |
49 | # Release to Nuget
50 | - name: Release Nuget
51 | run: npx -p jsii-release jsii-release-nuget
52 | env:
53 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
54 |
55 | # Release to Maven
56 | - name: Release Maven
57 | run: npx -p jsii-release jsii-release-maven
58 | env:
59 | MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
60 | MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
61 | MAVEN_GPG_PRIVATE_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
62 | MAVEN_GPG_PRIVATE_KEY_PASSPHRASE: ${{ secrets.MAVEN_GPG_PRIVATE_KEY_PASSPHRASE }}
63 | MAVEN_STAGING_PROFILE_ID: ${{ secrets.MAVEN_STAGING_PROFILE_ID }}
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.js
2 | !jest.config.js
3 | *.d.ts
4 | node_modules
5 | dist
6 |
7 | # CDK asset staging directory
8 | .cdk.staging
9 | cdk.out
10 |
--------------------------------------------------------------------------------
/.jsii:
--------------------------------------------------------------------------------
1 | {
2 | "author": {
3 | "name": "hi@cdkpatterns.com",
4 | "roles": [
5 | "author"
6 | ]
7 | },
8 | "dependencies": {
9 | "@aws-cdk/aws-certificatemanager": "^1.103.0",
10 | "@aws-cdk/aws-cloudfront": "^1.103.0",
11 | "@aws-cdk/aws-iam": "^1.103.0",
12 | "@aws-cdk/aws-route53": "^1.103.0",
13 | "@aws-cdk/aws-route53-patterns": "^1.103.0",
14 | "@aws-cdk/aws-route53-targets": "^1.103.0",
15 | "@aws-cdk/aws-s3": "^1.103.0",
16 | "@aws-cdk/aws-s3-deployment": "^1.103.0",
17 | "@aws-cdk/core": "^1.103.0",
18 | "constructs": "^3.3.75"
19 | },
20 | "dependencyClosure": {
21 | "@aws-cdk/assets": {
22 | "targets": {
23 | "dotnet": {
24 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
25 | "namespace": "Amazon.CDK.Assets",
26 | "packageId": "Amazon.CDK.Assets"
27 | },
28 | "java": {
29 | "maven": {
30 | "artifactId": "cdk-assets",
31 | "groupId": "software.amazon.awscdk"
32 | },
33 | "package": "software.amazon.awscdk.assets"
34 | },
35 | "js": {
36 | "npm": "@aws-cdk/assets"
37 | },
38 | "python": {
39 | "classifiers": [
40 | "Framework :: AWS CDK",
41 | "Framework :: AWS CDK :: 1"
42 | ],
43 | "distName": "aws-cdk.assets",
44 | "module": "aws_cdk.assets"
45 | }
46 | }
47 | },
48 | "@aws-cdk/aws-apigateway": {
49 | "targets": {
50 | "dotnet": {
51 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
52 | "namespace": "Amazon.CDK.AWS.APIGateway",
53 | "packageId": "Amazon.CDK.AWS.APIGateway"
54 | },
55 | "java": {
56 | "maven": {
57 | "artifactId": "apigateway",
58 | "groupId": "software.amazon.awscdk"
59 | },
60 | "package": "software.amazon.awscdk.services.apigateway"
61 | },
62 | "js": {
63 | "npm": "@aws-cdk/aws-apigateway"
64 | },
65 | "python": {
66 | "classifiers": [
67 | "Framework :: AWS CDK",
68 | "Framework :: AWS CDK :: 1"
69 | ],
70 | "distName": "aws-cdk.aws-apigateway",
71 | "module": "aws_cdk.aws_apigateway"
72 | }
73 | }
74 | },
75 | "@aws-cdk/aws-applicationautoscaling": {
76 | "targets": {
77 | "dotnet": {
78 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
79 | "namespace": "Amazon.CDK.AWS.ApplicationAutoScaling",
80 | "packageId": "Amazon.CDK.AWS.ApplicationAutoScaling"
81 | },
82 | "java": {
83 | "maven": {
84 | "artifactId": "applicationautoscaling",
85 | "groupId": "software.amazon.awscdk"
86 | },
87 | "package": "software.amazon.awscdk.services.applicationautoscaling"
88 | },
89 | "js": {
90 | "npm": "@aws-cdk/aws-applicationautoscaling"
91 | },
92 | "python": {
93 | "classifiers": [
94 | "Framework :: AWS CDK",
95 | "Framework :: AWS CDK :: 1"
96 | ],
97 | "distName": "aws-cdk.aws-applicationautoscaling",
98 | "module": "aws_cdk.aws_applicationautoscaling"
99 | }
100 | }
101 | },
102 | "@aws-cdk/aws-autoscaling-common": {
103 | "targets": {
104 | "dotnet": {
105 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
106 | "namespace": "Amazon.CDK.AWS.AutoScaling.Common",
107 | "packageId": "Amazon.CDK.AWS.AutoScaling.Common"
108 | },
109 | "java": {
110 | "maven": {
111 | "artifactId": "autoscaling-common",
112 | "groupId": "software.amazon.awscdk"
113 | },
114 | "package": "software.amazon.awscdk.services.autoscaling.common"
115 | },
116 | "js": {
117 | "npm": "@aws-cdk/aws-autoscaling-common"
118 | },
119 | "python": {
120 | "classifiers": [
121 | "Framework :: AWS CDK",
122 | "Framework :: AWS CDK :: 1"
123 | ],
124 | "distName": "aws-cdk.aws-autoscaling-common",
125 | "module": "aws_cdk.aws_autoscaling_common"
126 | }
127 | }
128 | },
129 | "@aws-cdk/aws-certificatemanager": {
130 | "targets": {
131 | "dotnet": {
132 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
133 | "namespace": "Amazon.CDK.AWS.CertificateManager",
134 | "packageId": "Amazon.CDK.AWS.CertificateManager"
135 | },
136 | "java": {
137 | "maven": {
138 | "artifactId": "certificatemanager",
139 | "groupId": "software.amazon.awscdk"
140 | },
141 | "package": "software.amazon.awscdk.services.certificatemanager"
142 | },
143 | "js": {
144 | "npm": "@aws-cdk/aws-certificatemanager"
145 | },
146 | "python": {
147 | "classifiers": [
148 | "Framework :: AWS CDK",
149 | "Framework :: AWS CDK :: 1"
150 | ],
151 | "distName": "aws-cdk.aws-certificatemanager",
152 | "module": "aws_cdk.aws_certificatemanager"
153 | }
154 | }
155 | },
156 | "@aws-cdk/aws-cloudformation": {
157 | "targets": {
158 | "dotnet": {
159 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
160 | "namespace": "Amazon.CDK.AWS.CloudFormation",
161 | "packageId": "Amazon.CDK.AWS.CloudFormation"
162 | },
163 | "java": {
164 | "maven": {
165 | "artifactId": "cloudformation",
166 | "groupId": "software.amazon.awscdk"
167 | },
168 | "package": "software.amazon.awscdk.services.cloudformation"
169 | },
170 | "js": {
171 | "npm": "@aws-cdk/aws-cloudformation"
172 | },
173 | "python": {
174 | "classifiers": [
175 | "Framework :: AWS CDK",
176 | "Framework :: AWS CDK :: 1"
177 | ],
178 | "distName": "aws-cdk.aws-cloudformation",
179 | "module": "aws_cdk.aws_cloudformation"
180 | }
181 | }
182 | },
183 | "@aws-cdk/aws-cloudfront": {
184 | "submodules": {
185 | "@aws-cdk/aws-cloudfront.experimental": {
186 | "locationInModule": {
187 | "filename": "lib/index.ts",
188 | "line": 11
189 | }
190 | }
191 | },
192 | "targets": {
193 | "dotnet": {
194 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
195 | "namespace": "Amazon.CDK.AWS.CloudFront",
196 | "packageId": "Amazon.CDK.AWS.CloudFront"
197 | },
198 | "java": {
199 | "maven": {
200 | "artifactId": "cloudfront",
201 | "groupId": "software.amazon.awscdk"
202 | },
203 | "package": "software.amazon.awscdk.services.cloudfront"
204 | },
205 | "js": {
206 | "npm": "@aws-cdk/aws-cloudfront"
207 | },
208 | "python": {
209 | "classifiers": [
210 | "Framework :: AWS CDK",
211 | "Framework :: AWS CDK :: 1"
212 | ],
213 | "distName": "aws-cdk.aws-cloudfront",
214 | "module": "aws_cdk.aws_cloudfront"
215 | }
216 | }
217 | },
218 | "@aws-cdk/aws-cloudwatch": {
219 | "targets": {
220 | "dotnet": {
221 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
222 | "namespace": "Amazon.CDK.AWS.CloudWatch",
223 | "packageId": "Amazon.CDK.AWS.CloudWatch"
224 | },
225 | "java": {
226 | "maven": {
227 | "artifactId": "cloudwatch",
228 | "groupId": "software.amazon.awscdk"
229 | },
230 | "package": "software.amazon.awscdk.services.cloudwatch"
231 | },
232 | "js": {
233 | "npm": "@aws-cdk/aws-cloudwatch"
234 | },
235 | "python": {
236 | "classifiers": [
237 | "Framework :: AWS CDK",
238 | "Framework :: AWS CDK :: 1"
239 | ],
240 | "distName": "aws-cdk.aws-cloudwatch",
241 | "module": "aws_cdk.aws_cloudwatch"
242 | }
243 | }
244 | },
245 | "@aws-cdk/aws-codeguruprofiler": {
246 | "targets": {
247 | "dotnet": {
248 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
249 | "namespace": "Amazon.CDK.AWS.CodeGuruProfiler",
250 | "packageId": "Amazon.CDK.AWS.CodeGuruProfiler"
251 | },
252 | "java": {
253 | "maven": {
254 | "artifactId": "codeguruprofiler",
255 | "groupId": "software.amazon.awscdk"
256 | },
257 | "package": "software.amazon.awscdk.services.codeguruprofiler"
258 | },
259 | "js": {
260 | "npm": "@aws-cdk/aws-codeguruprofiler"
261 | },
262 | "python": {
263 | "classifiers": [
264 | "Framework :: AWS CDK",
265 | "Framework :: AWS CDK :: 1"
266 | ],
267 | "distName": "aws-cdk.aws-codeguruprofiler",
268 | "module": "aws_cdk.aws_codeguruprofiler"
269 | }
270 | }
271 | },
272 | "@aws-cdk/aws-cognito": {
273 | "targets": {
274 | "dotnet": {
275 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
276 | "namespace": "Amazon.CDK.AWS.Cognito",
277 | "packageId": "Amazon.CDK.AWS.Cognito"
278 | },
279 | "java": {
280 | "maven": {
281 | "artifactId": "cognito",
282 | "groupId": "software.amazon.awscdk"
283 | },
284 | "package": "software.amazon.awscdk.services.cognito"
285 | },
286 | "js": {
287 | "npm": "@aws-cdk/aws-cognito"
288 | },
289 | "python": {
290 | "classifiers": [
291 | "Framework :: AWS CDK",
292 | "Framework :: AWS CDK :: 1"
293 | ],
294 | "distName": "aws-cdk.aws-cognito",
295 | "module": "aws_cdk.aws_cognito"
296 | }
297 | }
298 | },
299 | "@aws-cdk/aws-ec2": {
300 | "targets": {
301 | "dotnet": {
302 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
303 | "namespace": "Amazon.CDK.AWS.EC2",
304 | "packageId": "Amazon.CDK.AWS.EC2"
305 | },
306 | "java": {
307 | "maven": {
308 | "artifactId": "ec2",
309 | "groupId": "software.amazon.awscdk"
310 | },
311 | "package": "software.amazon.awscdk.services.ec2"
312 | },
313 | "js": {
314 | "npm": "@aws-cdk/aws-ec2"
315 | },
316 | "python": {
317 | "classifiers": [
318 | "Framework :: AWS CDK",
319 | "Framework :: AWS CDK :: 1"
320 | ],
321 | "distName": "aws-cdk.aws-ec2",
322 | "module": "aws_cdk.aws_ec2"
323 | }
324 | }
325 | },
326 | "@aws-cdk/aws-ecr": {
327 | "targets": {
328 | "dotnet": {
329 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
330 | "namespace": "Amazon.CDK.AWS.ECR",
331 | "packageId": "Amazon.CDK.AWS.ECR"
332 | },
333 | "java": {
334 | "maven": {
335 | "artifactId": "ecr",
336 | "groupId": "software.amazon.awscdk"
337 | },
338 | "package": "software.amazon.awscdk.services.ecr"
339 | },
340 | "js": {
341 | "npm": "@aws-cdk/aws-ecr"
342 | },
343 | "python": {
344 | "classifiers": [
345 | "Framework :: AWS CDK",
346 | "Framework :: AWS CDK :: 1"
347 | ],
348 | "distName": "aws-cdk.aws-ecr",
349 | "module": "aws_cdk.aws_ecr"
350 | }
351 | }
352 | },
353 | "@aws-cdk/aws-ecr-assets": {
354 | "targets": {
355 | "dotnet": {
356 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
357 | "namespace": "Amazon.CDK.AWS.Ecr.Assets",
358 | "packageId": "Amazon.CDK.ECR.Assets"
359 | },
360 | "java": {
361 | "maven": {
362 | "artifactId": "ecr-assets",
363 | "groupId": "software.amazon.awscdk"
364 | },
365 | "package": "software.amazon.awscdk.services.ecr.assets"
366 | },
367 | "js": {
368 | "npm": "@aws-cdk/aws-ecr-assets"
369 | },
370 | "python": {
371 | "classifiers": [
372 | "Framework :: AWS CDK",
373 | "Framework :: AWS CDK :: 1"
374 | ],
375 | "distName": "aws-cdk.aws-ecr-assets",
376 | "module": "aws_cdk.aws_ecr_assets"
377 | }
378 | }
379 | },
380 | "@aws-cdk/aws-efs": {
381 | "targets": {
382 | "dotnet": {
383 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
384 | "namespace": "Amazon.CDK.AWS.EFS",
385 | "packageId": "Amazon.CDK.AWS.EFS"
386 | },
387 | "java": {
388 | "maven": {
389 | "artifactId": "efs",
390 | "groupId": "software.amazon.awscdk"
391 | },
392 | "package": "software.amazon.awscdk.services.efs"
393 | },
394 | "js": {
395 | "npm": "@aws-cdk/aws-efs"
396 | },
397 | "python": {
398 | "classifiers": [
399 | "Framework :: AWS CDK",
400 | "Framework :: AWS CDK :: 1"
401 | ],
402 | "distName": "aws-cdk.aws-efs",
403 | "module": "aws_cdk.aws_efs"
404 | }
405 | }
406 | },
407 | "@aws-cdk/aws-elasticloadbalancing": {
408 | "targets": {
409 | "dotnet": {
410 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
411 | "namespace": "Amazon.CDK.AWS.ElasticLoadBalancing",
412 | "packageId": "Amazon.CDK.AWS.ElasticLoadBalancing"
413 | },
414 | "java": {
415 | "maven": {
416 | "artifactId": "elasticloadbalancing",
417 | "groupId": "software.amazon.awscdk"
418 | },
419 | "package": "software.amazon.awscdk.services.elasticloadbalancing"
420 | },
421 | "js": {
422 | "npm": "@aws-cdk/aws-elasticloadbalancing"
423 | },
424 | "python": {
425 | "classifiers": [
426 | "Framework :: AWS CDK",
427 | "Framework :: AWS CDK :: 1"
428 | ],
429 | "distName": "aws-cdk.aws-elasticloadbalancing",
430 | "module": "aws_cdk.aws_elasticloadbalancing"
431 | }
432 | }
433 | },
434 | "@aws-cdk/aws-elasticloadbalancingv2": {
435 | "targets": {
436 | "dotnet": {
437 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
438 | "namespace": "Amazon.CDK.AWS.ElasticLoadBalancingV2",
439 | "packageId": "Amazon.CDK.AWS.ElasticLoadBalancingV2"
440 | },
441 | "java": {
442 | "maven": {
443 | "artifactId": "elasticloadbalancingv2",
444 | "groupId": "software.amazon.awscdk"
445 | },
446 | "package": "software.amazon.awscdk.services.elasticloadbalancingv2"
447 | },
448 | "js": {
449 | "npm": "@aws-cdk/aws-elasticloadbalancingv2"
450 | },
451 | "python": {
452 | "classifiers": [
453 | "Framework :: AWS CDK",
454 | "Framework :: AWS CDK :: 1"
455 | ],
456 | "distName": "aws-cdk.aws-elasticloadbalancingv2",
457 | "module": "aws_cdk.aws_elasticloadbalancingv2"
458 | }
459 | }
460 | },
461 | "@aws-cdk/aws-events": {
462 | "targets": {
463 | "dotnet": {
464 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
465 | "namespace": "Amazon.CDK.AWS.Events",
466 | "packageId": "Amazon.CDK.AWS.Events"
467 | },
468 | "java": {
469 | "maven": {
470 | "artifactId": "events",
471 | "groupId": "software.amazon.awscdk"
472 | },
473 | "package": "software.amazon.awscdk.services.events"
474 | },
475 | "js": {
476 | "npm": "@aws-cdk/aws-events"
477 | },
478 | "python": {
479 | "classifiers": [
480 | "Framework :: AWS CDK",
481 | "Framework :: AWS CDK :: 1"
482 | ],
483 | "distName": "aws-cdk.aws-events",
484 | "module": "aws_cdk.aws_events"
485 | }
486 | }
487 | },
488 | "@aws-cdk/aws-globalaccelerator": {
489 | "targets": {
490 | "dotnet": {
491 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
492 | "namespace": "Amazon.CDK.AWS.GlobalAccelerator",
493 | "packageId": "Amazon.CDK.AWS.GlobalAccelerator"
494 | },
495 | "java": {
496 | "maven": {
497 | "artifactId": "globalaccelerator",
498 | "groupId": "software.amazon.awscdk"
499 | },
500 | "package": "software.amazon.awscdk.services.globalaccelerator"
501 | },
502 | "js": {
503 | "npm": "@aws-cdk/aws-globalaccelerator"
504 | },
505 | "python": {
506 | "classifiers": [
507 | "Framework :: AWS CDK",
508 | "Framework :: AWS CDK :: 1"
509 | ],
510 | "distName": "aws-cdk.aws-globalaccelerator",
511 | "module": "aws_cdk.aws_globalaccelerator"
512 | }
513 | }
514 | },
515 | "@aws-cdk/aws-iam": {
516 | "targets": {
517 | "dotnet": {
518 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
519 | "namespace": "Amazon.CDK.AWS.IAM",
520 | "packageId": "Amazon.CDK.AWS.IAM"
521 | },
522 | "java": {
523 | "maven": {
524 | "artifactId": "iam",
525 | "groupId": "software.amazon.awscdk"
526 | },
527 | "package": "software.amazon.awscdk.services.iam"
528 | },
529 | "js": {
530 | "npm": "@aws-cdk/aws-iam"
531 | },
532 | "python": {
533 | "classifiers": [
534 | "Framework :: AWS CDK",
535 | "Framework :: AWS CDK :: 1"
536 | ],
537 | "distName": "aws-cdk.aws-iam",
538 | "module": "aws_cdk.aws_iam"
539 | }
540 | }
541 | },
542 | "@aws-cdk/aws-kms": {
543 | "targets": {
544 | "dotnet": {
545 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
546 | "namespace": "Amazon.CDK.AWS.KMS",
547 | "packageId": "Amazon.CDK.AWS.KMS"
548 | },
549 | "java": {
550 | "maven": {
551 | "artifactId": "kms",
552 | "groupId": "software.amazon.awscdk"
553 | },
554 | "package": "software.amazon.awscdk.services.kms"
555 | },
556 | "js": {
557 | "npm": "@aws-cdk/aws-kms"
558 | },
559 | "python": {
560 | "classifiers": [
561 | "Framework :: AWS CDK",
562 | "Framework :: AWS CDK :: 1"
563 | ],
564 | "distName": "aws-cdk.aws-kms",
565 | "module": "aws_cdk.aws_kms"
566 | }
567 | }
568 | },
569 | "@aws-cdk/aws-lambda": {
570 | "targets": {
571 | "dotnet": {
572 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
573 | "namespace": "Amazon.CDK.AWS.Lambda",
574 | "packageId": "Amazon.CDK.AWS.Lambda"
575 | },
576 | "java": {
577 | "maven": {
578 | "artifactId": "lambda",
579 | "groupId": "software.amazon.awscdk"
580 | },
581 | "package": "software.amazon.awscdk.services.lambda"
582 | },
583 | "js": {
584 | "npm": "@aws-cdk/aws-lambda"
585 | },
586 | "python": {
587 | "classifiers": [
588 | "Framework :: AWS CDK",
589 | "Framework :: AWS CDK :: 1"
590 | ],
591 | "distName": "aws-cdk.aws-lambda",
592 | "module": "aws_cdk.aws_lambda"
593 | }
594 | }
595 | },
596 | "@aws-cdk/aws-logs": {
597 | "targets": {
598 | "dotnet": {
599 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
600 | "namespace": "Amazon.CDK.AWS.Logs",
601 | "packageId": "Amazon.CDK.AWS.Logs"
602 | },
603 | "java": {
604 | "maven": {
605 | "artifactId": "logs",
606 | "groupId": "software.amazon.awscdk"
607 | },
608 | "package": "software.amazon.awscdk.services.logs"
609 | },
610 | "js": {
611 | "npm": "@aws-cdk/aws-logs"
612 | },
613 | "python": {
614 | "classifiers": [
615 | "Framework :: AWS CDK",
616 | "Framework :: AWS CDK :: 1"
617 | ],
618 | "distName": "aws-cdk.aws-logs",
619 | "module": "aws_cdk.aws_logs"
620 | }
621 | }
622 | },
623 | "@aws-cdk/aws-route53": {
624 | "targets": {
625 | "dotnet": {
626 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
627 | "namespace": "Amazon.CDK.AWS.Route53",
628 | "packageId": "Amazon.CDK.AWS.Route53"
629 | },
630 | "java": {
631 | "maven": {
632 | "artifactId": "route53",
633 | "groupId": "software.amazon.awscdk"
634 | },
635 | "package": "software.amazon.awscdk.services.route53"
636 | },
637 | "js": {
638 | "npm": "@aws-cdk/aws-route53"
639 | },
640 | "python": {
641 | "classifiers": [
642 | "Framework :: AWS CDK",
643 | "Framework :: AWS CDK :: 1"
644 | ],
645 | "distName": "aws-cdk.aws-route53",
646 | "module": "aws_cdk.aws_route53"
647 | }
648 | }
649 | },
650 | "@aws-cdk/aws-route53-patterns": {
651 | "targets": {
652 | "dotnet": {
653 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
654 | "namespace": "Amazon.CDK.AWS.Route53.Patterns",
655 | "packageId": "Amazon.CDK.AWS.Route53.Patterns"
656 | },
657 | "java": {
658 | "maven": {
659 | "artifactId": "route53-patterns",
660 | "groupId": "software.amazon.awscdk"
661 | },
662 | "package": "software.amazon.awscdk.services.route53.patterns"
663 | },
664 | "js": {
665 | "npm": "@aws-cdk/aws-route53-patterns"
666 | },
667 | "python": {
668 | "classifiers": [
669 | "Framework :: AWS CDK",
670 | "Framework :: AWS CDK :: 1"
671 | ],
672 | "distName": "aws-cdk.aws-route53-patterns",
673 | "module": "aws_cdk.aws_route53_patterns"
674 | }
675 | }
676 | },
677 | "@aws-cdk/aws-route53-targets": {
678 | "targets": {
679 | "dotnet": {
680 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
681 | "namespace": "Amazon.CDK.AWS.Route53.Targets",
682 | "packageId": "Amazon.CDK.AWS.Route53.Targets"
683 | },
684 | "java": {
685 | "maven": {
686 | "artifactId": "route53-targets",
687 | "groupId": "software.amazon.awscdk"
688 | },
689 | "package": "software.amazon.awscdk.services.route53.targets"
690 | },
691 | "js": {
692 | "npm": "@aws-cdk/aws-route53-targets"
693 | },
694 | "python": {
695 | "classifiers": [
696 | "Framework :: AWS CDK",
697 | "Framework :: AWS CDK :: 1"
698 | ],
699 | "distName": "aws-cdk.aws-route53-targets",
700 | "module": "aws_cdk.aws_route53_targets"
701 | }
702 | }
703 | },
704 | "@aws-cdk/aws-s3": {
705 | "targets": {
706 | "dotnet": {
707 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
708 | "namespace": "Amazon.CDK.AWS.S3",
709 | "packageId": "Amazon.CDK.AWS.S3"
710 | },
711 | "java": {
712 | "maven": {
713 | "artifactId": "s3",
714 | "groupId": "software.amazon.awscdk"
715 | },
716 | "package": "software.amazon.awscdk.services.s3"
717 | },
718 | "js": {
719 | "npm": "@aws-cdk/aws-s3"
720 | },
721 | "python": {
722 | "classifiers": [
723 | "Framework :: AWS CDK",
724 | "Framework :: AWS CDK :: 1"
725 | ],
726 | "distName": "aws-cdk.aws-s3",
727 | "module": "aws_cdk.aws_s3"
728 | }
729 | }
730 | },
731 | "@aws-cdk/aws-s3-assets": {
732 | "targets": {
733 | "dotnet": {
734 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
735 | "namespace": "Amazon.CDK.AWS.S3.Assets",
736 | "packageId": "Amazon.CDK.AWS.S3.Assets"
737 | },
738 | "java": {
739 | "maven": {
740 | "artifactId": "s3-assets",
741 | "groupId": "software.amazon.awscdk"
742 | },
743 | "package": "software.amazon.awscdk.services.s3.assets"
744 | },
745 | "js": {
746 | "npm": "@aws-cdk/aws-s3-assets"
747 | },
748 | "python": {
749 | "classifiers": [
750 | "Framework :: AWS CDK",
751 | "Framework :: AWS CDK :: 1"
752 | ],
753 | "distName": "aws-cdk.aws-s3-assets",
754 | "module": "aws_cdk.aws_s3_assets"
755 | }
756 | }
757 | },
758 | "@aws-cdk/aws-s3-deployment": {
759 | "targets": {
760 | "dotnet": {
761 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
762 | "namespace": "Amazon.CDK.AWS.S3.Deployment",
763 | "packageId": "Amazon.CDK.AWS.S3.Deployment"
764 | },
765 | "java": {
766 | "maven": {
767 | "artifactId": "s3-deployment",
768 | "groupId": "software.amazon.awscdk"
769 | },
770 | "package": "software.amazon.awscdk.services.s3.deployment"
771 | },
772 | "js": {
773 | "npm": "@aws-cdk/aws-s3-deployment"
774 | },
775 | "python": {
776 | "classifiers": [
777 | "Framework :: AWS CDK",
778 | "Framework :: AWS CDK :: 1"
779 | ],
780 | "distName": "aws-cdk.aws-s3-deployment",
781 | "module": "aws_cdk.aws_s3_deployment"
782 | }
783 | }
784 | },
785 | "@aws-cdk/aws-signer": {
786 | "targets": {
787 | "dotnet": {
788 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
789 | "namespace": "Amazon.CDK.AWS.Signer",
790 | "packageId": "Amazon.CDK.AWS.Signer"
791 | },
792 | "java": {
793 | "maven": {
794 | "artifactId": "signer",
795 | "groupId": "software.amazon.awscdk"
796 | },
797 | "package": "software.amazon.awscdk.services.signer"
798 | },
799 | "js": {
800 | "npm": "@aws-cdk/aws-signer"
801 | },
802 | "python": {
803 | "classifiers": [
804 | "Framework :: AWS CDK",
805 | "Framework :: AWS CDK :: 1"
806 | ],
807 | "distName": "aws-cdk.aws-signer",
808 | "module": "aws_cdk.aws_signer"
809 | }
810 | }
811 | },
812 | "@aws-cdk/aws-sns": {
813 | "targets": {
814 | "dotnet": {
815 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
816 | "namespace": "Amazon.CDK.AWS.SNS",
817 | "packageId": "Amazon.CDK.AWS.SNS"
818 | },
819 | "java": {
820 | "maven": {
821 | "artifactId": "sns",
822 | "groupId": "software.amazon.awscdk"
823 | },
824 | "package": "software.amazon.awscdk.services.sns"
825 | },
826 | "js": {
827 | "npm": "@aws-cdk/aws-sns"
828 | },
829 | "python": {
830 | "classifiers": [
831 | "Framework :: AWS CDK",
832 | "Framework :: AWS CDK :: 1"
833 | ],
834 | "distName": "aws-cdk.aws-sns",
835 | "module": "aws_cdk.aws_sns"
836 | }
837 | }
838 | },
839 | "@aws-cdk/aws-sqs": {
840 | "targets": {
841 | "dotnet": {
842 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
843 | "namespace": "Amazon.CDK.AWS.SQS",
844 | "packageId": "Amazon.CDK.AWS.SQS"
845 | },
846 | "java": {
847 | "maven": {
848 | "artifactId": "sqs",
849 | "groupId": "software.amazon.awscdk"
850 | },
851 | "package": "software.amazon.awscdk.services.sqs"
852 | },
853 | "js": {
854 | "npm": "@aws-cdk/aws-sqs"
855 | },
856 | "python": {
857 | "classifiers": [
858 | "Framework :: AWS CDK",
859 | "Framework :: AWS CDK :: 1"
860 | ],
861 | "distName": "aws-cdk.aws-sqs",
862 | "module": "aws_cdk.aws_sqs"
863 | }
864 | }
865 | },
866 | "@aws-cdk/aws-ssm": {
867 | "targets": {
868 | "dotnet": {
869 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
870 | "namespace": "Amazon.CDK.AWS.SSM",
871 | "packageId": "Amazon.CDK.AWS.SSM"
872 | },
873 | "java": {
874 | "maven": {
875 | "artifactId": "ssm",
876 | "groupId": "software.amazon.awscdk"
877 | },
878 | "package": "software.amazon.awscdk.services.ssm"
879 | },
880 | "js": {
881 | "npm": "@aws-cdk/aws-ssm"
882 | },
883 | "python": {
884 | "classifiers": [
885 | "Framework :: AWS CDK",
886 | "Framework :: AWS CDK :: 1"
887 | ],
888 | "distName": "aws-cdk.aws-ssm",
889 | "module": "aws_cdk.aws_ssm"
890 | }
891 | }
892 | },
893 | "@aws-cdk/cloud-assembly-schema": {
894 | "targets": {
895 | "dotnet": {
896 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
897 | "namespace": "Amazon.CDK.CloudAssembly.Schema",
898 | "packageId": "Amazon.CDK.CloudAssembly.Schema"
899 | },
900 | "java": {
901 | "maven": {
902 | "artifactId": "cdk-cloud-assembly-schema",
903 | "groupId": "software.amazon.awscdk"
904 | },
905 | "package": "software.amazon.awscdk.cloudassembly.schema"
906 | },
907 | "js": {
908 | "npm": "@aws-cdk/cloud-assembly-schema"
909 | },
910 | "python": {
911 | "classifiers": [
912 | "Framework :: AWS CDK",
913 | "Framework :: AWS CDK :: 1"
914 | ],
915 | "distName": "aws-cdk.cloud-assembly-schema",
916 | "module": "aws_cdk.cloud_assembly_schema"
917 | }
918 | }
919 | },
920 | "@aws-cdk/core": {
921 | "targets": {
922 | "dotnet": {
923 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
924 | "namespace": "Amazon.CDK",
925 | "packageId": "Amazon.CDK"
926 | },
927 | "java": {
928 | "maven": {
929 | "artifactId": "core",
930 | "groupId": "software.amazon.awscdk"
931 | },
932 | "package": "software.amazon.awscdk.core"
933 | },
934 | "js": {
935 | "npm": "@aws-cdk/core"
936 | },
937 | "python": {
938 | "classifiers": [
939 | "Framework :: AWS CDK",
940 | "Framework :: AWS CDK :: 1"
941 | ],
942 | "distName": "aws-cdk.core",
943 | "module": "aws_cdk.core"
944 | }
945 | }
946 | },
947 | "@aws-cdk/custom-resources": {
948 | "targets": {
949 | "dotnet": {
950 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
951 | "namespace": "Amazon.CDK.CustomResources",
952 | "packageId": "Amazon.CDK.AWS.CustomResources"
953 | },
954 | "java": {
955 | "maven": {
956 | "artifactId": "cdk-customresources",
957 | "groupId": "software.amazon.awscdk"
958 | },
959 | "package": "software.amazon.awscdk.customresources"
960 | },
961 | "js": {
962 | "npm": "@aws-cdk/custom-resources"
963 | },
964 | "python": {
965 | "classifiers": [
966 | "Framework :: AWS CDK",
967 | "Framework :: AWS CDK :: 1"
968 | ],
969 | "distName": "aws-cdk.custom-resources",
970 | "module": "aws_cdk.custom_resources"
971 | }
972 | }
973 | },
974 | "@aws-cdk/cx-api": {
975 | "targets": {
976 | "dotnet": {
977 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
978 | "namespace": "Amazon.CDK.CXAPI",
979 | "packageId": "Amazon.CDK.CXAPI"
980 | },
981 | "java": {
982 | "maven": {
983 | "artifactId": "cdk-cx-api",
984 | "groupId": "software.amazon.awscdk"
985 | },
986 | "package": "software.amazon.awscdk.cxapi"
987 | },
988 | "js": {
989 | "npm": "@aws-cdk/cx-api"
990 | },
991 | "python": {
992 | "classifiers": [
993 | "Framework :: AWS CDK",
994 | "Framework :: AWS CDK :: 1"
995 | ],
996 | "distName": "aws-cdk.cx-api",
997 | "module": "aws_cdk.cx_api"
998 | }
999 | }
1000 | },
1001 | "@aws-cdk/lambda-layer-awscli": {
1002 | "targets": {
1003 | "dotnet": {
1004 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
1005 | "namespace": "Amazon.CDK.LambdaLayer.AwsCli",
1006 | "packageId": "Amazon.CDK.LambdaLayer.AwsCli"
1007 | },
1008 | "java": {
1009 | "maven": {
1010 | "artifactId": "cdk-lambda-layer-awscli",
1011 | "groupId": "software.amazon.awscdk"
1012 | },
1013 | "package": "software.amazon.awscdk.lambdalayer.awscli"
1014 | },
1015 | "js": {
1016 | "npm": "@aws-cdk/lambda-layer-awscli"
1017 | },
1018 | "python": {
1019 | "classifiers": [
1020 | "Framework :: AWS CDK",
1021 | "Framework :: AWS CDK :: 1"
1022 | ],
1023 | "distName": "aws-cdk.lambda-layer-awscli",
1024 | "module": "aws_cdk.lambda_layer_awscli"
1025 | }
1026 | }
1027 | },
1028 | "@aws-cdk/region-info": {
1029 | "targets": {
1030 | "dotnet": {
1031 | "iconUrl": "https://raw.githubusercontent.com/aws/aws-cdk/master/logo/default-256-dark.png",
1032 | "namespace": "Amazon.CDK.RegionInfo",
1033 | "packageId": "Amazon.CDK.RegionInfo"
1034 | },
1035 | "java": {
1036 | "maven": {
1037 | "artifactId": "cdk-region-info",
1038 | "groupId": "software.amazon.awscdk"
1039 | },
1040 | "package": "software.amazon.awscdk.regioninfo"
1041 | },
1042 | "js": {
1043 | "npm": "@aws-cdk/region-info"
1044 | },
1045 | "python": {
1046 | "classifiers": [
1047 | "Framework :: AWS CDK",
1048 | "Framework :: AWS CDK :: 1"
1049 | ],
1050 | "distName": "aws-cdk.region-info",
1051 | "module": "aws_cdk.region_info"
1052 | }
1053 | }
1054 | },
1055 | "constructs": {
1056 | "targets": {
1057 | "dotnet": {
1058 | "namespace": "Constructs",
1059 | "packageId": "Constructs"
1060 | },
1061 | "go": {
1062 | "moduleName": "github.com/aws/constructs-go"
1063 | },
1064 | "java": {
1065 | "maven": {
1066 | "artifactId": "constructs",
1067 | "groupId": "software.constructs"
1068 | },
1069 | "package": "software.constructs"
1070 | },
1071 | "js": {
1072 | "npm": "constructs"
1073 | },
1074 | "python": {
1075 | "distName": "constructs",
1076 | "module": "constructs"
1077 | }
1078 | }
1079 | }
1080 | },
1081 | "description": "This is an AWS CDK Construct to make deploying a single page website (Angular/React/Vue) to AWS S3 behind SSL/Cloudfront as easy as 5 lines of code.",
1082 | "homepage": "https://github.com/nideveloper/CDK-SPA-Deploy.git",
1083 | "jsiiVersion": "1.29.0 (build 41df200)",
1084 | "keywords": [
1085 | "aws",
1086 | "cdk",
1087 | "spa",
1088 | "website",
1089 | "deploy",
1090 | "cloudfront"
1091 | ],
1092 | "license": "MIT",
1093 | "metadata": {
1094 | "jsii": {
1095 | "pacmak": {
1096 | "hasDefaultInterfaces": true
1097 | }
1098 | }
1099 | },
1100 | "name": "cdk-spa-deploy",
1101 | "readme": {
1102 | "markdown": "# CDK-SPA-Deploy\n[](https://www.npmjs.com/package/cdk-spa-deploy)\n[](https://www.npmjs.com/package/cdk-spa-deploy)\n\nThis is an AWS CDK Construct to make deploying a single page website (Angular/React/Vue) to AWS S3 behind SSL/Cloudfront as easy as 5 lines of code.\n\n\n## Installation and Usage\n\n### Typescript\n\n```console\nnpm install --save cdk-spa-deploy\n```\n\nAs of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself, here is a list:\n```json\n{\n \"constructs\": \"^3.3.75\",\n \"@aws-cdk/aws-certificatemanager\": \"^1.103.0\",\n \"@aws-cdk/aws-cloudfront\": \"^1.103.0\",\n \"@aws-cdk/aws-iam\": \"^1.103.0\",\n \"@aws-cdk/aws-route53\": \"^1.103.0\",\n \"@aws-cdk/aws-route53-patterns\": \"^1.103.0\",\n \"@aws-cdk/aws-route53-targets\": \"^1.103.0\",\n \"@aws-cdk/aws-s3\": \"^1.103.0\",\n \"@aws-cdk/aws-s3-deployment\": \"^1.103.0\",\n \"@aws-cdk/core\": \"^1.103.0\"\n}\n```\n\n```typescript\nimport cdk = require('@aws-cdk/core');\nimport { SPADeploy } from 'cdk-spa-deploy';\n\nexport class CdkStack extends cdk.Stack {\n constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n new SPADeploy(this, 'spaDeploy')\n .createBasicSite({\n indexDoc: 'index.html',\n websiteFolder: '../blog/dist/blog'\n });\n\n new SPADeploy(this, 'cfDeploy')\n .createSiteWithCloudfront({\n indexDoc: 'index.html',\n websiteFolder: '../blog/dist/blog'\n });\n }\n}\n\n```\n\n### Python\n```console\npip install cdk-spa-deploy\n```\n\nNote As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.\n\n```python\nfrom aws_cdk import core\nfrom spa_deploy import SPADeploy\n\nclass PythonStack(core.Stack):\n def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:\n super().__init__(scope, id, **kwargs)\n\n SPADeploy(self, 'spaDeploy').create_basic_site(\n index_doc='index.html',\n website_folder='../blog/blog/dist/blog'\n )\n\n\n SPADeploy(self, 'cfDeploy').create_site_with_cloudfront(\n index_doc='index.html',\n website_folder='../blog/blog/dist/blog'\n )\n```\n\n### Dotnet / C#\n\nThis project has now been published to nuget, more details to follow soon but you can find it [here](https://www.nuget.org/packages/CDKSPADeploy/1.80.0)\n\nNote As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.\n\n```bash\n# package manager\nInstall-Package CDKSPADeploy -Version 1.80.0\n# .NET CLI\ndotnet add package CDKSPADeploy --version 1.80.0\n# Package reference\n\n# Paket CLI\npaket add CDKSPADeploy --version 1.80.0\n```\n\n### Java\n\nA version has now been published to maven.\n\nNote As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.\n\n```xml\n\n com.cdkpatterns\n CDKSPADeploy\n 1.81.0\n\n```\n\n## Advanced Usage\n\n### Auto Deploy From Hosted Zone Name\n\nIf you purchased your domain through route 53 and already have a hosted zone then just use the name to deploy your site behind cloudfront. This handles the SSL cert and everything for you.\n\n```typescript\nnew SPADeploy(this, 'spaDeploy', { encryptBucket: true })\n .createSiteFromHostedZone({\n zoneName: 'cdkpatterns.com',\n indexDoc: 'index.html',\n websiteFolder: '../website/dist/website'\n });\n\n```\n\n### Custom Domain and SSL Certificates\n\nYou can also pass the ARN for an SSL certification and your alias routes to cloudfront\n\n```typescript\nimport cdk = require('@aws-cdk/core');\nimport { SPADeploy } from 'cdk-spa-deploy';\n\nexport class CdkStack extends cdk.Stack {\n constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n new SPADeploy(this, 'cfDeploy')\n .createSiteWithCloudfront({\n indexDoc: '../blog/dist/blog',\n certificateARN: 'arn:...',\n cfAliases: ['www.alias.com']\n });\n }\n}\n\n```\n\n### Encrypted S3 Bucket\n\nPass in one boolean to tell SPA Deploy to encrypt your website bucket\n\n```typescript\nnew SPADeploy(this, 'cfDeploy', {encryptBucket: true}).createBasicSite({\n indexDoc: 'index.html',\n websiteFolder: 'website'\n});\n\n```\n\n### Custom Origin Behaviors\n\nPass in an array of CloudFront Behaviors\n\n```typescript\nnew SPADeploy(this, 'cfDeploy').createSiteWithCloudfront({\n indexDoc: 'index.html',\n websiteFolder: 'website',\n cfBehaviors: [\n {\n isDefaultBehavior: true,\n allowedMethods: cf.CloudFrontAllowedMethods.ALL,\n forwardedValues: {\n queryString: true,\n cookies: { forward: 'all' },\n headers: ['*'],\n },\n },\n {\n pathPattern: '/virtual-path',\n allowedMethods: cf.CloudFrontAllowedMethods.GET_HEAD,\n cachedMethods: cf.CloudFrontAllowedCachedMethods.GET_HEAD,\n },\n ],\n});\n```\n\n### Restrict Access to Known IPs\n\nPass in a boolean and an array of IP addresses and your site is locked down!\n\n```typescript\nnew SPADeploy(stack, 'spaDeploy', {\n encryptBucket: true,\n ipFilter: true,\n ipList: ['1.1.1.1']\n}).createBasicSite({\n indexDoc: 'index.html',\n websiteFolder: 'website'\n })\n```\n\n### Modifying S3 Bucket Created in Construct\n\nAn object is now returned containing relevant artifacts created if you need to make any further modifications:\n * The S3 bucket is present for all of the methods\n * When a CloudFront Web distribution is created it will be present in the return object\n\n```typescript\nexport interface SPADeployment {\n readonly websiteBucket: s3.Bucket,\n}\n\nexport interface SPADeploymentWithCloudFront extends SPADeployment {\n readonly distribution: CloudFrontWebDistribution,\n}\n```\n\n## Issues / Feature Requests\n\nhttps://github.com/nideveloper/CDK-SPA-Deploy\n"
1103 | },
1104 | "repository": {
1105 | "type": "git",
1106 | "url": "https://github.com/nideveloper/CDK-SPA-Deploy.git"
1107 | },
1108 | "schema": "jsii/0.10.0",
1109 | "targets": {
1110 | "dotnet": {
1111 | "namespace": "com.cdkpatterns",
1112 | "packageId": "CDKSPADeploy"
1113 | },
1114 | "java": {
1115 | "maven": {
1116 | "artifactId": "CDKSPADeploy",
1117 | "groupId": "com.cdkpatterns"
1118 | },
1119 | "package": "com.cdkpatterns"
1120 | },
1121 | "js": {
1122 | "npm": "cdk-spa-deploy"
1123 | },
1124 | "python": {
1125 | "distName": "cdk-spa-deploy",
1126 | "module": "spa_deploy"
1127 | }
1128 | },
1129 | "types": {
1130 | "cdk-spa-deploy.HostedZoneConfig": {
1131 | "assembly": "cdk-spa-deploy",
1132 | "datatype": true,
1133 | "fqn": "cdk-spa-deploy.HostedZoneConfig",
1134 | "kind": "interface",
1135 | "locationInModule": {
1136 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1137 | "line": 33
1138 | },
1139 | "name": "HostedZoneConfig",
1140 | "properties": [
1141 | {
1142 | "abstract": true,
1143 | "immutable": true,
1144 | "locationInModule": {
1145 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1146 | "line": 34
1147 | },
1148 | "name": "indexDoc",
1149 | "type": {
1150 | "primitive": "string"
1151 | }
1152 | },
1153 | {
1154 | "abstract": true,
1155 | "immutable": true,
1156 | "locationInModule": {
1157 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1158 | "line": 37
1159 | },
1160 | "name": "websiteFolder",
1161 | "type": {
1162 | "primitive": "string"
1163 | }
1164 | },
1165 | {
1166 | "abstract": true,
1167 | "immutable": true,
1168 | "locationInModule": {
1169 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1170 | "line": 38
1171 | },
1172 | "name": "zoneName",
1173 | "type": {
1174 | "primitive": "string"
1175 | }
1176 | },
1177 | {
1178 | "abstract": true,
1179 | "immutable": true,
1180 | "locationInModule": {
1181 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1182 | "line": 36
1183 | },
1184 | "name": "cfBehaviors",
1185 | "optional": true,
1186 | "type": {
1187 | "collection": {
1188 | "elementtype": {
1189 | "fqn": "@aws-cdk/aws-cloudfront.Behavior"
1190 | },
1191 | "kind": "array"
1192 | }
1193 | }
1194 | },
1195 | {
1196 | "abstract": true,
1197 | "immutable": true,
1198 | "locationInModule": {
1199 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1200 | "line": 35
1201 | },
1202 | "name": "errorDoc",
1203 | "optional": true,
1204 | "type": {
1205 | "primitive": "string"
1206 | }
1207 | },
1208 | {
1209 | "abstract": true,
1210 | "immutable": true,
1211 | "locationInModule": {
1212 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1213 | "line": 40
1214 | },
1215 | "name": "role",
1216 | "optional": true,
1217 | "type": {
1218 | "fqn": "@aws-cdk/aws-iam.Role"
1219 | }
1220 | },
1221 | {
1222 | "abstract": true,
1223 | "immutable": true,
1224 | "locationInModule": {
1225 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1226 | "line": 39
1227 | },
1228 | "name": "subdomain",
1229 | "optional": true,
1230 | "type": {
1231 | "primitive": "string"
1232 | }
1233 | }
1234 | ]
1235 | },
1236 | "cdk-spa-deploy.SPADeploy": {
1237 | "assembly": "cdk-spa-deploy",
1238 | "base": "@aws-cdk/core.Construct",
1239 | "fqn": "cdk-spa-deploy.SPADeploy",
1240 | "initializer": {
1241 | "locationInModule": {
1242 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1243 | "line": 61
1244 | },
1245 | "parameters": [
1246 | {
1247 | "name": "scope",
1248 | "type": {
1249 | "fqn": "@aws-cdk/core.Construct"
1250 | }
1251 | },
1252 | {
1253 | "name": "id",
1254 | "type": {
1255 | "primitive": "string"
1256 | }
1257 | },
1258 | {
1259 | "name": "config",
1260 | "optional": true,
1261 | "type": {
1262 | "fqn": "cdk-spa-deploy.SPAGlobalConfig"
1263 | }
1264 | }
1265 | ]
1266 | },
1267 | "kind": "class",
1268 | "locationInModule": {
1269 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1270 | "line": 58
1271 | },
1272 | "methods": [
1273 | {
1274 | "docs": {
1275 | "summary": "Basic setup needed for a non-ssl, non vanity url, non cached s3 website."
1276 | },
1277 | "locationInModule": {
1278 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1279 | "line": 169
1280 | },
1281 | "name": "createBasicSite",
1282 | "parameters": [
1283 | {
1284 | "name": "config",
1285 | "type": {
1286 | "fqn": "cdk-spa-deploy.SPADeployConfig"
1287 | }
1288 | }
1289 | ],
1290 | "returns": {
1291 | "type": {
1292 | "fqn": "cdk-spa-deploy.SPADeployment"
1293 | }
1294 | }
1295 | },
1296 | {
1297 | "docs": {
1298 | "summary": "S3 Deployment, cloudfront distribution, ssl cert and error forwarding auto\r configured by using the details in the hosted zone provided."
1299 | },
1300 | "locationInModule": {
1301 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1302 | "line": 225
1303 | },
1304 | "name": "createSiteFromHostedZone",
1305 | "parameters": [
1306 | {
1307 | "name": "config",
1308 | "type": {
1309 | "fqn": "cdk-spa-deploy.HostedZoneConfig"
1310 | }
1311 | }
1312 | ],
1313 | "returns": {
1314 | "type": {
1315 | "fqn": "cdk-spa-deploy.SPADeploymentWithCloudFront"
1316 | }
1317 | }
1318 | },
1319 | {
1320 | "docs": {
1321 | "summary": "This will create an s3 deployment fronted by a cloudfront distribution\r It will also setup error forwarding and unauth forwarding back to indexDoc."
1322 | },
1323 | "locationInModule": {
1324 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1325 | "line": 199
1326 | },
1327 | "name": "createSiteWithCloudfront",
1328 | "parameters": [
1329 | {
1330 | "name": "config",
1331 | "type": {
1332 | "fqn": "cdk-spa-deploy.SPADeployConfig"
1333 | }
1334 | }
1335 | ],
1336 | "returns": {
1337 | "type": {
1338 | "fqn": "cdk-spa-deploy.SPADeploymentWithCloudFront"
1339 | }
1340 | }
1341 | }
1342 | ],
1343 | "name": "SPADeploy",
1344 | "properties": [
1345 | {
1346 | "locationInModule": {
1347 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1348 | "line": 59
1349 | },
1350 | "name": "globalConfig",
1351 | "type": {
1352 | "fqn": "cdk-spa-deploy.SPAGlobalConfig"
1353 | }
1354 | }
1355 | ]
1356 | },
1357 | "cdk-spa-deploy.SPADeployConfig": {
1358 | "assembly": "cdk-spa-deploy",
1359 | "datatype": true,
1360 | "fqn": "cdk-spa-deploy.SPADeployConfig",
1361 | "kind": "interface",
1362 | "locationInModule": {
1363 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1364 | "line": 18
1365 | },
1366 | "name": "SPADeployConfig",
1367 | "properties": [
1368 | {
1369 | "abstract": true,
1370 | "immutable": true,
1371 | "locationInModule": {
1372 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1373 | "line": 19
1374 | },
1375 | "name": "indexDoc",
1376 | "type": {
1377 | "primitive": "string"
1378 | }
1379 | },
1380 | {
1381 | "abstract": true,
1382 | "immutable": true,
1383 | "locationInModule": {
1384 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1385 | "line": 21
1386 | },
1387 | "name": "websiteFolder",
1388 | "type": {
1389 | "primitive": "string"
1390 | }
1391 | },
1392 | {
1393 | "abstract": true,
1394 | "immutable": true,
1395 | "locationInModule": {
1396 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1397 | "line": 27
1398 | },
1399 | "name": "blockPublicAccess",
1400 | "optional": true,
1401 | "type": {
1402 | "fqn": "@aws-cdk/aws-s3.BlockPublicAccess"
1403 | }
1404 | },
1405 | {
1406 | "abstract": true,
1407 | "immutable": true,
1408 | "locationInModule": {
1409 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1410 | "line": 22
1411 | },
1412 | "name": "certificateARN",
1413 | "optional": true,
1414 | "type": {
1415 | "primitive": "string"
1416 | }
1417 | },
1418 | {
1419 | "abstract": true,
1420 | "immutable": true,
1421 | "locationInModule": {
1422 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1423 | "line": 24
1424 | },
1425 | "name": "cfAliases",
1426 | "optional": true,
1427 | "type": {
1428 | "collection": {
1429 | "elementtype": {
1430 | "primitive": "string"
1431 | },
1432 | "kind": "array"
1433 | }
1434 | }
1435 | },
1436 | {
1437 | "abstract": true,
1438 | "immutable": true,
1439 | "locationInModule": {
1440 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1441 | "line": 23
1442 | },
1443 | "name": "cfBehaviors",
1444 | "optional": true,
1445 | "type": {
1446 | "collection": {
1447 | "elementtype": {
1448 | "fqn": "@aws-cdk/aws-cloudfront.Behavior"
1449 | },
1450 | "kind": "array"
1451 | }
1452 | }
1453 | },
1454 | {
1455 | "abstract": true,
1456 | "immutable": true,
1457 | "locationInModule": {
1458 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1459 | "line": 20
1460 | },
1461 | "name": "errorDoc",
1462 | "optional": true,
1463 | "type": {
1464 | "primitive": "string"
1465 | }
1466 | },
1467 | {
1468 | "abstract": true,
1469 | "immutable": true,
1470 | "locationInModule": {
1471 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1472 | "line": 26
1473 | },
1474 | "name": "exportWebsiteUrlName",
1475 | "optional": true,
1476 | "type": {
1477 | "primitive": "string"
1478 | }
1479 | },
1480 | {
1481 | "abstract": true,
1482 | "immutable": true,
1483 | "locationInModule": {
1484 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1485 | "line": 25
1486 | },
1487 | "name": "exportWebsiteUrlOutput",
1488 | "optional": true,
1489 | "type": {
1490 | "primitive": "boolean"
1491 | }
1492 | },
1493 | {
1494 | "abstract": true,
1495 | "immutable": true,
1496 | "locationInModule": {
1497 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1498 | "line": 30
1499 | },
1500 | "name": "role",
1501 | "optional": true,
1502 | "type": {
1503 | "fqn": "@aws-cdk/aws-iam.Role"
1504 | }
1505 | },
1506 | {
1507 | "abstract": true,
1508 | "immutable": true,
1509 | "locationInModule": {
1510 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1511 | "line": 29
1512 | },
1513 | "name": "securityPolicy",
1514 | "optional": true,
1515 | "type": {
1516 | "fqn": "@aws-cdk/aws-cloudfront.SecurityPolicyProtocol"
1517 | }
1518 | },
1519 | {
1520 | "abstract": true,
1521 | "immutable": true,
1522 | "locationInModule": {
1523 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1524 | "line": 28
1525 | },
1526 | "name": "sslMethod",
1527 | "optional": true,
1528 | "type": {
1529 | "fqn": "@aws-cdk/aws-cloudfront.SSLMethod"
1530 | }
1531 | }
1532 | ]
1533 | },
1534 | "cdk-spa-deploy.SPADeployment": {
1535 | "assembly": "cdk-spa-deploy",
1536 | "datatype": true,
1537 | "fqn": "cdk-spa-deploy.SPADeployment",
1538 | "kind": "interface",
1539 | "locationInModule": {
1540 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1541 | "line": 50
1542 | },
1543 | "name": "SPADeployment",
1544 | "properties": [
1545 | {
1546 | "abstract": true,
1547 | "immutable": true,
1548 | "locationInModule": {
1549 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1550 | "line": 51
1551 | },
1552 | "name": "websiteBucket",
1553 | "type": {
1554 | "fqn": "@aws-cdk/aws-s3.Bucket"
1555 | }
1556 | }
1557 | ]
1558 | },
1559 | "cdk-spa-deploy.SPADeploymentWithCloudFront": {
1560 | "assembly": "cdk-spa-deploy",
1561 | "datatype": true,
1562 | "fqn": "cdk-spa-deploy.SPADeploymentWithCloudFront",
1563 | "interfaces": [
1564 | "cdk-spa-deploy.SPADeployment"
1565 | ],
1566 | "kind": "interface",
1567 | "locationInModule": {
1568 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1569 | "line": 54
1570 | },
1571 | "name": "SPADeploymentWithCloudFront",
1572 | "properties": [
1573 | {
1574 | "abstract": true,
1575 | "immutable": true,
1576 | "locationInModule": {
1577 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1578 | "line": 55
1579 | },
1580 | "name": "distribution",
1581 | "type": {
1582 | "fqn": "@aws-cdk/aws-cloudfront.CloudFrontWebDistribution"
1583 | }
1584 | }
1585 | ]
1586 | },
1587 | "cdk-spa-deploy.SPAGlobalConfig": {
1588 | "assembly": "cdk-spa-deploy",
1589 | "datatype": true,
1590 | "fqn": "cdk-spa-deploy.SPAGlobalConfig",
1591 | "kind": "interface",
1592 | "locationInModule": {
1593 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1594 | "line": 43
1595 | },
1596 | "name": "SPAGlobalConfig",
1597 | "properties": [
1598 | {
1599 | "abstract": true,
1600 | "immutable": true,
1601 | "locationInModule": {
1602 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1603 | "line": 44
1604 | },
1605 | "name": "encryptBucket",
1606 | "optional": true,
1607 | "type": {
1608 | "primitive": "boolean"
1609 | }
1610 | },
1611 | {
1612 | "abstract": true,
1613 | "immutable": true,
1614 | "locationInModule": {
1615 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1616 | "line": 45
1617 | },
1618 | "name": "ipFilter",
1619 | "optional": true,
1620 | "type": {
1621 | "primitive": "boolean"
1622 | }
1623 | },
1624 | {
1625 | "abstract": true,
1626 | "immutable": true,
1627 | "locationInModule": {
1628 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1629 | "line": 46
1630 | },
1631 | "name": "ipList",
1632 | "optional": true,
1633 | "type": {
1634 | "collection": {
1635 | "elementtype": {
1636 | "primitive": "string"
1637 | },
1638 | "kind": "array"
1639 | }
1640 | }
1641 | },
1642 | {
1643 | "abstract": true,
1644 | "immutable": true,
1645 | "locationInModule": {
1646 | "filename": "lib/spa-deploy/spa-deploy-construct.ts",
1647 | "line": 47
1648 | },
1649 | "name": "role",
1650 | "optional": true,
1651 | "type": {
1652 | "fqn": "@aws-cdk/aws-iam.Role"
1653 | }
1654 | }
1655 | ]
1656 | }
1657 | },
1658 | "version": "1.104.0",
1659 | "fingerprint": "BnRHUz0fqnj/xPlmrwWCqyZ1SRzIsULYDaB3gmSMt4U="
1660 | }
1661 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *.ts
2 | !*.d.ts
3 |
4 | # CDK asset staging directory
5 | .cdk.staging
6 | cdk.out
7 |
8 |
9 | # Exclude jsii outdir
10 | dist
11 |
12 | # Include .jsii
13 | !.jsii
14 |
15 |
16 | # Exclude jsii outdir
17 | dist
18 |
19 | # Include .jsii
20 | !.jsii
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Matt Coulter
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CDK-SPA-Deploy
2 | [](https://www.npmjs.com/package/cdk-spa-deploy)
3 | [](https://www.npmjs.com/package/cdk-spa-deploy)
4 |
5 | This is an AWS CDK Construct to make deploying a single page website (Angular/React/Vue) to AWS S3 behind SSL/Cloudfront as easy as 5 lines of code.
6 |
7 |
8 | ## Installation and Usage
9 |
10 | ### Typescript
11 |
12 | ```console
13 | npm install --save cdk-spa-deploy
14 | ```
15 |
16 | There is now a v1 and a v2 CDK version of this construct
17 |
18 | #### For AWS CDK V1 Usage:
19 |
20 | As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself, here is a list:
21 | ```json
22 | {
23 | "constructs": "^3.3.75",
24 | "@aws-cdk/aws-certificatemanager": "^1.103.0",
25 | "@aws-cdk/aws-cloudfront": "^1.103.0",
26 | "@aws-cdk/aws-iam": "^1.103.0",
27 | "@aws-cdk/aws-route53": "^1.103.0",
28 | "@aws-cdk/aws-route53-patterns": "^1.103.0",
29 | "@aws-cdk/aws-route53-targets": "^1.103.0",
30 | "@aws-cdk/aws-s3": "^1.103.0",
31 | "@aws-cdk/aws-s3-deployment": "^1.103.0",
32 | "@aws-cdk/core": "^1.103.0"
33 | }
34 | ```
35 |
36 | #### For AWS CDK V2 usage:
37 | Install v2.0.0-alpha.1 and use it like below based on your chosen language, no extra steps
38 |
39 | ```typescript
40 | import * as cdk from '@aws-cdk/core';
41 | import { SPADeploy } from 'cdk-spa-deploy';
42 |
43 | export class CdkStack extends cdk.Stack {
44 | constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
45 | super(scope, id, props);
46 |
47 | new SPADeploy(this, 'spaDeploy')
48 | .createBasicSite({
49 | indexDoc: 'index.html',
50 | websiteFolder: '../blog/dist/blog'
51 | });
52 |
53 | new SPADeploy(this, 'cfDeploy')
54 | .createSiteWithCloudfront({
55 | indexDoc: 'index.html',
56 | websiteFolder: '../blog/dist/blog'
57 | });
58 | }
59 | }
60 |
61 | ```
62 |
63 | ### Python
64 | ```console
65 | pip install cdk-spa-deploy
66 | ```
67 |
68 | Note As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.
69 |
70 | ```python
71 | from aws_cdk import core
72 | from spa_deploy import SPADeploy
73 |
74 | class PythonStack(core.Stack):
75 | def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
76 | super().__init__(scope, id, **kwargs)
77 |
78 | SPADeploy(self, 'spaDeploy').create_basic_site(
79 | index_doc='index.html',
80 | website_folder='../blog/blog/dist/blog'
81 | )
82 |
83 |
84 | SPADeploy(self, 'cfDeploy').create_site_with_cloudfront(
85 | index_doc='index.html',
86 | website_folder='../blog/blog/dist/blog'
87 | )
88 | ```
89 |
90 | ### Dotnet / C#
91 |
92 | This project has now been published to nuget, more details to follow soon but you can find it [here](https://www.nuget.org/packages/CDKSPADeploy/1.80.0)
93 |
94 | Note As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.
95 |
96 | ```bash
97 | # package manager
98 | Install-Package CDKSPADeploy -Version 1.80.0
99 | # .NET CLI
100 | dotnet add package CDKSPADeploy --version 1.80.0
101 | # Package reference
102 |
103 | # Paket CLI
104 | paket add CDKSPADeploy --version 1.80.0
105 | ```
106 |
107 | ### Java
108 |
109 | A version has now been published to maven.
110 |
111 | Note As of version 103.0 this construct now declares peer dependencies rather than bundling them so you can use it with any version of CDK higher than 103.0 without waiting on me to release a new version. The downside is that you will need to install the dependencies it uses for yourself. The npm versioms are listed above.
112 |
113 | ```xml
114 |
115 | com.cdkpatterns
116 | CDKSPADeploy
117 | 1.81.0
118 |
119 | ```
120 |
121 | ## Advanced Usage
122 |
123 | ### Auto Deploy From Hosted Zone Name
124 |
125 | If you purchased your domain through route 53 and already have a hosted zone then just use the name to deploy your site behind cloudfront. This handles the SSL cert and everything for you.
126 |
127 | ```typescript
128 | new SPADeploy(this, 'spaDeploy', { encryptBucket: true })
129 | .createSiteFromHostedZone({
130 | zoneName: 'cdkpatterns.com',
131 | indexDoc: 'index.html',
132 | websiteFolder: '../website/dist/website'
133 | });
134 |
135 | ```
136 |
137 | ### Custom Domain and SSL Certificates
138 |
139 | You can also pass the ARN for an SSL certification and your alias routes to cloudfront
140 |
141 | ```typescript
142 | import cdk = require('@aws-cdk/core');
143 | import { SPADeploy } from 'cdk-spa-deploy';
144 |
145 | export class CdkStack extends cdk.Stack {
146 | constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
147 | super(scope, id, props);
148 |
149 | new SPADeploy(this, 'cfDeploy')
150 | .createSiteWithCloudfront({
151 | indexDoc: '../blog/dist/blog',
152 | certificateARN: 'arn:...',
153 | cfAliases: ['www.alias.com']
154 | });
155 | }
156 | }
157 |
158 | ```
159 |
160 | ### Encrypted S3 Bucket
161 |
162 | Pass in one boolean to tell SPA Deploy to encrypt your website bucket
163 |
164 | ```typescript
165 | new SPADeploy(this, 'cfDeploy', {encryptBucket: true}).createBasicSite({
166 | indexDoc: 'index.html',
167 | websiteFolder: 'website'
168 | });
169 |
170 | ```
171 |
172 | ### Custom Origin Behaviors
173 |
174 | Pass in an array of CloudFront Behaviors
175 |
176 | ```typescript
177 | new SPADeploy(this, 'cfDeploy').createSiteWithCloudfront({
178 | indexDoc: 'index.html',
179 | websiteFolder: 'website',
180 | cfBehaviors: [
181 | {
182 | isDefaultBehavior: true,
183 | allowedMethods: cf.CloudFrontAllowedMethods.ALL,
184 | forwardedValues: {
185 | queryString: true,
186 | cookies: { forward: 'all' },
187 | headers: ['*'],
188 | },
189 | },
190 | {
191 | pathPattern: '/virtual-path',
192 | allowedMethods: cf.CloudFrontAllowedMethods.GET_HEAD,
193 | cachedMethods: cf.CloudFrontAllowedCachedMethods.GET_HEAD,
194 | },
195 | ],
196 | });
197 | ```
198 |
199 | ### Restrict Access to Known IPs
200 |
201 | Pass in a boolean and an array of IP addresses and your site is locked down!
202 |
203 | ```typescript
204 | new SPADeploy(stack, 'spaDeploy', {
205 | encryptBucket: true,
206 | ipFilter: true,
207 | ipList: ['1.1.1.1']
208 | }).createBasicSite({
209 | indexDoc: 'index.html',
210 | websiteFolder: 'website'
211 | })
212 | ```
213 |
214 | ### Modifying S3 Bucket Created in Construct
215 |
216 | An object is now returned containing relevant artifacts created if you need to make any further modifications:
217 | * The S3 bucket is present for all of the methods
218 | * When a CloudFront Web distribution is created it will be present in the return object
219 |
220 | ```typescript
221 | export interface SPADeployment {
222 | readonly websiteBucket: s3.Bucket,
223 | }
224 |
225 | export interface SPADeploymentWithCloudFront extends SPADeployment {
226 | readonly distribution: CloudFrontWebDistribution,
227 | }
228 | ```
229 |
230 | ## Issues / Feature Requests
231 |
232 | https://github.com/nideveloper/CDK-SPA-Deploy
233 |
--------------------------------------------------------------------------------
/cdk.context.json:
--------------------------------------------------------------------------------
1 | {
2 | "@aws-cdk/core:enableStackNameDuplicates": "true",
3 | "aws-cdk:enableDiffNoFail": "true"
4 | }
5 |
--------------------------------------------------------------------------------
/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "npx ts-node bin/cdk-spa-deploy.ts"
3 | }
4 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "roots": [
3 | "/test"
4 | ],
5 | testMatch: [ '**/*.test.ts'],
6 | "transform": {
7 | "^.+\\.tsx?$": "ts-jest"
8 | },
9 | }
10 |
--------------------------------------------------------------------------------
/lib/index.ts:
--------------------------------------------------------------------------------
1 | export * from './spa-deploy/spa-deploy-construct';
2 |
--------------------------------------------------------------------------------
/lib/spa-deploy/spa-deploy-construct.ts:
--------------------------------------------------------------------------------
1 | import {
2 | CloudFrontWebDistribution,
3 | ViewerCertificate,
4 | OriginAccessIdentity,
5 | Behavior,
6 | SSLMethod,
7 | SecurityPolicyProtocol,
8 | } from 'aws-cdk-lib/aws-cloudfront';
9 | import { PolicyStatement, Role, AnyPrincipal, Effect } from 'aws-cdk-lib/aws-iam';
10 | import { HostedZone, ARecord, RecordTarget } from 'aws-cdk-lib/aws-route53';
11 | import { DnsValidatedCertificate } from 'aws-cdk-lib/aws-certificatemanager';
12 | import { HttpsRedirect } from 'aws-cdk-lib/aws-route53-patterns';
13 | import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
14 | import { CfnOutput } from 'aws-cdk-lib';
15 | import s3deploy= require('aws-cdk-lib/aws-s3-deployment');
16 | import s3 = require('aws-cdk-lib/aws-s3');
17 | import { Construct } from 'constructs';
18 |
19 | export interface SPADeployConfig {
20 | readonly indexDoc:string,
21 | readonly errorDoc?:string,
22 | readonly websiteFolder: string,
23 | readonly certificateARN?: string,
24 | readonly cfBehaviors?: Behavior[],
25 | readonly cfAliases?: string[],
26 | readonly exportWebsiteUrlOutput?:boolean,
27 | readonly exportWebsiteUrlName?: string,
28 | readonly blockPublicAccess?:s3.BlockPublicAccess
29 | readonly sslMethod?: SSLMethod,
30 | readonly securityPolicy?: SecurityPolicyProtocol,
31 | readonly role?:Role,
32 | }
33 |
34 | export interface HostedZoneConfig {
35 | readonly indexDoc:string,
36 | readonly errorDoc?:string,
37 | readonly cfBehaviors?: Behavior[],
38 | readonly websiteFolder: string,
39 | readonly zoneName: string,
40 | readonly subdomain?: string,
41 | readonly role?: Role,
42 | }
43 |
44 | export interface SPAGlobalConfig {
45 | readonly encryptBucket?:boolean,
46 | readonly ipFilter?:boolean,
47 | readonly ipList?:string[],
48 | readonly role?:Role,
49 | }
50 |
51 | export interface SPADeployment {
52 | readonly websiteBucket: s3.Bucket,
53 | }
54 |
55 | export interface SPADeploymentWithCloudFront extends SPADeployment {
56 | readonly distribution: CloudFrontWebDistribution,
57 | }
58 |
59 | export class SPADeploy extends Construct {
60 | globalConfig: SPAGlobalConfig;
61 |
62 | constructor(scope: Construct, id:string, config?:SPAGlobalConfig) {
63 | super(scope, id);
64 |
65 | if (typeof config !== 'undefined') {
66 | this.globalConfig = config;
67 | } else {
68 | this.globalConfig = {
69 | encryptBucket: false,
70 | ipFilter: false,
71 | };
72 | }
73 | }
74 |
75 | /**
76 | * Helper method to provide a configured s3 bucket
77 | */
78 | private getS3Bucket(config:SPADeployConfig, isForCloudFront: boolean) {
79 | const bucketConfig:any = {
80 | websiteIndexDocument: config.indexDoc,
81 | websiteErrorDocument: config.errorDoc,
82 | publicReadAccess: true,
83 | };
84 |
85 | if (this.globalConfig.encryptBucket === true) {
86 | bucketConfig.encryption = s3.BucketEncryption.S3_MANAGED;
87 | }
88 |
89 | if (this.globalConfig.ipFilter === true || isForCloudFront === true || typeof config.blockPublicAccess !== 'undefined') {
90 | bucketConfig.publicReadAccess = false;
91 | if (typeof config.blockPublicAccess !== 'undefined') {
92 | bucketConfig.blockPublicAccess = config.blockPublicAccess;
93 | }
94 | }
95 |
96 | const bucket = new s3.Bucket(this, 'WebsiteBucket', bucketConfig);
97 |
98 | if (this.globalConfig.ipFilter === true && isForCloudFront === false) {
99 | if (typeof this.globalConfig.ipList === 'undefined') {
100 | throw new Error('When IP Filter is true then the IP List is required');
101 | }
102 |
103 | const bucketPolicy = new PolicyStatement();
104 | bucketPolicy.addAnyPrincipal();
105 | bucketPolicy.addActions('s3:GetObject');
106 | bucketPolicy.addResources(`${bucket.bucketArn}/*`);
107 | bucketPolicy.addCondition('IpAddress', {
108 | 'aws:SourceIp': this.globalConfig.ipList,
109 | });
110 |
111 | bucket.addToResourcePolicy(bucketPolicy);
112 | }
113 |
114 | //The below "reinforces" the IAM Role's attached policy, it's not required but it allows for customers using permission boundaries to write into the bucket.
115 | if (config.role) {
116 | bucket.addToResourcePolicy(
117 | new PolicyStatement({
118 | actions: [
119 | "s3:GetObject*",
120 | "s3:GetBucket*",
121 | "s3:List*",
122 | "s3:DeleteObject*",
123 | "s3:PutObject*",
124 | "s3:Abort*"
125 | ],
126 | effect: Effect.ALLOW,
127 | resources: [bucket.arnForObjects('*'), bucket.bucketArn],
128 | conditions: {
129 | StringEquals: {
130 | 'aws:PrincipalArn': config.role.roleArn,
131 | },
132 | },
133 | principals: [new AnyPrincipal()]
134 | })
135 | );
136 | }
137 |
138 | return bucket;
139 | }
140 |
141 | /**
142 | * Helper method to provide configuration for cloudfront
143 | */
144 | private getCFConfig(websiteBucket:s3.Bucket, config:any, accessIdentity: OriginAccessIdentity, cert?:DnsValidatedCertificate) {
145 | const cfConfig:any = {
146 | originConfigs: [
147 | {
148 | s3OriginSource: {
149 | s3BucketSource: websiteBucket,
150 | originAccessIdentity: accessIdentity,
151 | },
152 | behaviors: config.cfBehaviors ? config.cfBehaviors : [{ isDefaultBehavior: true }],
153 | },
154 | ],
155 | // We need to redirect all unknown routes back to index.html for angular routing to work
156 | errorConfigurations: [{
157 | errorCode: 403,
158 | responsePagePath: (config.errorDoc ? `/${config.errorDoc}` : `/${config.indexDoc}`),
159 | responseCode: 200,
160 | },
161 | {
162 | errorCode: 404,
163 | responsePagePath: (config.errorDoc ? `/${config.errorDoc}` : `/${config.indexDoc}`),
164 | responseCode: 200,
165 | }],
166 | };
167 |
168 | if (typeof config.certificateARN !== 'undefined' && typeof config.cfAliases !== 'undefined') {
169 | cfConfig.aliasConfiguration = {
170 | acmCertRef: config.certificateARN,
171 | names: config.cfAliases,
172 | };
173 | }
174 | if (typeof config.sslMethod !== 'undefined') {
175 | cfConfig.aliasConfiguration.sslMethod = config.sslMethod;
176 | }
177 |
178 | if (typeof config.securityPolicy !== 'undefined') {
179 | cfConfig.aliasConfiguration.securityPolicy = config.securityPolicy;
180 | }
181 |
182 | if (typeof config.zoneName !== 'undefined' && typeof cert !== 'undefined') {
183 | cfConfig.viewerCertificate = ViewerCertificate.fromAcmCertificate(cert, {
184 | aliases: [config.subdomain ? `${config.subdomain}.${config.zoneName}` : config.zoneName],
185 | });
186 | }
187 |
188 | return cfConfig;
189 | }
190 |
191 | /**
192 | * Basic setup needed for a non-ssl, non vanity url, non cached s3 website
193 | */
194 | public createBasicSite(config:SPADeployConfig): SPADeployment {
195 | const websiteBucket = this.getS3Bucket(config, false);
196 |
197 | new s3deploy.BucketDeployment(this, 'BucketDeployment', {
198 | sources: [s3deploy.Source.asset(config.websiteFolder)],
199 | role: config.role,
200 | destinationBucket: websiteBucket,
201 | });
202 |
203 | const cfnOutputConfig:any = {
204 | description: 'The url of the website',
205 | value: websiteBucket.bucketWebsiteUrl,
206 | };
207 |
208 | if (config.exportWebsiteUrlOutput === true) {
209 | if (typeof config.exportWebsiteUrlName === 'undefined' || config.exportWebsiteUrlName === '') {
210 | throw new Error('When Output URL as AWS Export property is true then the output name is required');
211 | }
212 | cfnOutputConfig.exportName = config.exportWebsiteUrlName;
213 | }
214 |
215 | let output = new CfnOutput(this, 'URL', cfnOutputConfig);
216 | //set the output name to be the same as the export name
217 | if(typeof config.exportWebsiteUrlName !== 'undefined' && config.exportWebsiteUrlName !== ''){
218 | output.overrideLogicalId(config.exportWebsiteUrlName);
219 | }
220 |
221 | return { websiteBucket };
222 | }
223 |
224 | /**
225 | * This will create an s3 deployment fronted by a cloudfront distribution
226 | * It will also setup error forwarding and unauth forwarding back to indexDoc
227 | */
228 | public createSiteWithCloudfront(config:SPADeployConfig): SPADeploymentWithCloudFront {
229 | const websiteBucket = this.getS3Bucket(config, true);
230 | const accessIdentity = new OriginAccessIdentity(this, 'OriginAccessIdentity', { comment: `${websiteBucket.bucketName}-access-identity` });
231 | const distribution = new CloudFrontWebDistribution(this, 'cloudfrontDistribution', this.getCFConfig(websiteBucket, config, accessIdentity));
232 |
233 | new s3deploy.BucketDeployment(this, 'BucketDeployment', {
234 | sources: [s3deploy.Source.asset(config.websiteFolder)],
235 | destinationBucket: websiteBucket,
236 | // Invalidate the cache for / and index.html when we deploy so that cloudfront serves latest site
237 | distribution,
238 | distributionPaths: ['/', `/${config.indexDoc}`],
239 | role: config.role,
240 | });
241 |
242 | new CfnOutput(this, 'cloudfront domain', {
243 | description: 'The domain of the website',
244 | value: distribution.distributionDomainName,
245 | });
246 |
247 | return { websiteBucket, distribution };
248 | }
249 |
250 | /**
251 | * S3 Deployment, cloudfront distribution, ssl cert and error forwarding auto
252 | * configured by using the details in the hosted zone provided
253 | */
254 | public createSiteFromHostedZone(config:HostedZoneConfig): SPADeploymentWithCloudFront {
255 | const websiteBucket = this.getS3Bucket(config, true);
256 | const zone = HostedZone.fromLookup(this, 'HostedZone', { domainName: config.zoneName });
257 | const domainName = config.subdomain ? `${config.subdomain}.${config.zoneName}` : config.zoneName;
258 | const cert = new DnsValidatedCertificate(this, 'Certificate', {
259 | hostedZone: zone,
260 | domainName,
261 | region: 'us-east-1',
262 | });
263 |
264 | const accessIdentity = new OriginAccessIdentity(this, 'OriginAccessIdentity', { comment: `${websiteBucket.bucketName}-access-identity` });
265 | const distribution = new CloudFrontWebDistribution(this, 'cloudfrontDistribution', this.getCFConfig(websiteBucket, config, accessIdentity, cert));
266 |
267 | new s3deploy.BucketDeployment(this, 'BucketDeployment', {
268 | sources: [s3deploy.Source.asset(config.websiteFolder)],
269 | destinationBucket: websiteBucket,
270 | // Invalidate the cache for / and index.html when we deploy so that cloudfront serves latest site
271 | distribution,
272 | role: config.role,
273 | distributionPaths: ['/', `/${config.indexDoc}`],
274 | });
275 |
276 | new ARecord(this, 'Alias', {
277 | zone,
278 | recordName: domainName,
279 | target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
280 | });
281 |
282 | if (!config.subdomain) {
283 | new HttpsRedirect(this, 'Redirect', {
284 | zone,
285 | recordNames: [`www.${config.zoneName}`],
286 | targetDomain: config.zoneName,
287 | });
288 | }
289 |
290 | return { websiteBucket, distribution };
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cdk-spa-deploy",
3 | "version": "2.0.0-alpha.1",
4 | "description": "This is an AWS CDK Construct to make deploying a single page website (Angular/React/Vue) to AWS S3 behind SSL/Cloudfront as easy as 5 lines of code.",
5 | "main": "lib/index.js",
6 | "types": "lib/index.d.ts",
7 | "publishConfig": {
8 | "registry": "https://registry.npmjs.org/",
9 | "access": "public"
10 | },
11 | "scripts": {
12 | "build": "jsii",
13 | "build:watch": "jsii -w",
14 | "test": "tsc && jest",
15 | "lint": "eslint --ext .ts,.tsx --format node_modules/eslint-formatter-pretty .",
16 | "lint:fix": "eslint --fix --ext .ts,.tsx --format node_modules/eslint-formatter-pretty .",
17 | "cdk": "cdk",
18 | "package": "jsii-pacmak"
19 | },
20 | "jsii": {
21 | "outdir": "dist",
22 | "targets": {
23 | "python": {
24 | "distName": "cdk-spa-deploy",
25 | "module": "spa_deploy"
26 | },
27 | "java": {
28 | "package": "com.cdkpatterns",
29 | "maven": {
30 | "groupId": "com.cdkpatterns",
31 | "artifactId": "CDKSPADeploy"
32 | }
33 | },
34 | "dotnet": {
35 | "namespace": "com.cdkpatterns",
36 | "packageId": "CDKSPADeploy"
37 | }
38 | }
39 | },
40 | "awscdkio": {
41 | "twitter": "nideveloper"
42 | },
43 | "devDependencies": {
44 | "@types/jest": "^26.0.23",
45 | "@types/node": "17.0.2",
46 | "@typescript-eslint/eslint-plugin": "^4.23.0",
47 | "@typescript-eslint/parser": "^4.23.0",
48 | "aws-cdk-lib": "^2.2.0",
49 | "constructs": "^10.0.13",
50 | "eslint": "^7.26.0",
51 | "eslint-config-airbnb-base": "^14.2.1",
52 | "eslint-formatter-pretty": "^4.0.0",
53 | "eslint-plugin-import": "^2.22.1",
54 | "eslint-plugin-jest": "^24.3.6",
55 | "jest": "^26.6.3",
56 | "jest-extended": "^0.11.5",
57 | "jest-junit": "^12.0.0",
58 | "jsii": "1.48.0",
59 | "jsii-pacmak": "1.48.0",
60 | "source-map-support": "^0.5.19",
61 | "ts-jest": "^26.5.6",
62 | "ts-node": "^9.1.1",
63 | "typescript": "~4.2.4"
64 | },
65 | "dependencies": {},
66 | "peerDependencies": {
67 | "constructs": "^10.0.13",
68 | "aws-cdk-lib": "^2.2.0"
69 | },
70 | "keywords": [
71 | "aws",
72 | "cdk",
73 | "spa",
74 | "website",
75 | "deploy",
76 | "cloudfront"
77 | ],
78 | "author": "hi@cdkpatterns.com",
79 | "repository": {
80 | "url": "https://github.com/nideveloper/CDK-SPA-Deploy.git",
81 | "type": "git"
82 | },
83 | "license": "MIT"
84 | }
85 |
--------------------------------------------------------------------------------
/test/cdk-spa-deploy.test.ts:
--------------------------------------------------------------------------------
1 | import { Match, Template } from "aws-cdk-lib/assertions";
2 | import * as cf from 'aws-cdk-lib/aws-cloudfront';
3 | import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
4 | import { BlockPublicAccess } from 'aws-cdk-lib/aws-s3';
5 | import { Stack, App } from 'aws-cdk-lib/';
6 | import { SPADeploy } from '../lib';
7 |
8 |
9 | test('Cloudfront Distribution Included', () => {
10 | const stack = new Stack();
11 | // WHEN
12 | const deploy = new SPADeploy(stack, 'spaDeploy');
13 |
14 | deploy.createSiteWithCloudfront({
15 | indexDoc: 'index.html',
16 | websiteFolder: 'website',
17 | });
18 |
19 | const template = Template.fromStack(stack);
20 | // THEN
21 | template.hasResourceProperties('AWS::S3::Bucket',
22 | Match.objectLike({
23 | WebsiteConfiguration: {
24 | IndexDocument: 'index.html',
25 | },
26 | }));
27 |
28 | template.hasResource('Custom::CDKBucketDeployment', {});
29 |
30 | template.hasResourceProperties('AWS::CloudFront::Distribution',
31 | Match.objectLike({
32 | DistributionConfig: {
33 | CustomErrorResponses: [
34 | {
35 | ErrorCode: 403,
36 | ResponseCode: 200,
37 | ResponsePagePath: '/index.html',
38 | },
39 | {
40 | ErrorCode: 404,
41 | ResponseCode: 200,
42 | ResponsePagePath: '/index.html',
43 | },
44 | ],
45 | DefaultCacheBehavior: {
46 | ViewerProtocolPolicy: 'redirect-to-https',
47 | },
48 | DefaultRootObject: 'index.html',
49 | HttpVersion: 'http2',
50 | IPV6Enabled: true,
51 | PriceClass: 'PriceClass_100',
52 | ViewerCertificate: {
53 | CloudFrontDefaultCertificate: true,
54 | },
55 | },
56 | }));
57 |
58 | template.hasResourceProperties('AWS::S3::BucketPolicy',
59 | Match.objectLike({
60 | PolicyDocument: {
61 | Statement: [
62 | Match.objectLike({
63 | Action: 's3:GetObject',
64 | Effect: 'Allow'
65 | })],
66 | },
67 | }));
68 | });
69 |
70 | test('Cloudfront Distribution Included - with non-default error-doc cfg set', () => {
71 | const stack = new Stack();
72 | // WHEN
73 | const deploy = new SPADeploy(stack, 'spaDeploy');
74 |
75 | deploy.createSiteWithCloudfront({
76 | indexDoc: 'index.html',
77 | errorDoc: 'error.html',
78 | websiteFolder: 'website',
79 | });
80 |
81 | const template = Template.fromStack(stack);
82 |
83 |
84 | // THEN
85 | template.hasResourceProperties('AWS::S3::Bucket',
86 | Match.objectLike({
87 | WebsiteConfiguration: {
88 | IndexDocument: 'index.html',
89 | ErrorDocument: 'error.html',
90 | },
91 | }));
92 |
93 | template.hasResource('Custom::CDKBucketDeployment', {});
94 |
95 | template.hasResourceProperties('AWS::CloudFront::Distribution',
96 | Match.objectLike({
97 | DistributionConfig: {
98 | CustomErrorResponses: [
99 | {
100 | ErrorCode: 403,
101 | ResponseCode: 200,
102 | ResponsePagePath: '/error.html',
103 | },
104 | {
105 | ErrorCode: 404,
106 | ResponseCode: 200,
107 | ResponsePagePath: '/error.html',
108 | },
109 | ],
110 | DefaultCacheBehavior: {
111 | ViewerProtocolPolicy: 'redirect-to-https',
112 | },
113 | DefaultRootObject: 'index.html',
114 | HttpVersion: 'http2',
115 | IPV6Enabled: true,
116 | PriceClass: 'PriceClass_100',
117 | ViewerCertificate: {
118 | CloudFrontDefaultCertificate: true,
119 | },
120 | },
121 | }));
122 |
123 | template.hasResourceProperties('AWS::S3::BucketPolicy',
124 | Match.objectLike({
125 | PolicyDocument: {
126 | Statement: [
127 | Match.objectLike({
128 | Action: 's3:GetObject',
129 | Effect: 'Allow'
130 | })],
131 | },
132 | }));
133 | });
134 |
135 | test('Cloudfront With Custom Cert and Aliases', () => {
136 | const stack = new Stack();
137 | // WHEN
138 | const deploy = new SPADeploy(stack, 'spaDeploy');
139 |
140 | deploy.createSiteWithCloudfront({
141 | indexDoc: 'index.html',
142 | websiteFolder: 'website',
143 | certificateARN: 'arn:1234',
144 | cfAliases: ['www.test.com'],
145 | });
146 |
147 | const template = Template.fromStack(stack);
148 |
149 | // THEN
150 | template.hasResourceProperties('AWS::S3::Bucket',
151 | Match.objectLike({
152 | WebsiteConfiguration: {
153 | IndexDocument: 'index.html'
154 | },
155 | }));
156 |
157 | template.hasResource('Custom::CDKBucketDeployment', {});
158 |
159 | template.hasResourceProperties('AWS::CloudFront::Distribution',
160 | Match.objectLike({
161 | DistributionConfig: {
162 | Aliases: [
163 | 'www.test.com',
164 | ],
165 | ViewerCertificate: {
166 | AcmCertificateArn: 'arn:1234',
167 | SslSupportMethod: 'sni-only',
168 | },
169 | },
170 | }));
171 | });
172 |
173 |
174 | test('Cloudfront With Custom Role', () => {
175 | const stack = new Stack();
176 | // WHEN
177 | const deploy = new SPADeploy(stack, 'spaDeploy');
178 |
179 | deploy.createSiteWithCloudfront({
180 | indexDoc: 'index.html',
181 | websiteFolder: 'website',
182 | certificateARN: 'arn:1234',
183 | cfAliases: ['www.test.com'],
184 | role: new Role(stack, 'myRole', {roleName: 'testRole', assumedBy: new ServicePrincipal('lambda.amazonaws.com')})
185 | });
186 |
187 | const template = Template.fromStack(stack);
188 |
189 | // THEN
190 | template.hasResourceProperties('AWS::Lambda::Function',
191 | Match.objectLike({
192 | Role: {
193 | "Fn::GetAtt": [
194 | "myRoleE60D68E8",
195 | "Arn"
196 | ]
197 | }
198 | }));
199 | });
200 |
201 |
202 | test('Basic Site Setup', () => {
203 | const stack = new Stack();
204 |
205 | // WHEN
206 | const deploy = new SPADeploy(stack, 'spaDeploy');
207 |
208 | deploy.createBasicSite({
209 | indexDoc: 'index.html',
210 | websiteFolder: 'website',
211 | });
212 |
213 | const template = Template.fromStack(stack);
214 |
215 | // THEN
216 | template.hasResourceProperties('AWS::S3::Bucket',
217 | Match.objectLike({
218 | WebsiteConfiguration: {
219 | IndexDocument: 'index.html'
220 | },
221 | }));
222 |
223 | template.hasResource('Custom::CDKBucketDeployment', {});
224 |
225 | template.hasResourceProperties('AWS::S3::BucketPolicy',
226 | Match.objectLike({
227 | PolicyDocument: {
228 | Statement: [
229 | Match.objectLike({
230 | Action: 's3:GetObject',
231 | Effect: 'Allow',
232 | Principal: {
233 | "AWS": "*"
234 | },
235 | })],
236 | },
237 | }));
238 | });
239 |
240 | test('Basic Site Setup with Error Doc set', () => {
241 | const stack = new Stack();
242 |
243 | // WHEN
244 | const deploy = new SPADeploy(stack, 'spaDeploy');
245 |
246 | deploy.createBasicSite({
247 | indexDoc: 'index.html',
248 | errorDoc: 'error.html',
249 | websiteFolder: 'website',
250 | });
251 |
252 | const template = Template.fromStack(stack);
253 |
254 | // THEN
255 | template.hasResourceProperties('AWS::S3::Bucket',
256 | Match.objectLike({
257 | WebsiteConfiguration: {
258 | IndexDocument: 'index.html',
259 | ErrorDocument: 'error.html',
260 | },
261 | }));
262 |
263 | template.hasResource('Custom::CDKBucketDeployment', {});
264 |
265 | template.hasResourceProperties('AWS::S3::BucketPolicy',
266 | Match.objectLike({
267 | PolicyDocument: {
268 | Statement: [
269 | Match.objectLike({
270 | Action: 's3:GetObject',
271 | Effect: 'Allow',
272 | Principal: {
273 | "AWS": "*"
274 | },
275 | })],
276 | },
277 | }));
278 | });
279 |
280 | test('Basic Site Setup with Custom Role', () => {
281 | const stack = new Stack();
282 |
283 | // WHEN
284 | const deploy = new SPADeploy(stack, 'spaDeploy');
285 |
286 | deploy.createBasicSite({
287 | indexDoc: 'index.html',
288 | errorDoc: 'error.html',
289 | websiteFolder: 'website',
290 | role: new Role(stack, 'myRole', {roleName: 'testRole', assumedBy: new ServicePrincipal('lambda.amazonaws.com')}),
291 | });
292 |
293 | const template = Template.fromStack(stack);
294 |
295 | // THEN
296 | template.hasResourceProperties('AWS::Lambda::Function',
297 | Match.objectLike({
298 | Role: {
299 | "Fn::GetAtt": [
300 | "myRoleE60D68E8",
301 | "Arn"
302 | ]
303 | }
304 | }));
305 |
306 | template.hasResourceProperties('AWS::S3::BucketPolicy',
307 | Match.objectLike({
308 | PolicyDocument: {
309 | Statement: [
310 | Match.objectLike({
311 | Action: 's3:GetObject',
312 | Effect: 'Allow',
313 | Principal: {
314 | "AWS": "*"
315 | }
316 | }),
317 | Match.objectLike({
318 | Action: [
319 | "s3:GetObject*",
320 | "s3:GetBucket*",
321 | "s3:List*",
322 | "s3:DeleteObject*",
323 | "s3:PutObject*",
324 | "s3:Abort*"
325 | ],
326 | Condition: {
327 | StringEquals: {
328 | "aws:PrincipalArn": {
329 | "Fn::GetAtt": [
330 | "myRoleE60D68E8",
331 | "Arn"
332 | ]
333 | }
334 | }
335 | },
336 | Effect: 'Allow',
337 | Principal: {
338 | "AWS": "*"
339 | }
340 | })],
341 | }
342 | }));
343 | });
344 |
345 |
346 | test('Basic Site Setup with Undefined Role', () => {
347 | const stack = new Stack();
348 |
349 | // WHEN
350 | const deploy = new SPADeploy(stack, 'spaDeploy');
351 |
352 | deploy.createBasicSite({
353 | indexDoc: 'index.html',
354 | errorDoc: 'error.html',
355 | websiteFolder: 'website',
356 | role: undefined
357 | });
358 |
359 | const template = Template.fromStack(stack);
360 |
361 | // THEN
362 | template.hasResourceProperties('AWS::Lambda::Function',
363 | Match.objectLike({
364 | Runtime: "python3.7",
365 | Role: {
366 | "Fn::GetAtt": [
367 | "CustomCDKBucketDeployment8693BB64968944B69AAFB0CC9EB8756CServiceRole89A01265",
368 | "Arn"
369 | ]
370 | }
371 | }));
372 | });
373 |
374 |
375 | test('Basic Site Setup, Encrypted Bucket', () => {
376 | const stack = new Stack();
377 |
378 | // WHEN
379 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true })
380 | .createBasicSite({
381 | indexDoc: 'index.html',
382 | websiteFolder: 'website',
383 | });
384 |
385 | const template = Template.fromStack(stack);
386 |
387 | // THEN
388 | template.hasResourceProperties('AWS::S3::Bucket',
389 | Match.objectLike({
390 | BucketEncryption: {
391 | ServerSideEncryptionConfiguration: [
392 | {
393 | ServerSideEncryptionByDefault: {
394 | SSEAlgorithm: 'AES256',
395 | },
396 | },
397 | ],
398 | },
399 | WebsiteConfiguration: {
400 | IndexDocument: 'index.html',
401 | },
402 | }));
403 |
404 | template.hasResource('Custom::CDKBucketDeployment', {});
405 |
406 | template.hasResourceProperties('AWS::S3::BucketPolicy',
407 | Match.objectLike({
408 | PolicyDocument: {
409 | Statement: [
410 | Match.objectLike({
411 | Action: 's3:GetObject',
412 | Effect: 'Allow',
413 | Principal: {
414 | "AWS": "*"
415 | },
416 | })],
417 | },
418 | }));
419 | });
420 |
421 | test('Cloudfront With Encrypted Bucket', () => {
422 | const stack = new Stack();
423 | // WHEN
424 | const deploy = new SPADeploy(stack, 'spaDeploy', { encryptBucket: true });
425 |
426 | deploy.createSiteWithCloudfront({
427 | indexDoc: 'index.html',
428 | websiteFolder: 'website',
429 | certificateARN: 'arn:1234',
430 | cfAliases: ['www.test.com'],
431 | });
432 |
433 | const template = Template.fromStack(stack);
434 |
435 | // THEN
436 | template.hasResourceProperties('AWS::S3::Bucket',
437 | Match.objectLike({
438 | BucketEncryption: {
439 | ServerSideEncryptionConfiguration: [
440 | {
441 | ServerSideEncryptionByDefault: {
442 | SSEAlgorithm: 'AES256',
443 | },
444 | },
445 | ],
446 | },
447 | WebsiteConfiguration: {
448 | IndexDocument: 'index.html',
449 | },
450 | }));
451 |
452 | template.hasResource('Custom::CDKBucketDeployment', {});
453 |
454 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
455 | DistributionConfig: {
456 | Aliases: [
457 | 'www.test.com',
458 | ],
459 | ViewerCertificate: {
460 | AcmCertificateArn: 'arn:1234',
461 | SslSupportMethod: 'sni-only',
462 | },
463 | },
464 | }));
465 | });
466 |
467 | test('Cloudfront With Custom Defined Behaviors', () => {
468 | const stack = new Stack();
469 |
470 | // WHEN
471 | const deploy = new SPADeploy(stack, 'spaDeploy');
472 |
473 | deploy.createSiteWithCloudfront({
474 | indexDoc: 'index.html',
475 | websiteFolder: 'website',
476 | cfBehaviors: [
477 | {
478 | isDefaultBehavior: true,
479 | allowedMethods: cf.CloudFrontAllowedMethods.ALL,
480 | forwardedValues: {
481 | queryString: true,
482 | cookies: { forward: 'all' },
483 | headers: ['*'],
484 | },
485 | },
486 | {
487 | pathPattern: '/virtual-path',
488 | allowedMethods: cf.CloudFrontAllowedMethods.GET_HEAD,
489 | cachedMethods: cf.CloudFrontAllowedCachedMethods.GET_HEAD,
490 | },
491 | ],
492 | });
493 |
494 | const template = Template.fromStack(stack);
495 |
496 | // THEN
497 | template.hasResource('Custom::CDKBucketDeployment', {});
498 |
499 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
500 | DistributionConfig: {
501 | CacheBehaviors: [
502 | Match.objectLike({
503 | AllowedMethods: ['GET', 'HEAD'],
504 | CachedMethods: ['GET', 'HEAD'],
505 | PathPattern: '/virtual-path',
506 | }),
507 | ],
508 | DefaultCacheBehavior: {
509 | AllowedMethods: ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PATCH', 'POST', 'PUT'],
510 | ForwardedValues: {
511 | Cookies: { Forward: 'all' },
512 | Headers: ['*'],
513 | QueryString: true,
514 | },
515 | TargetOriginId: 'origin1',
516 | },
517 | },
518 | }));
519 | });
520 |
521 | test('Cloudfront With Custom Security Policy', () => {
522 | const stack = new Stack();
523 | // WHEN
524 | const deploy = new SPADeploy(stack, 'spaDeploy');
525 |
526 | deploy.createSiteWithCloudfront({
527 | indexDoc: 'index.html',
528 | websiteFolder: 'website',
529 | certificateARN: 'arn:1234',
530 | cfAliases: ['www.test.com'],
531 | securityPolicy: cf.SecurityPolicyProtocol.TLS_V1_2_2019,
532 | });
533 |
534 | const template = Template.fromStack(stack);
535 |
536 | // THEN
537 | template.hasResource('Custom::CDKBucketDeployment', {});
538 |
539 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
540 | DistributionConfig: {
541 | Aliases: [
542 | 'www.test.com',
543 | ],
544 | ViewerCertificate: {
545 | AcmCertificateArn: 'arn:1234',
546 | SslSupportMethod: 'sni-only',
547 | MinimumProtocolVersion: 'TLSv1.2_2019',
548 | },
549 | },
550 | }));
551 | });
552 |
553 | test('Cloudfront With Custom SSL Method', () => {
554 | const stack = new Stack();
555 | // WHEN
556 | const deploy = new SPADeploy(stack, 'spaDeploy');
557 |
558 | deploy.createSiteWithCloudfront({
559 | indexDoc: 'index.html',
560 | websiteFolder: 'website',
561 | certificateARN: 'arn:1234',
562 | cfAliases: ['www.test.com'],
563 | sslMethod: cf.SSLMethod.VIP,
564 | });
565 |
566 | const template = Template.fromStack(stack);
567 |
568 | // THEN
569 | template.hasResource('Custom::CDKBucketDeployment', {});
570 |
571 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
572 | DistributionConfig: {
573 | Aliases: [
574 | 'www.test.com',
575 | ],
576 | ViewerCertificate: {
577 | AcmCertificateArn: 'arn:1234',
578 | SslSupportMethod: 'vip',
579 | },
580 | },
581 | }));
582 | });
583 |
584 | test('Basic Site Setup, IP Filter', () => {
585 | const stack = new Stack();
586 |
587 | // WHEN
588 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true, ipFilter: true, ipList: ['1.1.1.1'] })
589 | .createBasicSite({
590 | indexDoc: 'index.html',
591 | websiteFolder: 'website',
592 | });
593 |
594 | const template = Template.fromStack(stack);
595 |
596 | // THEN
597 | template.hasResourceProperties('AWS::S3::Bucket',
598 | Match.objectLike({
599 | BucketEncryption: {
600 | ServerSideEncryptionConfiguration: [
601 | {
602 | ServerSideEncryptionByDefault: {
603 | SSEAlgorithm: 'AES256',
604 | },
605 | },
606 | ],
607 | },
608 | WebsiteConfiguration: {
609 | IndexDocument: 'index.html',
610 | },
611 | }));
612 |
613 | template.hasResource('Custom::CDKBucketDeployment', {});
614 |
615 | template.hasResourceProperties('AWS::S3::BucketPolicy', Match.objectLike({
616 | PolicyDocument: {
617 | Statement: [
618 | Match.objectLike({
619 | Action: 's3:GetObject',
620 | Condition: {
621 | IpAddress: {
622 | 'aws:SourceIp': [
623 | '1.1.1.1',
624 | ],
625 | },
626 | },
627 | Effect: 'Allow',
628 | Principal: {
629 | "AWS": "*"
630 | },
631 | })],
632 | },
633 | }));
634 | });
635 |
636 | test('Create From Hosted Zone', () => {
637 | const app = new App();
638 | const stack = new Stack(app, 'testStack', {
639 | env: {
640 | region: 'us-east-1',
641 | account: '1234',
642 | },
643 | });
644 | // WHEN
645 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true })
646 | .createSiteFromHostedZone({
647 | zoneName: 'cdkspadeploy.com',
648 | indexDoc: 'index.html',
649 | websiteFolder: 'website',
650 | });
651 |
652 | const template = Template.fromStack(stack);
653 |
654 | // THEN
655 | template.hasResourceProperties('AWS::S3::Bucket',
656 | Match.objectLike({
657 | BucketEncryption: {
658 | ServerSideEncryptionConfiguration: [
659 | {
660 | ServerSideEncryptionByDefault: {
661 | SSEAlgorithm: 'AES256',
662 | },
663 | },
664 | ],
665 | },
666 | WebsiteConfiguration: {
667 | IndexDocument: 'index.html',
668 | },
669 | }));
670 |
671 | template.hasResource('Custom::CDKBucketDeployment', {});
672 |
673 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
674 | DistributionConfig: {
675 | Aliases: [
676 | 'www.cdkspadeploy.com',
677 | ],
678 | ViewerCertificate: {
679 | SslSupportMethod: 'sni-only',
680 | },
681 | },
682 | }));
683 |
684 | template.hasResourceProperties('AWS::S3::BucketPolicy',
685 | Match.objectLike({
686 | PolicyDocument: {
687 | Statement: [
688 | Match.objectLike({
689 | Action: 's3:GetObject',
690 | Effect: 'Allow'
691 | })],
692 | },
693 | }));
694 | });
695 |
696 | test('Create From Hosted Zone with subdomain', () => {
697 | const app = new App();
698 | const stack = new Stack(app, 'testStack', {
699 | env: {
700 | region: 'us-east-1',
701 | account: '1234',
702 | },
703 | });
704 | // WHEN
705 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true })
706 | .createSiteFromHostedZone({
707 | zoneName: 'cdkspadeploy.com',
708 | indexDoc: 'index.html',
709 | websiteFolder: 'website',
710 | subdomain: 'myhost',
711 | });
712 |
713 | const template = Template.fromStack(stack);
714 |
715 | // THEN
716 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
717 | DistributionConfig: {
718 | Aliases: [
719 | 'myhost.cdkspadeploy.com',
720 | ],
721 | ViewerCertificate: {
722 | SslSupportMethod: 'sni-only',
723 | },
724 | },
725 | }));
726 | });
727 |
728 | test('Create From Hosted Zone with Custom Role', () => {
729 | const app = new App();
730 | const stack = new Stack(app, 'testStack', {
731 | env: {
732 | region: 'us-east-1',
733 | account: '1234',
734 | },
735 | });
736 | // WHEN
737 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true })
738 | .createSiteFromHostedZone({
739 | zoneName: 'cdkspadeploy.com',
740 | indexDoc: 'index.html',
741 | errorDoc: 'error.html',
742 | websiteFolder: 'website',
743 | role: new Role(stack, 'myRole', {roleName: 'testRole', assumedBy: new ServicePrincipal('lambda.amazonaws.com')})
744 | });
745 |
746 | const template = Template.fromStack(stack);
747 |
748 | // THEN
749 |
750 | template.hasResourceProperties('AWS::Lambda::Function', Match.objectLike({
751 | Role: {
752 | "Fn::GetAtt": [
753 | "myRoleE60D68E8",
754 | "Arn"
755 | ]
756 | }
757 | }));
758 | });
759 |
760 | test('Create From Hosted Zone with Error Bucket', () => {
761 | const app = new App();
762 | const stack = new Stack(app, 'testStack', {
763 | env: {
764 | region: 'us-east-1',
765 | account: '1234',
766 | },
767 | });
768 | // WHEN
769 | new SPADeploy(stack, 'spaDeploy', { encryptBucket: true })
770 | .createSiteFromHostedZone({
771 | zoneName: 'cdkspadeploy.com',
772 | indexDoc: 'index.html',
773 | errorDoc: 'error.html',
774 | websiteFolder: 'website',
775 | });
776 |
777 | const template = Template.fromStack(stack);
778 |
779 | // THEN
780 | template.hasResourceProperties('AWS::S3::Bucket', Match.objectLike({
781 | BucketEncryption: {
782 | ServerSideEncryptionConfiguration: [
783 | {
784 | ServerSideEncryptionByDefault: {
785 | SSEAlgorithm: 'AES256',
786 | },
787 | },
788 | ],
789 | },
790 | WebsiteConfiguration: {
791 | IndexDocument: 'index.html',
792 | ErrorDocument: 'error.html',
793 | },
794 | }));
795 |
796 | template.hasResource('Custom::CDKBucketDeployment', {});
797 |
798 | template.hasResourceProperties('AWS::CloudFront::Distribution', Match.objectLike({
799 | DistributionConfig: {
800 | Aliases: [
801 | 'www.cdkspadeploy.com',
802 | ],
803 | ViewerCertificate: {
804 | SslSupportMethod: 'sni-only',
805 | },
806 | },
807 | }));
808 | });
809 |
810 | test('Basic Site Setup, Block Public Enabled', () => {
811 | const stack = new Stack();
812 |
813 | // WHEN
814 | new SPADeploy(stack, 'spaDeploy')
815 | .createBasicSite({
816 | indexDoc: 'index.html',
817 | websiteFolder: 'website',
818 | blockPublicAccess: BlockPublicAccess.BLOCK_ALL
819 | });
820 |
821 | const template = Template.fromStack(stack);
822 |
823 | // THEN
824 | template.hasResourceProperties('AWS::S3::Bucket', Match.objectLike({
825 | WebsiteConfiguration: {
826 | IndexDocument: 'index.html',
827 | },
828 | PublicAccessBlockConfiguration: {
829 | BlockPublicAcls: true,
830 | BlockPublicPolicy: true,
831 | IgnorePublicAcls: true,
832 | RestrictPublicBuckets: true,
833 | },
834 | }));
835 | });
836 |
837 |
838 | test('Basic Site Setup, URL Output Enabled With Name', () => {
839 | const stack = new Stack();
840 | const exportName = 'test-export-name';
841 |
842 | // WHEN
843 | new SPADeploy(stack, 'spaDeploy', {})
844 | .createBasicSite({
845 | indexDoc: 'index.html',
846 | websiteFolder: 'website',
847 | exportWebsiteUrlOutput: true,
848 | exportWebsiteUrlName: exportName,
849 | });
850 |
851 | const template = Template.fromStack(stack);
852 |
853 | // THEN
854 | template.hasOutput(exportName, {
855 | "Export": {
856 | "Name": exportName
857 | }
858 | });
859 | });
860 |
861 | test('Basic Site Setup, URL Output Enabled With No Name', () => {
862 | const stack = new Stack();
863 |
864 | // WHEN
865 | expect(() => {new SPADeploy(stack, 'spaDeploy', {})
866 | .createBasicSite({
867 | indexDoc: 'index.html',
868 | websiteFolder: 'website',
869 | exportWebsiteUrlOutput: true,
870 | })}).toThrowError();
871 | });
872 |
873 | test('Basic Site Setup, URL Output Not Enabled', () => {
874 | const stack = new Stack();
875 | const exportName = 'test-export-name';
876 |
877 | // WHEN
878 | new SPADeploy(stack, 'spaDeploy', {})
879 | .createBasicSite({
880 | indexDoc: 'index.html',
881 | websiteFolder: 'website',
882 | exportWebsiteUrlOutput: false,
883 | });
884 |
885 | const template = Template.fromStack(stack);
886 |
887 | // THEN
888 | expect(() => {template.hasOutput(exportName, {
889 | "Export": {
890 | "Name": exportName
891 | }
892 | })}).toThrowError();
893 | });
894 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "alwaysStrict": true,
4 | "charset": "utf8",
5 | "declaration": true,
6 | "experimentalDecorators": true,
7 | "incremental": true,
8 | "inlineSourceMap": true,
9 | "inlineSources": true,
10 | "lib": [
11 | "es2018"
12 | ],
13 | "module": "CommonJS",
14 | "newLine": "lf",
15 | "noEmitOnError": true,
16 | "noFallthroughCasesInSwitch": true,
17 | "noImplicitAny": true,
18 | "noImplicitReturns": true,
19 | "noImplicitThis": true,
20 | "noUnusedLocals": true,
21 | "noUnusedParameters": true,
22 | "resolveJsonModule": true,
23 | "strict": true,
24 | "strictNullChecks": true,
25 | "strictPropertyInitialization": true,
26 | "stripInternal": false,
27 | "target": "ES2018",
28 | "composite": false,
29 | "tsBuildInfoFile": "tsconfig.tsbuildinfo"
30 | },
31 | "include": [
32 | "**/*.ts"
33 | ],
34 | "exclude": [
35 | "node_modules"
36 | ],
37 | "_generated_by_jsii_": "Generated by jsii - safe to delete, and ideally should be in .gitignore"
38 | }
39 |
--------------------------------------------------------------------------------
/website/index.html:
--------------------------------------------------------------------------------
1 | This is a test page
--------------------------------------------------------------------------------