├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── npm-publish.yml
│ ├── on-docs-update.yml
│ ├── on-issue-opened.yml
│ ├── on-push.yml
│ ├── on-workflow-update.yml
│ └── run-security-checks.yml
├── .gitignore
├── .npmignore
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── NOTICE
├── README.md
├── SECURITY.md
├── bin
├── cli
│ ├── actions
│ │ ├── delete.ts
│ │ ├── deploy.ts
│ │ ├── init.ts
│ │ ├── show.ts
│ │ └── status.ts
│ ├── index.ts
│ ├── shared
│ │ ├── constants.ts
│ │ └── types.ts
│ └── utils
│ │ ├── awsSDKUtil.ts
│ │ ├── helper.ts
│ │ └── prompt_questions.ts
└── cloudfront-hosting-toolkit.ts
├── cdk.json
├── cdk.json.built
├── cdk.json.dev
├── docs
├── .gitignore
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public
│ └── img
│ │ ├── architecture.jpg
│ │ ├── deploy.gif
│ │ ├── flow.png
│ │ └── init.gif
├── src
│ ├── assets
│ │ └── fonts
│ │ │ ├── JetBrainsMonoNerdFont-Bold.ttf
│ │ │ ├── JetBrainsMonoNerdFont-BoldItalic.ttf
│ │ │ ├── JetBrainsMonoNerdFont-Italic.ttf
│ │ │ └── JetBrainsMonoNerdFont-Regular.ttf
│ ├── components
│ │ └── code.astro
│ ├── content
│ │ ├── config.ts
│ │ └── docs
│ │ │ ├── advanced
│ │ │ ├── bring-your-own-framework.md
│ │ │ └── configuration.md
│ │ │ ├── architecture
│ │ │ ├── github-workflow.md
│ │ │ ├── overview.md
│ │ │ └── s3-workflow.md
│ │ │ ├── features
│ │ │ ├── custom-domains.md
│ │ │ ├── github-integration.md
│ │ │ ├── instant-deployment.md
│ │ │ ├── optimized-caching.md
│ │ │ ├── overview.md
│ │ │ ├── security-headers.md
│ │ │ └── setup-wizard.md
│ │ │ ├── getting-started
│ │ │ ├── how-it-works.md
│ │ │ ├── introduction.md
│ │ │ └── quickstart.md
│ │ │ ├── index.mdx
│ │ │ ├── project
│ │ │ └── faq.md
│ │ │ ├── troubleshooting
│ │ │ └── guide.md
│ │ │ └── user-guide
│ │ │ ├── cdk-configuration.md
│ │ │ ├── cdk-construct.md
│ │ │ ├── cdk-guide.md
│ │ │ ├── cdk-source-code.md
│ │ │ └── cli-guide.md
│ └── styles
│ │ ├── custom.css
│ │ ├── font.css
│ │ ├── landing.css
│ │ └── terminal.css
└── tsconfig.json
├── img
├── architecture.jpg
├── deploy.gif
└── init.gif
├── jest.config.js
├── lambda
├── delete_old_deployments
│ └── index.js
├── layers
│ └── aws_sdk
│ │ └── nodejs
│ │ ├── package-lock.json
│ │ └── package.json
├── new_build
│ └── index.js
└── update_kvs
│ └── index.js
├── lib
├── cfn_nag
│ └── cfn_nag_utils.ts
├── deploy_type.ts
├── deployment_workflow_sf.ts
├── hosting.ts
├── hosting_infrastructure.ts
├── hosting_stack.ts
├── index.ts
├── pipeline_infrastructure.ts
├── repository_connection.ts
├── repository_stack.ts
└── utility.ts
├── package-lock.json
├── package.json
├── resources
├── build_config_templates
│ ├── hosting_angularjs.yml
│ ├── hosting_basic.yml
│ ├── hosting_nextjs.yml
│ ├── hosting_reactjs.yml
│ ├── hosting_vuejs.yml
│ └── s3_build_config.yml
├── cff_templates
│ ├── index_angularjs.js
│ ├── index_basic.js
│ ├── index_nextjs.js
│ ├── index_reactjs.js
│ └── index_vuejs.js
├── initial_repository
│ └── index.html
├── initial_s3
│ └── index.html
└── s3_trigger
│ └── dummy.txt
├── roadmap.md
├── scripts
└── createDummyZip.js
├── solution.context.json.template.github
├── solution.context.json.template.s3
├── test
├── cloudfront-hosting-toolkit
│ ├── angularjs
│ │ └── package.json
│ ├── nextjs
│ │ └── package.json
│ ├── no_framework
│ │ └── index.html
│ ├── reactjs
│ │ └── package.json
│ └── vuejs
│ │ └── package.json
├── deploy.test.ts
├── detect_framework.test.ts
├── hosting_stack.test.ts
├── init.test.ts
├── repository_stack.test.ts
└── uri_rewrite.test.ts
└── tsconfig.json
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: Report a reproducible bug to help us improve
3 | title: "Bug: TITLE"
4 | labels: ["bug"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thank you for submitting a bug report. Please add as much information as possible to help us reproduce, and remove any potential sensitive data.
10 |
11 | - type: textarea
12 | id: expected_behaviour
13 | attributes:
14 | label: Expected Behaviour
15 | description: Please share details on the behaviour you expected
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: current_behaviour
20 | attributes:
21 | label: Current Behaviour
22 | description: Please share details on the current issue
23 | validations:
24 | required: true
25 | - type: textarea
26 | id: code_snippet
27 | attributes:
28 | label: Code snippet
29 | description: Please share a code snippet to help us reproduce the issue
30 | render: python
31 | validations:
32 | required: true
33 | - type: textarea
34 | id: solution
35 | attributes:
36 | label: Possible Solution
37 | description: If known, please suggest a potential resolution
38 | validations:
39 | required: false
40 | - type: textarea
41 | id: steps
42 | attributes:
43 | label: Steps to Reproduce
44 | description: Please share how we might be able to reproduce this issue
45 | validations:
46 | required: true
47 | - type: markdown
48 | attributes:
49 | value: |
50 | ---
51 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for CloudFront Hosting Toolkit
3 | title: "Feature request: TITLE"
4 | labels: ["feature-request", "triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thank you for taking the time to suggest an idea to the CloudFront Hosting Toolkit project.
10 |
11 | *Future readers*: Please react with 👍 and your use case to help us understand customer demand.
12 | - type: textarea
13 | id: problem
14 | attributes:
15 | label: Use case
16 | description: Please help us understand your use case or problem you're facing
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: suggestion
21 | attributes:
22 | label: Solution/User Experience
23 | description: Please share what a good solution would look like to this use case
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: alternatives
28 | attributes:
29 | label: Alternative solutions
30 | description: Please describe what alternative solutions to this use case, if any
31 | render: markdown
32 | validations:
33 | required: false
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 | **Issue number:**
3 |
4 | ## Summary
5 |
6 | ### Changes
7 |
8 | > Please provide a summary of what's being changed
9 |
10 | ### User experience
11 |
12 | > Please share what the user experience looks like before and after this change
13 |
14 | ## Checklist
15 |
16 | If your change doesn't seem to apply, please leave them unchecked.
17 |
18 | * [ ] I have performed a self-review of this change
19 | * [ ] Changes have been tested
20 | * [ ] Changes are documented
21 |
22 |
23 | Is this a breaking change?
24 |
25 | **RFC issue number**:
26 |
27 | Checklist:
28 |
29 | * [ ] Migration process documented
30 | * [ ] Implement warnings (if it can live side by side)
31 |
32 |
33 |
34 | ## Acknowledgment
35 |
36 | By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
37 |
38 | **Disclaimer**: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.
39 |
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
3 |
4 | name: Publish to NPM
5 |
6 | on:
7 | workflow_dispatch
8 |
9 | jobs:
10 | build-and-publish:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@6ccd57f4c5d15bdc2fef309bd9fb6cc9db2ef1c6
14 | - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
15 | with:
16 | node-version: 20
17 | registry-url: https://registry.npmjs.org/
18 | - run: npm install
19 | - run: npm run build
20 | - run: cp cdk.json.built cdk.json
21 | - run: npm pack
22 | - run: npm publish --access=public
23 | env:
24 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
25 |
--------------------------------------------------------------------------------
/.github/workflows/on-docs-update.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy Documentation
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - 'docs/**'
9 | workflow_dispatch:
10 |
11 | permissions:
12 | contents: read
13 | pages: write
14 | id-token: write
15 |
16 | jobs:
17 | # Build the documentation.
18 | build:
19 | concurrency: ci-${{ github.ref }}
20 | runs-on: ubuntu-latest
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08
24 | - name: Install, build, and upload documentation
25 | uses: withastro/action@9a7959a16949e620a22e74f81c10cb7ce3b76924
26 | with:
27 | path: ./docs
28 | - name: Upload artifact
29 | uses: actions/upload-pages-artifact@027b0ddc3de8dbe7e5a699814c4508ca8ecefc5f
30 | with:
31 | path: ./docs/dist
32 |
33 | # Deploy the documentation to GitHub Pages.
34 | deploy:
35 | needs: build
36 | runs-on: ubuntu-latest
37 | environment:
38 | name: github-pages
39 | url: ${{ steps.deployment.outputs.page_url }}
40 | steps:
41 | - name: Deploy to GitHub Pages
42 | id: deployment
43 | uses: actions/deploy-pages@7a9bd943aa5e5175aeb8502edcc6c1c02d398e10
44 |
--------------------------------------------------------------------------------
/.github/workflows/on-issue-opened.yml:
--------------------------------------------------------------------------------
1 | name: Label issues
2 |
3 | on:
4 | issues:
5 | types:
6 | - reopened
7 | - opened
8 |
9 | permissions:
10 | issues: write
11 |
12 | jobs:
13 | label_issues:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/github-script@1f16022c7518aad314c43abcd029895291be0f52
17 | with:
18 | script: |
19 | github.rest.issues.addLabels({
20 | issue_number: context.issue.number,
21 | owner: context.repo.owner,
22 | repo: context.repo.repo,
23 | labels: ["triage"]
24 | })
25 |
--------------------------------------------------------------------------------
/.github/workflows/on-push.yml:
--------------------------------------------------------------------------------
1 | name: Push Workflow
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | types:
9 | - opened
10 | - edited
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | security-checks:
17 | uses: ./.github/workflows/run-security-checks.yml
18 | secrets: inherit
--------------------------------------------------------------------------------
/.github/workflows/on-workflow-update.yml:
--------------------------------------------------------------------------------
1 | name: Lockdown untrusted workflows
2 |
3 | on:
4 | push:
5 | paths:
6 | - ".github/workflows/**"
7 | pull_request:
8 | paths:
9 | - ".github/workflows/**"
10 | workflow_dispatch:
11 |
12 | permissions:
13 | contents: read
14 |
15 | jobs:
16 | enforce_pinned_workflows:
17 | name: Harden Security
18 | runs-on: ubuntu-latest
19 | steps:
20 | - name: Checkout code
21 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
22 | - name: Ensure 3rd party workflows have SHA pinned
23 | uses: zgosalvez/github-actions-ensure-sha-pinned-actions@f32435541e24cd6a4700a7f52bb2ec59e80603b1
24 |
--------------------------------------------------------------------------------
/.github/workflows/run-security-checks.yml:
--------------------------------------------------------------------------------
1 | name: Run security checks on the project
2 |
3 | on:
4 | workflow_call:
5 | workflow_dispatch:
6 |
7 | permissions:
8 | contents: read
9 |
10 | jobs:
11 | scan:
12 | runs-on: ubuntu-latest
13 | steps:
14 | # Checkout and setup.
15 | - name: Checkout repository
16 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
17 | - name: Install dependencies
18 | run: npm install
19 |
20 | # NPM audit.
21 | - name: Run audit
22 | run: npm audit
23 |
24 | # GitLeaks.
25 | - name: Run Gitleaks
26 | uses: gitleaks/gitleaks-action@4df650038e2eb9f7329218df929c2780866e61a3
27 | env:
28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29 | GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
30 |
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | !jest.config.js
2 | *.d.ts
3 | node_modules
4 | dist
5 |
6 |
7 | bin/*.js
8 |
9 | .cdk.staging
10 | cdk.out
11 | solution.context.json
12 | resources/s3_trigger/dummy.zip
13 | resources/build_config/*.*
14 | *.tgz
15 | cloudfront-hosting-toolkit/*.*
16 | cloudfront-hosting-toolkit
17 | coverage
18 |
19 | .DS_Store
20 | resources/.DS_Store
21 | resources/s3_trigger/.DS_Store
22 |
23 | lib/**/*.d.ts
24 | lib/**/*.js
25 |
26 | bin/**/*.d.ts
27 | bin/**/*.js
28 |
29 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 |
2 |
3 | *
4 |
5 | !lib/**/*.d.ts
6 | !lib/**/*.js
7 |
8 | !bin/**/*.d.ts
9 | !bin/**/*.js
10 |
11 | !lambda/**/*.js
12 | !resources/**/*/*.*
13 |
14 | !scripts/*.js
15 |
16 | !package.json
17 | !package-lock.json
18 |
19 | !cdk.json
20 |
21 | docs/
22 |
23 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [1.0.0] - 2023-09-31
8 | ### Added
9 | - Initial version
10 |
11 | ## [1.1.0] - 2024-01-10
12 | ### Added
13 |
14 | - Use CloudFront KeyValueStore to store commitId
15 |
16 | ### Changed
17 | ### Fixed
18 |
19 | ## [1.1.1] - 2024-01-10
20 | ### Added
21 |
22 | ### Changed
23 |
24 | - remove age and date header
25 |
26 | ### Fixed
27 |
28 | ## [1.1.2] - 2024-01-10
29 | ### Added
30 |
31 | ### Changed
32 |
33 | - build AWS Layer manually
34 |
35 | ### Fixed
36 |
37 | ## [1.1.3] - 2024-01-25
38 | ### Added
39 |
40 | - max name for OAC & remove old comments
41 |
42 | ### Changed
43 | ### Fixed
44 |
45 | ## [1.1.4] - 2024-01-25
46 | ### Added
47 |
48 | ### Changed
49 |
50 | - use custom name for KVS
51 |
52 | ### Fixed
53 |
54 | ## [1.1.5] - 2024-01-25
55 | ### Added
56 |
57 | - Use Lambda Power Tools for logging and tracing
58 |
59 | ### Changed
60 | ### Fixed
61 |
62 |
63 | ## [1.1.6] - 2024-05-24
64 | ### Added
65 |
66 |
67 | ### Changed
68 |
69 | - Use one CloudFront Function template per framework
70 | - Generate the necessary dummy zip file required by the Pipeline during installation, instead of using the CLI deploy command
71 |
72 | ### Fixed
73 |
74 | ## [1.1.7] - 2024-06-04
75 | ### Added
76 |
77 |
78 | ### Changed
79 |
80 |
81 | ### Fixed
82 |
83 | - Address the behavior when a user wants to utilize their own framework that is not included in the existing list of supported frameworks
84 |
85 | ## [1.1.8] - 2024-06-05
86 | ### Added
87 |
88 |
89 | ### Changed
90 |
91 |
92 | ### Fixed
93 |
94 | - Lambda layer path
95 | - Update Readme CDK Usage
96 |
97 | ## [1.1.9] - 2024-06-05
98 | ### Added
99 |
100 |
101 | ### Changed
102 |
103 |
104 | ### Fixed
105 |
106 | - Fix A record
107 |
108 |
109 | ## [1.1.10] - 2024-06-07
110 | ### Added
111 |
112 | - Add option to submit a feature request
113 |
114 |
115 | ### Changed
116 |
117 |
118 | ### Fixed
119 |
120 |
121 | ## [1.1.11] - 2024-06-07
122 | ### Added
123 |
124 |
125 | ### Changed
126 |
127 |
128 | ### Fixed
129 |
130 | - fix wording for A record
131 | - update a few prompts to be more explicit
132 |
133 | ## [1.1.12] - 2024-06-07
134 | ### Added
135 |
136 |
137 | ### Changed
138 |
139 |
140 | ### Fixed
141 |
142 | - Properly bundles package before publishing to npm
143 | - Ensure connection stack name follows naming pattern
144 |
145 | ## [1.1.15] - 2024-06-07
146 | ### Added
147 |
148 |
149 | ### Changed
150 |
151 |
152 | ### Fixed
153 |
154 | - Removal special characters Action name in CodePipeline
155 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Code of Conduct
2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
4 | opensource-codeofconduct@amazon.com with any additional questions or comments.
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines
2 |
3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
4 | documentation, we greatly value feedback and contributions from our community.
5 |
6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
7 | information to effectively respond to your bug report or contribution.
8 |
9 |
10 | ## Reporting Bugs/Feature Requests
11 |
12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features.
13 |
14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already
15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
16 |
17 | * A reproducible test case or series of steps
18 | * The version of our code being used
19 | * Any modifications you've made relevant to the bug
20 | * Anything unusual about your environment or deployment
21 |
22 |
23 | ## Contributing via Pull Requests
24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
25 |
26 | 1. You are working against the latest source on the *main* branch.
27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
29 |
30 | To send us a pull request, please:
31 |
32 | 1. Fork the repository.
33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
34 | 3. Ensure local tests pass.
35 | 4. Commit to your fork using clear commit messages.
36 | 5. Send us a pull request, answering any default questions in the pull request interface.
37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
38 |
39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
41 |
42 |
43 | ## Finding contributions to work on
44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.
45 |
46 |
47 | ## Code of Conduct
48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
50 | opensource-codeofconduct@amazon.com with any additional questions or comments.
51 |
52 |
53 | ## Security issue notifications
54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
55 |
56 |
57 | ## Licensing
58 |
59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
60 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CloudFront Hosting Toolkit
2 |
3 | CloudFront Hosting Toolkit is an open-source command-line tool designed to simplify the deployment and management of fast, secure frontend applications on AWS. It offers the convenience of a managed frontend hosting service while giving developers full control over their hosting and deployment infrastructure.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | ## What is CloudFront Hosting Toolkit?
14 |
15 | CloudFront Hosting Toolkit is a comprehensive solution that automates the process of setting up and managing a robust, scalable frontend hosting infrastructure on AWS. It leverages several AWS services, including CloudFront, S3, CodePipeline, and Lambda, to create a powerful hosting environment tailored for modern web applications.
16 |
17 | Key features include:
18 | - 🚀 Automated setup of AWS resources for frontend hosting
19 | - 🔄 Continuous deployment pipeline for GitHub and S3-based workflows
20 | - 🌐 Optimized content delivery through CloudFront
21 | - 🔒 Built-in security features including HTTPS and security headers
22 | - 🔗 Custom domain support with automatic SSL/TLS certificate management
23 | - 🛠️ Flexible configuration options for various frontend frameworks
24 |
25 | ## How It Works
26 |
27 | CloudFront Hosting Toolkit streamlines the deployment process through a simple CLI interface. It automatically provisions and configures necessary AWS resources, handles the deployment pipeline, and manages content delivery through CloudFront.
28 |
29 | For a detailed explanation of the architecture and workflow, please refer to our [Architecture documentation](https://awslabs.github.io/cloudfront-hosting-toolkit/architecture/overview).
30 |
31 | ## Why Use CloudFront Hosting Toolkit?
32 |
33 | - **Simplicity**: Deploy complex frontend hosting setups with just a few commands.
34 | - **Speed**: Leverage CloudFront's global CDN for fast content delivery.
35 | - **Security**: Automatic HTTPS configuration and security headers.
36 | - **Flexibility**: Support for various frontend frameworks and deployment sources.
37 | - **Cost-Effective**: Utilize AWS services efficiently without unnecessary overhead.
38 | - **Full Control**: Retain the ability to customize and extend your infrastructure.
39 |
40 | ## Re:Invent 2024 lightning talk
41 |
42 |
47 |
48 | Learn how to leverage CloudFront Hosting Toolkit for deploying secure and fast frontends using Git-based workflows while maintaining full control over your AWS resources.
49 |
50 |
51 |
52 | ## Getting Started
53 |
54 | Check out our [documentation](https://awslabs.github.io/cloudfront-hosting-toolkit/) for comprehensive guides on setting up and using the Cloudfront Hosting Toolkit!
55 |
56 |
57 |
58 | ### Requirements
59 |
60 | - Node.js 18+
61 | - AWS CLI 2+ configured with your AWS account
62 | - (Optional) A GitHub account for GitHub-based deployments
63 |
64 | ### Installation
65 |
66 | ```bash
67 | npm install -g @aws/cloudfront-hosting-toolkit
68 | ```
69 |
70 | ### Quick Start
71 |
72 | 1. Initialize your project:
73 | ```bash
74 | cloudfront-hosting-toolkit init
75 | ```
76 | The animated GIF below demonstrates the initialization process
77 | 
78 |
79 | 2. Deploy your website:
80 | ```bash
81 | cloudfront-hosting-toolkit deploy
82 | ```
83 | The animated GIF below demonstrates the deployment process
84 | 
85 |
86 |
87 | For more detailed instructions and advanced usage, please refer to our [CLI Guide](https://awslabs.github.io/cloudfront-hosting-toolkit/user-guide/cli-guide).
88 |
89 | ## Example Commands
90 |
91 | ```bash
92 | # Show domain name
93 | cloudfront-hosting-toolkit show
94 |
95 | # Check deployment status
96 | cloudfront-hosting-toolkit status
97 |
98 | # Remove hosting infrastructure
99 | cloudfront-hosting-toolkit delete
100 | ```
101 |
102 | ## Architecture
103 |
104 | 
105 |
106 | CloudFront Hosting Toolkit sets up a comprehensive AWS architecture for your frontend hosting:
107 |
108 | - **Source Control**: GitHub repository or S3 bucket
109 | - **CI/CD**: AWS CodePipeline for automated builds and deployments
110 | - **Build Process**: AWS CodeBuild for compiling and creating deployment artifacts
111 | - **Storage**: S3 buckets for hosting website files
112 | - **Content Delivery**: CloudFront for global content distribution
113 | - **Routing**: CloudFront Functions for request handling and routing
114 | - **Orchestration**: Step Functions for managing deployment processes
115 | - **State Management**: KVS for storing deployment state information
116 |
117 | This architecture ensures a scalable, performant, and maintainable hosting solution for your frontend applications.
118 |
119 | ## Advanced Usage
120 |
121 | CloudFront Hosting Toolkit offers flexibility in how it can be used:
122 |
123 | - **CLI**: Use the Command-Line Interface for a straightforward, step-by-step deployment process.
124 | - **CDK Construct**: Leverage the CloudFront Hosting Toolkit as a ready-made L3 CDK construct for seamless integration into your AWS CDK projects.
125 | - **CDK Source Code**: Customize the CDK source code to tailor the infrastructure to your specific requirements.
126 |
127 | For more information on how to use CloudFront Hosting Toolkit, including advanced usage scenarios and in-depth customization options, please refer to our extensive documentation in the [Advanced section](https://awslabs.github.io/cloudfront-hosting-toolkit/advanced/configuration/).
128 |
129 | ## Documentation
130 |
131 | - [How it works](https://awslabs.github.io/cloudfront-hosting-toolkit/getting-started/how-it-works)
132 | - [CLI Guide](https://awslabs.github.io/cloudfront-hosting-toolkit/user-guide/cli-guide)
133 | - [CDK Integration](https://awslabs.github.io/cloudfront-hosting-toolkit/user-guide/cdk-guide)
134 | - [Troubleshooting Guide](https://awslabs.github.io/cloudfront-hosting-toolkit/troubleshooting/guide)
135 | - [FAQ](https://awslabs.github.io/cloudfront-hosting-toolkit/project/faq)
136 | - [Contributing Guidelines](CONTRIBUTING.md)
137 |
138 | ## Roadmap
139 |
140 | For information about upcoming features and improvements, please see our [Roadmap](roadmap.md).
141 |
142 | ## 🤝 Contributing
143 |
144 | We welcome contributions! Please see our [Contributing Guide](https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/main/CONTRIBUTING.md) for more details.
145 |
146 | # Author
147 |
148 | - [Corneliu Croitoru](https://www.linkedin.com/in/corneliucroitoru/)
149 |
150 | # Contributors
151 | [](https://github.com/awslabs/cloudfront-hosting-toolkit/graphs/contributors)
152 |
153 |
154 |
155 |
156 |
157 | ## License
158 |
159 | This library is licensed under the Apache-2.0 License.
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Reporting a vulnerability
4 |
5 | If you discover a potential security issue in this project, we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/) or directly via email to .
6 |
7 | Please do **not** create a public GitHub issue.
8 |
--------------------------------------------------------------------------------
/bin/cli/actions/delete.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | import {
19 | startPrompt,
20 | executeCommands,
21 | getToolFolder,
22 | getCLIInstallationFolder,
23 | loadHostingConfiguration,
24 | } from "../utils/helper";
25 | import { hostingInfrastructureDeletionConfirmation } from "../utils/prompt_questions";
26 | import checkAWSConnection, {
27 | checkCertificateExists,
28 | checkCFARecordExists,
29 | deleteACMCertificate,
30 | deleteCFCNAME,
31 | getSSMParameter,
32 | } from "../utils/awsSDKUtil";
33 | import { SSM_DOMAIN_STR } from "../shared/constants";
34 |
35 | export async function handleDeleteCommand() {
36 | await checkAWSConnection();
37 |
38 | var counter = 1;
39 | const confirm = await startPrompt(hostingInfrastructureDeletionConfirmation);
40 | if (confirm.value == "exit") {
41 | process.exit(0);
42 | }
43 |
44 | var certificateArnCmdParam = "";
45 | var certificateArn;
46 | const hostingConfiguration = await loadHostingConfiguration();
47 |
48 |
49 | if (hostingConfiguration.domainName) {
50 | const certificateInfo = await checkCertificateExists(hostingConfiguration.domainName);
51 | certificateArn = certificateInfo.certificateArn;
52 | if (certificateArn) {
53 | certificateArnCmdParam = `--context certificate-arn=${certificateArn}`;
54 | }
55 | }
56 |
57 | console.log(`\n --> ${counter++}. Deleting the hosting infrastructure \n`);
58 |
59 | console.log(
60 | "Please wait while deleting the infrastructure, it may take a few minutes."
61 | );
62 | const deleteCmd= `npx cdk destroy --all --force --context config-path=${getToolFolder()} ${certificateArnCmdParam}`;
63 |
64 | await executeCommands(deleteCmd, getCLIInstallationFolder());
65 |
66 | if (hostingConfiguration.domainName && hostingConfiguration.hostedZoneId) {
67 | const domainName = await getSSMParameter(SSM_DOMAIN_STR);
68 |
69 | if(domainName){
70 | const cFCNAMEExists = await checkCFARecordExists(
71 | hostingConfiguration.domainName,
72 | domainName,
73 | hostingConfiguration.hostedZoneId
74 | );
75 | if (cFCNAMEExists) {
76 | console.log(
77 | `\n --> ${counter++}. Removing entries from the Route53 Hosted Zone \n`
78 | );
79 |
80 | await deleteCFCNAME(
81 | hostingConfiguration.domainName,
82 | domainName,
83 | hostingConfiguration.hostedZoneId
84 | );
85 | }
86 | }
87 |
88 | }
89 |
90 | if (certificateArn) {
91 | console.log(
92 | `\n --> ${counter++}. Deleting the SSL/TLS certificate from AWS Certificate Manager (ACM)\n`
93 | );
94 |
95 | await deleteACMCertificate(certificateArn);
96 | }
97 |
98 | console.log(
99 | "\nThe hosting infrastructure has been completely removed from your AWS account."
100 | );
101 | }
102 |
--------------------------------------------------------------------------------
/bin/cli/actions/show.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | import checkAWSConnection, {
19 | checkCFARecordExists,
20 | checkCertificateExists,
21 | getSSMParameter,
22 | } from "../utils/awsSDKUtil";
23 | import { IHosting } from "../shared/types";
24 | import { SSM_DOMAIN_STR } from "../shared/constants";
25 | import { isRepoConfig, loadHostingConfiguration } from "../utils/helper";
26 |
27 | /**
28 | * Display the Source and Domain Name of the currently deployed infrastructure.
29 | * It first checks the AWS connection, then retrieves the details of the hosting configuration.
30 | * If a hosting configuration exists, it prints the Source and its associated Domain Name.
31 | * If no hosting configuration is found, it informs the user that there is no domain name available
32 | * as no infrastructure has been deployed yet.
33 | */
34 | export async function handleShowCommand() {
35 | await checkAWSConnection();
36 | const hostingConfiguration = await loadHostingConfiguration();
37 | const domainName = await getSSMParameter(SSM_DOMAIN_STR);
38 | if (domainName) {
39 | console.log(
40 | "\nThe Origin paired with its associated CloudFront domain name:\n"
41 | );
42 |
43 | if (isRepoConfig(hostingConfiguration)) {
44 |
45 | console.log(
46 | `Code Repository: ${hostingConfiguration.repoUrl}/${hostingConfiguration.branchName} --> Hosting: https://${domainName}\n`
47 | );
48 | } else {
49 | console.log(
50 | `S3 Source Code: ${hostingConfiguration.s3bucket}/${hostingConfiguration.s3path} --> Hosting: https://${domainName}\n`
51 | );
52 | }
53 |
54 | if (hostingConfiguration.domainName) {
55 | let { certificateArn, status } = await checkCertificateExists(
56 | hostingConfiguration.domainName
57 | );
58 | if (certificateArn && status == "ISSUED") {
59 | if (hostingConfiguration.hostedZoneId) {
60 | const cFCNAMEExists = await checkCFARecordExists(
61 | hostingConfiguration.domainName,
62 | domainName,
63 | hostingConfiguration.hostedZoneId
64 | );
65 | if (cFCNAMEExists) {
66 | console.log(
67 | `${hostingConfiguration.domainName} --> Hosting: ${domainName} \n`
68 | );
69 | }
70 | } else {
71 | console.log(
72 | `${hostingConfiguration.domainName} --> Hosting: ${domainName} \n`
73 | );
74 | }
75 | }
76 | }
77 | } else {
78 | console.log(
79 | "\nAt the moment, there is no hosting infrastructure deployed.\n"
80 | );
81 | process.exit(0);
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/bin/cli/actions/status.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | import checkAWSConnection from "../utils/awsSDKUtil";
19 | import { checkPipelineStatus } from "../utils/helper";
20 |
21 | /**
22 | * Retrieves the status of an AWS CodePipeline and displays the status of its stages.
23 | *
24 | * @async
25 | * @function getPipelineStatus
26 | * @throws {Error} Throws an error if there is a problem retrieving the pipeline state.
27 | */
28 |
29 | export async function handleStatusCommand() {
30 | await checkAWSConnection();
31 | await checkPipelineStatus();
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/bin/cli/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License").
6 | * You may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | import { handleDeleteCommand } from "./actions/delete";
19 | import handleDeployCommand from "./actions/deploy";
20 | import { handleShowCommand } from "./actions/show";
21 | import handleInitCommand from "./actions/init";
22 | import { ERROR_PREFIX } from "./shared/constants";
23 | import { handleStatusCommand } from "./actions/status";
24 |
25 | const yargs = require("yargs");
26 |
27 | async function main() {
28 | const args = yargs
29 | .usage("Usage: $0 [options]")
30 | .command(
31 | "init",
32 | "Step by step guide for configuring a GitHub source code repository and generate a configuration file",
33 | (yargs: any) => {
34 | yargs
35 | .option("s3", {
36 | describe:
37 | "Step by step guide for configuring an S3 source code repository and generate a configuration file",
38 | type: "boolean",
39 | })
40 | }
41 | )
42 | .command(
43 | "deploy",
44 | 'Initiate a deployment of the infrastructure, utilizing the configuration file generated during the execution of the "init" command'
45 | )
46 | .command(
47 | "show",
48 | "Show the domain name connected to the deployed source code repository for a website that has been deployed"
49 | )
50 | .command(
51 | "delete",
52 | "Completely remove the hosting infrastructure from your AWS account"
53 | )
54 | .command("status", "Display the current status of the pipeline deployment")
55 | .help()
56 | .parse();
57 |
58 | if (args._.length > 1) {
59 | console.error(`${ERROR_PREFIX} Only one command at a time`);
60 | process.exit(1);
61 | }
62 |
63 | await handleCommand(args);
64 | }
65 |
66 | async function handleCommand({
67 | _: [command],
68 | s3,
69 | }: {
70 | _: string[];
71 | s3?: boolean;
72 | }) {
73 | switch (command) {
74 | case "deploy":
75 | await handleDeployCommand();
76 | break;
77 |
78 | case "show":
79 | await handleShowCommand();
80 | break;
81 | case "init":
82 | await handleInitCommand(s3 || false);
83 | break;
84 | case "delete":
85 | await handleDeleteCommand();
86 | break;
87 | case "status":
88 | await handleStatusCommand();
89 | break;
90 | default:
91 | yargs.showHelp()
92 | }
93 | }
94 |
95 | if (require.main === module) {
96 | main().catch((err) => {
97 | console.error(err);
98 | process.exit(1);
99 | });
100 | }
101 |
--------------------------------------------------------------------------------
/bin/cli/shared/constants.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | import { Dictionary } from "./types";
19 | import * as Joi from "joi";
20 |
21 | export const TOOL_NAME = "cloudfront-hosting-toolkit";
22 | export const CONFIG_FILE_NAME = TOOL_NAME + "-config.json";
23 | export const BUILD_FILE_NAME = TOOL_NAME + "-build.yml";
24 | export const CFF_FILE_NAME = TOOL_NAME + "-cff.js";
25 |
26 |
27 | /*
28 | export const SOURCE_STR = "HostingHostingInfrastructureDeployTypeSource";
29 | export const DOMAIN_STR = "HostingHostingInfrastructureDomainName";
30 | export const PIPELINENAME_STR = "HostingPipelineInfrastructurePipelineName";
31 |
32 | export const CONNECTION_ARN_STR = "RepositoryConnectionConnectionArn";
33 | export const CONNECTION_NAME_STR = "RepositoryConnectionConnectionName";
34 | export const CONNECTION_REGION_STR = "RepositoryConnectionHostingRegion";
35 | */
36 |
37 | export const SSM_SOURCE_STR = "HostingHostingInfrastructureDeployTypeSource";
38 |
39 | export const SSM_DOMAIN_STR = "DomainName";
40 | export const SSM_PIPELINENAME_STR = "PipelineName";
41 | export const SSM_CONNECTION_ARN_STR = "ConnectionArn";
42 | export const SSM_CONNECTION_NAME_STR = "ConnectionName";
43 | export const SSM_CONNECTION_REGION_STR = "ConnectionRegion";
44 |
45 |
46 | export const CONNECTION_STACK_NAME = "hosting-connection";
47 | export const MAIN_STACK_NAME = "hosting-main";
48 |
49 | export const CLOUDFRONT_HOSTEDZONE_ID = "Z2FDTNDATAQYW2";
50 |
51 | export const GITHUB_REGEX =
52 | /^((https:\/\/github\.com\/([^/]+)\/([^/]+))|(git@github\.com:([^/]+)\/([^/]+)))\.git$/;
53 | export const DOMAIN_NAME_REGEX =
54 | /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$/i;
55 |
56 |
57 | export const ERROR_PREFIX = "\n\n[ERROR]";
58 |
59 | export const FRAMEWORKS: Dictionary = {
60 | reactjs: "React Framework",
61 | nextjs: "Next.js Framework",
62 | angularjs: "AngularJS Framework",
63 | vuejs: "Vue.js Framework",
64 | astro: "Astro Framework",
65 | basic: "No FrontEnd framework used; Basic implementation (no build required)",
66 | };
67 |
68 | export const SCHEMA = Joi.object()
69 | .keys({
70 | repoUrl: Joi.string().optional(),
71 | branchName: Joi.string().optional(),
72 | framework: Joi.string().optional(),
73 | s3bucket: Joi.string().optional(),
74 | s3path: Joi.string().allow("").optional(),
75 | domainNameRegex: Joi.string().allow("").optional(),
76 | hostedZoneId: Joi.string().allow("").optional(),
77 | })
78 | .unknown();
79 |
--------------------------------------------------------------------------------
/bin/cli/shared/types.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | export interface CDKCommand {
19 | label: string;
20 | cmd: any;
21 | }
22 |
23 |
24 | export type CommonAttributes = {
25 | domainName?: string;
26 | hostedZoneId?: string;
27 | };
28 |
29 | export type HostingConfiguration = (
30 | {
31 | repoUrl: string;
32 | branchName: string;
33 | framework: string;
34 | } & CommonAttributes
35 | ) | (
36 | {
37 | s3bucket: string;
38 | s3path: string;
39 | } & CommonAttributes
40 | );
41 |
42 |
43 | export interface IChoice {
44 | title: string;
45 | value: string;
46 | }
47 |
48 | export interface IConnection {
49 | arn: string;
50 | name: string;
51 | region: string;
52 | }
53 |
54 | export interface IHosting {
55 | domain: string;
56 | source: string;
57 | type: string;
58 | pipeline: string;
59 | }
60 |
61 | export interface Dictionary {
62 | [key: string]: T;
63 | }
64 |
65 | export interface PackageJson {
66 | dependencies?: Record;
67 | devDependencies?: Record;
68 | scripts?: Record;
69 | }
70 |
71 | export const FrontendFramework = {
72 | REACT: "reactjs",
73 | VUE: "vuejs",
74 | ANGULAR: "angularjs",
75 | NEXT: "nextjs",
76 | BASIC: "basic",
77 | };
78 |
79 | export interface CNAMES {
80 | key: string;
81 | value: any;
82 | }
83 |
84 | export interface PromptItems {
85 | title: string;
86 | value: string;
87 | }
88 |
--------------------------------------------------------------------------------
/bin/cli/utils/prompt_questions.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /*
3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 |
5 | Licensed under the Apache License, Version 2.0 (the "License").
6 | You may not use this file except in compliance with the License.
7 | You may obtain a copy of the License at
8 |
9 | http://www.apache.org/licenses/LICENSE-2.0
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 | */
17 |
18 | import { frameworkList, isValidBucketName, isValidDomainName, isValidGithubUrl, validateNoLeadingTrailingSlashes } from "./helper";
19 |
20 | //export const getFrameworkSelectionQuestions = (initialValue?: string) => {
21 |
22 | export const getGithubRepositoryQuestions = (
23 | initialUrl?: string,
24 | initialBranch?: string
25 | ) => {
26 | const question = [
27 | {
28 | type: "text",
29 | name: "repoUrl",
30 | message: "Please provide your GitHub repository URL",
31 | ...(initialUrl !== undefined && { initial: initialUrl }), // Conditionally include 'initial'
32 | validate: (value: string) =>
33 | isValidGithubUrl(value)
34 | ? true
35 | : "GitHub repository format must be https://github.com/USERNAME/REPOSITORY.git or git@github.com:USERNAME/REPOSITORY.git and can be added only once",
36 | },
37 | {
38 | type: "text",
39 | name: "branchName",
40 | message:
41 | "What is the name of the branch you would like to use? Hit Enter to confirm or change the selection.",
42 | initial: initialBranch || "main",
43 | validate: (value: string) =>
44 | value.length > 0 ? true : "Branch name is mandatory",
45 | },
46 | ];
47 |
48 | return question;
49 | };
50 |
51 | export const getS3BucketConfigurationQuestions = (
52 | defaultBucket: string,
53 | defaultPath: string = ""
54 | ) => [
55 | {
56 | type: "text",
57 | name: "s3bucket",
58 | ...(defaultBucket !== undefined && { initial: defaultBucket }),
59 | message: "Please enter the name of the bucket you would like to use",
60 | validate: (value: string) =>
61 | isValidBucketName(value) ? true : "The bucket name must not be empty, and the corresponding bucket must exist",
62 | },
63 | {
64 | type: "text",
65 | name: "s3path",
66 | ...(defaultPath !== undefined && { initial: defaultPath }),
67 | message:
68 | "If you would like to specify a prefix, please enter it below. Otherwise, leave it blank",
69 | validate: (value:string) => validateNoLeadingTrailingSlashes(value) ? true : "The prefix should not have leading or trailing slashes",
70 |
71 | },
72 | ];
73 |
74 | function findIndexByValue(
75 | objects: { title: string; value: string }[],
76 | value?: string
77 | ) {
78 | if (!value) return 0;
79 | for (let i = 0; i < objects.length; i++) {
80 | if (objects[i].value === value) {
81 | return i;
82 | }
83 | }
84 | return 0;
85 | }
86 |
87 | export const getFrameworkSelectionQuestions = (initialValue?: string) => {
88 | const index = findIndexByValue(frameworkList(), initialValue);
89 | const question = {
90 | type: "select",
91 | name: "framework",
92 | message:
93 | "Which framework did you use for website construction? Press Enter to confirm or change the selection.",
94 | choices: frameworkList(),
95 | initial: index,
96 | };
97 | return [question];
98 | };
99 |
100 | export const getDomainNameQuestion = (defaultDomainName?: string) => [
101 | {
102 | type: "select",
103 | name: "value",
104 | message: "Do you own a domain name that you would like to use?",
105 | choices: [
106 | { title: "Yes", value: "yes" },
107 | { title: "No", value: "no" },
108 | ],
109 | initial: defaultDomainName ? 0 : 1,
110 | },
111 | ];
112 |
113 | export const continueConfirmationQuestion = {
114 | type: "text",
115 | name: "value",
116 | message: "Please complete the operation and type 'ok' to continue ",
117 | validate: (value: string) =>
118 | value.toLowerCase() == "ok" ? true : "You have to type OK to continue",
119 | };
120 |
121 | export const domainNameDetailsQuestions = (defaultDomainName?: string) => [
122 | {
123 | type: "text",
124 | name: "domainName",
125 | ...(defaultDomainName !== undefined && { initial: defaultDomainName }),
126 |
127 | message:
128 | "Please provide your domain name in the following formats: www.mydomainname.com or mydomainname.com ?",
129 | validate: (value: string) =>
130 | isValidDomainName(value)
131 | ? true
132 | : "Domain name format must be www.mydomainname.com or mydomainname.com",
133 | },
134 | {
135 | type: "select",
136 | name: "registrar",
137 | message: "Where is the authoritative DNS server of this domain?",
138 | choices: [
139 | { title: "Elsewhere", value: "another" },
140 | { title: "Route 53 in this AWS Account", value: "current" },
141 | ],
142 | initial: 1,
143 | },
144 | ];
145 |
146 | export const hostedZoneIdQuestion = (defaultHostedZoneId?: string) => [
147 | {
148 | type: "text",
149 | name: "hostedZoneId",
150 | ...(defaultHostedZoneId !== undefined && { initial: defaultHostedZoneId }),
151 | message: "Please type the hosted zone ID",
152 | validate: (value: string) =>
153 | value.length > 0 ? true : "The hosted zone must not be empty",
154 | },
155 | ];
156 |
157 | export const cloudFrontAssociationQuestion = {
158 | type: "select",
159 | name: "value",
160 | message:
161 | "Would you like to associate the domain name to the CloudFront distribution automatically now, or would you prefer to do it later?",
162 | choices: [
163 | { title: "Associate automatically now.", value: "yes" },
164 | { title: "Do it later.", value: "no" },
165 | ],
166 | initial: 0,
167 | };
168 |
169 |
170 |
171 | export const manualGitHubConfigConfirmationQuestion = {
172 | type: "select",
173 | name: "value",
174 | message:
175 | "Would you like to manually enter your GitHub repository information?",
176 | choices: [
177 | { title: "Yes", value: "manual" },
178 | { title: "No, exit", value: "exit" },
179 | ],
180 | initial: 0,
181 | };
182 |
183 | export const hostingInfrastructureDeletionConfirmation = {
184 | type: "select",
185 | name: "value",
186 | message:
187 | "Are you sure you want to completely remove the hosting infrastructure from your AWS account?",
188 | choices: [
189 | { title: "Yes", value: "save" },
190 | { title: "No", value: "exit" },
191 | ],
192 | initial: 1,
193 | };
194 |
195 |
--------------------------------------------------------------------------------
/bin/cloudfront-hosting-toolkit.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import "source-map-support/register";
18 | import { App } from "aws-cdk-lib";
19 | import { HostingStack } from "../lib/hosting_stack";
20 | import { RepositoryStack } from "../lib/repository_stack";
21 |
22 | import * as path from "path";
23 | import {
24 | BUILD_FILE_NAME,
25 | CONFIG_FILE_NAME,
26 | CFF_FILE_NAME,
27 | TOOL_NAME,
28 | } from "./cli/shared/constants";
29 | import { AwsSolutionsChecks } from "cdk-nag";
30 | import { Aspects } from "aws-cdk-lib";
31 | import { calculateConnectionStackName, calculateMainStackName, isRepoConfig, loadHostingConfiguration } from "./cli/utils/helper";
32 |
33 | const app = new App();
34 |
35 | //Aspects.of(app).add(new AwsSolutionsChecks());
36 |
37 | (async () => {
38 | var configFilePath, configFile, certificateArn;
39 |
40 | if (app.node.tryGetContext("config-path")) {
41 | configFilePath = app.node.tryGetContext("config-path");
42 | }
43 | else {
44 | configFilePath = path.join(__dirname, "..", TOOL_NAME);
45 | }
46 |
47 |
48 | if (app.node.tryGetContext("certificate-arn")) {
49 | certificateArn = app.node.tryGetContext("certificate-arn");
50 | }
51 |
52 | configFile = configFilePath + "/" + CONFIG_FILE_NAME;
53 |
54 | const hostingConfiguration = await loadHostingConfiguration(configFile);
55 |
56 | const buildFilePath = configFilePath + "/" + BUILD_FILE_NAME;
57 |
58 | const cffSourceFilePath = configFilePath + "/" + CFF_FILE_NAME;
59 |
60 | var connectionStack;
61 |
62 | const mainStackName = calculateMainStackName(hostingConfiguration);
63 |
64 | if (isRepoConfig(hostingConfiguration)) {
65 |
66 | const connectionStackName = calculateConnectionStackName(hostingConfiguration.repoUrl, hostingConfiguration.branchName!);
67 |
68 | connectionStack = new RepositoryStack(
69 | app,
70 | connectionStackName,
71 | hostingConfiguration,
72 | {
73 | description: 'Cloudfront Hosting Toolkit Repository Stack',
74 | env: {
75 | region: process.env.CDK_DEFAULT_REGION,
76 | account: process.env.CDK_DEFAULT_ACCOUNT,
77 | },
78 | }
79 | );
80 | }
81 |
82 | new HostingStack(
83 | app,
84 | mainStackName,
85 | {
86 | connectionArn: connectionStack?.repositoryConnection.connectionArn,
87 | hostingConfiguration: hostingConfiguration,
88 | buildFilePath: buildFilePath,
89 | cffSourceFilePath: cffSourceFilePath,
90 | certificateArn: certificateArn,
91 | },
92 | {
93 | description: 'Cloudfront Hosting Toolkit Hosting Stack (uksb-1tupboc37)',
94 | env: {
95 | region: process.env.CDK_DEFAULT_REGION,
96 | account: process.env.CDK_DEFAULT_ACCOUNT,
97 | },
98 | crossRegionReferences: true,
99 | }
100 | );
101 | })();
102 |
--------------------------------------------------------------------------------
/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "npx ts-node --prefer-ts-exts bin/cloudfront-hosting-toolkit.ts",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "**/*.d.ts",
11 | "**/*.js",
12 | "tsconfig.json",
13 | "package*.json",
14 | "yarn.lock",
15 | "node_modules",
16 | "test"
17 | ]
18 | },
19 | "context": {
20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
21 | "@aws-cdk/core:stackRelativeExports": true,
22 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
23 | "@aws-cdk/aws-lambda:recognizeVersionProps": true,
24 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
25 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28 | "@aws-cdk/core:checkSecretUsage": true,
29 | "@aws-cdk/aws-iam:minimizePolicies": true,
30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32 | "@aws-cdk/core:target-partitions": [
33 | "aws",
34 | "aws-cn"
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cdk.json.built:
--------------------------------------------------------------------------------
1 | {
2 | "app": "npx ts-node --prefer-ts-exts bin/cloudfront-hosting-toolkit.js",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "**/*.d.ts",
11 | "**/*.js",
12 | "tsconfig.json",
13 | "package*.json",
14 | "yarn.lock",
15 | "node_modules",
16 | "test"
17 | ]
18 | },
19 | "context": {
20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
21 | "@aws-cdk/core:stackRelativeExports": true,
22 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
23 | "@aws-cdk/aws-lambda:recognizeVersionProps": true,
24 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
25 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28 | "@aws-cdk/core:checkSecretUsage": true,
29 | "@aws-cdk/aws-iam:minimizePolicies": true,
30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32 | "@aws-cdk/core:target-partitions": [
33 | "aws",
34 | "aws-cn"
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cdk.json.dev:
--------------------------------------------------------------------------------
1 | {
2 | "app": "npx ts-node --prefer-ts-exts bin/cloudfront-hosting-toolkit.ts",
3 | "watch": {
4 | "include": [
5 | "**"
6 | ],
7 | "exclude": [
8 | "README.md",
9 | "cdk*.json",
10 | "**/*.d.ts",
11 | "**/*.js",
12 | "tsconfig.json",
13 | "package*.json",
14 | "yarn.lock",
15 | "node_modules",
16 | "test"
17 | ]
18 | },
19 | "context": {
20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
21 | "@aws-cdk/core:stackRelativeExports": true,
22 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true,
23 | "@aws-cdk/aws-lambda:recognizeVersionProps": true,
24 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true,
25 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28 | "@aws-cdk/core:checkSecretUsage": true,
29 | "@aws-cdk/aws-iam:minimizePolicies": true,
30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32 | "@aws-cdk/core:target-partitions": [
33 | "aws",
34 | "aws-cn"
35 | ]
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | ## 🚀 Run
11 |
12 | To run the documentation locally, clone the repository and run:
13 |
14 |
15 | ```bash
16 | npm run dev
17 | ```
18 |
19 | ## 🧞 Commands
20 |
21 | All commands are run from the root of the project, from a terminal:
22 |
23 | | Command | Action |
24 | | :------------------------ | :----------------------------------------------- |
25 | | `npm install` | Installs dependencies |
26 | | `npm run dev` | Starts local dev server at `localhost:4321` |
27 | | `npm run build` | Build your production site to `./dist/` |
28 | | `npm run preview` | Preview your build locally, before deploying |
29 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
30 | | `npm run astro -- --help` | Get help using the Astro CLI |
31 |
32 | ## 👀 Want to learn more?
33 |
34 | Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
35 |
--------------------------------------------------------------------------------
/docs/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 | import starlight from '@astrojs/starlight';
3 |
4 | // https://astro.build/config
5 | export default defineConfig({
6 | site: process.env.ASTRO_SITE,
7 | base: '/cloudfront-hosting-toolkit',
8 | markdown: {
9 | gfm: true
10 | },
11 | integrations: [
12 | starlight({
13 | title: 'Cloudfront Hosting Toolkit',
14 | description: 'open source command line tool to help developers deploy fast and secure frontends in the cloud 🤖🚀',
15 | defaultLocale: 'en',
16 | favicon: '/src/assets/favicon.ico',
17 | customCss: [
18 | './src/styles/landing.css',
19 | './src/styles/font.css',
20 | './src/styles/custom.css',
21 | './src/styles/terminal.css'
22 | ],
23 | social: {
24 | github: 'https://github.com/awslabs/cloudfront-hosting-toolkit'
25 | },
26 | "sidebar": [
27 | {
28 | "label": "Getting Started",
29 | "items": [
30 | { "label": "Introduction", "link": "/getting-started/introduction" },
31 | { "label": "Quickstart", "link": "/getting-started/quickstart" },
32 | { "label": "How It Works", "link": "/getting-started/how-it-works" }
33 | ]
34 | },
35 | {
36 | "label": "Architecture",
37 | "items": [
38 | { "label": "Overview", "link": "/architecture/overview" },
39 | { "label": "GitHub Workflow", "link": "/architecture/github-workflow" },
40 | { "label": "S3 Workflow", "link": "/architecture/s3-workflow" }
41 | ]
42 | },
43 | {
44 | "label": "User Guide",
45 | "items": [
46 | { "label": "CLI Guide", "link": "/user-guide/cli-guide" },
47 | {
48 | label: 'CDK Guide',
49 | items: [
50 | { label: 'Overview', link: '/user-guide/cdk-guide' },
51 | { label: 'CDK Construct', link: '/user-guide/cdk-construct' },
52 | { label: 'CDK Source code', link: '/user-guide/cdk-source-code' },
53 | { label: 'Configuration guide', link: '/user-guide/cdk-configuration' },
54 | ]
55 | },
56 | ]
57 | },
58 | {
59 | "label": "Features",
60 | "items": [
61 | { "label": "Overview", "link": "/features/overview" },
62 | { "label": "Self-paced wizard", "link": "/features/setup-wizard" },
63 | { "label": "Instant deployment", "link": "/features/instant-deployment" },
64 | { "label": "GitHub integration", "link": "/features/github-integration" },
65 | { "label": "Optimized caching", "link": "/features/optimized-caching" },
66 | { "label": "Security headers", "link": "/features/security-headers" },
67 | { "label": "Custom domain support", "link": "/features/custom-domains" }
68 | ]
69 | },
70 | {
71 | "label": "Advanced Usage",
72 | "items": [
73 | { "label": "Advanced configuration", "link": "/advanced/configuration" },
74 | { "label": "Bring your own framework", "link": "/advanced/bring-your-own-framework" }
75 | ]
76 | },
77 | {
78 | "label": "Troubleshooting",
79 | "items": [
80 | { "label": "Troubleshooting guide", "link": "/troubleshooting/guide" }
81 | ]
82 | },
83 | {
84 | "label": "Project Info",
85 | "items": [
86 | { "label": "FAQ", "link": "/project/faq" },
87 | ]
88 | }
89 | ]
90 |
91 | })
92 | ]
93 | });
94 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@cloudfront-hosting-toolkit/docs",
3 | "description": "The official documentation for Multi Agent Orchestration",
4 | "type": "module",
5 | "version": "0.7.0",
6 | "private": true,
7 | "scripts": {
8 | "dev": "npx astro dev",
9 | "start": "npx astro dev",
10 | "build": "npx astro build",
11 | "preview": "npx astro preview",
12 | "astro": "npx astro",
13 | "audit": "npm audit",
14 | "clean": "npx rimraf .astro/ node_modules/ dist/"
15 | },
16 | "author": {
17 | "name": "Amazon Web Services",
18 | "url": "https://aws.amazon.com"
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git://github.com/awslabs/cloudfront-hosting-toolkit"
23 | },
24 | "license": "Apache-2.0",
25 | "dependencies": {
26 | "@astrojs/starlight": "^0.29.2",
27 | "astro": "^4.16.10",
28 | "sharp": "^0.33.4",
29 | "shiki": "^1.10.3"
30 | },
31 | "devDependencies": {
32 | "rimraf": "^5.0.7"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/public/img/architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/public/img/architecture.jpg
--------------------------------------------------------------------------------
/docs/public/img/deploy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/public/img/deploy.gif
--------------------------------------------------------------------------------
/docs/public/img/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/public/img/flow.png
--------------------------------------------------------------------------------
/docs/public/img/init.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/public/img/init.gif
--------------------------------------------------------------------------------
/docs/src/assets/fonts/JetBrainsMonoNerdFont-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/src/assets/fonts/JetBrainsMonoNerdFont-Bold.ttf
--------------------------------------------------------------------------------
/docs/src/assets/fonts/JetBrainsMonoNerdFont-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/src/assets/fonts/JetBrainsMonoNerdFont-BoldItalic.ttf
--------------------------------------------------------------------------------
/docs/src/assets/fonts/JetBrainsMonoNerdFont-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/src/assets/fonts/JetBrainsMonoNerdFont-Italic.ttf
--------------------------------------------------------------------------------
/docs/src/assets/fonts/JetBrainsMonoNerdFont-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/docs/src/assets/fonts/JetBrainsMonoNerdFont-Regular.ttf
--------------------------------------------------------------------------------
/docs/src/components/code.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { ExpressiveCode, ExpressiveCodeConfig } from 'expressive-code';
3 | import { toHtml } from 'hast-util-to-html';
4 | import { pluginCollapsibleSections } from '@expressive-code/plugin-collapsible-sections';
5 |
6 | import fs from 'node:fs/promises';
7 |
8 | interface Props {
9 | file: string;
10 | language?: string;
11 | meta?: string;
12 | }
13 |
14 | const { file, language, meta } = Astro.props;
15 | const fileNamePath = '../' + file;
16 | const fileEtension = file.split('.').pop() ?? 'js';
17 | const code = await fs.readFile(fileNamePath, 'utf-8');
18 | const ec = new ExpressiveCode({
19 | plugins: [pluginCollapsibleSections()],
20 | });
21 |
22 | // Get base styles that should be included on the page
23 | // (they are independent of the rendered code blocks)
24 | const baseStyles = await ec.getBaseStyles();
25 |
26 | // Render some example code to AST
27 | const { renderedGroupAst, styles } = await ec.render({
28 | code: code,
29 | language: language ?? fileEtension,
30 | meta: `title="${file}"` + (meta ? ` ${meta}` : ''),
31 | });
32 |
33 | // Convert the rendered AST to HTML
34 | let htmlContent = toHtml(renderedGroupAst);
35 |
36 | // Collect styles and add them before the HTML content
37 | const stylesToPrepend: string[] = [];
38 | stylesToPrepend.push(baseStyles);
39 | stylesToPrepend.push(...styles);
40 | if (stylesToPrepend.length) {
41 | htmlContent = `${htmlContent}`;
42 | }
43 | ---
44 |
45 |
--------------------------------------------------------------------------------
/docs/src/content/config.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2023 Amazon.com, Inc. or its affiliates.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | import { defineCollection } from 'astro:content';
18 | import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
19 |
20 | export const collections = {
21 | docs: defineCollection({ schema: docsSchema() }),
22 | i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
23 | };
24 |
--------------------------------------------------------------------------------
/docs/src/content/docs/advanced/bring-your-own-framework.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Bring your own framework
3 | ---
4 |
5 | While CloudFront Hosting Toolkit supports many popular frameworks out-of-the-box, you can configure it for custom frameworks. This allows you to create a reusable configuration for your specific framework that can be used across multiple projects.
6 |
7 | ## Steps to Integrate Your Custom Framework
8 |
9 | 1. Locate the CLI installation folder of CloudFront Hosting Toolkit.
10 |
11 | 2. Create two new files and place them in the following subfolders of the CLI installation folder:
12 | - A custom build configuration file named `hosting_YOUR_FRAMEWORK_NAME.yml` in the `resources/build_config_templates` folder.
13 | - A custom CloudFront Function file named `index_YOUR_FRAMEWORK_NAME.js` in the `resources/cff_templates` folder.
14 |
15 | 3. After creating and placing these files, run `cloudfront-hosting-toolkit init` in your project directory and select your custom framework when prompted.
16 |
17 | ## File Naming Convention and Locations
18 |
19 | It's crucial to follow the exact naming format for both files and place them in the correct folders:
20 |
21 | - The build configuration file must be named: `hosting_YOUR_FRAMEWORK_NAME.yml`
22 | Place this file in: `/resources/build_config_templates/`
23 |
24 | - The CloudFront Function file must be named: `index_YOUR_FRAMEWORK_NAME.js`
25 | Place this file in: `/resources/cff_templates/`
26 |
27 | Replace YOUR_FRAMEWORK_NAME with the name of your framework.
28 |
29 | For example:
30 | - For a framework called "MySSG":
31 | - `resources/build_config_templates/hosting_MySSG.yml`
32 | - `resources/cff_templates/index_MySSG.js`
33 | - For a framework called "Custom React":
34 | - `resources/build_config_templates/hosting_Custom_React.yml`
35 | - `resources/cff_templates/index_Custom_React.js`
36 |
37 | Note: The framework name displayed in the init wizard will be taken from the YOUR_FRAMEWORK_NAME part of the filename. For example, if your files are named `hosting_Custom_React.yml` and `index_Custom_React.js`, the framework name displayed will be "Custom React".
38 |
39 | ## Build Configuration File Structure
40 |
41 | When creating your custom build configuration file (`hosting_YOUR_FRAMEWORK_NAME.yml`), keep in mind the following structure and requirements:
42 |
43 | ```yaml
44 | version: 0.2
45 | phases:
46 | build:
47 | commands:
48 | # Your custom build commands go here
49 | - command1
50 | - command2
51 | # ...
52 | # The following command is mandatory and must be the last command
53 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
54 | ```
55 |
56 | Important notes:
57 | 1. You can include any number of custom build commands to suit your framework's needs.
58 | 2. The last command (the `aws s3 cp` command) is mandatory and must be included exactly as shown above.
59 | 3. `$DEST_BUCKET_NAME` and `$CODEBUILD_RESOLVED_SOURCE_VERSION` are environment variables automatically available in CodeBuild. Do not change these variable names.
60 |
61 | ## Example: Custom Static Site Generator
62 |
63 | Let's create a configuration for a custom static site generator called "MySSG":
64 |
65 | 1. Create `hosting_MySSG.yml` in the `/resources/build_config_templates/` folder:
66 |
67 | ```yaml
68 | version: 0.2
69 | phases:
70 | build:
71 | commands:
72 | - npm install
73 | - npm run generate
74 | - cd dist # Assuming 'dist' is your output directory
75 | # The following command is mandatory
76 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
77 | ```
78 |
79 | 2. Create `index_MySSG.js` in the `/resources/cff_templates/` folder:
80 |
81 | ```javascript
82 | function handler(event) {
83 | var request = event.request;
84 | var uri = request.uri;
85 |
86 | // Custom URL rewriting logic for MySSG
87 | if (uri.endsWith('/')) {
88 | request.uri += 'index.html';
89 | } else if (!uri.includes('.')) {
90 | request.uri += '.html';
91 | }
92 |
93 | return request;
94 | }
95 | ```
96 |
97 | 3. Run `cloudfront-hosting-toolkit init` in your project directory and select "MySSG" when prompted for the framework.
98 |
99 |
100 | By following these steps and ensuring your build configuration file includes the mandatory S3 copy command, you can create and use custom framework configurations across multiple projects, streamlining your deployment process for unique or in-house frameworks.
--------------------------------------------------------------------------------
/docs/src/content/docs/advanced/configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Advanced Configuration
3 | ---
4 |
5 | CloudFront Hosting Toolkit offers various advanced configuration options to tailor the deployment process to your specific needs. After running the `init` command, you have the flexibility to customize your deployment before running the `deploy` command.
6 |
7 | ## Configuration Files
8 |
9 | After running `cloudfront-hosting-toolkit init`, three configuration files are created in your project's `cloudfront-hosting-toolkit` folder:
10 |
11 | 1. `cloudfront-hosting-toolkit-config.yml`
12 | 2. `cloudfront-hosting-toolkit-cff.js`
13 | 3. `cloudfront-hosting-toolkit-config.json`
14 |
15 | You can edit these files to customize your deployment before running the `deploy` command.
16 |
17 | ## Customization Process
18 |
19 | 1. **Initial Setup**: Run `cloudfront-hosting-toolkit init` to generate the default configuration files.
20 | 2. **Customization**: Edit the configuration files as needed (optional).
21 | 3. **Deployment**: Run `cloudfront-hosting-toolkit deploy` to deploy your infrastructure using either the default or customized configuration.
22 |
23 | Note: You can deploy using the default configuration and later customize as needed. After making changes to any configuration file, simply run the `deploy` command again to update your infrastructure.
24 |
25 | ## Custom Build Configurations
26 |
27 | Modify the `cloudfront-hosting-toolkit-config.yml` file to customize the build process. This file contains instructions for CodeBuild on how to build your website.
28 |
29 | Example for a React app:
30 |
31 | ```yaml
32 | version: 0.2
33 | phases:
34 | install:
35 | runtime-versions:
36 | nodejs: 18
37 | pre_build:
38 | commands:
39 | - npm install
40 | build:
41 | commands:
42 | - npm run build
43 | artifacts:
44 | base-directory: build
45 | files:
46 | - '**/*'
47 | ```
48 |
49 | ## CloudFront Function Customization
50 |
51 | The `cloudfront-hosting-toolkit-cff.js` file contains the CloudFront Function code for URL rewriting. Modify this file to implement custom routing logic for your application.
52 |
53 | Example of a basic URL rewriting function:
54 |
55 | ```javascript
56 | function handler(event) {
57 | var request = event.request;
58 | var uri = request.uri;
59 |
60 | // Add custom routing logic here
61 | if (uri.endsWith('/')) {
62 | request.uri += 'index.html';
63 | } else if (!uri.includes('.')) {
64 | request.uri += '.html';
65 | }
66 |
67 | return request;
68 | }
69 | ```
70 |
71 | ## Project Configuration
72 |
73 | The `cloudfront-hosting-toolkit-config.json` file contains your project's configuration settings. You can modify this file to change settings such as the repository URL, branch name, or framework.
74 |
75 | Example:
76 |
77 | ```json
78 | {
79 | "repoUrl": "https://github.com/USERNAME/REPOSITORY.git",
80 | "branchName": "main",
81 | "framework": "react"
82 | }
83 | ```
84 |
85 | ## Potential Modifications
86 |
87 | Here are some examples of modifications you might make to each configuration file:
88 |
89 | ### 1. cloudfront-hosting-toolkit-config.yml
90 |
91 | This file controls your build process. Some potential modifications include:
92 |
93 | - Changing the Node.js version:
94 | ```yaml
95 | runtime-versions:
96 | nodejs: 16 # Change to a different version if needed
97 | ```
98 |
99 | - Adding a testing step:
100 | ```yaml
101 | phases:
102 | pre_build:
103 | commands:
104 | - npm install
105 | - npm run test # Add this line to run tests before building
106 | ```
107 |
108 | - Customizing the artifact output:
109 | ```yaml
110 | artifacts:
111 | base-directory: dist # Change if your build output is in a different folder
112 | files:
113 | - '**/*'
114 | - '!**/*.map' # Exclude source map files
115 | ```
116 |
117 | ### 2. cloudfront-hosting-toolkit-cff.js
118 |
119 | This file contains your CloudFront Function for URL rewriting. You might modify it to:
120 |
121 | - Handle single-page application (SPA) routing:
122 | ```javascript
123 | function handler(event) {
124 | var request = event.request;
125 | var uri = request.uri;
126 |
127 | // Route all requests to index.html for SPA
128 | if (!uri.includes('.')) {
129 | request.uri = '/index.html';
130 | }
131 |
132 | return request;
133 | }
134 | ```
135 |
136 | - Implement custom error page routing:
137 | ```javascript
138 | function handler(event) {
139 | var request = event.request;
140 | var uri = request.uri;
141 |
142 | if (uri === '/404') {
143 | request.uri = '/custom-404.html';
144 | } else if (uri === '/500') {
145 | request.uri = '/custom-500.html';
146 | }
147 |
148 | return request;
149 | }
150 | ```
151 |
152 | ### 3. cloudfront-hosting-toolkit-config.json
153 |
154 | This file contains your project configuration. Possible modifications include:
155 |
156 | - Changing the deployment branch:
157 | ```json
158 | {
159 | "repoUrl": "https://github.com/USERNAME/REPOSITORY.git",
160 | "branchName": "develop", // Change to deploy from a different branch
161 | "framework": "react"
162 | }
163 | ```
164 |
165 | - Adding a custom domain:
166 | ```json
167 | {
168 | "repoUrl": "https://github.com/USERNAME/REPOSITORY.git",
169 | "branchName": "main",
170 | "framework": "react",
171 | "domainName": "www.example.com", // Add your custom domain
172 | "hostedZoneId": "Z1234567890ABC" // Add your Route 53 hosted zone ID
173 | }
174 | ```
175 |
176 | Remember, you can always revert to the default configuration by re-running the `init` command, but this will overwrite any existing customizations. Always backup your custom configurations before reinitializing.
--------------------------------------------------------------------------------
/docs/src/content/docs/architecture/github-workflow.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: GitHub Workflow
3 | ---
4 |
5 | The GitHub workflow in CloudFront Hosting Toolkit provides a seamless integration between your GitHub repository and AWS deployment infrastructure.
6 |
7 | ## Process Overview
8 | 1. **Source Stage**: Code changes pushed to the GitHub repository trigger AWS CodePipeline.
9 | 2. **Build Stage**: CodeBuild compiles the code and creates deployment artifacts using the buildspec YAML.
10 | 3. **Deploy Stage**:
11 | - Artifacts are uploaded to the hosting S3 bucket in a new folder (identified by the commit ID).
12 | - A Step Function updates the DynamoDB Key-Value Store with the new folder information.
13 | - The CloudFront Function is updated to route traffic to the new folder.
14 |
15 | ## Benefits
16 | - Automated deployments triggered by code pushes
17 | - Version control integration
18 | - Consistent build and deployment process
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/src/content/docs/architecture/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Architecture Overview
3 | ---
4 |
5 | CloudFront Hosting Toolkit leverages several AWS services to create a robust, scalable, and efficient hosting infrastructure for your web applications. The architecture is designed to support both GitHub-based and S3-based source code repositories, ensuring flexibility in your deployment workflow.
6 |
7 |
8 |
9 | ## Key Components
10 |
11 | 1. **Source Code Management**:
12 | - **GitHub Repository**: For Git-based workflows.
13 | - **Amazon S3 (Source Code Repository)**: For S3-based workflows, allowing ZIP file uploads.
14 |
15 | 2. **Deployment Pipeline**:
16 | - **AWS CodePipeline**: Manages the overall deployment process, orchestrating the flow from source to production.
17 | - **AWS CodeBuild**: Handles the build process for your web application, compiling code and creating artifacts.
18 | - **Amazon S3 (Artifacts)**: Stores deployment artifacts during the pipeline process.
19 |
20 | 3. **Hosting Infrastructure**:
21 | - **Amazon S3 (Static files)**: Stores your website files for serving.
22 | - **Amazon CloudFront**: Serves as the content delivery network (CDN) for your website, ensuring fast global access.
23 | - **CloudFront Function**: Handles request routing to serve the latest version of your site.
24 | - **Amazon Route 53**: Manages DNS routing for your custom domain (if configured).
25 |
26 | 4. **Security and SSL**:
27 | - **AWS Certificate Manager (ACM)**: Provisions and manages SSL/TLS certificates for secure HTTPS connections.
28 |
29 | 5. **Deployment Orchestration**:
30 | - **AWS Step Functions**: Orchestrates the deployment process, ensuring proper sequencing of tasks.
31 | - **AWS Lambda**: Triggers the pipeline for S3-based deployments and potentially other serverless operations.
32 |
33 | 6. **State Management**:
34 | - **Key Value Store (DynamoDB)**: Stores routing information to direct traffic to the latest deployed version.
35 |
36 | ## Workflow Overview
37 |
38 | 1. **Code Push/Upload**:
39 | - Developers push code to GitHub or upload a ZIP file to the S3 source code repository.
40 |
41 | 2. **Pipeline Triggering**:
42 | - GitHub pushes or S3 uploads trigger the AWS CodePipeline, either directly or via AWS Lambda.
43 |
44 | 3. **Build and Artifact Creation**:
45 | - AWS CodeBuild compiles the code and creates deployment artifacts.
46 | - Artifacts are stored in an S3 bucket.
47 |
48 | 4. **Deployment**:
49 | - AWS Step Functions orchestrate the deployment process.
50 | - Static files are copied to the hosting S3 bucket.
51 | - The Key Value Store is updated with the latest deployment information.
52 |
53 | 5. **Content Delivery**:
54 | - CloudFront serves the website content globally.
55 | - CloudFront Functions use the Key Value Store to route requests to the latest version.
56 | - Amazon Route 53 handles DNS routing for custom domains.
57 |
58 | 6. **Security**:
59 | - AWS Certificate Manager provides SSL/TLS certificates for secure connections.
60 |
61 | This architecture ensures rapid, consistent deployments, optimal performance, and high availability for your web applications. It leverages AWS's global infrastructure to deliver content quickly to users worldwide while maintaining the flexibility to deploy from various source repositories.
--------------------------------------------------------------------------------
/docs/src/content/docs/architecture/s3-workflow.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: S3 Workflow
3 | ---
4 | The S3 workflow in CloudFront Hosting Toolkit allows for deployments from an S3 bucket, useful for pre-built artifacts or when GitHub integration is not needed.
5 |
6 | ## Process Overview
7 | 1. **Source Stage**: Uploading a ZIP file to a specified S3 bucket triggers AWS CodePipeline.
8 | 2. **Build Stage**: The ZIP file is copied from the source S3 bucket, unzipped, and files are copied to the hosting S3 bucket.
9 | 3. **Deploy Stage**: Similar to the GitHub process, updating the Key-Value Store and CloudFront Function.
10 |
11 | ## Benefits
12 | - Suitable for pre-built or static websites
13 | - Flexibility in deployment source
14 | - Consistent deployment process with GitHub workflow
--------------------------------------------------------------------------------
/docs/src/content/docs/features/custom-domains.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom domain support
3 | ---
4 |
5 | The CloudFront Hosting Toolkit supports custom domain configuration for both Amazon Route 53 users and those using other DNS providers. This flexibility ensures that regardless of your DNS management solution, you can easily set up a custom domain for your CloudFront-hosted website.
6 |
7 | ## Route 53 Users vs. Non-Route 53 Users
8 |
9 | 1. **Route 53 Users**
10 | - Benefit from a more automated process
11 | - The CLI can directly interact with your Route 53 hosted zones
12 | - Automatic creation of necessary DNS records
13 |
14 | 2. **Non-Route 53 Users**
15 | - Receive guided instructions for manual DNS configuration
16 | - Need to create DNS records with their respective DNS providers
17 | - Still benefit from automated certificate management and CloudFront configuration
18 |
19 | ## The Process
20 |
21 | Regardless of your DNS provider, the CLI handles the following steps:
22 |
23 | 1. **SSL/TLS Certificate Management**
24 | - Checks for an existing certificate in AWS Certificate Manager (ACM)
25 | - Creates a new certificate if one doesn't exist
26 | - Waits for the certificate to be issued and validated
27 |
28 | 2. **CloudFront Distribution Configuration**
29 | - Integrates your custom domain with the CloudFront distribution
30 |
31 | 3. **DNS Configuration**
32 | - This step differs based on your DNS provider:
33 |
34 | ### For Route 53 Users:
35 |
36 | 1. The CLI detects that you're using Route 53 based on the provided hosted zone ID
37 | 2. After deploying the CloudFront distribution, it checks if a CNAME record already exists
38 | 3. If no record exists, it prompts you to confirm the creation of a new CNAME record
39 | 4. Upon confirmation, it automatically creates the CNAME record in your Route 53 hosted zone
40 |
41 | ### For Non-Route 53 Users:
42 |
43 | 1. The CLI recognizes that you're not using Route 53 (no hosted zone ID provided)
44 | 2. After deploying the CloudFront distribution, it provides detailed instructions for manual DNS configuration
45 | 3. You receive step-by-step guidance on how to create a CNAME record with your DNS provider, including:
46 | - The record type (CNAME)
47 | - The host name (your custom domain)
48 | - The target (the CloudFront distribution domain)
49 |
50 | ## User Interaction
51 |
52 | - **Route 53 Users**: You'll be prompted to confirm the creation of the DNS record. The process is largely automated after your confirmation.
53 | - **Non-Route 53 Users**: You'll need to manually create the DNS record with your provider using the instructions provided by the CLI.
54 |
55 | In both cases, the CLI handles the complex tasks of certificate management and CloudFront configuration, simplifying the process of setting up a custom domain for your static website.
56 |
57 | ## Benefits
58 |
59 | - Supports users of all DNS providers
60 | - Automates certificate management and CloudFront configuration
61 | - Provides a guided experience for non-Route 53 users
62 | - Offers a near-fully automated process for Route 53 users
63 |
64 | By accommodating both Route 53 and non-Route 53 users, the CloudFront Hosting Toolkit ensures a smooth custom domain setup process, regardless of your DNS management solution.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/github-integration.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: GitHub Integration
3 | ---
4 |
5 | The GitHub Integration feature of CloudFront Hosting Toolkit provides seamless connectivity between your GitHub repository and your AWS hosting infrastructure, enabling efficient version control and collaborative development.
6 |
7 | ## Key Features
8 |
9 | - **Automatic deployments**: Triggers deployments automatically when code is pushed to the specified branch.
10 | - **Branch-based deployments**: Supports deployments from different branches for staging and production environments.
11 | - **Simplified collaboration**: Enables team members to contribute to the project using familiar GitHub workflows.
12 | - **Secure connection**: Utilizes AWS CodeStar connections for secure, OAuth-based authentication with GitHub.
13 |
14 | ## How It Works
15 |
16 | 1. **Repository connection**: During setup, you provide your GitHub repository details.
17 | 2. **AWS CodeStar Connection**: The toolkit creates an AWS CodeStar connection to your GitHub repository.
18 | - This connection uses OAuth to securely authenticate with GitHub.
19 | - You'll need to authorize the AWS Connector for GitHub app during the setup process.
20 | 3. **Repository access**: You can select specific repositories to make accessible to CodePipeline.
21 | 4. **Automated pipeline**: When code is pushed, it triggers the AWS CodePipeline to start the deployment process.
22 |
23 | ## Connection Setup Process
24 |
25 | 1. **Initiate connection**: The toolkit initiates the creation of a CodeStar connection to GitHub.
26 | 2. **Authorization**: You'll be prompted to authorize the AWS Connector for GitHub app.
27 | 3. **App installation**: If not already installed, you'll need to install the AWS Connector for GitHub app for your account or organization.
28 | 4. **Repository selection**: Choose the specific repositories you want to make accessible to AWS.
29 | 5. **Connection completion**: Once authorized and configured, the connection becomes active, enabling CodePipeline to access your GitHub repository.
30 |
31 | ## Benefits
32 |
33 | - **Streamlined workflow**: Integrates directly with your existing Git-based development process.
34 | - **Security**: OAuth-based authentication ensures secure access without the need for personal access tokens.
35 |
36 | > **Important**
37 | >
38 | > - To create the connection, you must be the GitHub organization owner. For repositories not under an organization, you must be the repository owner.
39 | > - The GitHub Integration feature is not available in certain AWS regions. Check the AWS documentation for the latest information on regional availability.
40 | > - If your CodePipeline service role was created before December 18, 2019, you might need to update its permissions to use `codestar-connections:UseConnection` for AWS CodeStar connections.
41 |
42 | GitHub Integration bridges the gap between your development workflow and your hosting infrastructure, providing a cohesive and efficient deployment process that aligns with modern development practices while maintaining security and ease of use.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/instant-deployment.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Instant deployment
3 | ---
4 |
5 | The Instant Deployment feature of CloudFront Hosting Toolkit enables rapid and efficient updates to your live website, significantly reducing deployment times and accelerating your development cycle.
6 |
7 | ## Key Features
8 |
9 | - **Automated Deployment Pipeline**: Leverages AWS CodePipeline for a streamlined deployment process.
10 | - **Quick Updates**: Changes are reflected on your live site within minutes of pushing code.
11 | - **Versioned Deployments**: Each deployment creates a new version in a separate S3 folder.
12 | - **Atomic Updates**: Ensures all users see the new version, never a mix of old and new version.
13 | - **No Cache Invalidation Required**: CloudFront Function redirects requests to the new folder in S3.
14 |
15 | ## How It Works
16 |
17 | 1. **Code Push**: You push your changes to the configured Git repository or upload a new ZIP file to S3.
18 | 2. **Pipeline Trigger**: This action automatically triggers the AWS CodePipeline.
19 | 3. **Build Process**: AWS CodeBuild compiles your code and creates deployment artifacts.
20 | 4. **Artifact Upload**: The built artifacts are uploaded to a new folder in the hosting S3 bucket.
21 | 5. **Key-Value Store Update**: The commit ID of the new deployment is stored in a Key-Value Store (KVS).
22 | 6. **Traffic Routing**: A CloudFront Function checks the KVS for the latest commit ID and routes traffic to the corresponding S3 folder.
23 |
24 | ## Benefits
25 |
26 | - **Instant availability**: New versions of your website are available immediately after deployment.
27 | - **Consistent user experience**: All users see the same version of the site at any given time.
28 | - **No mixed content**: Eliminates the risk of serving a mixture of old and new version files to users.
29 | - **Efficient resource usage**: No need for cache invalidation.
30 |
31 |
32 | Instant Deployment streamlines your development workflow, allowing you to focus on building features rather than managing complex deployment processes. By leveraging CloudFront Functions and Key-Value Store, it ensures that your users always see a consistent, up-to-date version of your website without the need for cache invalidation or concerns about mixed content during deployments.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/optimized-caching.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Optimized caching
3 | ---
4 |
5 | The Optimized Caching feature of CloudFront Hosting Toolkit leverages Amazon CloudFront's powerful caching capabilities to enhance your website's performance, ensuring faster response times and reduced server load.
6 |
7 | ## Key Features
8 |
9 | - **Specialized Cache Policies**: Implements distinct caching strategies for different types of content.
10 | - **Long-Term Caching**: Utilizes extended cache durations to maximize performance benefits.
11 | - **Compression Support**: Enables Gzip and Brotli compression for compatible content.
12 |
13 | ## How It Works
14 |
15 | ### Cache Policies
16 |
17 | 1. **Default Cache Policy**:
18 | - Applied to most content types
19 | - Cache duration: 365 days (1 year)
20 | - Ignores cookies and query strings
21 | - Enables Gzip and Brotli compression
22 |
23 | 2. **Images Cache Policy**:
24 | - Specifically for image files (jpg, jpeg, png, gif, bmp, tiff, ico)
25 | - Cache duration: 365 days (1 year)
26 | - Ignores cookies, headers, and query strings
27 |
28 | 3. **Static Assets Cache Policy**:
29 | - Applied to js, css, and html files
30 | - Cache duration: 365 days (1 year)
31 | - Ignores cookies, headers, and query strings
32 | - Enables compression
33 |
34 | ## Benefits
35 |
36 | - **Improved Load Times**: Long-term caching ensures faster content delivery for returning visitors.
37 | - **Reduced Origin Load**: Extended cache durations minimize requests to the origin S3 bucket.
38 | - **Optimized for Different Content Types**: Specialized policies for images and static assets ensure appropriate handling.
39 | - **Reduced Bandwidth Usage**: Compression and efficient caching reduce data transfer.
40 |
41 | The Optimized Caching feature ensures that your website delivers exceptional performance globally, enhancing user experience and reducing infrastructure load.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Overview
3 | ---
4 |
5 | CloudFront Hosting Toolkit offers a comprehensive set of features designed to simplify and enhance your frontend deployment process. Each feature is crafted to address specific aspects of modern web application hosting and deployment.
6 |
7 | Our key features include:
8 |
9 | 1. [Self-paced Setup Wizard](/features/setup-wizard)
10 | 2. [Instant Deployment](/features/instant-deployment)
11 | 3. [GitHub Integration](/features/github-integration)
12 | 4. [Optimized Caching](/features/optimized-caching)
13 | 5. [Enhanced Security Headers](/features/security-headers)
14 | 6. [Custom Domain Support](/features/custom-domains)
15 | 7. [SSL/TLS Management](/features/ssl-tls-management)
16 |
17 | Each of these features is designed to work seamlessly together, providing a robust and efficient hosting solution for your frontend applications. Click on any feature to learn more about its capabilities and how it can benefit your development workflow.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/security-headers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Security headers
3 | ---
4 |
5 | The CloudFront Hosting Toolkit implements a comprehensive set of security headers to enhance the protection of your website against common web vulnerabilities.
6 |
7 | ## Key Features
8 |
9 | - **Custom Response Headers Policy**: Applies a set of security headers to all responses from CloudFront.
10 | - **Comprehensive Protection**: Addresses multiple security concerns with a single configuration.
11 |
12 | ## Implemented Security Headers
13 |
14 | The following security headers are implemented through a custom Response Headers Policy:
15 |
16 | 1. **Content-Type Options**:
17 | - Prevents MIME type sniffing.
18 | - Helps protect against MIME confusion attacks.
19 |
20 | 2. **Frame Options**:
21 | - Set to DENY.
22 | - Prevents your content from being embedded in iframes on other domains.
23 | - Protects against clickjacking attacks.
24 |
25 | 3. **Strict Transport Security (HSTS)**:
26 | - Enforces HTTPS connections.
27 | - Includes subdomains.
28 | - Set for a duration of one year (31,536,000 seconds).
29 | - Enhances protection against protocol downgrade attacks and cookie hijacking.
30 |
31 | 4. **XSS Protection**:
32 | - Enables the browser's built-in XSS protection.
33 | - Set to block mode.
34 | - Provides an additional layer of protection against Cross-Site Scripting (XSS) attacks.
35 |
36 | 5. **Referrer Policy**:
37 | - Set to STRICT_ORIGIN_WHEN_CROSS_ORIGIN.
38 | - Controls the Referer header sent by the browser.
39 | - Balances security and functionality by sending the origin, path, and query string when performing a same-origin request, and only the origin when performing a cross-origin request.
40 |
41 | ## Benefits
42 |
43 | - **Enhanced Security Posture**: Protects against various common web vulnerabilities.
44 | - **Browser Compatibility**: Implemented headers are widely supported by modern browsers.
45 | - **Centralized Configuration**: Applied at the CloudFront level, ensuring consistent security across all resources.
46 | - **Compliance Support**: Helps meet security requirements for various compliance standards.
47 |
48 | These security headers work in conjunction with other security features of the CloudFront Hosting Toolkit to provide a robust defense for your web application.
--------------------------------------------------------------------------------
/docs/src/content/docs/features/setup-wizard.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Self-paced Setup Wizard
3 | ---
4 |
5 | The Self-paced setup wizard is a feature of CloudFront Hosting Toolkit that allows you to quickly deploy your website without needing in-depth knowledge of individual AWS services. It guides you through the process, handling the complexities of AWS infrastructure setup behind the scenes.
6 |
7 |
8 | ## Key Benefits
9 |
10 | - **Intuitive command-line interface**: Easy-to-follow prompts guide you through each step of the setup process.
11 | - **Automatic project detection**: The wizard automatically detects your project settings, including framework and repository details.
12 | - **Customizable configuration**: While providing smart defaults, the wizard allows you to customize every aspect of your setup.
13 | - **AWS resource setup**: Guides you through the process of setting up necessary AWS resources, ensuring proper configuration.
14 |
15 | ## How It Works
16 |
17 | 1. **Initiation**: Run `cloudfront-hosting-toolkit init` to start the wizard.
18 | 2. **Project analysis**: The wizard scans your project directory to detect the framework, repository, and other relevant details.
19 | 3. **Guided configuration**: You're prompted to confirm or modify detected settings and provide additional information as needed.
20 | 5. **Configuration save**: All settings are saved to a configuration file.
21 |
22 | ## Best Practices
23 |
24 | - Run the wizard in your project's root directory for the most accurate automatic detection.
25 | - Review each step carefully to ensure all settings align with your project requirements.
26 |
27 | The Self-paced setup wizard simplifies the often complex process of configuring a cloud hosting environment, allowing you to get your project up and running quickly and efficiently.
--------------------------------------------------------------------------------
/docs/src/content/docs/getting-started/how-it-works.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How it works
3 | ---
4 |
5 | CloudFront Hosting Toolkit simplifies the process of deploying and managing frontend applications on AWS. The toolkit operates in three main steps:
6 |
7 | 1. **Initialization**: Set up your project and configure the toolkit.
8 | 2. **Deployment**: Deploy your frontend application infrastructure to AWS.
9 | 3. **Updates**: Automatic updates and content delivery after deployment.
10 |
11 | ## Re:Invent 2024 lightning talk
12 |
13 |
18 |
19 | Learn how to leverage CloudFront Hosting Toolkit for deploying secure and fast frontends using Git-based workflows while maintaining full control over your AWS resources.
20 |
21 |
22 | ## Initialization
23 |
24 | When you run `cloudfront-hosting-toolkit init`:
25 |
26 | 1. The CLI detects your project's configuration, including GitHub repository details (if applicable).
27 | 2. It guides you through a setup process, allowing you to confirm or override detected information.
28 | 3. The command creates configuration files in a `cloudfront-hosting-toolkit` folder.
29 |
30 | ## Deployment
31 |
32 | When you run `cloudfront-hosting-toolkit deploy`:
33 |
34 | 1. The toolkit deploys the hosting infrastructure on AWS, including:
35 | - Amazon S3 bucket for storing your website files
36 | - Amazon CloudFront distribution for content delivery
37 | - AWS CodePipeline for continuous deployment
38 | - AWS CodeBuild project for building your application
39 | - CloudFront Functions for request handling and routing
40 | - Key-Value Store (KVS) for storing the latest deployment information
41 |
42 | 2. Once the infrastructure is set up, the toolkit triggers the initial deployment of your website content.
43 |
44 | ## Updates
45 |
46 | After the initial deployment, the update process and content delivery work as follows:
47 |
48 |
49 |
50 |
51 | 1. A developer pushes code changes to the GitHub repository, triggering the AWS CodePipeline (steps 4-5).
52 |
53 | 2. CodePipeline fetches the new code and builds the new website version (step 5).
54 |
55 | 3. The built artifacts are uploaded to a new folder in the S3 bucket, identified by the commit ID (step 6).
56 |
57 | 4. The Key-Value Store is updated with the new commit ID as the current served website version (step 7).
58 |
59 | 5. When an end-user requests the website (step 1):
60 | - The request hits Amazon CloudFront.
61 | - CloudFront executes a function that fetches the latest build ID from the Key-Value Store (step 2).
62 | - The function rewrites the URL to include the latest build ID and adds it to the cache key.
63 | - CloudFront then requests the content from the correct S3 folder using the rewritten URL (step 3).
64 | - The content is served to the user with a 200 OK status.
65 |
66 | 6. For subsequent requests (step 8), the process repeats, ensuring that users always see the latest version of the website.
67 |
68 | This approach enables atomic deployments, providing several key benefits:
69 |
70 | - All requests are immediately directed to the new version once it's deployed.
71 | - There's no risk of users seeing a mix of old and new content.
72 | - The transition is seamless and instantaneous for all users globally.
73 | - It eliminates the "partial update" problem, ensuring consistency across your entire user base.
74 | - It prevents potential issues that could arise from inconsistent state between old and new versions.
75 |
76 | By leveraging CloudFront's global content delivery network and this intelligent routing mechanism, visitors always see the most recent version of your website, regardless of their location or when they accessed the site. This ensures a consistent, up-to-date experience for all users while benefiting from the performance advantages of a CDN.
--------------------------------------------------------------------------------
/docs/src/content/docs/getting-started/introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | ---
4 |
5 | CloudFront Hosting Toolkit is an open-source command-line tool designed to simplify the deployment and management of frontend applications on AWS. It provides a seamless way to set up and maintain a robust, scalable, and secure hosting infrastructure for your web applications.
6 |
7 | Key benefits:
8 | - Simplified AWS resource management
9 | - Automated deployment pipelines
10 | - Optimized content delivery through CloudFront
11 | - Built-in security features
12 | - Flexible configuration options
13 |
14 | Whether you're a solo developer or part of a large team, CloudFront Hosting Toolkit can streamline your frontend deployment process and help you focus on what matters most - building great web applications.
15 |
--------------------------------------------------------------------------------
/docs/src/content/docs/getting-started/quickstart.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Quickstart
3 | ---
4 |
5 | Get up and running with CloudFront Hosting Toolkit in just a few minutes:
6 |
7 | ## Prerequisites
8 | - Node.js 18+
9 | - AWS CLI 2+ installed and configured
10 | - A GitHub account (if deploying from GitHub)
11 |
12 | ## Installation
13 | Install CloudFront Hosting Toolkit globally:
14 |
15 | ```bash
16 | npm install -g @aws/cloudfront-hosting-toolkit
17 | ```
18 |
19 | ## Deployment Steps
20 | 1. Navigate to your project directory:
21 | ```bash
22 | cd /path/to/your/project
23 | ```
24 |
25 | 2. Initialize your deployment configuration:
26 | ```bash
27 | cloudfront-hosting-toolkit init
28 | ```
29 | Follow the prompts to configure your deployment.
30 |
31 | 3. Deploy your website:
32 | ```bash
33 | cloudfront-hosting-toolkit deploy
34 | ```
35 |
36 | 4. Once deployment is complete, you'll receive a CloudFront domain name. Use this to access your deployed website.
37 |
--------------------------------------------------------------------------------
/docs/src/content/docs/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: CloudFront Hosting Toolkit
3 | description: Self-managed Frontend Hosting on AWS
4 | template: splash
5 | hero:
6 | tagline: Effortlessly deploy and manage fast, secure frontends in the cloud 🚀☁️
7 | actions:
8 | - text: How it works
9 | link: /cloudfront-hosting-toolkit/getting-started/how-it-works
10 | icon: right-arrow
11 | variant: primary
12 | - text: GitHub Repository
13 | link: https://github.com/awslabs/cloudfront-hosting-toolkit
14 | icon: external
15 | - text: NPM Package
16 | link: https://www.npmjs.com/package/@aws/cloudfront-hosting-toolkit
17 | icon: external
18 | ---
19 |
20 | import { Card, CardGrid } from '@astrojs/starlight/components';
21 |
22 | ## Key Features
23 |
24 |
25 | - **Self-paced wizard for easy setup**: Our self-paced setup wizard guides you through the installation process step by step, making it effortless to get started with our project.
26 | - **Instant deployment for quick results**: Experience rapid deployment of your project changes, reducing waiting times and accelerating your development cycle. The solution automatically clears the cache of the previous version.
27 | - **Seamless GitHub integration for version control**: Integrate your project seamlessly with GitHub, enabling efficient version control and collaboration with your team.
28 | - **Optimized caching for improved performance**: We've implemented advanced caching mechanisms to enhance your project's performance, ensuring faster response times and reduced server load.
29 | - **Enhanced security headers for protection**: Your project benefits from enhanced security headers to safeguard against potential security vulnerabilities, helping protect your users and data.
30 | - **Custom domain name support with TLS certificate**: Easily configure custom domain names for your project and secure them with TLS certificates, ensuring a professional and secure online presence.
31 |
32 |
33 |
34 |
35 |
36 | Get your website deployed in minutes:
37 | See our [Quick Start Guide](/cloudfront-hosting-toolkit/getting-started/quickstart) for step-by-step instructions.
38 |
39 |
40 | Works with popular frontend frameworks:
41 | - React
42 | - Vue.js
43 | - Angular
44 | - Next.js
45 | - [Bring your own framework](/cloudfront-hosting-toolkit/advanced/bring-your-own-framework)
46 |
47 |
48 | Ensure consistent user experience:
49 | - Instant updates
50 | - No mixed content during deployments
51 |
52 | Learn more about our [deployment process](/cloudfront-hosting-toolkit/features/instant-deployment).
53 |
54 |
55 | Seamlessly integrate with your infrastructure as code:
56 | - Use as a CDK construct
57 | - Customize and extend functionality
58 |
59 | See how to [integrate with CDK](/cloudfront-hosting-toolkit/user-guide/cdk-guide).
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/src/content/docs/project/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: FAQ
3 | ---
4 |
5 |
6 | ##### I've successfully deployed my website using the tool, and now I'd like to configure a custom domain name. What are the steps I should follow?
7 |
8 | To use a domain name for your deployed website, follow these steps:
9 |
10 | Run the init command again to initiate the setup process.
11 |
12 | During the setup process, select the option that allows you to specify your desired domain name.
13 |
14 | Once you've made the desired domain name selection, proceed with the deployment by running the deploy command.
15 |
16 |
17 | ---
18 |
19 | ##### Is it possible to deploy a website that was built without utilizing any frontend framework using this tool?
20 |
21 | Yes, you can. The tool is designed to be versatile and adaptable to your specific needs. If you've built your website without utilizing any frontend framework, our tool will automatically detect that no framework is in use. As a result, there won't be any build step required.
22 |
23 |
24 |
25 | ---
26 |
27 | ##### What is CloudFront Hosting Toolkit?
28 |
29 | CloudFront Hosting Toolkit is an open-source command-line tool designed for deploying and managing frontend applications on AWS. It simplifies the process of setting up and maintaining a robust, scalable hosting infrastructure using services like CloudFront, S3, and CodePipeline.
30 |
31 |
32 |
33 | ---
34 |
35 | ##### Who is CloudFront Hosting Toolkit for?
36 |
37 | CloudFront Hosting Toolkit is primarily designed for developers and teams working on frontend projects who want to leverage AWS services for hosting. It's particularly useful for those who need a streamlined deployment process, want to take advantage of CloudFront's global content delivery network, and require features like custom domains and SSL/TLS management.
38 |
39 |
40 |
41 | ---
42 |
43 | ##### What types of projects are supported?
44 |
45 | The toolkit supports a wide range of frontend projects, including:
46 | - Single-page applications (SPAs)
47 | - Static websites
48 | - Projects built with popular frameworks like React, Angular, and Vue.js
49 | - Custom or less common frameworks (via the [Bring your own framework](/cloudfront-hosting-toolkit/advanced/bring-your-own-framework) feature)
50 |
51 | Additionally, you can easily customize the build and deployment process to suit your specific project requirements.
52 |
53 |
54 |
55 | ---
56 |
57 | ##### Is custom domain support available?
58 |
59 | Yes, CloudFront Hosting Toolkit provides built-in support for custom domains. During the initialization process, you can specify your custom domain, and the toolkit will:
60 |
61 | 1. Configure your CloudFront distribution to use the custom domain.
62 | 2. Automatically provision and associate an SSL/TLS certificate using AWS Certificate Manager.
63 | 3. Provide guidance on setting up the necessary DNS records.
64 |
65 | This feature allows you to use your own branded domain while still benefiting from CloudFront's global content delivery network.
66 |
67 |
68 |
69 | ---
70 |
71 | ##### Is it necessary to acquire a domain name in advance or before deploying my website?
72 |
73 | Yes, it's advisable to acquire your desired domain name before configuring it for your website if you want to associate a custom domain name with your website. You have the flexibility to purchase the domain name either through your AWS account or from any other DNS provider of your choice. This ensures that you have ownership and control over the domain name as you proceed with the website configuration.
74 |
75 |
76 | ---
77 |
78 | ##### Can I use the toolkit with existing AWS resources?
79 |
80 | While CloudFront Hosting Toolkit is designed to set up a complete hosting infrastructure, it also offers flexibility for integration with existing AWS resources:
81 |
82 | - You can use an existing S3 bucket for deployments by specifying it during the initialization process.
83 | - For more advanced scenarios, you can use the toolkit's [CDK constructs](/cloudfront-hosting-toolkit/user-guide/cdk-guide) to integrate with your existing AWS CDK stacks.
84 |
85 |
86 |
87 | ---
88 |
89 | ##### Is continuous deployment supported?
90 |
91 | Yes, CloudFront Hosting Toolkit supports continuous deployment when using [GitHub](/cloudfront-hosting-toolkit/architecture/github-workflow) as your source repository. Each push to your configured branch will automatically trigger a new deployment through the AWS CodePipeline set up by the toolkit.
92 |
93 | For [S3-based deployments](/cloudfront-hosting-toolkit/architecture/s3-workflow), you can achieve continuous deployment by integrating the toolkit's commands into your existing CI/CD processes.
94 |
95 |
96 |
97 | ---
98 |
99 | ##### How can I contribute to the CloudFront Hosting Toolkit project?
100 |
101 | Contributions to CloudFront Hosting Toolkit are welcome! You can contribute in several ways:
102 |
103 | 1. Fork the [CloudFront Hosting Toolkit repository](https://github.com/awslabs/cloudfront-hosting-toolkit) on GitHub and submit pull requests for new features or bug fixes.
104 | 2. Report issues or suggest features using the GitHub issue tracker.
105 | 3. Improve the documentation by submitting updates or clarifications.
106 | 4. Share your experiences and help other users in the project's discussion forums.
107 |
108 | Before contributing, please review the project's contribution guidelines and code of conduct in the repository.
109 |
110 |
111 |
112 | ---
113 |
114 | ##### Can I use the toolkit for backend deployments?
115 |
116 | CloudFront Hosting Toolkit is primarily designed for frontend deployments. However, the toolkit's [CDK constructs](/cloudfront-hosting-toolkit/user-guide/cdk-construct) can be integrated into a broader CDK stack that includes both frontend and backend resources
117 |
--------------------------------------------------------------------------------
/docs/src/content/docs/troubleshooting/guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Troubleshooting guide
3 | ---
4 |
5 | If you encounter issues while using CloudFront Hosting Toolkit, follow this guide to diagnose and resolve common problems.
6 |
7 | ## 1. General debugging steps
8 |
9 | 1. Use `cloudfront-hosting-toolkit status` to check the current state of your deployment.
10 | 2. Review the logs in the `cloudfront-hosting-toolkit` folder (named with the format `YYYY-MM-DD_HH-MM-SS.log`) for detailed operation logs.
11 | 3. Use AWS Management Console to inspect the state of individual resources (S3, CloudFront, CodePipeline, CodeBuild).
12 |
13 | ## 2. Deployment fails
14 |
15 | - **Check AWS Credentials**: Ensure your AWS CLI is correctly configured with the right permissions.
16 | - **Verify Build Configuration**: Ensure your `cloudfront-hosting-toolkit-config.yml` is correctly formatted and contains all necessary commands.
17 | - **Review CodeBuild Logs**: Check the CodeBuild project in AWS Console for specific build failure reasons.
18 | - **GitHub Connection Issues**: For GitHub-based deployments, ensure the AWS CodeStar connection is properly set up and authorized.
19 | - **Project Structure and Framework Compatibility**: Verify that your project structure is correct and compatible with the chosen framework. If the framework specified in the JSON file is incorrect, you can:
20 | - Manually change it in the `cloudfront-hosting-toolkit-config.json` file to one of the supported values.
21 | - Customize the build configuration in `cloudfront-hosting-toolkit-config.yml` to use the correct commands for building your website.
22 |
23 | ## 3. Website not updating after deployment
24 |
25 | - **Review CodeBuild Logs**: Often, the issue lies in the build configuration. Inspect the CodeBuild logs in the AWS Console to understand if the build process completed successfully and if all expected files were generated.
26 | - **Verify Build Configuration**: Ensure your `cloudfront-hosting-toolkit-config.yml` is correctly configured for your framework and project structure. Pay special attention to build commands and output directories.
27 | - **Review CloudFront Function**: Ensure the function is correctly routing to the new folder. Check the function logs in CloudFront console.
28 | - **Check Key-Value Store (KVS)**: Verify that the KVS was updated with the new deployment information (commit ID). You can check this in the CloudFront console under the Functions section.
29 |
30 | ## 4. Custom domain issues
31 |
32 | - **Certificate Validation**: If using a custom domain, ensure the SSL/TLS certificate is properly validated in AWS Certificate Manager.
33 | - **DNS Configuration**: Verify that your domain's DNS settings are correctly pointing to the CloudFront distribution.
34 |
35 |
36 | ## Getting Help
37 |
38 | - **Documentation**: Refer to our comprehensive documentation for detailed information on each feature and process.
39 | - **GitHub Issues**: Check existing issues or create a new one on our [GitHub repository](https://github.com/awslabs/cloudfront-hosting-toolkit).
40 |
41 |
--------------------------------------------------------------------------------
/docs/src/content/docs/user-guide/cdk-configuration.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CDK Configuration guide
3 | ---
4 |
5 | Both the CDK Construct and CDK Source Code methods require some common configuration steps. Follow this guide to set up the necessary files.
6 |
7 | ## Configuration Files
8 |
9 | Create a `cloudfront-hosting-toolkit` folder at the root of your CDK project and add the following files:
10 |
11 | 1. `buildConfigurationFile.yml`: Configures the build process for your specific framework.
12 | 2. A JavaScript file for the CloudFront function (e.g., `url-rewriting.js`): Handles URL rewriting for your application.
13 | 3. `cloudfront-hosting-toolkit.json`: Contains your project configuration.
14 |
15 | ### 1. Build Configuration File
16 |
17 | Example for Vue.js:
18 |
19 | ```yaml
20 | version: 0.2
21 | phases:
22 | build:
23 | commands:
24 | - npx npm install
25 | - npx npm run build
26 | - cd dist
27 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
28 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
29 | ```
30 |
31 | [More build configuration templates](https://github.com/awslabs/cloudfront-hosting-toolkit/tree/main/resources/build_config_templates)
32 |
33 | ### 2. CloudFront Function File
34 |
35 | Example for Vue.js:
36 |
37 | ```javascript
38 | import cf from 'cloudfront';
39 |
40 | const kvsId = '__KVS_ID__';
41 |
42 | // This fails if the key value store is not associated with the function
43 | const kvsHandle = cf.kvs(kvsId);
44 |
45 | function pointsToFile(uri) {
46 | return /\/[^/]+\.[^/]+$/.test(uri);
47 | }
48 | var rulePatterns = {
49 | "/$": "/index.html", // When URI ends with a '/', append 'index.html'
50 | "!file": ".html", // When URI doesn't point to a specific file and doesn't have a trailing slash, append '.html'
51 | "!file/": "/index.html",// When URI has a trailing slash and doesn't point to a specific file, append 'index.html'
52 | };
53 |
54 | // Function to determine rule and update the URI
55 | async function updateURI(uri) {
56 |
57 | let pathToAdd = "";
58 |
59 | try {
60 | pathToAdd = await kvsHandle.get("path");
61 | } catch (err) {
62 | console.log(`No key 'path' present : ${err}`);
63 | return uri;
64 | }
65 |
66 | // Check for trailing slash and apply rule.
67 | if (uri.endsWith("/") && rulePatterns["/$"]) {
68 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["/$"];
69 | }
70 |
71 | // Check if URI doesn't point to a specific file.
72 | if (!pointsToFile(uri)) {
73 | // If URI doesn't have a trailing slash, apply rule.
74 | if (!uri.endsWith("/") && rulePatterns["!file"]) {
75 | return "/" + pathToAdd + uri + rulePatterns["!file"];
76 | }
77 |
78 | // If URI has a trailing slash, apply rule.
79 | if (uri.endsWith("/") && rulePatterns["!file/"]) {
80 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["!file/"];
81 | }
82 | }
83 |
84 | return "/" + pathToAdd + uri;
85 | }
86 |
87 | // Main CloudFront handler
88 | async function handler(event) {
89 | var request = event.request;
90 | var uri = request.uri;
91 |
92 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
93 | request.uri = await updateURI(uri);
94 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
95 |
96 |
97 |
98 | return request;
99 | }
100 |
101 | ```
102 |
103 | [More CloudFront function templates](https://github.com/awslabs/cloudfront-hosting-toolkit/tree/main/resources/cff_templates)
104 |
105 | ### 3. Project Configuration File
106 |
107 | For GitHub-based workflow:
108 |
109 | ```json
110 | {
111 | "repoUrl": "https://github.com/USERNAME/REPOSITORY.git",
112 | "branchName": "main",
113 | "framework": "nextjs",
114 | "domainName": "example.com",
115 | "hostedZoneId": "Z1234567890ABCDEF"
116 | }
117 | ```
118 |
119 | For S3-based workflow:
120 |
121 | ```json
122 | {
123 | "s3bucket": "my-source-bucket",
124 | "s3path": "path/to/source",
125 | "domainName": "example.com",
126 | "hostedZoneId": "Z1234567890ABCDEF"
127 | }
128 | ```
129 |
130 | [More configuration examples](https://github.com/your-repo-link/configuration-examples)
131 |
132 | ## Field Descriptions
133 |
134 | ### Mandatory Fields
135 |
136 | - For GitHub workflow:
137 | - `repoUrl`: The URL of your GitHub repository
138 | - `branchName`: The branch to deploy
139 | - `framework`: The framework used in your project (e.g., "nextjs", "react", "vue")
140 |
141 | - For S3 workflow:
142 | - `s3bucket`: The name of your S3 bucket containing the source code
143 | - `s3path`: The path within the bucket where your source code is located
144 |
145 | ### Optional Fields
146 |
147 | - `domainName`: Your custom domain name (if you want to use one)
148 | - `hostedZoneId`: The Route 53 hosted zone ID for your domain (required if using a custom domain)
149 |
150 | Note: If you include `domainName`, you must also include `hostedZoneId`. These fields are used together to set up a custom domain for your website.
--------------------------------------------------------------------------------
/docs/src/content/docs/user-guide/cdk-construct.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CDK Construct Guide
3 | ---
4 |
5 | The CloudFront Hosting Toolkit can be easily integrated into your existing CDK projects as a construct.
6 |
7 | ## Installation
8 |
9 | Install the CloudFront Hosting Toolkit in your CDK project:
10 |
11 | ```bash
12 | npm install @aws/cloudfront-hosting-toolkit
13 | ```
14 |
15 | ## Configuration
16 |
17 | Before using the construct, you need to set up some configuration files. See our [CDK Configuration Guide](/cloudfront-hosting-toolkit/user-guide/cdk-configuration) for detailed instructions.
18 |
19 | ## Usage
20 |
21 | After setting up the required configuration, you can use the CloudFront Hosting Toolkit construct in your CDK code:
22 |
23 | ### For GitHub Repository Deployment
24 |
25 | ```typescript
26 | import { RepositoryConnection, Hosting } from '@aws/cloudfront-hosting-toolkit';
27 |
28 | const config = {
29 | repoUrl: "https://github.com/USERNAME/REPOSITORY.git",
30 | branchName: "main",
31 | framework: "nextjs"
32 | };
33 |
34 | const repositoryConnection = new RepositoryConnection(this, "MyRepositoryConnection", config);
35 |
36 | new Hosting(this, "MyHosting", {
37 | hostingConfiguration: config,
38 | buildFilePath: "cloudfront-hosting-toolkit/buildConfigurationFile.yml",
39 | connectionArn: repositoryConnection.connectionArn,
40 | cffSourceFilePath: "cloudfront-hosting-toolkit/url-rewriting.js"
41 | });
42 | ```
43 |
44 | ### For S3 Repository Deployment
45 |
46 | ```typescript
47 | import { Hosting } from '@aws/cloudfront-hosting-toolkit';
48 |
49 | const config = {
50 | s3bucket: "frontend-hosting-source",
51 | s3path: ""
52 | };
53 |
54 | new Hosting(this, "MyHosting", {
55 | hostingConfiguration: config,
56 | buildFilePath: "cloudfront-hosting-toolkit/buildConfigurationFile.yml",
57 | cffSourceFilePath: "cloudfront-hosting-toolkit/url-rewriting.js"
58 | });
59 | ```
60 |
61 | ## Deployment
62 |
63 | Deploy your CDK project as usual. The CloudFront Hosting Toolkit infrastructure will be deployed as part of your stack.
64 |
65 |
--------------------------------------------------------------------------------
/docs/src/content/docs/user-guide/cdk-guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CDK Overview
3 | ---
4 |
5 | CloudFront Hosting Toolkit offers two primary methods for integration with AWS CDK (Cloud Development Kit):
6 |
7 | 1. **CDK Construct**: Use the CloudFront Hosting Toolkit as a pre-built construct in your existing CDK project. This method is ideal if you want to quickly integrate the toolkit's functionality without modifying its core logic.
8 |
9 | 2. **CDK Source Code**: Clone the CloudFront Hosting Toolkit repository, modify the source code as needed, and deploy it as a standalone CDK project. This approach offers maximum flexibility and customization.
10 |
11 | Both methods require some common setup steps, which are detailed in our [CDK Configuration Guide](cdk-configuration-guide.md).
12 |
13 | Choose the method that best fits your project's needs and level of customization required:
14 |
--------------------------------------------------------------------------------
/docs/src/content/docs/user-guide/cdk-source-code.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CDK Source Code Guide
3 | ---
4 |
5 | For maximum flexibility, you can deploy the CloudFront Hosting Toolkit by cloning and modifying its source code.
6 |
7 | ## Steps
8 |
9 | 1. Clone the project:
10 | ```bash
11 | git clone https://github.com/awslabs/cloudfront-hosting-toolkit.git
12 | cd cloudfront-hosting-toolkit
13 | ```
14 |
15 | 2. Modify the source code as needed to suit your requirements.
16 |
17 | 3. Set up the necessary configuration files. See our [CDK Configuration Guide](/cloudfront-hosting-toolkit/user-guide/cdk-configuration) for detailed instructions.
18 |
19 | 4. Deploy the project:
20 | ```bash
21 | npm run build
22 | cdk deploy
23 | ```
24 |
25 | 5. After deployment, you need to configure the GitHub connection by going to the AWS console. [More information on GitHub connections](https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-github.html).
26 |
27 | ## Note on deployment
28 |
29 | - The first time you deploy, the pipeline will be automatically triggered.
30 | - If you make changes to the infrastructure and need to redeploy, you may need to manually trigger the pipeline if the changes require a new deployment.
31 |
--------------------------------------------------------------------------------
/docs/src/content/docs/user-guide/cli-guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CLI Guide
3 | ---
4 |
5 | The CloudFront Hosting Toolkit CLI is designed to simplify the process of deploying and managing your frontend applications on AWS.
6 |
7 | ## Usage
8 |
9 | The CLI can be executed in two ways:
10 |
11 | 1. In a folder where your project is cloned from GitHub. This allows the CLI to auto-detect the framework, repository URL, and branch name.
12 | 2. In any other folder, where you'll need to manually input this information.
13 |
14 | ## Available Commands
15 |
16 | ### Init
17 |
18 | Initialize your deployment configuration:
19 |
20 | ```bash
21 | cloudfront-hosting-toolkit init
22 | ```
23 |
24 | Options:
25 | - `--s3`: Initialize an S3 repository deployment instead of GitHub.
26 |
27 | The following animated GIF demonstrates the initialization process:
28 |
29 |
30 |
31 |
32 | After running `cloudfront-hosting-toolkit init`, CloudFront Hosting Toolkit will create a folder named `cloudfront-hosting-toolkit` in the directory where the tool is executed.
33 |
34 | This `cloudfront-hosting-toolkit` folder contains essential files for managing your deployment process:
35 |
36 | 1. `cloudfront-hosting-toolkit-config.json`: This JSON file stores the configuration settings gathered during the `init` process. You can review and modify these settings as needed.
37 | 2. `cloudfront-hosting-toolkit-config.yml`: This YAML file is necessary for CodeBuild to build your website. It contains build configuration information, ensuring that your website is built correctly.
38 | 3. `cloudfront-hosting-toolkit-cff.js`: This JavaScript file encapsulates the code utilized by the CloudFront Function for URL rewriting. Given the variability in rules based on the framework, this file is accessible for modifications at any time, enabling the addition of additional logic required to execute at the edge.
39 | 4. During deployment, the CLI generates log files to capture important information and log messages. These log files are named using the format `YYYY-MM-DD_HH-MM-SS.log` and are stored in the `cloudfront-hosting-toolkit` folder. You can review these logs to troubleshoot any deployment issues or monitor the deployment process.
40 |
41 | Make sure to keep these files in the `cloudfront-hosting-toolkit` folder for seamless management of your future deployments.
42 |
43 | ### Deploy
44 |
45 | Deploy your website:
46 |
47 | ```bash
48 | cloudfront-hosting-toolkit deploy
49 | ```
50 |
51 | > **Important**
52 | >
53 | > You typically only need to run the deploy command once after your initial init command. Subsequent code updates will be automatically deployed through the established pipeline.
54 |
55 |
56 | You should only need to run deploy again if:
57 |
58 | - You've run the init command again to change your configuration.
59 | - You've manually deleted or significantly altered your AWS infrastructure.
60 |
61 |
62 | When you run this command, the CLI will:
63 |
64 | 1. For GitHub-based workflows, create an AWS CodeStar connection to your GitHub repository. This process involves:
65 |
66 | - Creating a connection in a PENDING state.
67 | - Prompting you to complete the connection setup in the AWS console.
68 | - Guiding you through the process of installing the AWS Connector for GitHub app and granting necessary permissions.
69 | - You'll need to select the specific GitHub repository you want to deploy.
70 |
71 | This step is crucial for establishing secure access between your AWS account and your GitHub repository. For more detailed information on this process, refer to the AWS documentation on GitHub connections.
72 | 2. Display the progress of the infrastructure deployment in real-time.
73 | 3. Continue to show updates until the entire infrastructure is successfully deployed.
74 | 4. After the infrastructure deployment is complete, automatically trigger the pipeline for your initial website deployment.
75 | 5. Wait for the pipeline to finish, providing status updates throughout the process.
76 |
77 | The deployment is only considered complete when both the infrastructure is set up and the initial pipeline run has finished successfully.
78 |
79 | Upon successful completion of the deployment:
80 | - The domain name under which your website is available will be displayed.
81 | - The pipeline status and name will be shown.
82 |
83 | If the pipeline fails, you'll receive an error message. For troubleshooting information and potential solutions, please refer to the [Troubleshooting Guide](/cloudfront-hosting-toolkit/troubleshooting/guide).
84 |
85 | The following animated GIF demonstrates the deployment process:
86 |
87 |
88 |
89 |
90 | Note: The actual time for deployment can vary based on the complexity of your project and current AWS service response times.
91 |
92 |
93 | ### Show
94 |
95 | Display the domain name linked to your deployed source code repository:
96 |
97 | ```bash
98 | cloudfront-hosting-toolkit show
99 | ```
100 |
101 | ### Status
102 |
103 | Check the current status of your pipeline deployment:
104 |
105 | ```bash
106 | cloudfront-hosting-toolkit status
107 | ```
108 |
109 | ### Delete
110 |
111 | Remove the hosting infrastructure from your AWS account:
112 |
113 | ```bash
114 | cloudfront-hosting-toolkit delete
115 | ```
116 |
117 | ## Best Practices
118 |
119 | 1. Run `init` in your project root directory for accurate auto-detection of project settings when using a GitHub repository.
120 | 2. Review the generated log files in the `cloudfront-hosting-toolkit` folder for troubleshooting and monitoring.
121 | 3. If you need to customize URL rewriting rules, modify the `cloudfront-hosting-toolkit-cff.js` file as needed.
--------------------------------------------------------------------------------
/docs/src/styles/custom.css:
--------------------------------------------------------------------------------
1 | /* Dark mode colors. */
2 | :root {
3 | --sl-color-accent-low: #1a2639;
4 | --sl-color-accent: #3e4a61;
5 | --sl-color-accent-high: #c9d1d9;
6 | --sl-color-white: #ffffff;
7 | --sl-color-gray-1: #f0f6fc;
8 | --sl-color-gray-2: #c9d1d9;
9 | --sl-color-gray-3: #8b949e;
10 | --sl-color-gray-4: #6e7681;
11 | --sl-color-gray-5: #484f58;
12 | --sl-color-gray-6: #30363d;
13 | --sl-color-black: #0d1117;
14 | --sl-label-api-color: #ff7b72;
15 | --sl-label-api-background-color: #ff7b72;
16 | --sl-label-version-color: #7ee787;
17 | --sl-label-version-background-color: #7ee787;
18 | --sl-label-package-color: #ffa657;
19 | --sl-label-package-background-color: #ffa657;
20 | }
21 |
22 | /* Light mode colors. */
23 | :root[data-theme='light'] {
24 | --sl-color-accent-low: #d0e8ff;
25 | --sl-color-accent: #0969da;
26 | --sl-color-accent-high: #033d8b;
27 | --sl-color-white: #0d1117;
28 | --sl-color-gray-1: #30363d;
29 | --sl-color-gray-2: #484f58;
30 | --sl-color-gray-3: #6e7681;
31 | --sl-color-gray-4: #8b949e;
32 | --sl-color-gray-5: #c9d1d9;
33 | --sl-color-gray-6: #f0f6fc;
34 | --sl-color-gray-7: #f8f9fa;
35 | --sl-color-black: #ffffff;
36 | --sl-label-api-color: #cf222e;
37 | --sl-label-api-background-color: #cf222e;
38 | --sl-label-version-color: #2da44e;
39 | --sl-label-version-background-color: #2da44e;
40 | --sl-label-package-color: #d4a72c;
41 | --sl-label-package-background-color: #d4a72c;
42 | }
43 |
44 | :root {
45 | --purple-hsl: 212, 72%, 59%;
46 | --overlay-blurple: hsla(var(--purple-hsl), 0.4);
47 | }
48 |
49 | [data-has-hero] .page {
50 | background: linear-gradient(215deg, var(--overlay-blurple), transparent 40%),
51 | radial-gradient(var(--overlay-blurple), transparent 40%) no-repeat -60vw -40vh / 105vw 200vh,
52 | radial-gradient(var(--overlay-blurple), transparent 65%) no-repeat 50% calc(100% + 20rem) / 60rem 30rem;
53 | }
54 |
55 | [data-has-hero] header {
56 | border-bottom: 1px solid transparent;
57 | background-color: transparent;
58 | -webkit-backdrop-filter: blur(16px);
59 | backdrop-filter: blur(16px);
60 | }
61 |
62 | [data-has-hero] .hero > img {
63 | filter: drop-shadow(0 0 3rem var(--overlay-blurple));
64 | }
65 |
66 | [data-page-title] {
67 | font-size: 3rem;
68 | }
69 |
70 | @media (max-width: 768px) {
71 | [data-page-title] {
72 | font-size: 2.5rem;
73 | }
74 | }
75 |
76 | .card-grid > .card {
77 | border-radius: 10px;
78 | }
79 |
80 | .card > .title {
81 | font-size: 1.3rem;
82 | font-weight: 600;
83 | line-height: 1.2;
84 | }
85 |
86 | .Label, .label {
87 | border: 1px solid;
88 | border-radius: 2em;
89 | display: inline-block;
90 | font-size: 0.75rem;
91 | font-weight: 500;
92 | line-height: 18px;
93 | padding: 0 7px;
94 | white-space: nowrap;
95 | }
96 |
97 | .Label > a, .label > a {
98 | color: inherit;
99 | text-decoration: none;
100 | }
101 |
102 | .Label > a:hover, .label > a:hover {
103 | color: inherit;
104 | text-decoration: none;
105 | }
106 |
107 | .Label.Label--api {
108 | color: var(--sl-label-api-color);
109 | border-color: var(--sl-label-api-background-color);
110 | }
111 |
112 | .Label.Label--version {
113 | color: var(--sl-label-version-color);
114 | border-color: var(--sl-label-version-background-color);
115 | }
116 |
117 | .Label.Label--package {
118 | color: var(--sl-label-package-color);
119 | border-color: var(--sl-label-package-background-color);
120 | }
121 |
122 | .text-uppercase {
123 | text-transform: uppercase !important;
124 | }
125 |
126 | .language-icon {
127 | margin-bottom: -8px;
128 | float: right;
129 | }
130 |
131 | @media only screen and (max-width: 1023px) {
132 | .language-icon {
133 | display: none;
134 | float: none;
135 | }
136 | }
--------------------------------------------------------------------------------
/docs/src/styles/font.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "JetBrainsMono NF";
3 | src: url("../assets/fonts/JetBrainsMonoNerdFont-Regular.ttf")
4 | format("truetype");
5 | font-weight: 400;
6 | font-style: normal;
7 | font-display: swap;
8 | }
9 |
10 | @font-face {
11 | font-family: "JetBrainsMono NF";
12 | src: url("../assets/fonts/JetBrainsMonoNerdFont-Italic.ttf")
13 | format("truetype");
14 | font-weight: 400;
15 | font-style: italic;
16 | font-display: swap;
17 | }
18 |
19 | @font-face {
20 | font-family: "JetBrainsMono NF";
21 | src: url("../assets/fonts/JetBrainsMonoNerdFont-Bold.ttf") format("truetype");
22 | font-weight: 700;
23 | font-style: normal;
24 | font-display: swap;
25 | }
26 |
27 | @font-face {
28 | font-family: "JetBrainsMono NF";
29 | src: url("../assets/fonts/JetBrainsMonoNerdFont-BoldItalic.ttf")
30 | format("truetype");
31 | font-weight: 700;
32 | font-style: italic;
33 | font-display: swap;
34 | }
35 |
36 | :root {
37 | --sl-font: "JetBrainsMono NF";
38 | --sl-font-mono: "JetBrainsMono NF";
39 | }
40 |
--------------------------------------------------------------------------------
/docs/src/styles/landing.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --sl-hue-accent: 255;
3 | --sl-color-accent-low: hsl(var(--sl-hue-accent), 14%, 20%);
4 | --sl-color-accent: hsl(var(--sl-hue-accent), 60%, 60%);
5 | --sl-color-accent-high: hsl(var(--sl-hue-accent), 60%, 87%);
6 | --overlay-blurple: hsla(var(--sl-hue-accent), 60%, 60%, 0.2);
7 | }
8 |
9 | :root[data-theme='light'] {
10 | --sl-hue-accent: 45; /*Color of top bar text and icons and Getting Started button*/
11 | --sl-color-accent-high: hsl(var(--sl-hue-accent), 90%, 20%);
12 | --sl-color-accent: hsl(var(--sl-hue-accent), 100%, 50%);
13 | --sl-color-accent-low: hsl(var(--sl-hue-accent), 98%, 80%);
14 | }
15 |
16 | [data-has-hero] .page {
17 | background: linear-gradient(215deg, var(--overlay-blurple), transparent 40%),
18 | radial-gradient(var(--overlay-blurple), transparent 40%) no-repeat -60vw -40vh / 105vw 200vh,
19 | radial-gradient(var(--overlay-blurple), transparent 65%) no-repeat 50% calc(100% + 20rem) / 60rem 30rem;
20 | }
21 |
22 | [data-has-hero] header {
23 | border-bottom: 1px solid transparent;
24 | background-color: transparent;
25 | -webkit-backdrop-filter: blur(16px);
26 | backdrop-filter: blur(16px);
27 | }
28 |
29 | [data-has-hero] .hero > img {
30 | filter: drop-shadow(0 0 3rem var(--overlay-blurple));
31 | }
32 |
33 | iframe[id='stackblitz-iframe'] {
34 | width: 100%;
35 | min-height: 600px;
36 | }
--------------------------------------------------------------------------------
/docs/src/styles/terminal.css:
--------------------------------------------------------------------------------
1 | /* Solarized color palette */
2 | :root {
3 | --sol-red: #dc322f;
4 | --sol-bright-red: #cb4b16;
5 | --sol-green: #859900;
6 | --sol-yellow: #b58900;
7 | --sol-blue: #268bd2;
8 | --sol-magenta: #d33682;
9 | --sol-bright-magenta: #6c71c4;
10 | --sol-cyan: #2aa198;
11 |
12 | --sol-base03: #002b36;
13 | --sol-base02: #073642;
14 | --sol-base00: #657b83;
15 | --sol-base0: #839496;
16 | --sol-base2: #eee8d5;
17 | --sol-base3: #fdf6e3;
18 | }
19 |
20 | pre.terminal {
21 | --black: var(--sol-base02);
22 | --red: var(--sol-red);
23 | --bright-red: var(--sol-bright-red);
24 | --green: var(--sol-green);
25 | --yellow: var(--sol-yellow);
26 | --blue: var(--sol-blue);
27 | --magenta: var(--sol-magenta);
28 | --bright-magenta: var(--sol-bright-magenta);
29 | --cyan: var(--sol-cyan);
30 | --white: var(--sol-base2);
31 |
32 | background-color: var(--sol-base03);
33 | color: var(--sol-base0);
34 | font-family: var(--__sl-font-mono);
35 | }
36 |
37 | :root[data-theme="light"] pre.terminal {
38 | background-color: var(--sol-base3);
39 | color: var(--sol-base00);
40 | }
41 |
42 | pre.terminal p {
43 | margin: -0.75rem -1rem;
44 | padding: 0.75rem 1rem;
45 | overflow-x: auto;
46 | }
47 |
48 | pre.astro-code + pre.terminal {
49 | margin-top: 0;
50 | border-top-width: 0;
51 | }
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strict"
3 | }
--------------------------------------------------------------------------------
/img/architecture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/img/architecture.jpg
--------------------------------------------------------------------------------
/img/deploy.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/img/deploy.gif
--------------------------------------------------------------------------------
/img/init.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awslabs/cloudfront-hosting-toolkit/199ce3142ba9f9c28f2849b78df387c8e59a26ec/img/init.gif
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | testEnvironment: 'node',
3 | roots: ['/test'],
4 | testMatch: ['**/*.test.ts'],
5 | transform: {
6 | '^.+\\.tsx?$': 'ts-jest'
7 | },
8 | coveragePathIgnorePatterns : [
9 | "/bin/cli/actions/*.d.ts","/bin/cli/actions/*.js"
10 | ]
11 | };
12 |
--------------------------------------------------------------------------------
/lambda/delete_old_deployments/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | const { S3 } = require("@aws-sdk/client-s3");
17 | const s3 = new S3({customUserAgent: "cht"});
18 |
19 | const bucketName = process.env.BUCKET_NAME; // Use the environment variable
20 |
21 | exports.handler = async (event, context) => {
22 | console.log("event=" + JSON.stringify(event));
23 |
24 | try {
25 | const commitId = event.commitId;
26 |
27 | const listObjectsParams = {
28 | Bucket: bucketName,
29 | Delimiter: "/",
30 | };
31 |
32 | const listResponse = await s3.listObjectsV2(listObjectsParams);
33 |
34 | const folderObjects = listResponse.CommonPrefixes.map((prefix) => ({
35 | Prefix: prefix.Prefix,
36 | }));
37 |
38 | const objectsToDelete = folderObjects.filter((object) => {
39 | const folderPath = object.Prefix;
40 | const folderName = folderPath.slice(0, -1); // Remove trailing slash
41 |
42 | return (
43 | !folderName.startsWith(commitId)
44 | );
45 | });
46 |
47 | if (objectsToDelete.length === 0) {
48 | console.log("No files or folders to delete.");
49 | } else {
50 | let deletedItemCount = 0;
51 |
52 | for (const object of objectsToDelete) {
53 | const deleteFilesParams = {
54 | Bucket: bucketName,
55 | Prefix: object.Prefix,
56 | };
57 |
58 | const files = await s3.listObjectsV2(deleteFilesParams);
59 |
60 | for (const file of files.Contents) {
61 | const deleteFileParams = {
62 | Bucket: bucketName,
63 | Key: file.Key,
64 | };
65 |
66 | await s3.deleteObject(deleteFileParams);
67 | console.log(`Deleted file: ${file.Key}`);
68 | deletedItemCount++;
69 | }
70 | }
71 |
72 | console.log(`Deleted ${deletedItemCount} objects successfully.`);
73 | }
74 |
75 | return "Execution completed successfully";
76 | } catch (error) {
77 | console.error("Error:", error);
78 | throw new Error(`Error deleting old files and folders: ${error.message}`);
79 | }
80 | };
81 |
--------------------------------------------------------------------------------
/lambda/layers/aws_sdk/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AWS_SDK_Layer",
3 | "version": "1.0.0",
4 | "description": "Latest AWS SDK libs",
5 | "main": "",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "dependencies": {
10 | "@aws-sdk/client-cloudfront-keyvaluestore": "^3.633.0",
11 | "@aws-sdk/signature-v4-crt": "^3.511.0",
12 | "@aws-sdk/signature-v4-multi-region": "^3.511.0"
13 | },
14 | "author": {
15 | "name": "Amazon Web Services",
16 | "url": "https://aws.amazon.com/solutions"
17 | },
18 | "license": "Apache-2.0"
19 | }
20 |
--------------------------------------------------------------------------------
/lambda/new_build/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | const { SSM } = require("@aws-sdk/client-ssm");
18 | const ssm = new SSM();
19 | const { CodePipeline } = require("@aws-sdk/client-codepipeline");
20 | const codepipeline = new CodePipeline();
21 |
22 | exports.handler = async (event, context) => {
23 | console.log('event is 👉', JSON.stringify(event, null, 4));
24 | const key = event.detail.object.key;
25 |
26 | const parts = key.split("/");
27 | const file_name_parts = parts[parts.length - 1].split(".").slice(0, -1);
28 | const commitId = file_name_parts.join(".");
29 | console.log("commitId="+commitId);
30 |
31 | const ssmCommitIdName = process.env.SSM_PARAM_COMMITID;
32 | const ssms3KeyName = process.env.SSM_PARAM_S3_KEY;
33 | await setSsmParameter(ssmCommitIdName, commitId);
34 | await setSsmParameter(ssms3KeyName, key);
35 | await startPipeline(process.env.PIPELINE_NAME);
36 |
37 | return {
38 | body: JSON.stringify({message: 'Success!'}),
39 | statusCode: 200,
40 | };
41 | }
42 |
43 | async function setSsmParameter (paramName, paramValue){
44 | const params = {
45 | Name: paramName,
46 | Value: paramValue,
47 | Type: "String",
48 | Overwrite: true
49 | };
50 |
51 | try {
52 | await ssm.putParameter(params);
53 | console.log(`Parameter ${paramName} set to ${paramValue}`);
54 | } catch (err) {
55 | console.log(`Error setting parameter ${paramName}: ${err}`);
56 | throw err;
57 | }
58 |
59 | }
60 |
61 |
62 | async function startPipeline(pipelineName) {
63 |
64 | const params = {
65 | name: pipelineName
66 | };
67 |
68 | try {
69 | await codepipeline.startPipelineExecution(params);
70 | console.log(`Pipeline ${pipelineName} started`);
71 | } catch (err) {
72 | console.log(`Error starting pipeline ${pipelineName}: ${err}`);
73 | throw err;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/lambda/update_kvs/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | const {
18 | CloudFrontKeyValueStoreClient,
19 | DescribeKeyValueStoreCommand,
20 | PutKeyCommand,
21 | } = require("@aws-sdk/client-cloudfront-keyvaluestore");
22 |
23 | const {
24 | SignatureV4MultiRegion,
25 | } = require("@aws-sdk/signature-v4-multi-region");
26 | require("@aws-sdk/signature-v4-crt");
27 |
28 | const client = new CloudFrontKeyValueStoreClient({
29 | region: "us-east-1",
30 | signerConstructor: SignatureV4MultiRegion,
31 | });
32 |
33 | const kvsARN = process.env.KVS_ARN;
34 |
35 | async function updateKvs(path) {
36 | console.log("Get ETAG for KVS " + process.env.KVS_ARN);
37 |
38 | const { ETag } = await client.send(new DescribeKeyValueStoreCommand({ KvsARN: kvsARN }));
39 |
40 | console.log("Update KVS using ETAG " + ETag);
41 |
42 | await client.send(new PutKeyCommand({
43 | Key: "path",
44 | Value: path,
45 | KvsARN: kvsARN,
46 | IfMatch: ETag,
47 | }));
48 |
49 | console.log("KVS updated");
50 | }
51 |
52 | exports.handler = async (event, context) => {
53 | console.log("event=" + JSON.stringify(event));
54 |
55 | try {
56 | await updateKvs(event.commitId);
57 | return {};
58 |
59 | } catch (error) {
60 | console.error("Error updating KVS:", error);
61 | throw error;
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/lib/cfn_nag/cfn_nag_utils.ts:
--------------------------------------------------------------------------------
1 | /*********************************************************************************************************************
2 | * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. *
3 | * *
4 | * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance *
5 | * with the License. A copy of the License is located at *
6 | * *
7 | * http://www.apache.org/licenses/LICENSE-2.0 *
8 | * *
9 | * or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES *
10 | * OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions *
11 | * and limitations under the License. *
12 | *********************************************************************************************************************/
13 | import { CfnCondition, CfnResource, Resource } from "aws-cdk-lib";
14 |
15 | interface CfnNagSuppressRule {
16 | id: string;
17 | reason: string;
18 | }
19 |
20 | /**
21 | * Adds CFN NAG suppress rules to the CDK resource.
22 | * @param resource The CDK resource.
23 | * @param rules The CFN NAG suppress rules.
24 | */
25 | export function addCfnSuppressRules(
26 | resource: Resource | CfnResource | undefined,
27 | rules: CfnNagSuppressRule[]
28 | ) {
29 | if (typeof resource === "undefined") return;
30 |
31 | if (resource instanceof Resource) {
32 | resource = resource.node.defaultChild as CfnResource;
33 | }
34 |
35 | if (resource.cfnOptions.metadata?.cfn_nag?.rules_to_suppress) {
36 | resource.cfnOptions.metadata.cfn_nag.rules_to_suppress.push(...rules);
37 | } else {
38 | resource.addMetadata("cfn_nag", { rules_to_suppress: rules });
39 | }
40 | }
41 |
42 | /**
43 | * Adds CDK condition to the CDK resource.
44 | * @param resource The CDK resource.
45 | * @param condition The CDK condition.
46 | */
47 | export function addCfnCondition(
48 | resource: Resource | CfnResource | undefined,
49 | condition: CfnCondition
50 | ) {
51 | if (typeof resource === "undefined") return;
52 |
53 | if (resource instanceof Resource) {
54 | resource = resource.node.defaultChild as CfnResource;
55 | }
56 |
57 | (resource as CfnResource).cfnOptions.condition = condition;
58 | }
59 |
--------------------------------------------------------------------------------
/lib/deploy_type.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import { Construct } from "constructs";
18 | import { isRepoConfig, parseRepositoryUrl } from "../bin/cli/utils/helper";
19 | import { CfnOutput, Stack } from "aws-cdk-lib";
20 | import { HostingConfiguration } from "../bin/cli/shared/types";
21 | export class DeployType extends Construct {
22 | public readonly deployIdentifier: string;
23 | /**
24 | * Constructs a deployment stack based on the provided configuration.
25 | * Handles Git repository and S3 bucket deployment scenarios, setting up
26 | * deployment identifiers and CloudFormation outputs accordingly.
27 | * In case of incorrect configuration, logs an error and exits the process.
28 | *
29 | * @param stackConfig - Configuration object containing deployment details.
30 | */
31 | constructor(
32 | scope: Construct,
33 | id: string,
34 | hostingConfiguration: HostingConfiguration
35 | ) {
36 | //export function geteDeployIdentifier(stackConfig: IConfiguration) {
37 | super(scope, id);
38 |
39 | if (isRepoConfig(hostingConfiguration)) {
40 | const repoUrl = hostingConfiguration.repoUrl;
41 | const parsedUrl = parseRepositoryUrl(repoUrl as string);
42 | this.deployIdentifier = parsedUrl.repoOwner + " - " + parsedUrl.repoName + "-" + Stack.of(this).region;
43 |
44 | new CfnOutput(this, "Source", {
45 | value: hostingConfiguration.repoUrl,
46 | });
47 | } else if (hostingConfiguration.s3bucket) {
48 | this.deployIdentifier = hostingConfiguration.s3bucket;
49 |
50 | new CfnOutput(this, "Source", {
51 | value:
52 | hostingConfiguration.s3bucket + "/" + hostingConfiguration.s3path,
53 | });
54 | } else {
55 | console.log("Wrong configuration found. Exiting.");
56 | console.log(
57 | "Configuration found: " + JSON.stringify(hostingConfiguration)
58 | );
59 | process.exit(1);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/deployment_workflow_sf.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import {
18 | Aws,
19 | Duration,
20 | aws_iam as iam,
21 | aws_cloudfront as cloudfront,
22 | aws_stepfunctions as sfn,
23 | aws_lambda as lambda,
24 | aws_stepfunctions_tasks as tasks,
25 | aws_logs as logs,
26 | aws_ssm as ssm,
27 | RemovalPolicy,
28 | Stack,
29 | } from "aws-cdk-lib";
30 |
31 | import { Construct } from "constructs";
32 | import * as path from "path";
33 | import { IChainable, JsonPath, LogLevel } from "aws-cdk-lib/aws-stepfunctions";
34 | import { IBucket } from "aws-cdk-lib/aws-s3";
35 | import { addCfnSuppressRules } from "./cfn_nag/cfn_nag_utils";
36 | import { NagSuppressions } from "cdk-nag";
37 | import { LogGroup, RetentionDays } from "aws-cdk-lib/aws-logs";
38 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
39 | import { LayerVersion, Runtime, Tracing } from 'aws-cdk-lib/aws-lambda';
40 |
41 |
42 | interface IParamProps {
43 | changeUri: cloudfront.Function;
44 | kvsArn: string,
45 | hostingBucket: IBucket;
46 | ssmCommitIdParam?: ssm.StringParameter;
47 | ssmS3KeyParam?: ssm.StringParameter;
48 | }
49 |
50 |
51 | export class DeploymentWorkflowStepFunction extends Construct {
52 | public readonly stepFunction: sfn.IStateMachine;
53 |
54 | constructor(scope: Construct, id: string, params: IParamProps) {
55 | super(scope, id);
56 |
57 |
58 | const basicLambdaRole = new iam.Role(this, "BasicLambdaRole", {
59 | assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
60 | });
61 |
62 | const awsSdkLayer = new lambda.LayerVersion(this, "AwsSdkLayer", {
63 | compatibleRuntimes: [lambda.Runtime.NODEJS_20_X],
64 | code: lambda.Code.fromAsset(path.join(__dirname, "../lambda/layers/aws_sdk")),
65 | description: "AWS SDK lib including client-cloudfront-keyvaluestore",
66 | });
67 |
68 | const updateKvs = new lambda.Function(this, "UpdateKvsFunction", {
69 | runtime: lambda.Runtime.NODEJS_20_X,
70 | code: lambda.Code.fromAsset(path.join(__dirname, "../lambda/update_kvs")),
71 | handler: "index.handler",
72 | memorySize: 512,
73 | timeout: Duration.minutes(10),
74 | logRetention: logs.RetentionDays.ONE_WEEK,
75 | tracing: lambda.Tracing.ACTIVE,
76 | layers: [awsSdkLayer],
77 | environment: {
78 | KVS_ARN: params.kvsArn,
79 | },
80 | role: basicLambdaRole,
81 | });
82 |
83 |
84 | updateKvs.addToRolePolicy(
85 | new iam.PolicyStatement({
86 | effect: iam.Effect.ALLOW,
87 | actions: [
88 | "logs:CreateLogGroup",
89 | "logs:CreateLogStream",
90 | "logs:PutLogEvents",
91 | ],
92 | resources: ["arn:aws:logs:*:*:*"],
93 | })
94 | );
95 |
96 | updateKvs.addToRolePolicy(
97 | new iam.PolicyStatement({
98 | effect: iam.Effect.ALLOW,
99 | actions: [
100 | "cloudfront-keyvaluestore:DescribeKeyValueStore",
101 | "cloudfront-keyvaluestore:PutKey",
102 | ],
103 | resources: [params.kvsArn],
104 | })
105 | );
106 |
107 | addCfnSuppressRules(updateKvs, [
108 | {
109 | id: "W58",
110 | reason:
111 | "Lambda has CloudWatch permissions by using service role AWSLambdaBasicExecutionRole",
112 | },
113 | ]);
114 | addCfnSuppressRules(updateKvs, [
115 | {
116 | id: "W89",
117 | reason:
118 | "We don t have any VPC in the stack, we only use serverless services",
119 | },
120 | ]);
121 | addCfnSuppressRules(updateKvs, [
122 | {
123 | id: "W92",
124 | reason:
125 | "No need for ReservedConcurrentExecutions, some are used only for the demo website, and others are not used in a concurrent mode.",
126 | },
127 | ]);
128 |
129 | const deleteOldDeployments = new lambda.Function(
130 | this,
131 | "DeleteOldDeployments",
132 | {
133 | runtime: lambda.Runtime.NODEJS_18_X,
134 | code: lambda.Code.fromAsset(
135 | path.join(__dirname, "../lambda/delete_old_deployments")
136 | ),
137 | timeout: Duration.seconds(300),
138 | handler: "index.handler",
139 | environment: {
140 | BUCKET_NAME: params.hostingBucket.bucketName,
141 | },
142 | logRetention: logs.RetentionDays.ONE_WEEK,
143 | role: basicLambdaRole,
144 | }
145 | );
146 |
147 |
148 | deleteOldDeployments.addToRolePolicy(
149 | new iam.PolicyStatement({
150 | effect: iam.Effect.ALLOW,
151 | actions: [
152 | "logs:CreateLogGroup",
153 | "logs:CreateLogStream",
154 | "logs:PutLogEvents",
155 | ],
156 | resources: ["arn:aws:logs:*:*:*"],
157 | })
158 | );
159 |
160 | addCfnSuppressRules(deleteOldDeployments, [
161 | {
162 | id: "W58",
163 | reason:
164 | "Lambda has CloudWatch permissions by using service role AWSLambdaBasicExecutionRole",
165 | },
166 | ]);
167 | addCfnSuppressRules(deleteOldDeployments, [
168 | {
169 | id: "W89",
170 | reason:
171 | "We don t have any VPC in the stack, we only use serverless services",
172 | },
173 | ]);
174 | addCfnSuppressRules(deleteOldDeployments, [
175 | {
176 | id: "W92",
177 | reason:
178 | "No need for ReservedConcurrentExecutions, some are used only for the demo website, and others are not used in a concurrent mode.",
179 | },
180 | ]);
181 |
182 | params.hostingBucket.grantReadWrite(deleteOldDeployments);
183 |
184 | NagSuppressions.addResourceSuppressions(
185 | basicLambdaRole,
186 | [
187 | {
188 | id: "AwsSolutions-IAM5",
189 | reason: "Permissions to get objects and delete them is required",
190 | },
191 | ],
192 | true
193 | );
194 |
195 | const successState = new sfn.Pass(this, "SuccessState");
196 |
197 | const updateCloudFrontFunctionJob = new tasks.LambdaInvoke(
198 | this,
199 | "Update KeyValueStore",
200 | {
201 | lambdaFunction: updateKvs,
202 | resultPath: JsonPath.DISCARD,
203 | }
204 | );
205 |
206 | const deleteOldDeploymentsJob = new tasks.LambdaInvoke(
207 | this,
208 | "Purge previous deployments from S3",
209 | {
210 | lambdaFunction: deleteOldDeployments,
211 | resultPath: JsonPath.DISCARD,
212 | }
213 | );
214 |
215 |
216 | const communDefinition = updateCloudFrontFunctionJob
217 | .next(deleteOldDeploymentsJob);
218 |
219 | var stepFunctionDefinition: IChainable;
220 |
221 | if (params.ssmCommitIdParam) {
222 | const getCommitId = new tasks.CallAwsService(
223 | this,
224 | "Get CommitID from Parameter Store",
225 | {
226 | service: "ssm",
227 | action: "getParameter",
228 | parameters: {
229 | Name: params.ssmCommitIdParam.parameterName,
230 | },
231 | iamResources: [params.ssmCommitIdParam.parameterArn],
232 | iamAction: "ssm:getParameter",
233 | resultSelector: {
234 | commitId: sfn.JsonPath.stringAt("$.Parameter.Value"),
235 | },
236 | }
237 | );
238 |
239 | const ssmHasValue = new sfn.Choice(this, "SSM Param is SET ?")
240 | .when(sfn.Condition.stringEquals("$.commitId", "init"), successState)
241 | .otherwise(communDefinition);
242 |
243 | stepFunctionDefinition = getCommitId.next(ssmHasValue);
244 | } else {
245 | stepFunctionDefinition = communDefinition;
246 | }
247 |
248 | const sfnLog = new LogGroup(this, "sfnLog", {
249 | logGroupName:
250 | "/aws/vendedlogs/states/" + Stack.of(this).stackName,
251 | removalPolicy: RemovalPolicy.DESTROY,
252 | retention: RetentionDays.ONE_WEEK,
253 | });
254 |
255 | this.stepFunction = new sfn.StateMachine(this, "StaticHostingSF", {
256 | definitionBody : sfn.DefinitionBody.fromChainable(stepFunctionDefinition),
257 | tracingEnabled: true,
258 | logs: {
259 | destination: sfnLog,
260 | includeExecutionData: true,
261 | level: LogLevel.ALL,
262 | },
263 | });
264 |
265 | NagSuppressions.addResourceSuppressions(
266 | this.stepFunction,
267 | [
268 | {
269 | id: "AwsSolutions-IAM5",
270 | reason: "Required permissions for this Step Function",
271 | },
272 | ],
273 | true
274 | );
275 | }
276 | }
277 |
--------------------------------------------------------------------------------
/lib/hosting.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | Licensed under the Apache License, Version 2.0 (the "License").
4 | You may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 | http://www.apache.org/licenses/LICENSE-2.0
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | See the License for the specific language governing permissions and
11 | limitations under the License.
12 | */
13 | import {
14 | Aws,
15 | aws_cloudfront as cloudfront,
16 | aws_s3 as s3,
17 | Stack
18 | } from "aws-cdk-lib";
19 | import * as path from "path";
20 | import * as fs from "fs";
21 | import { Construct } from "constructs";
22 | import { HostingInfrastructure } from "./hosting_infrastructure";
23 | import { PipelineInfrastructure } from "./pipeline_infrastructure";
24 | import { HostingConfiguration } from "../bin/cli/shared/types";
25 | import { truncateString } from "./utility";
26 |
27 | interface IParamProps {
28 | hostingConfiguration: HostingConfiguration;
29 | buildFilePath: string;
30 | cffSourceFilePath: string;
31 | connectionArn?: string;
32 | certificateArn?: string;
33 | }
34 |
35 | /**
36 | * Custom CDK Construct for hosting resources.
37 | *
38 | * This construct sets up hosting based on the provided configuration,
39 | * build file path, and optional connection and certificate ARNs.
40 | *
41 | * @param scope - The Construct scope in which this construct is defined.
42 | * @param id - The identifier for this construct within the scope.
43 | * @param params - Parameters for configuring hosting resources.
44 | */
45 | export class Hosting extends Construct {
46 | /**
47 | * The CloudFront Distribution created by this construct.
48 | */
49 | public readonly distribution: cloudfront.Distribution;
50 |
51 | /**
52 | * The S3 Bucket used for hosting the content.
53 | */
54 | public readonly hostingBucket: s3.IBucket;
55 |
56 | /**
57 | * The CloudFront Function used for URI manipulation.
58 | */
59 | public readonly changeUriFunction: cloudfront.Function;
60 |
61 | /**
62 | * The Key-Value Store used by CloudFront.
63 | */
64 | public readonly uriStore: cloudfront.KeyValueStore;
65 |
66 | /**
67 | * The distribution's domain name.
68 | */
69 | public readonly distributionDomainName: string;
70 |
71 | /**
72 | * The distribution's URL (https://{domainName}).
73 | */
74 | public readonly distributionUrl: string;
75 |
76 | /**
77 | * Reference to the hosting infrastructure construct.
78 | */
79 | public readonly hostingInfrastructure: HostingInfrastructure;
80 |
81 | /**
82 | * Reference to the pipeline infrastructure construct.
83 | */
84 | public readonly pipelineInfrastructure: PipelineInfrastructure;
85 |
86 | constructor(scope: Construct, id: string, params: IParamProps) {
87 | super(scope, id);
88 |
89 | const stackName = Stack.of(this).stackName;
90 | const region = Stack.of(this).region;
91 |
92 | // Create URI Store
93 | this.uriStore = new cloudfront.KeyValueStore(this, 'UriStore', {
94 | keyValueStoreName: truncateString(stackName + "-" + region, 64)
95 | });
96 |
97 | // Setup CloudFront Function
98 | let cloudFrontFunctionCode = fs.readFileSync(params.cffSourceFilePath, 'utf-8');
99 | cloudFrontFunctionCode = cloudFrontFunctionCode.replace(/__KVS_ID__/g, this.uriStore.keyValueStoreId);
100 |
101 | this.changeUriFunction = new cloudfront.Function(this, "ChangeUri", {
102 | code: cloudfront.FunctionCode.fromInline(cloudFrontFunctionCode),
103 | runtime: cloudfront.FunctionRuntime.JS_2_0,
104 | comment: "Change uri",
105 | });
106 |
107 | (this.changeUriFunction.node.defaultChild as cloudfront.CfnFunction).addPropertyOverride(
108 | "FunctionConfig.KeyValueStoreAssociations",
109 | [{
110 | "KeyValueStoreARN": this.uriStore.keyValueStoreArn
111 | }]
112 | );
113 |
114 | // Create Hosting Infrastructure
115 | this.hostingInfrastructure = new HostingInfrastructure(this, "HostingInfrastructure", {
116 | changeUri: this.changeUriFunction,
117 | certificateArn: params.certificateArn,
118 | hostingConfiguration: params.hostingConfiguration,
119 | });
120 |
121 | // Set properties from hosting infrastructure
122 | this.distribution = this.hostingInfrastructure.distribution;
123 | this.hostingBucket = this.hostingInfrastructure.hostingBucket;
124 | this.distributionDomainName = this.distribution.distributionDomainName;
125 | this.distributionUrl = `https://${this.distributionDomainName}`;
126 |
127 | // Create Pipeline Infrastructure
128 | this.pipelineInfrastructure = new PipelineInfrastructure(this, "PipelineInfrastructure", {
129 | hostingConfiguration: params.hostingConfiguration,
130 | connectionArn: params.connectionArn,
131 | kvsArn: this.uriStore.keyValueStoreArn,
132 | hostingBucket: this.hostingBucket,
133 | changeUri: this.changeUriFunction,
134 | buildFilePath: params.buildFilePath,
135 | });
136 | }
137 | }
--------------------------------------------------------------------------------
/lib/hosting_stack.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import { Stack, StackProps } from "aws-cdk-lib";
18 |
19 | import { Construct } from "constructs";
20 | import { HostingConfiguration } from "../bin/cli/shared/types";
21 | import { Hosting } from "./hosting";
22 |
23 | interface IParamProps {
24 | hostingConfiguration: HostingConfiguration;
25 | buildFilePath: string;
26 | cffSourceFilePath: string;
27 | connectionArn?: string;
28 | certificateArn?: string;
29 | }
30 |
31 | export class HostingStack extends Stack {
32 | public readonly hosting: Hosting;
33 | constructor(
34 | scope: Construct,
35 | id: string,
36 | params: IParamProps,
37 | props?: StackProps
38 | ) {
39 | super(scope, id, props);
40 |
41 | this.hosting = new Hosting(this, "Hosting", params);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/index.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | import { Construct } from "constructs";
17 |
18 | export * from './hosting';
19 | export * from './repository_connection';
20 |
--------------------------------------------------------------------------------
/lib/repository_connection.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Stack,
3 | StackProps,
4 | aws_cloudfront as cloudfront,
5 | aws_ssm as ssm,
6 | CfnOutput,
7 | Aws,
8 | aws_codestarconnections as codestarconnections,
9 | } from "aws-cdk-lib";
10 |
11 | import { Construct } from "constructs";
12 | import {
13 | calculateCodeStarConnectionStackName,
14 | calculateConnectionStackName,
15 | isRepoConfig,
16 | parseRepositoryUrl,
17 | } from "../bin/cli/utils/helper";
18 | import {
19 | SSM_CONNECTION_ARN_STR,
20 | SSM_CONNECTION_NAME_STR,
21 | SSM_CONNECTION_REGION_STR,
22 | } from "../bin/cli/shared/constants";
23 | import { HostingConfiguration } from "../bin/cli/shared/types";
24 |
25 | /**
26 | * Custom CDK Construct for setting up a repository connection.
27 | *
28 | * This construct creates a connection to a hosting repository using the provided configuration.
29 | *
30 | * @param scope - The Construct scope in which this construct is defined.
31 | * @param id - The identifier for this construct within the scope.
32 | * @param params - Parameters for configuring the repository connection.
33 | * - `repoUrl` (optional): The URL of the hosting repository.
34 | * - `branchName` (optional): The name of the branch in the repository.
35 | * - `framework` (optional): The framework used for hosting.
36 | * - `s3bucket` (optional): The name of the Amazon S3 bucket for hosting content.
37 | * - `s3path` (optional): The path within the S3 bucket where content is stored.
38 | * - `domainName` (optional): The domain name associated with the hosting.
39 | * - `hostedZoneId` (optional): The ID of the Route 53 hosted zone associated with the domain.
40 | */
41 | export class RepositoryConnection extends Construct {
42 | public readonly connectionArn: string;
43 | public readonly repoUrl: string;
44 |
45 | constructor(
46 | scope: Construct,
47 | id: string,
48 | hostingConfiguration: HostingConfiguration
49 | ) {
50 | super(scope, id);
51 |
52 | if (isRepoConfig(hostingConfiguration)) {
53 | const repoUrl = hostingConfiguration.repoUrl;
54 | const parsedUrl = parseRepositoryUrl(repoUrl as string);
55 |
56 | if (parsedUrl) {
57 | const { repoName } = parsedUrl;
58 | const conn = new codestarconnections.CfnConnection(
59 | this,
60 | "MyCfnConnection" + repoName,
61 | {
62 | connectionName: calculateCodeStarConnectionStackName(
63 | hostingConfiguration.repoUrl,
64 | hostingConfiguration.branchName
65 | ),
66 | providerType: "GitHub",
67 | }
68 | );
69 |
70 | this.connectionArn = conn.attrConnectionArn;
71 | this.repoUrl = hostingConfiguration.repoUrl;
72 |
73 | new CfnOutput(this, "ConnectionArn", {
74 | value: conn.attrConnectionArn,
75 | });
76 |
77 | new CfnOutput(this, "ConnectionName", {
78 | value: conn.connectionName,
79 | });
80 |
81 | const stackName = calculateConnectionStackName(
82 | hostingConfiguration.repoUrl,
83 | hostingConfiguration.branchName
84 | );
85 |
86 | new ssm.StringParameter(this, "SSMConnectionArn", {
87 | parameterName: "/" + stackName + "/" + SSM_CONNECTION_ARN_STR,
88 | stringValue: conn.attrConnectionArn,
89 | });
90 | new ssm.StringParameter(this, "SSMConnectionName", {
91 | parameterName: "/" + stackName + "/" + SSM_CONNECTION_NAME_STR,
92 | stringValue: conn.connectionName,
93 | });
94 |
95 | new ssm.StringParameter(this, "SSMConnectionRegion", {
96 | parameterName: "/" + stackName + "/" + SSM_CONNECTION_REGION_STR,
97 | stringValue: Aws.REGION,
98 | });
99 | }
100 | } else {
101 | // Handle case where the URL did not match the expected format
102 | console.log(`The configuration for repository URL is invalid, exiting.`);
103 | process.exit(0);
104 | }
105 | new CfnOutput(this, "HostingRegion", {
106 | value: Aws.REGION,
107 | });
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/lib/repository_stack.ts:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License").
5 | You may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import {
18 | Stack,
19 | StackProps,
20 | } from "aws-cdk-lib";
21 |
22 | import { Construct } from "constructs";
23 |
24 | import { RepositoryConnection } from "./repository_connection";
25 | import { HostingConfiguration } from "../bin/cli/shared/types";
26 |
27 | export class RepositoryStack extends Stack {
28 | public readonly repositoryConnection: RepositoryConnection;
29 |
30 | constructor(
31 | scope: Construct,
32 | id: string,
33 | hostingConfiguration: HostingConfiguration,
34 | props?: StackProps
35 | ) {
36 | super(scope, id, props);
37 |
38 | this.repositoryConnection = new RepositoryConnection(this, "RepositoryConnection", hostingConfiguration);
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/utility.ts:
--------------------------------------------------------------------------------
1 | export function truncateString(inputString: string, maxLength: number): string {
2 | if (inputString.length <= maxLength) {
3 | // No need to truncate, the string is already within the specified length
4 | return inputString;
5 | } else {
6 | // Truncate the string
7 | return inputString.substring(0, maxLength);
8 | }
9 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@aws/cloudfront-hosting-toolkit",
3 | "version": "1.1.22",
4 | "description": "CloudFront Hosting Toolkit offers the convenience of a managed frontend hosting service while retaining full control over the hosting and deployment infrastructure to make it your own.",
5 | "license": "Apache-2.0",
6 | "bin": {
7 | "cloudfront-hosting-toolkit": "./bin/cli/index.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/awslabs/cloudfront-hosting-toolkit"
12 | },
13 | "main": "lib/index.js",
14 | "types": "lib/index.d.ts",
15 | "homepage": "https://github.com/awslabs/cloudfront-hosting-toolkit",
16 | "keywords": [
17 | "AWS",
18 | "NextJs",
19 | "ReactJs",
20 | "AngularJs",
21 | "VueJs",
22 | "hosting",
23 | "static website",
24 | "infrastructure",
25 | "deployment",
26 | "automation",
27 | "awscdk"
28 | ],
29 | "author": "Corneliu Croitoru",
30 | "scripts": {
31 | "build": "tsc",
32 | "watch": "tsc -w",
33 | "clean": "rm -rf node_modules/ dist/ coverage/ package-lock.json",
34 | "audit": "npm audit && cdk synth | cfn_nag",
35 | "cloudfront-hosting-toolkit": "node bin/cli/index.js",
36 | "test": "jest --coverage",
37 | "zipfile": "node scripts/createDummyZip.js",
38 | "postinstall": "cd lambda/layers/aws_sdk/nodejs && npm install && cd ../../../.. && npm run zipfile",
39 | "postversion": "git push && git push --tags"
40 | },
41 | "devDependencies": {
42 | "@types/archiver": "5.3.2",
43 | "@types/aws-lambda": "^8.10.133",
44 | "@types/glob": "8.1.0",
45 | "@types/jest": "^29.5.5",
46 | "@types/node": "20.5.9",
47 | "@types/prompts": "2.4.4",
48 | "aws-cdk": "2.163.1",
49 | "aws-sdk-client-mock": "^3.0.0",
50 | "esbuild": "^0.20.0",
51 | "jest": "^29.7.0",
52 | "ts-jest": "^29.1.1",
53 | "ts-node": "10.9.1",
54 | "typescript": "^5.2.2"
55 | },
56 | "dependencies": {
57 | "@aws-lambda-powertools/logger": "^1.18.0",
58 | "@aws-lambda-powertools/tracer": "^1.18.0",
59 | "@aws-sdk/client-acm": "^3.484.0",
60 | "@aws-sdk/client-cloudfront": "^3.484.0",
61 | "@aws-sdk/client-cloudfront-keyvaluestore": "^3.484.0",
62 | "@aws-sdk/client-codepipeline": "^3.484.0",
63 | "@aws-sdk/client-codestar-connections": "^3.484.0",
64 | "@aws-sdk/client-route-53": "^3.484.0",
65 | "@aws-sdk/client-route-53-domains": "^3.484.0",
66 | "@aws-sdk/client-s3": "^3.484.0",
67 | "@aws-sdk/client-ssm": "^3.484.0",
68 | "@aws-sdk/client-sts": "^3.484.0",
69 | "@aws-sdk/config-resolver": "^3.374.0",
70 | "@aws-sdk/node-config-provider": "^3.374.0",
71 | "@aws-sdk/types": "^3.484.0",
72 | "adm-zip": "^0.5.10",
73 | "aws-cdk": "^2.163.1",
74 | "aws-cdk-lib": "^2.163.1",
75 | "aws-crt": "^1.20.1",
76 | "cdk-nag": "^2.27.129",
77 | "cli-progress": "^3.12.0",
78 | "constructs": "^10.2.70",
79 | "esbuild": "^0.20.0",
80 | "glob": "^10.3.4",
81 | "joi": "^17.10.1",
82 | "prompts": "^2.4.2",
83 | "source-map-support": "^0.5.21",
84 | "ts-node": "^10.9.1",
85 | "yaml": "^2.3.2",
86 | "yargs": "^17.7.2"
87 | },
88 | "preferGlobal": true
89 | }
90 |
--------------------------------------------------------------------------------
/resources/build_config_templates/hosting_angularjs.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - aws --version
7 | - node -v
8 | - ls
9 | - npm install
10 | - npm install -g @angular/cli
11 | - ng build
12 | - cd dist/static-frontend-angularjs
13 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
14 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/resources/build_config_templates/hosting_basic.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
7 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/resources/build_config_templates/hosting_nextjs.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - n install 18.18.0
7 | - npx npm install
8 | - npx next build
9 | - cd out
10 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
11 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
12 |
13 |
--------------------------------------------------------------------------------
/resources/build_config_templates/hosting_reactjs.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - npx npm install
7 | - npx npm run build
8 | - cd build
9 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
10 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/resources/build_config_templates/hosting_vuejs.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | build:
5 | commands:
6 | - npx npm install
7 | - npx npm run build
8 | - cd dist
9 | - echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
10 | - aws s3 cp ./ s3://$DEST_BUCKET_NAME/$CODEBUILD_RESOLVED_SOURCE_VERSION/ --recursive #don't change this line
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/resources/build_config_templates/s3_build_config.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 | env:
3 | parameter-store:
4 | COMMITID: $SSM_PARAM_COMMITID
5 | S3KEY: $SSM_PARAM_S3_KEY
6 | phases:
7 | build:
8 | commands:
9 | - |
10 | if [ "$COMMITID" = "init" ] && [ "$S3KEY" = "init" ]; then
11 | echo "No zip, this must be the first execution of the pipeline after infrastructure deployment"
12 | else
13 | mkdir temp
14 | aws s3 cp s3://$SRC_BUCKET_NAME/$S3KEY ./temp
15 | cd temp && ls
16 | unzip *.zip
17 | rm *.zip
18 | echo aws s3 cp ./ s3://$DEST_BUCKET_NAME/$COMMITID/ --recursive #don't change this line
19 | aws s3 cp ./ s3://$DEST_BUCKET_NAME/$COMMITID/ --recursive #don't change this line
20 | fi
21 |
--------------------------------------------------------------------------------
/resources/cff_templates/index_angularjs.js:
--------------------------------------------------------------------------------
1 | import cf from 'cloudfront';
2 |
3 | const kvsId = '__KVS_ID__';
4 |
5 | // This fails if the key value store is not associated with the function
6 | const kvsHandle = cf.kvs(kvsId);
7 |
8 | // Function to update the URI to point to index.html
9 | async function updateURI(uri) {
10 | let pathToAdd = "";
11 |
12 | try {
13 | pathToAdd = await kvsHandle.get("path");
14 | } catch (err) {
15 | console.log(`No key 'path' present: ${err}`);
16 | return uri;
17 | }
18 |
19 | // Always return index.html
20 | return `/${pathToAdd}/index.html`;
21 | }
22 |
23 |
24 | // Main CloudFront handler
25 | async function handler(event) {
26 | var request = event.request;
27 | var uri = request.uri;
28 |
29 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
30 | request.uri = await updateURI(uri);
31 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
32 |
33 | return request;
34 | }
35 |
--------------------------------------------------------------------------------
/resources/cff_templates/index_basic.js:
--------------------------------------------------------------------------------
1 | import cf from 'cloudfront';
2 |
3 | const kvsId = '__KVS_ID__';
4 |
5 | // This fails if the key value store is not associated with the function
6 | const kvsHandle = cf.kvs(kvsId);
7 |
8 | function pointsToFile(uri) {
9 | return /\/[^/]+\.[^/]+$/.test(uri);
10 | }
11 | var rulePatterns = {
12 | "/$": "/index.html", // When URI ends with a '/', append 'index.html'
13 | "!file": ".html", // When URI doesn't point to a specific file and doesn't have a trailing slash, append '.html'
14 | "!file/": "/index.html",// When URI has a trailing slash and doesn't point to a specific file, append 'index.html'
15 | };
16 |
17 | // Function to determine rule and update the URI
18 | async function updateURI(uri) {
19 |
20 | let pathToAdd = "";
21 |
22 | try {
23 | pathToAdd = await kvsHandle.get("path");
24 | } catch (err) {
25 | console.log(`No key 'path' present : ${err}`);
26 | return uri;
27 | }
28 |
29 | // Check for trailing slash and apply rule.
30 | if (uri.endsWith("/") && rulePatterns["/$"]) {
31 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["/$"];
32 | }
33 |
34 | // Check if URI doesn't point to a specific file.
35 | if (!pointsToFile(uri)) {
36 | // If URI doesn't have a trailing slash, apply rule.
37 | if (!uri.endsWith("/") && rulePatterns["!file"]) {
38 | return "/" + pathToAdd + uri + rulePatterns["!file"];
39 | }
40 |
41 | // If URI has a trailing slash, apply rule.
42 | if (uri.endsWith("/") && rulePatterns["!file/"]) {
43 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["!file/"];
44 | }
45 | }
46 |
47 | return "/" + pathToAdd + uri;
48 | }
49 |
50 | // Main CloudFront handler
51 | async function handler(event) {
52 | var request = event.request;
53 | var uri = request.uri;
54 |
55 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
56 | request.uri = await updateURI(uri);
57 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
58 |
59 |
60 |
61 | return request;
62 | }
63 |
--------------------------------------------------------------------------------
/resources/cff_templates/index_nextjs.js:
--------------------------------------------------------------------------------
1 | import cf from 'cloudfront';
2 |
3 | const kvsId = '__KVS_ID__';
4 |
5 | // This fails if the key value store is not associated with the function
6 | const kvsHandle = cf.kvs(kvsId);
7 |
8 | function pointsToFile(uri) {
9 | return /\/[^/]+\.[^/]+$/.test(uri);
10 | }
11 | var rulePatterns = {
12 | "/$": "/index.html", // When URI ends with a '/', append 'index.html'
13 | "!file": ".html", // When URI doesn't point to a specific file and doesn't have a trailing slash, append '.html'
14 | "!file/": "/index.html",// When URI has a trailing slash and doesn't point to a specific file, append 'index.html'
15 | };
16 |
17 | // Function to determine rule and update the URI
18 | async function updateURI(uri) {
19 |
20 | let pathToAdd = "";
21 |
22 | try {
23 | pathToAdd = await kvsHandle.get("path");
24 | } catch (err) {
25 | console.log(`No key 'path' present : ${err}`);
26 | return uri;
27 | }
28 |
29 | // Check for trailing slash and apply rule.
30 | if (uri.endsWith("/") && rulePatterns["/$"]) {
31 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["/$"];
32 | }
33 |
34 | // Check if URI doesn't point to a specific file.
35 | if (!pointsToFile(uri)) {
36 | // If URI doesn't have a trailing slash, apply rule.
37 | if (!uri.endsWith("/") && rulePatterns["!file"]) {
38 | return "/" + pathToAdd + uri + rulePatterns["!file"];
39 | }
40 |
41 | // If URI has a trailing slash, apply rule.
42 | if (uri.endsWith("/") && rulePatterns["!file/"]) {
43 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["!file/"];
44 | }
45 | }
46 |
47 | return "/" + pathToAdd + uri;
48 | }
49 |
50 | // Main CloudFront handler
51 | async function handler(event) {
52 | var request = event.request;
53 | var uri = request.uri;
54 |
55 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
56 | request.uri = await updateURI(uri);
57 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
58 |
59 |
60 |
61 | return request;
62 | }
63 |
--------------------------------------------------------------------------------
/resources/cff_templates/index_reactjs.js:
--------------------------------------------------------------------------------
1 | import cf from 'cloudfront';
2 |
3 | const kvsId = '__KVS_ID__';
4 |
5 | // This fails if the key value store is not associated with the function
6 | const kvsHandle = cf.kvs(kvsId);
7 |
8 | function pointsToFile(uri) {
9 | return /\/[^/]+\.[^/]+$/.test(uri);
10 | }
11 |
12 | // Function to update the URI to point to index.html
13 | async function updateURI(uri) {
14 | try {
15 | const pathToAdd = await kvsHandle.get("path");
16 |
17 | if (!pointsToFile(uri)) {
18 | return `/${pathToAdd}/index.html`;
19 | }
20 |
21 | return `/${pathToAdd}${uri}`;
22 |
23 | } catch (err) {
24 | console.log(`No key 'path' present: ${err}`);
25 | return uri;
26 | }
27 | }
28 |
29 |
30 |
31 | // Main CloudFront handler
32 | async function handler(event) {
33 | var request = event.request;
34 | var uri = request.uri;
35 |
36 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
37 | request.uri = await updateURI(uri);
38 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
39 |
40 |
41 |
42 | return request;
43 | }
44 |
--------------------------------------------------------------------------------
/resources/cff_templates/index_vuejs.js:
--------------------------------------------------------------------------------
1 | import cf from 'cloudfront';
2 |
3 | const kvsId = '__KVS_ID__';
4 |
5 | // This fails if the key value store is not associated with the function
6 | const kvsHandle = cf.kvs(kvsId);
7 |
8 | function pointsToFile(uri) {
9 | return /\/[^/]+\.[^/]+$/.test(uri);
10 | }
11 | var rulePatterns = {
12 | "/$": "/index.html", // When URI ends with a '/', append 'index.html'
13 | "!file": ".html", // When URI doesn't point to a specific file and doesn't have a trailing slash, append '.html'
14 | "!file/": "/index.html",// When URI has a trailing slash and doesn't point to a specific file, append 'index.html'
15 | };
16 |
17 | // Function to determine rule and update the URI
18 | async function updateURI(uri) {
19 |
20 | let pathToAdd = "";
21 |
22 | try {
23 | pathToAdd = await kvsHandle.get("path");
24 | } catch (err) {
25 | console.log(`No key 'path' present : ${err}`);
26 | return uri;
27 | }
28 |
29 | // Check for trailing slash and apply rule.
30 | if (uri.endsWith("/") && rulePatterns["/$"]) {
31 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["/$"];
32 | }
33 |
34 | // Check if URI doesn't point to a specific file.
35 | if (!pointsToFile(uri)) {
36 | // If URI doesn't have a trailing slash, apply rule.
37 | if (!uri.endsWith("/") && rulePatterns["!file"]) {
38 | return "/" + pathToAdd + uri + rulePatterns["!file"];
39 | }
40 |
41 | // If URI has a trailing slash, apply rule.
42 | if (uri.endsWith("/") && rulePatterns["!file/"]) {
43 | return "/" + pathToAdd + uri.slice(0, -1) + rulePatterns["!file/"];
44 | }
45 | }
46 |
47 | return "/" + pathToAdd + uri;
48 | }
49 |
50 | // Main CloudFront handler
51 | async function handler(event) {
52 | var request = event.request;
53 | var uri = request.uri;
54 |
55 | //console.log("URI BEFORE: " + request.uri); // Uncomment if needed
56 | request.uri = await updateURI(uri);
57 | //console.log("URI AFTER: " + request.uri); // Uncomment if needed
58 |
59 |
60 |
61 | return request;
62 | }
63 |
--------------------------------------------------------------------------------
/resources/initial_repository/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Your website is currently being deployed
8 |
16 |
17 |
18 |
19 |
Deployment status
20 |
21 |
Please note that your are currently seeing this screen because this is the first deployment of the website. So, just take it easy and unwind, the page will automatically refresh on its own.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/resources/initial_s3/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Your website is currently being deployed
8 |
16 |
17 |
18 |
19 |
Deployment status
20 |
21 |
Please note that you are currently seeing this screen either because no zip file has been uploaded to your S3 bucket yet, or because the deployment is currently in progress. Please be patient and the page will automatically refresh once the deployment is complete.