What's the answer to today's increasingly complex web applications? Micro-frontends. Inspired by the microservices model, this approach lets you break interfaces into separate features managed by different teams of developers. With this practical guide, Luca Mezzalira shows software architects, tech leads, and software developers how to build and deliver artifacts atomically rather than use a big bang deployment.
43 |
44 | You'll learn how micro-frontends enable your team to choose any library or framework. This gives your organization technical flexibility and allows you to hire and retain a broad spectrum of talent. Micro-frontends also support distributed or colocated teams more efficiently. Pick up this book and learn how to get started with this technological breakthrough right away.
45 |
46 |
Explore available frontend development architectures
47 |
Learn how microservice principles apply to frontend development
48 |
Understand the four pillars for creating a successful micro-frontend architecture
49 |
Examine the benefits and pitfalls of existing micro-frontend architectures
50 |
Learn principles and best practices for creating successful automation strategies
51 |
Discover patterns for integrating micro-frontend architectures using microservices or a monolith API layer
52 |
`
53 | }
54 | };
55 |
56 | try {
57 | const res = await ddbDocClient.put(postBookParams);
58 | response = await axios.put(ResponseURL, buildResponse(event, context, "SUCCESS"))
59 |
60 | } catch (error) {
61 | console.error("error adding product details in DDB from custom resource", error);
62 | response = await axios.put(ResponseURL, buildResponse(event, context, "FAILED"))
63 | }
64 | } else {
65 |
66 | response = await axios.put(ResponseURL, buildResponse(event, context, "SUCCESS"))
67 |
68 | }
69 |
70 | return response
71 |
72 | }
--------------------------------------------------------------------------------
/SSR-catalog-example/ui-composer/src/utils/mfe-loader.js:
--------------------------------------------------------------------------------
1 | const { LambdaClient, InvokeCommand, InvocationType } = require("@aws-sdk/client-lambda");
2 | const { SFNClient, StartSyncExecutionCommand } = require("@aws-sdk/client-sfn");
3 | const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
4 | const axios = require('axios');
5 |
6 | // const localdev = {
7 | // credentials: {
8 | // accessKeyId: "xxx",
9 | // secretAccessKey: "xxx"
10 | // },
11 | // region: "eu-west-1"
12 | // }
13 |
14 | const loadFromURL = async (url, payload = {}) => {
15 | let res
16 |
17 | try {
18 | res = await axios.get(url, payload)
19 | } catch (error) {
20 | throw new Error(`Error loading ${url} ! details ${error}`)
21 | }
22 |
23 | return {
24 | statusCode: res.status,
25 | body: res.data
26 | }
27 | }
28 | const loadFromStepFunction = async (arn, payload = {}) => {
29 | try {
30 | // const client = new SFNClient(localdev);
31 | const client = new SFNClient();
32 | const command = new StartSyncExecutionCommand({
33 | stateMachineArn: arn,
34 | index: JSON.stringify(payload)
35 | });
36 |
37 | const sfnResponse = await client.send(command);
38 |
39 | if(sfnResponse.status === "SUCCEEDED"){
40 | const data = {
41 | statusCode: 200,
42 | body: JSON.parse(sfnResponse.output)
43 | }
44 | return data
45 | } else {
46 | throw new Error(`${arn} called but error ${sfnResponse.status}`);
47 | }
48 |
49 | } catch (error) {
50 | throw new Error(`Error for ${arn} step function called! details ${error}`);
51 | }
52 | }
53 | const loadFromLambda = async (arn, payload = {}) => {
54 | try {
55 | // const lambdaClient = new LambdaClient(localdev);
56 | const lambdaClient = new LambdaClient();
57 | const invokeCommand = new InvokeCommand({
58 | FunctionName: arn,
59 | InvocationType: InvocationType.RequestResponse,
60 | Payload: JSON.stringify(payload),
61 | });
62 |
63 | const response = await lambdaClient.send(invokeCommand);
64 |
65 | if(response.StatusCode < 400){
66 | const payload = Buffer.from(response.Payload).toString();
67 | const data = {
68 | statusCode: response.StatusCode,
69 | body: JSON.parse(payload).body
70 | }
71 | return data;
72 | } else {
73 | throw new Error(`${arn} called but error ${response.StatusCode}`);
74 | }
75 | } catch (error) {
76 | throw new Error(`Error for ${arn} function called! details ${error}`);
77 | }
78 | }
79 |
80 | const loadFromS3 = async (key, bucket) => {
81 |
82 | // const client = new S3Client(localdev);
83 | const client = new S3Client();
84 |
85 | try {
86 | const command = new GetObjectCommand({
87 | Key: key,
88 | Bucket: bucket
89 | });
90 |
91 | const response = await client.send(command);
92 | const stream = response.Body;
93 |
94 | return new Promise((resolve, reject) => {
95 | const chunks = []
96 | stream.on('data', chunk => chunks.push(chunk))
97 | stream.once('end', () => resolve(Buffer.concat(chunks).toString()))
98 | stream.once('error', reject)
99 | })
100 | } catch (error) {
101 | console.error(error)
102 | }
103 |
104 | }
105 |
106 | module.exports = {
107 | loadFromURL,
108 | loadFromStepFunction,
109 | loadFromLambda,
110 | loadFromS3
111 | }
--------------------------------------------------------------------------------
/SSR-catalog-example/ui-composer/src/utils/html-transformer.js:
--------------------------------------------------------------------------------
1 | const { parse } = require('node-html-parser');
2 | const { SSMClient, GetParametersCommand } = require("@aws-sdk/client-ssm");
3 | const behaviour = require('../errorBehaviours');
4 | const {loadFromURL, loadFromStepFunction, loadFromLambda} = require("./mfe-loader");
5 |
6 | const APP = "ssr-mfe";
7 | const ARN = "ARN";
8 |
9 | const STEP_FUNCTION = "stepfunction";
10 | const LAMBDA = "lambda";
11 | const URL = "url";
12 |
13 | const getMfeVO = (id, errorBehaviour, loader) => {
14 |
15 | if(!id || !loader)
16 | throw new Error("MFE tag not configured correctly, ID and loader must be defined")
17 |
18 | if(!errorBehaviour)
19 | errorBehaviour = behaviour.HIDE;
20 |
21 | const ssmKey = `/${APP}/${id}${ARN}`;
22 | let chosenLoader;
23 |
24 | switch(loader.toLowerCase()){
25 | case STEP_FUNCTION:
26 | chosenLoader = loadFromStepFunction
27 | break;
28 | case LAMBDA:
29 | chosenLoader = loadFromLambda
30 | break;
31 | case URL:
32 | chosenLoader = loadFromURL
33 | break;
34 | default:
35 | throw new Error("loader not recognised")
36 | }
37 |
38 | return {
39 | id:id,
40 | ssmKey: ssmKey,
41 | errorBehaviour: errorBehaviour,
42 | loader: chosenLoader,
43 | service: "",
44 | }
45 | }
46 |
47 | const getMfeElements = (root) => {
48 | return root.querySelectorAll("micro-frontend") || [];
49 | }
50 |
51 | const analyseMFEresponse = (response, behaviour) => {
52 | let html = "";
53 |
54 | if(response.status !== "fulfilled"){
55 | switch (behaviour) {
56 | case behaviour.ERROR:
57 | throw new Error()
58 | case behaviour.HIDE:
59 | default:
60 | html = ""
61 | break;
62 | }
63 | } else {
64 | html = response.value.body
65 | }
66 |
67 | return html;
68 | }
69 |
70 | const getServices = async (mfeList) => {
71 | const list = mfeList
72 |
73 | const ssmKeys = list.map(element => element.ssmKey)
74 |
75 | const client = new SSMClient({ region: process.env.REGION });
76 |
77 | const paramCommand = new GetParametersCommand({
78 | Names: ssmKeys
79 | })
80 |
81 | try {
82 | const servicesList = await client.send(paramCommand);
83 | servicesList.Parameters.forEach((element, index) => list[index].service = element.Value);
84 | return list;
85 | } catch (err) {
86 | console.log("error to get params from SSM", err)
87 | throw new Error(err);
88 | }
89 |
90 | }
91 |
92 | const transformTemplate = async (html) => {
93 | try{
94 | const root = parse(html);
95 | const mfeElements = getMfeElements(root);
96 | let mfeList = [];
97 |
98 | // generate VOs for MFEs available in a template
99 |
100 | if(mfeElements.length > 0) {
101 | mfeElements.forEach(element => {
102 | mfeList.push(
103 | getMfeVO(
104 | element.getAttribute("id"),
105 | element.getAttribute("errorbehaviour"),
106 | element.getAttribute("loader")
107 | )
108 | )
109 | });
110 | } else {
111 | return ""
112 | }
113 |
114 | // retrieve service to call in Parameter Store
115 |
116 | mfeList = await getServices(mfeList);
117 |
118 | // retrieve HTML fragments
119 |
120 | const fragmentsResponses = await Promise.allSettled(mfeList.map(element => element.loader(element.service)))
121 |
122 | // analyse responses
123 |
124 | const mfeToRender = fragmentsResponses.map((element, index) => analyseMFEresponse(element, mfeList[index].errorBehaviour))
125 |
126 | // transclusion in the template
127 |
128 | mfeElements.forEach((element, index) => element.replaceWith(mfeToRender[index]))
129 |
130 | return root.toString();
131 |
132 | } catch(error) {
133 | console.error("page generation failed", error)
134 | }
135 |
136 | }
137 |
138 | module.exports = {
139 | transformTemplate
140 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | !jest.config.js
3 | *.d.ts
4 | node_modules
5 |
6 | # CDK asset staging directory
7 | .cdk.staging
8 | cdk.out
9 |
10 | ### build ###
11 | client-build
12 | server-build
13 |
14 | ### Linux ###
15 | *~
16 |
17 | # temporary files which can be created if a process still has a handle open of a deleted file
18 | .fuse_hidden*
19 |
20 | # KDE directory preferences
21 | .directory
22 |
23 | # Linux trash folder which might appear on any partition or disk
24 | .Trash-*
25 |
26 | # .nfs files are created when an open file is removed but is still being accessed
27 | .nfs*
28 |
29 | ### Node ###
30 | # Logs
31 | logs
32 | *.log
33 | npm-debug.log*
34 | yarn-debug.log*
35 | yarn-error.log*
36 | lerna-debug.log*
37 |
38 | # Diagnostic reports (https://nodejs.org/api/report.html)
39 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
40 |
41 | # Runtime data
42 | pids
43 | *.pid
44 | *.seed
45 | *.pid.lock
46 |
47 | # Directory for instrumented libs generated by jscoverage/JSCover
48 | lib-cov
49 |
50 | # Coverage directory used by tools like istanbul
51 | coverage
52 | *.lcov
53 |
54 | # nyc test coverage
55 | .nyc_output
56 |
57 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
58 | .grunt
59 |
60 | # Bower dependency directory (https://bower.io/)
61 | bower_components
62 |
63 | # node-waf configuration
64 | .lock-wscript
65 |
66 | # Compiled binary addons (https://nodejs.org/api/addons.html)
67 | build/Release
68 |
69 | # Dependency directories
70 | node_modules/
71 | jspm_packages/
72 |
73 | # TypeScript v1 declaration files
74 | typings/
75 |
76 | # TypeScript cache
77 | *.tsbuildinfo
78 |
79 | # Optional npm cache directory
80 | .npm
81 |
82 | # Optional eslint cache
83 | .eslintcache
84 |
85 | # Optional stylelint cache
86 | .stylelintcache
87 |
88 | # Microbundle cache
89 | .rpt2_cache/
90 | .rts2_cache_cjs/
91 | .rts2_cache_es/
92 | .rts2_cache_umd/
93 |
94 | # Optional REPL history
95 | .node_repl_history
96 |
97 | # Output of 'npm pack'
98 | *.tgz
99 |
100 | # Yarn Integrity file
101 | .yarn-integrity
102 |
103 | # dotenv environment variables file
104 | .env
105 | .env.test
106 | .env*.local
107 |
108 | # parcel-bundler cache (https://parceljs.org/)
109 | .cache
110 | .parcel-cache
111 |
112 | # Next.js build output
113 | .next
114 |
115 | # Nuxt.js build / generate output
116 | .nuxt
117 | dist
118 |
119 | # Storybook build outputs
120 | .out
121 | .storybook-out
122 | storybook-static
123 |
124 | # rollup.js default build output
125 | dist/
126 |
127 | # Gatsby files
128 | .cache/
129 | # Comment in the public line in if your project uses Gatsby and not Next.js
130 | # https://nextjs.org/blog/next-9-1#public-directory-support
131 | # public
132 |
133 | # vuepress build output
134 | .vuepress/dist
135 |
136 | # Serverless directories
137 | .serverless/
138 |
139 | # FuseBox cache
140 | .fusebox/
141 |
142 | # DynamoDB Local files
143 | .dynamodb/
144 |
145 | # TernJS port file
146 | .tern-port
147 |
148 | # Stores VSCode versions used for testing VSCode extensions
149 | .vscode-test
150 |
151 | # Temporary folders
152 | tmp/
153 | temp/
154 |
155 | ### OSX ###
156 | # General
157 | .DS_Store
158 | .AppleDouble
159 | .LSOverride
160 |
161 | # Icon must end with two \r
162 | Icon
163 |
164 |
165 | # Thumbnails
166 | ._*
167 |
168 | # Files that might appear in the root of a volume
169 | .DocumentRevisions-V100
170 | .fseventsd
171 | .Spotlight-V100
172 | .TemporaryItems
173 | .Trashes
174 | .VolumeIcon.icns
175 | .com.apple.timemachine.donotpresent
176 |
177 | # Directories potentially created on remote AFP share
178 | .AppleDB
179 | .AppleDesktop
180 | Network Trash Folder
181 | Temporary Items
182 | .apdisk
183 |
184 | ### SAM ###
185 | # Ignore build directories for the AWS Serverless Application Model (SAM)
186 | # Info: https://aws.amazon.com/serverless/sam/
187 | # Docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html
188 |
189 | **/.aws-sam
190 | **/*.toml
191 | *.toml
192 |
193 | ### Windows ###
194 | # Windows thumbnail cache files
195 | Thumbs.db
196 | Thumbs.db:encryptable
197 | ehthumbs.db
198 | ehthumbs_vista.db
199 |
200 | # Dump file
201 | *.stackdump
202 |
203 | # Folder config file
204 | [Dd]esktop.ini
205 |
206 | # Recycle Bin used on file shares
207 | $RECYCLE.BIN/
208 |
209 | # Windows Installer files
210 | *.cab
211 | *.msi
212 | *.msix
213 | *.msm
214 | *.msp
215 |
216 | # Windows shortcuts
217 | *.lnk
218 |
219 | # Other IDE settings
220 | .idea/
221 |
--------------------------------------------------------------------------------
/SSR-catalog-example/reviews-mfe/README.md:
--------------------------------------------------------------------------------
1 | # reviews-mfe
2 |
3 | This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders.
4 |
5 | - hello-world - Code for the application's Lambda function.
6 | - events - Invocation events that you can use to invoke the function.
7 | - hello-world/tests - Unit tests for the application code.
8 | - template.yaml - A template that defines the application's AWS resources.
9 |
10 | The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code.
11 |
12 | If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit.
13 | The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started.
14 |
15 | * [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
16 | * [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
17 | * [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
18 | * [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
19 | * [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
20 | * [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
21 | * [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
22 | * [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
23 | * [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html)
24 | * [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html)
25 | * [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html)
26 |
27 | ## Deploy the sample application
28 |
29 | The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API.
30 |
31 | To use the SAM CLI, you need the following tools.
32 |
33 | * SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
34 | * Node.js - [Install Node.js 16](https://nodejs.org/en/), including the NPM package management tool.
35 | * Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community)
36 |
37 | To build and deploy your application for the first time, run the following in your shell:
38 |
39 | ```bash
40 | sam build
41 | sam deploy --guided
42 | ```
43 |
44 | The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts:
45 |
46 | * **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name.
47 | * **AWS Region**: The AWS region you want to deploy your app to.
48 | * **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes.
49 | * **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command.
50 | * **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application.
51 |
52 | You can find your API Gateway Endpoint URL in the output values displayed after deployment.
53 |
54 | ## Use the SAM CLI to build and test locally
55 |
56 | Build your application with the `sam build` command.
57 |
58 | ```bash
59 | reviews-mfe$ sam build
60 | ```
61 |
62 | The SAM CLI installs dependencies defined in `hello-world/package.json`, creates a deployment package, and saves it in the `.aws-sam/build` folder.
63 |
64 | Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project.
65 |
66 | Run functions locally and invoke them with the `sam local invoke` command.
67 |
68 | ```bash
69 | reviews-mfe$ sam local invoke HelloWorldFunction --event events/event.json
70 | ```
71 |
72 | The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000.
73 |
74 | ```bash
75 | reviews-mfe$ sam local start-api
76 | reviews-mfe$ curl http://localhost:3000/
77 | ```
78 |
79 | The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path.
80 |
81 | ```yaml
82 | Events:
83 | HelloWorld:
84 | Type: Api
85 | Properties:
86 | Path: /hello
87 | Method: get
88 | ```
89 |
90 | ## Add a resource to your application
91 | The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types.
92 |
93 | ## Fetch, tail, and filter Lambda function logs
94 |
95 | To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug.
96 |
97 | `NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM.
98 |
99 | ```bash
100 | reviews-mfe$ sam logs -n HelloWorldFunction --stack-name reviews-mfe --tail
101 | ```
102 |
103 | You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html).
104 |
105 | ## Unit tests
106 |
107 | Tests are defined in the `hello-world/tests` folder in this project. Use NPM to install the [Mocha test framework](https://mochajs.org/) and run unit tests.
108 |
109 | ```bash
110 | reviews-mfe$ cd hello-world
111 | hello-world$ npm install
112 | hello-world$ npm run test
113 | ```
114 |
115 | ## Cleanup
116 |
117 | To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following:
118 |
119 | ```bash
120 | aws cloudformation delete-stack --stack-name reviews-mfe
121 | ```
122 |
123 | ## Resources
124 |
125 | See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts.
126 |
127 | Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/)
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Micro-Frontends in AWS
2 |
3 | ## Context
4 |
5 | Micro-Frontends are the technical representation of a business subdomain, they allow independent implementations with the same or different technology, they should minimize the code shared with other subdomains and they are own by a single team.
6 |
7 | These characteristics might seem familiar if you have built distibuted systems in the past. Micro-Frontends are the answer when you need to scale your organizations having multiple teams working together in the same project.
8 |
9 | In this repository we collect examples to implement Micro-Frontends in AWS, leveraging several AWS services that represents the building blocks for stitching together distributed architecterues not only for the backend but now for the frontend too.
10 |
11 | ## Server-side rendering Micro-Frontends
12 |
13 | In this repository we have created a basic example that leverages the building blocks to create a server-side rendering (SSR) micro-frontends implementation.
14 |
15 | The architecture characteristics we focus in these projects are:
16 |
17 | - being framework agnostic
18 | - using standards for communicating between micro-frontends and the UI composer using [HTML-over-the-wire](https://alistapart.com/article/the-future-of-web-software-is-html-over-websockets/)
19 | - using the best practices for SSR workloads such as [progressive hydration](https://www.patterns.dev/posts/progressive-hydration/) and [streaming to the browser](https://www.patterns.dev/posts/ssr/)
20 | - allowing teams to operate independently with little coordination for composing their micro-frontends inside a view
21 | - implementing best practices once a micro-frontend is hydrated using a pub/sub system for communication inside the browser
22 | - having the possibility to choose between client-side rendering and server-side rendering based on the needs
23 |
24 | The architecture in this example is represented in the following diagram:
25 |
26 | 
27 |
28 | It's important to highlight that this project is managed by several teams in an organization. Hence why the deployment is not as simple as a monolithic project but covers already the idea of a centralized team responsible for the UI-composer and several teams building individual micro-frontends.
29 |
30 | You can read an extensive description of this approach in this blog series:
31 |
32 | - [server-side rendering micro-frontends - the architecture](https://aws.amazon.com/blogs/compute/server-side-rendering-micro-frontends-the-architecture/)
33 | - [server-side rendering micro-frontends – UI composer and service discovery](https://aws.amazon.com/blogs/compute/server-side-rendering-micro-frontends-ui-composer-and-service-discovery/)
34 |
35 | More posts are written as we speak so keep an eye on the [AWS Compute Blog](https://aws.amazon.com/blogs/compute/).
36 |
37 | ### Pre-requisites
38 |
39 | - [Node.js](https://nodejs.org/en/download/)
40 | - [Docker Desktop](https://www.docker.com/products/docker-desktop/)
41 | - [AWS CLI](https://aws.amazon.com/cli/)
42 | - [AWS SAM](https://aws.amazon.com/serverless/sam/)
43 | - [AWS CDK](https://aws.amazon.com/cdk/)
44 |
45 | ### How to deploy this project
46 |
47 | We assume you have installed and configured the AWS CLI, if not please follow these [instructions](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions)
48 |
49 | As seen in the diagram above, the system is composed by different parts.
50 | The first thing to do is deploying the UI composer alongside the CloudFront distribution and related S3 bucket.
51 |
52 | In the ```SSR-catalog-example/ui-composer``` we have the implementation and configuration of these parts of the system.
53 | For this project we are using AWS CDK, so follow the [instructions](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) to install in your machine and then run the commands inside the ```SSR-catalog-example/ui-composer``` folder:
54 |
55 | ```shell
56 | npm install
57 | # this command is used just the first time. Use the cdk bootstrap command to bootstrap one or more AWS environments
58 | cdk bootstrap
59 | # this command allows you to deploy the UI-composer in an AWS account
60 | cdk deploy
61 | ```
62 |
63 | At the end of the deployment we should have in our AWS account the following elements:
64 |
65 | - a CloudFront Distribution
66 | - an S3 bucket
67 | - an Application Load Balancer
68 | - a Fargate cluster running our application server
69 | - a VPC configured with access logs
70 | - IAM policies attached to the Fargate cluster
71 | - A parameter in parameter store with the information to retrieve the HTML templates used in the application.
72 |
73 | Now, we can deploy the micro-frontends: two of them are using the server-side rendering (```reviews-mfe``` and ```catalog-mfe```) approach and another one is leveraging client-side rendering (```notifications-mfe```).
74 |
75 | ```reviews-mfe``` and ```catalog-mfe``` are similar in terms of deployment approach.
76 | First install the Node.js dependecies running the command ```npm install``` in both projects.
77 |
78 | These server-side rendering micro-frontends use AWS SAM as IaC tool, so first you need to follow the instructions to [install AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) and then run the following commands inside the folder of both projects:
79 |
80 | ```shell
81 | npm install
82 | # this command minimize the code of the lambda function(s)
83 | npm run build-server
84 | # this command build the project using SAM
85 | sam build
86 | # this command triggers a wizard for deploying a micro-frontend in the AWS account
87 | sam deploy --guided
88 | ```
89 |
90 | All the micro-frontends in this project requires to generate a JavaScript file used for hydrating the code inside a browser to attach listeners to the user interface and run business logic after the page is rendered.
91 | For generating these static JavaScript files you have to run the following command for ```reviews-mfe```, ```catalog-mfe``` and ```notifications-mfe```:
92 |
93 | ```shell
94 | npm run build-client
95 | ```
96 |
97 | This command will generate static files in ```client-build``` folder in every project.
98 | All these JavaScript files are now ready to be uploaded in the S3 bucket created at the beginning inside the static folder.
99 |
100 | In this project, we have also a folder dependencies that collects all the common depdencies used by different micro-frontends such as [Preact](https://preactjs.com/) as UI library or [nanoevents](https://www.npmjs.com/package/nanoevents) as event bus used for allowing the micro-frontends communications.
101 | Deploy all the files inside the ```static``` folder in the S3 bucket alongside the micro-frontends JavaScript files.
102 |
103 | The ```static``` folder should look like this screenshot now:
104 |
105 | 
106 |
107 | Finally, add a JPG image called ```book.jpg``` in the ```static``` folder of the S3 bucket, that is the image that will be displayed by default when you deploy for the first time this project in your AWS account.
108 |
109 | We now need to create a new folder in the S3 bucket called ```templates``` and upload the file used as HTML template for rendering the final page. Upload ```SSR-catalog-example/ui-composer/static/catalog.template``` in the ```templates``` folder.
110 |
111 | 
112 |
113 | ### Set endpoint for reviews service
114 |
115 | After provisioning the reviews micro-frontend in the AWS account, you get an open endpoint used only for demo purposes.
116 |
117 | **IMPORTANT**: This endpoint has no associated authorizers and is therefore is public.
118 | In a real world application, some form of authentication authentication should be used e.g. Cognito User Pools, AWS IAM or a Lambda authorizer.
119 |
120 | Get the API Gateway URL from AWS console or from the provisioning output of SAM CLI and add it to ```ReviewForm.js``` (it's inside the ```reviews-mfe``` folder) in the ```URL``` constant.
121 |
122 | 
123 |
124 | The endpoint created is called ```review``` and is in the ```Prod``` stage.
125 |
126 | The final endpoint should look like this one:
127 |
128 | ```shell
129 | https://xxxxxxxx.execute-api.REGION.amazonaws.com/Prod/review
130 | ```
131 |
132 | After this, you can run ```npm run build-client``` and upload the file in the S3 bucket inside the ```static``` folder.
133 |
134 | ### Loading the website in a browser
135 |
136 | At the end of the deployment, you can see from the CloudFormation dashboard in the output panel the URL to paste in a browser for seeing the final solution.
137 |
138 | If you are deploying the solution from your laptop, in the CLI Outputs you can find the endpoint to paste in a browser (```UiComposerStack.distributionDomainName```).
139 |
140 | ### Deleting the Solution
141 |
142 | To delete the micro-frontend stacks and UI Composer stacks via AWS Console:
143 |
144 | 1. Open the [CloudFormation Console](https://console.aws.amazon.com/cloudformation/home) page and choose the relevant stack, then choose _"Delete"_
145 | 2. Once the confirmation modal appears, choose _"Delete stack"_.
146 | 3. Wait for the CloudFormation stack to finish updating. Completion is indicated when the _"Stack status"_ is _"DELETE_COMPLETE"_
147 |
148 | Remember to follow these steps for the UI composer and every micro-frontend stack created.
149 |
150 | To delete a stack via the AWS CLI consult [the documentation](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/delete-stack.html).
--------------------------------------------------------------------------------
/SSR-catalog-example/dependencies/preact.min.js:
--------------------------------------------------------------------------------
1 | !function(){var n,l,u,t,i,o,r,e,f={},c=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function s(n,l){for(var u in l)n[u]=l[u];return n}function h(n){var l=n.parentNode;l&&l.removeChild(n)}function v(l,u,t){var i,o,r,e={};for(r in u)"key"==r?i=u[r]:"ref"==r?o=u[r]:e[r]=u[r];if(arguments.length>2&&(e.children=arguments.length>3?n.call(arguments,2):t),"function"==typeof l&&null!=l.defaultProps)for(r in l.defaultProps)void 0===e[r]&&(e[r]=l.defaultProps[r]);return y(l,e,i,o,null)}function y(n,t,i,o,r){var e={type:n,props:t,key:i,ref:o,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==r?++u:r};return null==r&&null!=l.vnode&&l.vnode(e),e}function d(n){return n.children}function p(n,l){this.props=n,this.context=l}function _(n,l){if(null==l)return n.__?_(n.__,n.__.__k.indexOf(n)+1):null;for(var u;l0?y(m.type,m.props,m.key,null,m.__v):m)){if(m.__=u,m.__b=u.__b+1,null===(p=C[h])||p&&m.key==p.key&&m.type===p.type)C[h]=void 0;else for(v=0;v2&&(e.children=arguments.length>3?n.call(arguments,2):t),y(l.type,e,i||l.key,o||l.ref,null)},createContext:function(n,l){var u={__c:l="__cC"+r++,__:n,Consumer:function(n,l){return n.children(l)},Provider:function(n){var u,t;return this.getChildContext||(u=[],(t={})[l]=this,this.getChildContext=function(){return t},this.shouldComponentUpdate=function(n){this.props.value!==n.value&&u.some(k)},this.sub=function(n){u.push(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){u.splice(u.indexOf(n),1),l&&l.call(n)}}),n.children}};return u.Provider.__=u.Consumer.contextType=u},toChildArray:function n(l,u){return u=u||[],null==l||"boolean"==typeof l||(Array.isArray(l)?l.some(function(l){n(l,u)}):u.push(l)),u},options:l},typeof module<"u"?module.exports=e:self.preact=e}();
2 | //# sourceMappingURL=preact.min.js.map
--------------------------------------------------------------------------------
/SSR-catalog-example/ui-composer/lib/ui-composer-stack.ts:
--------------------------------------------------------------------------------
1 | import {Stack, StackProps, aws_iam, App, RemovalPolicy, CfnOutput } from 'aws-cdk-lib';
2 | import { CloudFrontWebDistribution, OriginAccessIdentity, CloudFrontAllowedMethods, CloudFrontAllowedCachedMethods, OriginProtocolPolicy } from 'aws-cdk-lib/aws-cloudfront';
3 | import { Bucket, BlockPublicAccess, BucketEncryption } from 'aws-cdk-lib/aws-s3';
4 | import { Cluster, ContainerImage } from 'aws-cdk-lib/aws-ecs';
5 | import { Vpc, FlowLog, FlowLogResourceType, FlowLogDestination, CfnPrefixList, SecurityGroup, Port, Peer } from "aws-cdk-lib/aws-ec2";
6 | import { AccountRootPrincipal, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
7 | import { LogGroup } from 'aws-cdk-lib/aws-logs';
8 | import { ApplicationLoadBalancedFargateService } from 'aws-cdk-lib/aws-ecs-patterns';
9 |
10 | import * as path from 'path';
11 | import { NagSuppressions } from 'cdk-nag';
12 | import { StringParameter } from 'aws-cdk-lib/aws-ssm';
13 |
14 | export class UiComposerStack extends Stack {
15 | constructor(scope: App, id: string, props?: StackProps) {
16 | super(scope, id, props);
17 | // -------- S3 Buckets ------------
18 | const accesslogsBucket = process.env.ACCESS_LOGS_BUCKET
19 | ? Bucket.fromBucketName(this, "access-logs-bucket", process.env.ACCESS_LOGS_BUCKET)
20 | : undefined;
21 | const sourceBucket = new Bucket(this, 'mfe-static-assets', {
22 | blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
23 | enforceSSL: true,
24 | serverAccessLogsBucket: accesslogsBucket,
25 | serverAccessLogsPrefix: "s3-logs",
26 | encryption: BucketEncryption.S3_MANAGED,
27 | removalPolicy: RemovalPolicy.DESTROY
28 | });
29 |
30 | // -------- UI-COMPOSER-NETWORKING ------------
31 | const vpc = new Vpc(this, "ui-composer-vpc", {
32 | maxAzs: 3
33 | });
34 |
35 | const cluster = new Cluster(this, "ui-composer-cluster", {
36 | vpc: vpc,
37 | containerInsights: true,
38 | });
39 |
40 | const vpcLogGroup = new LogGroup(this, 'VPCLogGroup');
41 | const role = new Role(this, "vpc-log-group", {
42 | assumedBy: new ServicePrincipal('vpc-flow-logs.amazonaws.com')
43 | });
44 |
45 | const flowlog = new FlowLog(this, 'FlowLog', {
46 | resourceType: FlowLogResourceType.fromVpc(vpc),
47 | destination: FlowLogDestination.toCloudWatchLogs(vpcLogGroup, role)
48 | });
49 |
50 | const uiComposerSG = new SecurityGroup(this, 'ui-composer-sg', {
51 | vpc: vpc,
52 | allowAllOutbound: true,
53 | description: 'ui-composer-sg'
54 | })
55 |
56 | // -------- UI-COMPOSER-FARGATE ------------
57 |
58 | // ----------------------------------------
59 |
60 | // -------- SSM Parameter Store ----------
61 |
62 | new StringParameter(this, 'ui-composer-params', {
63 | parameterName: '/ssr-mfe/catalogpage',
64 | description: "template config for UI-composer",
65 | stringValue: `{"template": "templates/catalog.template", "templatesBucket": "${sourceBucket.bucketName}"}`,
66 | });
67 |
68 | // -------- UI-COMPOSER -------------
69 |
70 | const taskRole = new aws_iam.Role(this, "fargate-task-role", {
71 | assumedBy: new aws_iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
72 | roleName: "fargate-task-role",
73 | description: "IAM role for consuming MFEs"
74 | });
75 |
76 | const account = new AccountRootPrincipal()
77 |
78 | taskRole.attachInlinePolicy(
79 | new aws_iam.Policy(this, "task-access-policy", {
80 | statements: [
81 | new aws_iam.PolicyStatement({
82 | effect: aws_iam.Effect.ALLOW,
83 | actions: [
84 | "ssm:GetParameter",
85 | "ssm:GetParameters"
86 | ],
87 | resources: [`arn:aws:ssm:${process.env.region || "eu-west-1"}:${account.accountId}:parameter/ssr-mfe/*`]
88 | }),
89 | new aws_iam.PolicyStatement({
90 | effect: aws_iam.Effect.ALLOW,
91 | actions: [
92 | "lambda:InvokeFunction",
93 | "states:StartSyncExecution"
94 | ],
95 | resources: [
96 | `arn:aws:lambda:${process.env.region || "eu-west-1"}:${account.accountId}:function:*`,
97 | `arn:aws:states:${process.env.region || "eu-west-1"}:${account.accountId}:stateMachine:*`
98 | ]
99 | }),
100 | new aws_iam.PolicyStatement({
101 | effect: aws_iam.Effect.ALLOW,
102 | actions: [
103 | "s3:GetObject",
104 | "s3:ListBucket"
105 | ],
106 | resources: [
107 | sourceBucket.bucketArn,
108 | `${sourceBucket.bucketArn}/*`
109 | ],
110 | })
111 | ],
112 | })
113 | )
114 |
115 | const loadBalancedFargateService = new ApplicationLoadBalancedFargateService(this, 'ui-composer-service', {
116 | cluster,
117 | memoryLimitMiB: 2048,
118 | desiredCount: 2,
119 | cpu: 512,
120 | listenerPort: 80,
121 | publicLoadBalancer: true,
122 | openListener: false,
123 | securityGroups: [uiComposerSG],
124 | serviceName: "ui-composer-service",
125 | circuitBreaker: {
126 | rollback: true,
127 | },
128 | taskImageOptions:{
129 | image: ContainerImage.fromAsset(path.resolve(__dirname, '../')),
130 | taskRole: taskRole,
131 | executionRole: taskRole,
132 | enableLogging: true,
133 | environment: {
134 | REGION: process.env.region || "eu-west-1"
135 | }
136 | },
137 | });
138 |
139 | const albSG = new SecurityGroup(this, 'alb-sg', {
140 | vpc: vpc,
141 | allowAllOutbound: true,
142 | description: 'alb-sg'
143 | })
144 |
145 | const PREFIX_GLOBAL_CF_EU_WEST_1 = "pl-4fa04526";
146 | albSG.addIngressRule(Peer.prefixList(PREFIX_GLOBAL_CF_EU_WEST_1), Port.tcp(80), 'allow ingress from CF')
147 | loadBalancedFargateService.loadBalancer.addSecurityGroup(albSG)
148 |
149 | if (accesslogsBucket !== undefined) {
150 | loadBalancedFargateService.loadBalancer.logAccessLogs(accesslogsBucket as Bucket, "alb-logs");
151 | }
152 |
153 | loadBalancedFargateService.targetGroup.configureHealthCheck({
154 | path: "/health",
155 | });
156 |
157 | const scalableTarget = loadBalancedFargateService.service.autoScaleTaskCount({
158 | minCapacity: 1,
159 | maxCapacity: 3,
160 | });
161 |
162 | scalableTarget.scaleOnCpuUtilization('CpuScaling', {
163 | targetUtilizationPercent: 70,
164 | });
165 |
166 | scalableTarget.scaleOnMemoryUtilization('MemoryScaling', {
167 | targetUtilizationPercent: 70,
168 | });
169 |
170 | // ----------------------------------------
171 |
172 | // -------- CF distro ------------
173 |
174 | const oai = new OriginAccessIdentity(this, 'mfe-oai')
175 | let loggingConfiguration;
176 | if (accesslogsBucket !== undefined) {
177 | loggingConfiguration = {
178 | bucket: accesslogsBucket,
179 | includeCookies: false,
180 | };
181 | }
182 |
183 | const distribution = new CloudFrontWebDistribution(this, 'mfe-distro', {
184 | loggingConfig: loggingConfiguration,
185 | originConfigs: [
186 | {
187 |
188 | s3OriginSource: {
189 | s3BucketSource: sourceBucket,
190 | originAccessIdentity: oai
191 | },
192 | behaviors : [
193 | { pathPattern: '/static/*',
194 | allowedMethods: CloudFrontAllowedMethods.GET_HEAD,
195 | cachedMethods: CloudFrontAllowedCachedMethods.GET_HEAD
196 | }
197 | ],
198 | },
199 | {
200 | customOriginSource: {
201 | domainName: loadBalancedFargateService.loadBalancer.loadBalancerDnsName,
202 | originProtocolPolicy: OriginProtocolPolicy.HTTP_ONLY,
203 | },
204 | behaviors : [
205 | {
206 | isDefaultBehavior: true,
207 | allowedMethods: CloudFrontAllowedMethods.ALL,
208 | forwardedValues: {
209 | queryString: true,
210 | cookies: {
211 | forward: 'all'
212 | },
213 | headers: ['*'],
214 | }
215 | }
216 | ]
217 | }
218 | ],
219 | });
220 |
221 | // ----------------------------------------
222 |
223 | new CfnOutput(this, 'distributionDomainName', {
224 | value: `https://${distribution.distributionDomainName}/productdetails`,
225 | description: 'the URL to access the website in a browser',
226 | exportName: 'website-url'
227 | });
228 |
229 | // -------- NAG suppression statements ------------
230 |
231 | NagSuppressions.addResourceSuppressions(loadBalancedFargateService.taskDefinition, [
232 | {id: 'AwsSolutions-ECS2', reason: 'It\'s a demo'},
233 | ])
234 |
235 | NagSuppressions.addStackSuppressions(this, [
236 | {id: 'AwsSolutions-ELB2', reason: 'It\'s a demo so access logs are opt-in using the ACCESS_LOGS_BUCKET env var' },
237 | {id: 'AwsSolutions-IAM5', reason: 'remediate with override inline policies'}
238 | ])
239 |
240 | NagSuppressions.addResourceSuppressions(distribution, [
241 | { id: 'AwsSolutions-CFR5', reason: 'It\'s a demo so no need to enforce SSLv3 or TLSv1' },
242 | { id: 'AwsSolutions-CFR4', reason: 'It\'s a demo so no need to enforce SSLv3 or TLSv1' },
243 | { id: 'AwsSolutions-CFR3', reason: 'It\'s a demo so no need to have access logs' },
244 | { id: 'AwsSolutions-CFR2', reason: 'It\'s a demo so no need to integrate WAF on the CloudFront Distribution' },
245 | { id: 'AwsSolutions-CFR1', reason: 'It\'s a demo so no need to implement GEO restriction rules' },
246 | ]);
247 | }
248 | }
--------------------------------------------------------------------------------
/THIRD-PARTY-LICENSES.txt:
--------------------------------------------------------------------------------
1 | ** aws-cdk; version 2.33.0 -- https://github.com/aws/aws-cdk
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
180 | APPENDIX: How to apply the Apache License to your work.
181 |
182 | To apply the Apache License to your work, attach the following
183 | boilerplate notice, with the fields enclosed by brackets "[]"
184 | replaced with your own identifying information. (Don't include
185 | the brackets!) The text should be enclosed in the appropriate
186 | comment syntax for the file format. We also recommend that a
187 | file or class name and description of purpose be included on the
188 | same "printed page" as the copyright notice for easier
189 | identification within third-party archives.
190 |
191 | Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
192 |
193 | Licensed under the Apache License, Version 2.0 (the "License");
194 | you may not use this file except in compliance with the License.
195 | You may obtain a copy of the License at
196 |
197 | http://www.apache.org/licenses/LICENSE-2.0
198 |
199 | Unless required by applicable law or agreed to in writing, software
200 | distributed under the License is distributed on an "AS IS" BASIS,
201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
202 | See the License for the specific language governing permissions and
203 | limitations under the License.
204 |
205 | * For aws-cdk see also this required NOTICE:
206 | AWS Cloud Development Kit (AWS CDK)
207 | Copyright 2018-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
208 |
209 |
210 | ------
211 |
212 | ** cdk-nag; version 2.22.2 -- https://github.com/cdklabs/cdk-nag
213 |
214 | Apache License
215 | Version 2.0, January 2004
216 | http://www.apache.org/licenses/
217 |
218 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
219 |
220 | 1. Definitions.
221 |
222 | "License" shall mean the terms and conditions for use, reproduction,
223 | and distribution as defined by Sections 1 through 9 of this document.
224 |
225 | "Licensor" shall mean the copyright owner or entity authorized by
226 | the copyright owner that is granting the License.
227 |
228 | "Legal Entity" shall mean the union of the acting entity and all
229 | other entities that control, are controlled by, or are under common
230 | control with that entity. For the purposes of this definition,
231 | "control" means (i) the power, direct or indirect, to cause the
232 | direction or management of such entity, whether by contract or
233 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
234 | outstanding shares, or (iii) beneficial ownership of such entity.
235 |
236 | "You" (or "Your") shall mean an individual or Legal Entity
237 | exercising permissions granted by this License.
238 |
239 | "Source" form shall mean the preferred form for making modifications,
240 | including but not limited to software source code, documentation
241 | source, and configuration files.
242 |
243 | "Object" form shall mean any form resulting from mechanical
244 | transformation or translation of a Source form, including but
245 | not limited to compiled object code, generated documentation,
246 | and conversions to other media types.
247 |
248 | "Work" shall mean the work of authorship, whether in Source or
249 | Object form, made available under the License, as indicated by a
250 | copyright notice that is included in or attached to the work
251 | (an example is provided in the Appendix below).
252 |
253 | "Derivative Works" shall mean any work, whether in Source or Object
254 | form, that is based on (or derived from) the Work and for which the
255 | editorial revisions, annotations, elaborations, or other modifications
256 | represent, as a whole, an original work of authorship. For the purposes
257 | of this License, Derivative Works shall not include works that remain
258 | separable from, or merely link (or bind by name) to the interfaces of,
259 | the Work and Derivative Works thereof.
260 |
261 | "Contribution" shall mean any work of authorship, including
262 | the original version of the Work and any modifications or additions
263 | to that Work or Derivative Works thereof, that is intentionally
264 | submitted to Licensor for inclusion in the Work by the copyright owner
265 | or by an individual or Legal Entity authorized to submit on behalf of
266 | the copyright owner. For the purposes of this definition, "submitted"
267 | means any form of electronic, verbal, or written communication sent
268 | to the Licensor or its representatives, including but not limited to
269 | communication on electronic mailing lists, source code control systems,
270 | and issue tracking systems that are managed by, or on behalf of, the
271 | Licensor for the purpose of discussing and improving the Work, but
272 | excluding communication that is conspicuously marked or otherwise
273 | designated in writing by the copyright owner as "Not a Contribution."
274 |
275 | "Contributor" shall mean Licensor and any individual or Legal Entity
276 | on behalf of whom a Contribution has been received by Licensor and
277 | subsequently incorporated within the Work.
278 |
279 | 2. Grant of Copyright License. Subject to the terms and conditions of
280 | this License, each Contributor hereby grants to You a perpetual,
281 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
282 | copyright license to reproduce, prepare Derivative Works of,
283 | publicly display, publicly perform, sublicense, and distribute the
284 | Work and such Derivative Works in Source or Object form.
285 |
286 | 3. Grant of Patent License. Subject to the terms and conditions of
287 | this License, each Contributor hereby grants to You a perpetual,
288 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
289 | (except as stated in this section) patent license to make, have made,
290 | use, offer to sell, sell, import, and otherwise transfer the Work,
291 | where such license applies only to those patent claims licensable
292 | by such Contributor that are necessarily infringed by their
293 | Contribution(s) alone or by combination of their Contribution(s)
294 | with the Work to which such Contribution(s) was submitted. If You
295 | institute patent litigation against any entity (including a
296 | cross-claim or counterclaim in a lawsuit) alleging that the Work
297 | or a Contribution incorporated within the Work constitutes direct
298 | or contributory patent infringement, then any patent licenses
299 | granted to You under this License for that Work shall terminate
300 | as of the date such litigation is filed.
301 |
302 | 4. Redistribution. You may reproduce and distribute copies of the
303 | Work or Derivative Works thereof in any medium, with or without
304 | modifications, and in Source or Object form, provided that You
305 | meet the following conditions:
306 |
307 | (a) You must give any other recipients of the Work or
308 | Derivative Works a copy of this License; and
309 |
310 | (b) You must cause any modified files to carry prominent notices
311 | stating that You changed the files; and
312 |
313 | (c) You must retain, in the Source form of any Derivative Works
314 | that You distribute, all copyright, patent, trademark, and
315 | attribution notices from the Source form of the Work,
316 | excluding those notices that do not pertain to any part of
317 | the Derivative Works; and
318 |
319 | (d) If the Work includes a "NOTICE" text file as part of its
320 | distribution, then any Derivative Works that You distribute must
321 | include a readable copy of the attribution notices contained
322 | within such NOTICE file, excluding those notices that do not
323 | pertain to any part of the Derivative Works, in at least one
324 | of the following places: within a NOTICE text file distributed
325 | as part of the Derivative Works; within the Source form or
326 | documentation, if provided along with the Derivative Works; or,
327 | within a display generated by the Derivative Works, if and
328 | wherever such third-party notices normally appear. The contents
329 | of the NOTICE file are for informational purposes only and
330 | do not modify the License. You may add Your own attribution
331 | notices within Derivative Works that You distribute, alongside
332 | or as an addendum to the NOTICE text from the Work, provided
333 | that such additional attribution notices cannot be construed
334 | as modifying the License.
335 |
336 | You may add Your own copyright statement to Your modifications and
337 | may provide additional or different license terms and conditions
338 | for use, reproduction, or distribution of Your modifications, or
339 | for any such Derivative Works as a whole, provided Your use,
340 | reproduction, and distribution of the Work otherwise complies with
341 | the conditions stated in this License.
342 |
343 | 5. Submission of Contributions. Unless You explicitly state otherwise,
344 | any Contribution intentionally submitted for inclusion in the Work
345 | by You to the Licensor shall be under the terms and conditions of
346 | this License, without any additional terms or conditions.
347 | Notwithstanding the above, nothing herein shall supersede or modify
348 | the terms of any separate license agreement you may have executed
349 | with Licensor regarding such Contributions.
350 |
351 | 6. Trademarks. This License does not grant permission to use the trade
352 | names, trademarks, service marks, or product names of the Licensor,
353 | except as required for reasonable and customary use in describing the
354 | origin of the Work and reproducing the content of the NOTICE file.
355 |
356 | 7. Disclaimer of Warranty. Unless required by applicable law or
357 | agreed to in writing, Licensor provides the Work (and each
358 | Contributor provides its Contributions) on an "AS IS" BASIS,
359 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
360 | implied, including, without limitation, any warranties or conditions
361 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
362 | PARTICULAR PURPOSE. You are solely responsible for determining the
363 | appropriateness of using or redistributing the Work and assume any
364 | risks associated with Your exercise of permissions under this License.
365 |
366 | 8. Limitation of Liability. In no event and under no legal theory,
367 | whether in tort (including negligence), contract, or otherwise,
368 | unless required by applicable law (such as deliberate and grossly
369 | negligent acts) or agreed to in writing, shall any Contributor be
370 | liable to You for damages, including any direct, indirect, special,
371 | incidental, or consequential damages of any character arising as a
372 | result of this License or out of the use or inability to use the
373 | Work (including but not limited to damages for loss of goodwill,
374 | work stoppage, computer failure or malfunction, or any and all
375 | other commercial damages or losses), even if such Contributor
376 | has been advised of the possibility of such damages.
377 |
378 | 9. Accepting Warranty or Additional Liability. While redistributing
379 | the Work or Derivative Works thereof, You may choose to offer,
380 | and charge a fee for, acceptance of support, warranty, indemnity,
381 | or other liability obligations and/or rights consistent with this
382 | License. However, in accepting such obligations, You may act only
383 | on Your own behalf and on Your sole responsibility, not on behalf
384 | of any other Contributor, and only if You agree to indemnify,
385 | defend, and hold each Contributor harmless for any liability
386 | incurred by, or claims asserted against, such Contributor by reason
387 | of your accepting any such warranty or additional liability.
388 |
389 | END OF TERMS AND CONDITIONS
390 |
391 | APPENDIX: How to apply the Apache License to your work.
392 |
393 | To apply the Apache License to your work, attach the following
394 | boilerplate notice, with the fields enclosed by brackets "[]"
395 | replaced with your own identifying information. (Don't include
396 | the brackets!) The text should be enclosed in the appropriate
397 | comment syntax for the file format. We also recommend that a
398 | file or class name and description of purpose be included on the
399 | same "printed page" as the copyright notice for easier
400 | identification within third-party archives.
401 |
402 | Copyright [yyyy] [name of copyright owner]
403 |
404 | Licensed under the Apache License, Version 2.0 (the "License");
405 | you may not use this file except in compliance with the License.
406 | You may obtain a copy of the License at
407 |
408 | http://www.apache.org/licenses/LICENSE-2.0
409 |
410 | Unless required by applicable law or agreed to in writing, software
411 | distributed under the License is distributed on an "AS IS" BASIS,
412 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
413 | See the License for the specific language governing permissions and
414 | limitations under the License.
415 | * For cdk-nag see also this required NOTICE:
416 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
417 | SPDX-License-Identifier: Apache-2.0
418 |
419 | ------
420 |
421 | ** NodeJS-preact; version 10.12.1 -- https://preactjs.com/
422 | The MIT License (MIT)
423 |
424 | Copyright (c) 2015-present Jason Miller
425 |
426 | Permission is hereby granted, free of charge, to any person obtaining a copy
427 | of this software and associated documentation files (the "Software"), to deal
428 | in the Software without restriction, including without limitation the rights
429 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
430 | copies of the Software, and to permit persons to whom the Software is
431 | furnished to do so, subject to the following conditions:
432 |
433 | The above copyright notice and this permission notice shall be included in all
434 | copies or substantial portions of the Software.
435 |
436 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
437 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
438 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
439 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
440 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
441 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
442 | SOFTWARE.
443 | ** node-html-parser; version 6.1.4 -- https://github.com/taoqf/node-html-parser
444 | Copyright 2019 Tao Qiufeng
445 |
446 | Permission is hereby granted, free of charge, to any person obtaining a copy of
447 | this software and associated documentation files (the "Software"), to deal in
448 | the Software without restriction, including without limitation the rights to
449 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
450 | the Software, and to permit persons to whom the Software is furnished to do so,
451 | subject to the following conditions:
452 |
453 | The above copyright notice and this permission notice shall be included in all
454 | copies or substantial portions of the Software.
455 |
456 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
457 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
458 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
459 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
460 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
461 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
462 | ** htm; version 2.1.1 -- https://github.com/developit/htm
463 |
464 | Apache License
465 | Version 2.0, January 2004
466 | http://www.apache.org/licenses/
467 |
468 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
469 |
470 | 1. Definitions.
471 |
472 | "License" shall mean the terms and conditions for use, reproduction,
473 | and distribution as defined by Sections 1 through 9 of this document.
474 |
475 | "Licensor" shall mean the copyright owner or entity authorized by
476 | the copyright owner that is granting the License.
477 |
478 | "Legal Entity" shall mean the union of the acting entity and all
479 | other entities that control, are controlled by, or are under common
480 | control with that entity. For the purposes of this definition,
481 | "control" means (i) the power, direct or indirect, to cause the
482 | direction or management of such entity, whether by contract or
483 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
484 | outstanding shares, or (iii) beneficial ownership of such entity.
485 |
486 | "You" (or "Your") shall mean an individual or Legal Entity
487 | exercising permissions granted by this License.
488 |
489 | "Source" form shall mean the preferred form for making modifications,
490 | including but not limited to software source code, documentation
491 | source, and configuration files.
492 |
493 | "Object" form shall mean any form resulting from mechanical
494 | transformation or translation of a Source form, including but
495 | not limited to compiled object code, generated documentation,
496 | and conversions to other media types.
497 |
498 | "Work" shall mean the work of authorship, whether in Source or
499 | Object form, made available under the License, as indicated by a
500 | copyright notice that is included in or attached to the work
501 | (an example is provided in the Appendix below).
502 |
503 | "Derivative Works" shall mean any work, whether in Source or Object
504 | form, that is based on (or derived from) the Work and for which the
505 | editorial revisions, annotations, elaborations, or other modifications
506 | represent, as a whole, an original work of authorship. For the purposes
507 | of this License, Derivative Works shall not include works that remain
508 | separable from, or merely link (or bind by name) to the interfaces of,
509 | the Work and Derivative Works thereof.
510 |
511 | "Contribution" shall mean any work of authorship, including
512 | the original version of the Work and any modifications or additions
513 | to that Work or Derivative Works thereof, that is intentionally
514 | submitted to Licensor for inclusion in the Work by the copyright owner
515 | or by an individual or Legal Entity authorized to submit on behalf of
516 | the copyright owner. For the purposes of this definition, "submitted"
517 | means any form of electronic, verbal, or written communication sent
518 | to the Licensor or its representatives, including but not limited to
519 | communication on electronic mailing lists, source code control systems,
520 | and issue tracking systems that are managed by, or on behalf of, the
521 | Licensor for the purpose of discussing and improving the Work, but
522 | excluding communication that is conspicuously marked or otherwise
523 | designated in writing by the copyright owner as "Not a Contribution."
524 |
525 | "Contributor" shall mean Licensor and any individual or Legal Entity
526 | on behalf of whom a Contribution has been received by Licensor and
527 | subsequently incorporated within the Work.
528 |
529 | 2. Grant of Copyright License. Subject to the terms and conditions of
530 | this License, each Contributor hereby grants to You a perpetual,
531 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
532 | copyright license to reproduce, prepare Derivative Works of,
533 | publicly display, publicly perform, sublicense, and distribute the
534 | Work and such Derivative Works in Source or Object form.
535 |
536 | 3. Grant of Patent License. Subject to the terms and conditions of
537 | this License, each Contributor hereby grants to You a perpetual,
538 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
539 | (except as stated in this section) patent license to make, have made,
540 | use, offer to sell, sell, import, and otherwise transfer the Work,
541 | where such license applies only to those patent claims licensable
542 | by such Contributor that are necessarily infringed by their
543 | Contribution(s) alone or by combination of their Contribution(s)
544 | with the Work to which such Contribution(s) was submitted. If You
545 | institute patent litigation against any entity (including a
546 | cross-claim or counterclaim in a lawsuit) alleging that the Work
547 | or a Contribution incorporated within the Work constitutes direct
548 | or contributory patent infringement, then any patent licenses
549 | granted to You under this License for that Work shall terminate
550 | as of the date such litigation is filed.
551 |
552 | 4. Redistribution. You may reproduce and distribute copies of the
553 | Work or Derivative Works thereof in any medium, with or without
554 | modifications, and in Source or Object form, provided that You
555 | meet the following conditions:
556 |
557 | (a) You must give any other recipients of the Work or
558 | Derivative Works a copy of this License; and
559 |
560 | (b) You must cause any modified files to carry prominent notices
561 | stating that You changed the files; and
562 |
563 | (c) You must retain, in the Source form of any Derivative Works
564 | that You distribute, all copyright, patent, trademark, and
565 | attribution notices from the Source form of the Work,
566 | excluding those notices that do not pertain to any part of
567 | the Derivative Works; and
568 |
569 | (d) If the Work includes a "NOTICE" text file as part of its
570 | distribution, then any Derivative Works that You distribute must
571 | include a readable copy of the attribution notices contained
572 | within such NOTICE file, excluding those notices that do not
573 | pertain to any part of the Derivative Works, in at least one
574 | of the following places: within a NOTICE text file distributed
575 | as part of the Derivative Works; within the Source form or
576 | documentation, if provided along with the Derivative Works; or,
577 | within a display generated by the Derivative Works, if and
578 | wherever such third-party notices normally appear. The contents
579 | of the NOTICE file are for informational purposes only and
580 | do not modify the License. You may add Your own attribution
581 | notices within Derivative Works that You distribute, alongside
582 | or as an addendum to the NOTICE text from the Work, provided
583 | that such additional attribution notices cannot be construed
584 | as modifying the License.
585 |
586 | You may add Your own copyright statement to Your modifications and
587 | may provide additional or different license terms and conditions
588 | for use, reproduction, or distribution of Your modifications, or
589 | for any such Derivative Works as a whole, provided Your use,
590 | reproduction, and distribution of the Work otherwise complies with
591 | the conditions stated in this License.
592 |
593 | 5. Submission of Contributions. Unless You explicitly state otherwise,
594 | any Contribution intentionally submitted for inclusion in the Work
595 | by You to the Licensor shall be under the terms and conditions of
596 | this License, without any additional terms or conditions.
597 | Notwithstanding the above, nothing herein shall supersede or modify
598 | the terms of any separate license agreement you may have executed
599 | with Licensor regarding such Contributions.
600 |
601 | 6. Trademarks. This License does not grant permission to use the trade
602 | names, trademarks, service marks, or product names of the Licensor,
603 | except as required for reasonable and customary use in describing the
604 | origin of the Work and reproducing the content of the NOTICE file.
605 |
606 | 7. Disclaimer of Warranty. Unless required by applicable law or
607 | agreed to in writing, Licensor provides the Work (and each
608 | Contributor provides its Contributions) on an "AS IS" BASIS,
609 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
610 | implied, including, without limitation, any warranties or conditions
611 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
612 | PARTICULAR PURPOSE. You are solely responsible for determining the
613 | appropriateness of using or redistributing the Work and assume any
614 | risks associated with Your exercise of permissions under this License.
615 |
616 | 8. Limitation of Liability. In no event and under no legal theory,
617 | whether in tort (including negligence), contract, or otherwise,
618 | unless required by applicable law (such as deliberate and grossly
619 | negligent acts) or agreed to in writing, shall any Contributor be
620 | liable to You for damages, including any direct, indirect, special,
621 | incidental, or consequential damages of any character arising as a
622 | result of this License or out of the use or inability to use the
623 | Work (including but not limited to damages for loss of goodwill,
624 | work stoppage, computer failure or malfunction, or any and all
625 | other commercial damages or losses), even if such Contributor
626 | has been advised of the possibility of such damages.
627 |
628 | 9. Accepting Warranty or Additional Liability. While redistributing
629 | the Work or Derivative Works thereof, You may choose to offer,
630 | and charge a fee for, acceptance of support, warranty, indemnity,
631 | or other liability obligations and/or rights consistent with this
632 | License. However, in accepting such obligations, You may act only
633 | on Your own behalf and on Your sole responsibility, not on behalf
634 | of any other Contributor, and only if You agree to indemnify,
635 | defend, and hold each Contributor harmless for any liability
636 | incurred by, or claims asserted against, such Contributor by reason
637 | of your accepting any such warranty or additional liability.
638 |
639 | END OF TERMS AND CONDITIONS
640 |
641 | APPENDIX: How to apply the Apache License to your work.
642 |
643 | To apply the Apache License to your work, attach the following
644 | boilerplate notice, with the fields enclosed by brackets "[]"
645 | replaced with your own identifying information. (Don't include
646 | the brackets!) The text should be enclosed in the appropriate
647 | comment syntax for the file format. We also recommend that a
648 | file or class name and description of purpose be included on the
649 | same "printed page" as the copyright notice for easier
650 | identification within third-party archives.
651 |
652 | Copyright 2018 Google Inc.
653 |
654 | Licensed under the Apache License, Version 2.0 (the "License");
655 | you may not use this file except in compliance with the License.
656 | You may obtain a copy of the License at
657 |
658 | http://www.apache.org/licenses/LICENSE-2.0
659 |
660 | Unless required by applicable law or agreed to in writing, software
661 | distributed under the License is distributed on an "AS IS" BASIS,
662 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
663 | See the License for the specific language governing permissions and
664 | limitations under the License.
665 | ** Fastify; version 4.13.0 -- https://www.fastify.io/
666 | MIT License
667 |
668 | Copyright (c) 2016-2023 The Fastify Team
669 |
670 | The Fastify team members are listed at https://github.com/fastify/fastify#team
671 | and in the README file.
672 |
673 | Permission is hereby granted, free of charge, to any person obtaining a copy
674 | of this software and associated documentation files (the "Software"), to deal
675 | in the Software without restriction, including without limitation the rights
676 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
677 | copies of the Software, and to permit persons to whom the Software is
678 | furnished to do so, subject to the following conditions:
679 |
680 | The above copyright notice and this permission notice shall be included in all
681 | copies or substantial portions of the Software.
682 |
683 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
684 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
685 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
686 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
687 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
688 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
689 | SOFTWARE.
690 | ** @babel/plugin-transform-react-jsx; version 7.18.6 -- https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx
691 | MIT License
692 |
693 | Copyright (c) 2014-present Sebastian McKenzie and other contributors
694 |
695 | Permission is hereby granted, free of charge, to any person obtaining
696 | a copy of this software and associated documentation files (the
697 | "Software"), to deal in the Software without restriction, including
698 | without limitation the rights to use, copy, modify, merge, publish,
699 | distribute, sublicense, and/or sell copies of the Software, and to
700 | permit persons to whom the Software is furnished to do so, subject to
701 | the following conditions:
702 |
703 | The above copyright notice and this permission notice shall be
704 | included in all copies or substantial portions of the Software.
705 |
706 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
707 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
708 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
709 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
710 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
711 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
712 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
713 |
714 | MIT License
715 |
716 | Copyright (c)
717 |
718 | Permission is hereby granted, free of charge, to any person obtaining a copy of
719 | this software and associated documentation files (the "Software"), to deal in
720 | the Software without restriction, including without limitation the rights to
721 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
722 | the Software, and to permit persons to whom the Software is furnished to do so,
723 | subject to the following conditions:
724 |
725 | The above copyright notice and this permission notice shall be included in all
726 | copies or substantial portions of the Software.
727 |
728 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
729 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
730 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
731 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
732 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
733 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
734 |
735 | ------
736 |
737 | ** babel-loader; version 8.2.2 -- https://github.com/babel/babel-loader
738 | Copyright (c) 2014-2019 Luís Couto
739 |
740 | Copyright (c) 2014-2019 Luís Couto
741 |
742 | MIT License
743 |
744 | Permission is hereby granted, free of charge, to any person obtaining
745 | a copy of this software and associated documentation files (the
746 | "Software"), to deal in the Software without restriction, including
747 | without limitation the rights to use, copy, modify, merge, publish,
748 | distribute, sublicense, and/or sell copies of the Software, and to
749 | permit persons to whom the Software is furnished to do so, subject to
750 | the following conditions:
751 |
752 | The above copyright notice and this permission notice shall be
753 | included in all copies or substantial portions of the Software.
754 |
755 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
756 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
757 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
758 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
759 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
760 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
761 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
762 |
763 | ------
764 |
765 | ** axios; version 0.27.0 -- https://github.com/axios/axios
766 | Copyright (c) 2014-present Matt Zabriskie
767 |
768 | Copyright (c) 2014-present Matt Zabriskie
769 |
770 | Permission is hereby granted, free of charge, to any person obtaining a copy
771 | of this software and associated documentation files (the "Software"), to deal
772 | in the Software without restriction, including without limitation the rights
773 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
774 | copies of the Software, and to permit persons to whom the Software is
775 | furnished to do so, subject to the following conditions:
776 |
777 | The above copyright notice and this permission notice shall be included in
778 | all copies or substantial portions of the Software.
779 |
780 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
781 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
782 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
783 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
784 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
785 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
786 | THE SOFTWARE.
787 |
788 | ------
789 |
790 | ** @babel/core; version 7.18.13 -- https://github.com/babel/babel/tree/master/packages/babel-core
791 | Copyright (c) 2014-present Sebastian McKenzie and other contributors
792 | ** @babel/preset-env; version 7.18.10 -- https://github.com/babel/babel/tree/master/packages/babel-preset-env
793 | Copyright (c) 2014-present Sebastian McKenzie and other contributors
794 |
795 | MIT License
796 |
797 | Copyright (c) 2014-present Sebastian McKenzie and other contributors
798 |
799 | Permission is hereby granted, free of charge, to any person obtaining
800 | a copy of this software and associated documentation files (the
801 | "Software"), to deal in the Software without restriction, including
802 | without limitation the rights to use, copy, modify, merge, publish,
803 | distribute, sublicense, and/or sell copies of the Software, and to
804 | permit persons to whom the Software is furnished to do so, subject to
805 | the following conditions:
806 |
807 | The above copyright notice and this permission notice shall be
808 | included in all copies or substantial portions of the Software.
809 |
810 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
811 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
812 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
813 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
814 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
815 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
816 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
817 |
818 | ------
819 |
820 | ** webpack-cli; version 4.10.0 -- https://github.com/webpack/webpack-cli
821 | Copyright JS Foundation and other contributors
822 |
823 | Copyright JS Foundation and other contributors
824 |
825 | Permission is hereby granted, free of charge, to any person obtaining
826 | a copy of this software and associated documentation files (the
827 | 'Software'), to deal in the Software without restriction, including
828 | without limitation the rights to use, copy, modify, merge, publish,
829 | distribute, sublicense, and/or sell copies of the Software, and to
830 | permit persons to whom the Software is furnished to do so, subject to
831 | the following conditions:
832 |
833 | The above copyright notice and this permission notice shall be
834 | included in all copies or substantial portions of the Software.
835 |
836 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
837 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
838 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
839 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
840 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
841 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
842 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
843 |
844 | ------
845 |
846 | ** webpack; version 5.74.0 -- https://github.com/webpack/webpack
847 | Copyright JS Foundation and other contributors
848 |
849 | Permission is hereby granted, free of charge, to any person obtaining
850 | a copy of this software and associated documentation files (the
851 | 'Software'), to deal in the Software without restriction, including
852 | without limitation the rights to use, copy, modify, merge, publish,
853 | distribute, sublicense, and/or sell copies of the Software, and to
854 | permit persons to whom the Software is furnished to do so, subject to
855 | the following conditions:
856 |
857 | The above copyright notice and this permission notice shall be
858 | included in all copies or substantial portions of the Software.
859 |
860 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
861 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
862 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
863 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
864 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
865 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
866 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
867 |
--------------------------------------------------------------------------------